add nanopb (manual)

This commit is contained in:
Philippe G
2022-01-04 11:01:14 -08:00
parent 06b637c55b
commit 39f5a81238
554 changed files with 36793 additions and 3831 deletions

View File

@@ -0,0 +1,21 @@
all:
scons
clean:
scons -c
coverage:
rm -rf build coverage
# LCOV does not like the newer gcov format
scons CC=gcc-4.6 CXX=gcc-4.6
# Collect the data
mkdir build/coverage
lcov --base-directory . --directory build/ --gcov-tool gcov-4.6 -c -o build/coverage/nanopb.info
# Remove the test code from results
lcov -r build/coverage/nanopb.info '*tests*' -o build/coverage/nanopb.info
# Generate HTML
genhtml -o build/coverage build/coverage/nanopb.info

View File

@@ -0,0 +1,236 @@
Help('''
Type 'scons' to build and run all the available test cases.
It will automatically detect your platform and C compiler and
build appropriately.
You can modify the behaviour using following options:
BUILDDIR Directory to build into (default "build")
CC Name of C compiler
CXX Name of C++ compiler
CCFLAGS Flags to pass to the C compiler
CXXFLAGS Flags to pass to the C++ compiler
LINK Name of linker (usually same as CC)
LINKFLAGS Flags to pass to linker
LINKLIBS Flags to pass to linker after object files
PROTOC Path to protoc binary
PROTOCFLAGS Arguments to pass protoc
NODEFARGS Do not add the default CCFLAGS
NOVALGRIND Do not use valgrind for memory checks
For example, for a clang build, use:
scons CC=clang CXX=clang++
''')
import os
import platform
env = Environment(ENV = os.environ)
# Allow giving environment flags on command line.
list_vars = ['CCFLAGS', 'CXXFLAGS', 'LINKFLAGS', 'LINKLIBS', 'PROTOCFLAGS']
for var,val in ARGUMENTS.items():
if var in list_vars:
env.Append(**{var: val})
else:
env.Replace(**{var: val})
env.SetDefault(BUILDDIR = "build")
env.SConsignFile(env['BUILDDIR'] + "/sconsign")
env.Replace(CONFIGUREDIR = env['BUILDDIR'] + "/config")
# If a cross compilation platform is given, apply the environment settings
# from site_scons/platforms/X/X.py
if ARGUMENTS.get('PLATFORM'):
platform_func = platforms.get(ARGUMENTS.get('PLATFORM'))
if not platform_func:
print("Supported platforms: " + str(platforms.keys()))
raise Exception("Unsupported platform: " + ARGUMENTS.get('PLATFORM'))
else:
platform_func(env)
# Load nanopb generator build rules from site_scons/site_tools/nanopb.py
env.Tool("nanopb")
# Limit memory usage. This is to catch problems like issue #338
try:
import resource
soft, hard = resource.getrlimit(resourse.RLIMIT_AS)
resource.setrlimit(resource.RLIMIT_AS, (100*1024*1024, hard))
except:
pass
# On Mac OS X, gcc is usually alias for clang.
# To avoid problem with default options, use clang directly.
if platform.system() == "Darwin" and 'CC' not in ARGUMENTS:
env.Replace(CC = "clang", CXX = "clang++")
# Add the builders defined in site_init.py
add_nanopb_builders(env)
# Path to the files shared by tests, and to the nanopb core.
env.Append(CPPPATH = ["#../", "$COMMON"])
# Path for finding nanopb.proto
env.Append(PROTOCPATH = '#../generator')
# Check the compilation environment, unless we are just cleaning up.
if not env.GetOption('clean'):
def check_ccflags(context, flags, linkflags = ''):
'''Check if given CCFLAGS are supported'''
context.Message('Checking support for CCFLAGS="%s"... ' % flags)
oldflags = context.env['CCFLAGS']
oldlinkflags = context.env['LINKFLAGS']
context.env.Append(CCFLAGS = flags)
context.env.Append(LINKFLAGS = linkflags)
result = context.TryCompile("int main() {return 0;}", '.c')
context.env.Replace(CCFLAGS = oldflags)
context.env.Replace(LINKFLAGS = oldlinkflags)
context.Result(result)
return result
def check_protocversion(context):
context.Display("Checking protoc version... ")
status, output = context.TryAction('$PROTOC --version > $TARGET')
if status:
context.Result(str(output.strip()))
return str(output.strip())
else:
context.Display("error: %s\n" % output.strip())
context.did_show_result = 1
context.Result("unknown, assuming 3.6.1")
return "3.6.1"
conf = Configure(env, custom_tests =
{'CheckCCFLAGS': check_ccflags,
'CheckProtocVersion': check_protocversion})
# If the platform doesn't support C99, use our own header file instead.
stdbool = conf.CheckCHeader('stdbool.h')
stdint = conf.CheckCHeader('stdint.h')
stddef = conf.CheckCHeader('stddef.h')
string = conf.CheckCHeader('string.h')
stdlib = conf.CheckCHeader('stdlib.h')
limits = conf.CheckCHeader('limits.h')
if not stdbool or not stdint or not stddef or not string or not limits:
conf.env.Append(CPPDEFINES = {'PB_SYSTEM_HEADER': '\\"pb_syshdr.h\\"'})
conf.env.Append(CPPPATH = "#../extra")
conf.env.Append(SYSHDR = '\\"pb_syshdr.h\\"')
if stdbool: conf.env.Append(CPPDEFINES = {'HAVE_STDBOOL_H': 1})
if stdint: conf.env.Append(CPPDEFINES = {'HAVE_STDINT_H': 1})
if stddef: conf.env.Append(CPPDEFINES = {'HAVE_STDDEF_H': 1})
if string: conf.env.Append(CPPDEFINES = {'HAVE_STRING_H': 1})
if stdlib: conf.env.Append(CPPDEFINES = {'HAVE_STDLIB_H': 1})
if limits: conf.env.Append(CPPDEFINES = {'HAVE_LIMITS_H': 1})
# Check protoc version
conf.env['PROTOC_VERSION'] = conf.CheckProtocVersion()
# Initialize compiler arguments with defaults, unless overridden on
# command line.
if not env.get('NODEFARGS'):
# Check if libmudflap is available (only with GCC)
if 'gcc' in env['CC']:
if conf.CheckLib('mudflap'):
conf.env.Append(CCFLAGS = '-fmudflap')
conf.env.Append(LINKFLAGS = '-fmudflap')
# Check if we can use extra strict warning flags (only with GCC)
extra = '-Wcast-qual -Wlogical-op -Wconversion'
extra += ' -fstrict-aliasing -Wstrict-aliasing=1'
extra += ' -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls'
extra += ' -Wstack-protector '
if 'gcc' in env['CC']:
if conf.CheckCCFLAGS(extra):
conf.env.Append(CORECFLAGS = extra)
# Check if we can use undefined behaviour sanitizer (only with clang)
# TODO: Fuzz test triggers the bool sanitizer, figure out whether to
# modify the fuzz test or to keep ignoring the check.
extra = '-fsanitize=undefined,integer -fno-sanitize-recover=undefined,integer '
if 'clang' in env['CC']:
if conf.CheckCCFLAGS(extra, linkflags = extra):
conf.env.Append(CORECFLAGS = extra)
conf.env.Append(LINKFLAGS = extra)
# End the config stuff
env = conf.Finish()
if not env.get('NODEFARGS'):
# Initialize the CCFLAGS according to the compiler
if 'gcc' in env['CC']:
# GNU Compiler Collection
# Debug info, warnings as errors
env.Append(CFLAGS = '-g -Wall -Werror ')
env.Append(CORECFLAGS = '-Wextra')
# Pedantic ANSI C. On AVR this doesn't work because we use large
# enums in some of the tests.
if env.get("EMBEDDED") != "AVR":
env.Append(CFLAGS = '-ansi -pedantic')
# Profiling and coverage
if not env.get("EMBEDDED"):
env.Append(CFLAGS = '-fprofile-arcs -ftest-coverage ')
env.Append(LINKFLAGS = '-g --coverage')
# We currently need uint64_t anyway, even though ANSI C90 otherwise..
env.Append(CFLAGS = '-Wno-long-long')
elif 'clang' in env['CC']:
# CLang
env.Append(CFLAGS = '-ansi -g -Wall -Werror')
env.Append(CORECFLAGS = ' -Wextra -Wcast-qual -Wconversion')
elif 'cl' in env['CC']:
# Microsoft Visual C++
# Debug info on, warning level 2 for tests, warnings as errors
env.Append(CFLAGS = '/Zi /W2 /WX')
env.Append(LINKFLAGS = '/DEBUG')
# More strict checks on the nanopb core
env.Append(CORECFLAGS = '/W4')
# Disable warning about sizeof(union{}) construct that is used in
# message size macros, in e.g. multiple_files testcase. The C construct
# itself is valid, but quite rare, which causes Visual C++ to give a warning
# about it.
env.Append(CFLAGS = '/wd4116')
elif 'tcc' in env['CC']:
# Tiny C Compiler
env.Append(CFLAGS = '-Wall -Werror -g')
if 'clang' in env['CXX']:
env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers')
elif 'g++' in env['CXX'] or 'gcc' in env['CXX']:
env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers')
elif 'cl' in env['CXX']:
env.Append(CXXFLAGS = '/Zi /W2 /WX /wd4116 /wd4127')
env.SetDefault(CORECFLAGS = '')
if not env.get("EMBEDDED") and not env.get("NOVALGRIND"):
valgrind = env.WhereIs('valgrind')
if valgrind:
env.SetDefault(VALGRIND = valgrind)
# Make it possible to add commands to the end of linker line
env.SetDefault(LINKLIBS = '')
env.Replace(LINKCOM = env['LINKCOM'] + " $LINKLIBS")
# Place build files under separate folder
import os.path
env['VARIANT_DIR'] = env['BUILDDIR']
env['BUILD'] = '#' + env['VARIANT_DIR']
env['COMMON'] = '#' + env['VARIANT_DIR'] + '/common'
# Include common/SConscript first to make sure its exports are available
# to other SConscripts.
SConscript("common/SConscript", exports = 'env', variant_dir = env['VARIANT_DIR'] + '/common')
# Now include the SConscript files from all subdirectories
for subdir in Glob('*/SConscript') + Glob('regression/*/SConscript'):
if str(subdir).startswith("common/"): continue
if str(subdir).startswith("common\\"): continue
SConscript(subdir, exports = 'env', variant_dir = env['VARIANT_DIR'] + '/' + os.path.dirname(str(subdir)))

View File

@@ -0,0 +1,45 @@
# Build and run a test that encodes and decodes a message that contains
# all of the Protocol Buffers data types.
Import("env")
env.NanopbProto(["alltypes", "alltypes.options"])
enc = env.Program(["encode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
# Test the round-trip from nanopb encoder to nanopb decoder
env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"])
# Re-encode the data using protoc, and check that the results from nanopb
# match byte-per-byte to the protoc output.
env.Decode("encode_alltypes.output.decoded",
["encode_alltypes.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("encode_alltypes.output.recoded",
["encode_alltypes.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["encode_alltypes.output", "encode_alltypes.output.recoded"])
# Do the same checks with the optional fields present.
env.RunTest("optionals.output", enc, ARGS = ['1'])
env.RunTest("optionals.decout", [dec, "optionals.output"], ARGS = ['1'])
env.Decode("optionals.output.decoded",
["optionals.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("optionals.output.recoded",
["optionals.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["optionals.output", "optionals.output.recoded"])
# And for the _zero initializer
env.RunTest("zeroinit.output", enc, ARGS = ['2'])
env.RunTest("zeroinit.decout", [dec, "zeroinit.output"], ARGS = ['2'])
env.Decode("zeroinit.output.decoded",
["zeroinit.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("zeroinit.output.recoded",
["zeroinit.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["zeroinit.output", "zeroinit.output.recoded"])

View File

@@ -0,0 +1,8 @@
* max_size:16
* max_count:5
*.*fbytes fixed_length:true max_size:4
*.*farray fixed_count:true max_count:5
*.*farray2 fixed_count:true max_count:3
IntSizes.*int8 int_size:IS_8
IntSizes.*int16 int_size:IS_16
DescriptorSize8 descriptorsize:DS_8

View File

@@ -0,0 +1,166 @@
syntax = "proto2";
// package name placeholder
enum NonZeroBasedEnum {
Two = 2;
Three = 3;
Four = 4;
}
message SubMessage {
required string substuff1 = 1 [default = "1"];
required int32 substuff2 = 2 [default = 2];
optional fixed32 substuff3 = 3 [default = 3];
}
message EmptyMessage {
}
enum HugeEnum {
Negative = -2147483647; /* protoc doesn't accept -2147483648 here */
Positive = 2147483647;
}
message Limits {
required int32 int32_min = 1 [default = 2147483647];
required int32 int32_max = 2 [default = -2147483647];
required uint32 uint32_min = 3 [default = 4294967295];
required uint32 uint32_max = 4 [default = 0];
required int64 int64_min = 5 [default = 9223372036854775807];
required int64 int64_max = 6 [default = -9223372036854775807];
required uint64 uint64_min = 7 [default = 18446744073709551615];
required uint64 uint64_max = 8 [default = 0];
required HugeEnum enum_min = 9 [default = Positive];
required HugeEnum enum_max = 10 [default = Negative];
required int32 largetag = 65535 [default = 0];
}
message IntSizes {
required int32 req_int8 = 1 ;
required uint32 req_uint8 = 2 ;
required sint32 req_sint8 = 3 ;
required int32 req_int16 = 4 ;
required uint32 req_uint16 = 5 ;
required sint32 req_sint16 = 6 ;
}
message DescriptorSize8 {
required int32 first = 1;
required int32 second = 22222;
}
enum MyEnum {
Zero = 0;
First = 1;
Second = 2;
Truth = 42;
}
message AllTypes {
required int32 req_int32 = 1;
required int64 req_int64 = 2;
required uint32 req_uint32 = 3;
required uint64 req_uint64 = 4;
required sint32 req_sint32 = 5;
required sint64 req_sint64 = 6;
required bool req_bool = 7;
required fixed32 req_fixed32 = 8;
required sfixed32 req_sfixed32= 9;
required float req_float = 10;
required fixed64 req_fixed64 = 11;
required sfixed64 req_sfixed64= 12;
required double req_double = 13;
required string req_string = 14;
required bytes req_bytes = 15;
required SubMessage req_submsg = 16;
required MyEnum req_enum = 17;
required EmptyMessage req_emptymsg = 18;
required bytes req_fbytes = 19;
repeated int32 rep_int32 = 21 [packed = true];
repeated int64 rep_int64 = 22 [packed = true];
repeated uint32 rep_uint32 = 23 [packed = true];
repeated uint64 rep_uint64 = 24 [packed = true];
repeated sint32 rep_sint32 = 25 [packed = true];
repeated sint64 rep_sint64 = 26 [packed = true];
repeated bool rep_bool = 27 [packed = true];
repeated fixed32 rep_fixed32 = 28 [packed = true];
repeated sfixed32 rep_sfixed32= 29 [packed = true];
repeated float rep_float = 30 [packed = true];
repeated fixed64 rep_fixed64 = 31 [packed = true];
repeated sfixed64 rep_sfixed64= 32 [packed = true];
repeated double rep_double = 33 [packed = true];
repeated string rep_string = 34;
repeated bytes rep_bytes = 35;
repeated SubMessage rep_submsg = 36;
repeated MyEnum rep_enum = 37 [packed = true];
repeated EmptyMessage rep_emptymsg = 38;
repeated bytes rep_fbytes = 39;
repeated int32 rep_farray = 40 [packed = true];
optional int32 opt_int32 = 41 [default = 4041];
optional int64 opt_int64 = 42 [default = 4042];
optional uint32 opt_uint32 = 43 [default = 4043];
optional uint64 opt_uint64 = 44 [default = 4044];
optional sint32 opt_sint32 = 45 [default = 4045];
optional sint64 opt_sint64 = 46 [default = 4046];
optional bool opt_bool = 47 [default = false];
optional fixed32 opt_fixed32 = 48 [default = 4048];
optional sfixed32 opt_sfixed32= 49 [default = 4049];
optional float opt_float = 50 [default = 4050];
optional fixed64 opt_fixed64 = 51 [default = 4051];
optional sfixed64 opt_sfixed64= 52 [default = 4052];
optional double opt_double = 53 [default = 4053];
optional string opt_string = 54 [default = "4054"];
optional bytes opt_bytes = 55 [default = "\x34\x5C\x00\xff"];
optional SubMessage opt_submsg = 56;
optional MyEnum opt_enum = 57 [default = Second];
optional EmptyMessage opt_emptymsg = 58;
optional bytes opt_fbytes = 59 [default = "4059"];
oneof oneof
{
SubMessage oneof_msg1 = 60;
EmptyMessage oneof_msg2 = 61;
SubMessage static_msg = 63;
}
optional NonZeroBasedEnum opt_non_zero_based_enum = 62;
// Second fixed length array field to test the length check logic.
repeated fixed32 rep_farray2 = 95 [packed = true];
// Check support for custom integer sizes
required IntSizes req_intsizes = 96;
// Check support for 8-word descriptors
required DescriptorSize8 req_ds8 = 97;
// Check that extreme integer values are handled correctly
// Also checks support for 4-word descriptors
required Limits req_limits = 98;
// Just to make sure that the size of the fields has been calculated
// properly, i.e. otherwise a bug in last field might not be detected.
required int32 end = 999;
extensions 200 to 255;
}
message TestExtension {
extend AllTypes {
optional TestExtension testextension = 250;
}
optional string strval = 1;
}

View File

@@ -0,0 +1,332 @@
/* Tests the decoding of all types.
* This is the counterpart of test_encode3.
* Run e.g. ./test_encode3 | ./test_decode3
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "alltypes.pb.h"
#include "unittests.h"
#include "test_helpers.h"
/* This function is called once from main(), it handles
the decoding and checks the fields. */
bool check_alltypes(pb_istream_t *stream, int mode)
{
int status = 0;
/* Uses _init_default to just make sure that the macro works. */
AllTypes alltypes = AllTypes_init_default;
/* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes));
alltypes.extensions = 0;
if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false;
if (mode == 0 || mode == 1)
{
TEST(alltypes.req_int32 == -1001);
TEST(alltypes.req_int64 == -1002);
TEST(alltypes.req_uint32 == 1003);
TEST(alltypes.req_uint64 == 1004);
TEST(alltypes.req_sint32 == -1005);
TEST(alltypes.req_sint64 == -1006);
TEST(alltypes.req_bool == true);
TEST(alltypes.req_fixed32 == 1008);
TEST(alltypes.req_sfixed32 == -1009);
TEST(alltypes.req_float == 1010.0f);
TEST(alltypes.req_fixed64 == 1011);
TEST(alltypes.req_sfixed64 == -1012);
TEST(alltypes.req_double == 1013.0f);
TEST(strcmp(alltypes.req_string, "1014") == 0);
TEST(alltypes.req_bytes.size == 4);
TEST(memcmp(alltypes.req_bytes.bytes, "1015", 4) == 0);
TEST(strcmp(alltypes.req_submsg.substuff1, "1016") == 0);
TEST(alltypes.req_submsg.substuff2 == 1016);
TEST(alltypes.req_submsg.substuff3 == 3);
TEST(alltypes.req_enum == MyEnum_Truth);
TEST(memcmp(alltypes.req_fbytes, "1019", 4) == 0);
TEST(alltypes.rep_int32_count == 5 && alltypes.rep_int32[4] == -2001 && alltypes.rep_int32[0] == 0);
TEST(alltypes.rep_int64_count == 5 && alltypes.rep_int64[4] == -2002 && alltypes.rep_int64[0] == 0);
TEST(alltypes.rep_uint32_count == 5 && alltypes.rep_uint32[4] == 2003 && alltypes.rep_uint32[0] == 0);
TEST(alltypes.rep_uint64_count == 5 && alltypes.rep_uint64[4] == 2004 && alltypes.rep_uint64[0] == 0);
TEST(alltypes.rep_sint32_count == 5 && alltypes.rep_sint32[4] == -2005 && alltypes.rep_sint32[0] == 0);
TEST(alltypes.rep_sint64_count == 5 && alltypes.rep_sint64[4] == -2006 && alltypes.rep_sint64[0] == 0);
TEST(alltypes.rep_bool_count == 5 && alltypes.rep_bool[4] == true && alltypes.rep_bool[0] == false);
TEST(alltypes.rep_fixed32_count == 5 && alltypes.rep_fixed32[4] == 2008 && alltypes.rep_fixed32[0] == 0);
TEST(alltypes.rep_sfixed32_count == 5 && alltypes.rep_sfixed32[4] == -2009 && alltypes.rep_sfixed32[0] == 0);
TEST(alltypes.rep_float_count == 5 && alltypes.rep_float[4] == 2010.0f && alltypes.rep_float[0] == 0.0f);
TEST(alltypes.rep_fixed64_count == 5 && alltypes.rep_fixed64[4] == 2011 && alltypes.rep_fixed64[0] == 0);
TEST(alltypes.rep_sfixed64_count == 5 && alltypes.rep_sfixed64[4] == -2012 && alltypes.rep_sfixed64[0] == 0);
TEST(alltypes.rep_double_count == 5 && alltypes.rep_double[4] == 2013.0 && alltypes.rep_double[0] == 0.0);
TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0');
TEST(alltypes.rep_bytes_count == 5 && alltypes.rep_bytes[4].size == 4 && alltypes.rep_bytes[0].size == 0);
TEST(memcmp(alltypes.rep_bytes[4].bytes, "2015", 4) == 0);
TEST(alltypes.rep_submsg_count == 5);
TEST(strcmp(alltypes.rep_submsg[4].substuff1, "2016") == 0 && alltypes.rep_submsg[0].substuff1[0] == '\0');
TEST(alltypes.rep_submsg[4].substuff2 == 2016 && alltypes.rep_submsg[0].substuff2 == 0);
TEST(alltypes.rep_submsg[4].substuff3 == 2016 && alltypes.rep_submsg[0].substuff3 == 3);
TEST(alltypes.rep_enum_count == 5 && alltypes.rep_enum[4] == MyEnum_Truth && alltypes.rep_enum[0] == MyEnum_Zero);
TEST(alltypes.rep_emptymsg_count == 5);
TEST(alltypes.rep_fbytes_count == 5);
TEST(alltypes.rep_fbytes[0][0] == 0 && alltypes.rep_fbytes[0][3] == 0);
TEST(memcmp(alltypes.rep_fbytes[4], "2019", 4) == 0);
TEST(alltypes.rep_farray[0] == 0 && alltypes.rep_farray[4] == 2040);
TEST(alltypes.rep_farray2[0] == 0 && alltypes.rep_farray2[2] == 2095);
TEST(alltypes.req_limits.int32_min == INT32_MIN);
TEST(alltypes.req_limits.int32_max == INT32_MAX);
TEST(alltypes.req_limits.uint32_min == 0);
TEST(alltypes.req_limits.uint32_max == UINT32_MAX);
TEST(alltypes.req_limits.int64_min == INT64_MIN);
TEST(alltypes.req_limits.int64_max == INT64_MAX);
TEST(alltypes.req_limits.uint64_min == 0);
TEST(alltypes.req_limits.uint64_max == UINT64_MAX);
TEST(alltypes.req_limits.enum_min == HugeEnum_Negative);
TEST(alltypes.req_limits.enum_max == HugeEnum_Positive);
TEST(alltypes.req_limits.largetag == 1001);
TEST(alltypes.req_ds8.first == 9991);
TEST(alltypes.req_ds8.second == 9992);
TEST(alltypes.req_intsizes.req_int8 == -128);
TEST(alltypes.req_intsizes.req_uint8 == 255);
TEST(alltypes.req_intsizes.req_sint8 == -128);
TEST(alltypes.req_intsizes.req_int16 == -32768);
TEST(alltypes.req_intsizes.req_uint16 == 65535);
TEST(alltypes.req_intsizes.req_sint16 == -32768);
}
if (mode == 0)
{
/* Expect default values */
TEST(alltypes.has_opt_int32 == false);
TEST(alltypes.opt_int32 == 4041);
TEST(alltypes.has_opt_int64 == false);
TEST(alltypes.opt_int64 == 4042);
TEST(alltypes.has_opt_uint32 == false);
TEST(alltypes.opt_uint32 == 4043);
TEST(alltypes.has_opt_uint64 == false);
TEST(alltypes.opt_uint64 == 4044);
TEST(alltypes.has_opt_sint32 == false);
TEST(alltypes.opt_sint32 == 4045);
TEST(alltypes.has_opt_sint64 == false);
TEST(alltypes.opt_sint64 == 4046);
TEST(alltypes.has_opt_bool == false);
TEST(alltypes.opt_bool == false);
TEST(alltypes.has_opt_fixed32 == false);
TEST(alltypes.opt_fixed32 == 4048);
TEST(alltypes.has_opt_sfixed32 == false);
TEST(alltypes.opt_sfixed32 == 4049);
TEST(alltypes.has_opt_float == false);
TEST(alltypes.opt_float == 4050.0f);
TEST(alltypes.has_opt_fixed64 == false);
TEST(alltypes.opt_fixed64 == 4051);
TEST(alltypes.has_opt_sfixed64 == false);
TEST(alltypes.opt_sfixed64 == 4052);
TEST(alltypes.has_opt_double == false);
TEST(alltypes.opt_double == 4053.0);
TEST(alltypes.has_opt_string == false);
TEST(strcmp(alltypes.opt_string, "4054") == 0);
TEST(alltypes.has_opt_bytes == false);
TEST(alltypes.opt_bytes.size == 4);
TEST(memcmp(alltypes.opt_bytes.bytes, "\x34\x5C\x00\xff", 4) == 0);
TEST(alltypes.has_opt_submsg == false);
TEST(strcmp(alltypes.opt_submsg.substuff1, "1") == 0);
TEST(alltypes.opt_submsg.substuff2 == 2);
TEST(alltypes.opt_submsg.substuff3 == 3);
TEST(alltypes.has_opt_enum == false);
TEST(alltypes.opt_enum == MyEnum_Second);
TEST(alltypes.has_opt_emptymsg == false);
TEST(alltypes.has_opt_fbytes == false);
TEST(memcmp(alltypes.opt_fbytes, "4059", 4) == 0);
TEST(alltypes.which_oneof == 0);
TEST(alltypes.has_opt_non_zero_based_enum == false);
TEST(alltypes.opt_non_zero_based_enum == NonZeroBasedEnum_Two);
}
else if (mode == 1)
{
/* Expect filled-in values */
TEST(alltypes.has_opt_int32 == true);
TEST(alltypes.opt_int32 == 3041);
TEST(alltypes.has_opt_int64 == true);
TEST(alltypes.opt_int64 == 3042);
TEST(alltypes.has_opt_uint32 == true);
TEST(alltypes.opt_uint32 == 3043);
TEST(alltypes.has_opt_uint64 == true);
TEST(alltypes.opt_uint64 == 3044);
TEST(alltypes.has_opt_sint32 == true);
TEST(alltypes.opt_sint32 == 3045);
TEST(alltypes.has_opt_sint64 == true);
TEST(alltypes.opt_sint64 == 3046);
TEST(alltypes.has_opt_bool == true);
TEST(alltypes.opt_bool == true);
TEST(alltypes.has_opt_fixed32 == true);
TEST(alltypes.opt_fixed32 == 3048);
TEST(alltypes.has_opt_sfixed32 == true);
TEST(alltypes.opt_sfixed32 == 3049);
TEST(alltypes.has_opt_float == true);
TEST(alltypes.opt_float == 3050.0f);
TEST(alltypes.has_opt_fixed64 == true);
TEST(alltypes.opt_fixed64 == 3051);
TEST(alltypes.has_opt_sfixed64 == true);
TEST(alltypes.opt_sfixed64 == 3052);
TEST(alltypes.has_opt_double == true);
TEST(alltypes.opt_double == 3053.0);
TEST(alltypes.has_opt_string == true);
TEST(strcmp(alltypes.opt_string, "3054") == 0);
TEST(alltypes.has_opt_bytes == true);
TEST(alltypes.opt_bytes.size == 4);
TEST(memcmp(alltypes.opt_bytes.bytes, "3055", 4) == 0);
TEST(alltypes.has_opt_submsg == true);
TEST(strcmp(alltypes.opt_submsg.substuff1, "3056") == 0);
TEST(alltypes.opt_submsg.substuff2 == 3056);
TEST(alltypes.opt_submsg.substuff3 == 3);
TEST(alltypes.has_opt_enum == true);
TEST(alltypes.opt_enum == MyEnum_Truth);
TEST(alltypes.has_opt_emptymsg == true);
TEST(alltypes.has_opt_fbytes == true);
TEST(memcmp(alltypes.opt_fbytes, "3059", 4) == 0);
TEST(alltypes.which_oneof == AllTypes_oneof_msg1_tag);
TEST(strcmp(alltypes.oneof.oneof_msg1.substuff1, "4059") == 0);
TEST(alltypes.oneof.oneof_msg1.substuff2 == 4059);
TEST(alltypes.oneof.oneof_msg1.substuff3 == 3);
TEST(alltypes.has_opt_non_zero_based_enum == true);
TEST(alltypes.opt_non_zero_based_enum == NonZeroBasedEnum_Three);
}
else if (mode == 2)
{
/* Expect zero values */
TEST(alltypes.req_int32 == 0);
TEST(alltypes.req_int64 == 0);
TEST(alltypes.req_uint32 == 0);
TEST(alltypes.req_uint64 == 0);
TEST(alltypes.req_sint32 == 0);
TEST(alltypes.req_sint64 == 0);
TEST(alltypes.req_bool == false);
TEST(alltypes.req_fixed32 == 0);
TEST(alltypes.req_sfixed32 == 0);
TEST(alltypes.req_float == 0.0f);
TEST(alltypes.req_fixed64 == 0);
TEST(alltypes.req_sfixed64 == 0);
TEST(alltypes.req_double == 0.0f);
TEST(strcmp(alltypes.req_string, "") == 0);
TEST(alltypes.req_bytes.size == 0);
TEST(strcmp(alltypes.req_submsg.substuff1, "") == 0);
TEST(alltypes.req_submsg.substuff2 == 0);
TEST(alltypes.req_enum == MyEnum_Zero);
TEST(alltypes.rep_int32_count == 0);
TEST(alltypes.rep_int64_count == 0);
TEST(alltypes.rep_uint32_count == 0);
TEST(alltypes.rep_uint64_count == 0);
TEST(alltypes.rep_sint32_count == 0);
TEST(alltypes.rep_sint64_count == 0);
TEST(alltypes.rep_bool_count == 0);
TEST(alltypes.rep_fixed32_count == 0);
TEST(alltypes.rep_sfixed32_count == 0);
TEST(alltypes.rep_float_count == 0);
TEST(alltypes.rep_fixed64_count == 0);
TEST(alltypes.rep_sfixed64_count == 0);
TEST(alltypes.rep_double_count == 0);
TEST(alltypes.rep_string_count == 0);
TEST(alltypes.rep_bytes_count == 0);
TEST(alltypes.rep_submsg_count == 0);
TEST(alltypes.rep_enum_count == 0);
TEST(alltypes.rep_emptymsg_count == 0);
TEST(alltypes.rep_fbytes_count == 0);
TEST(alltypes.rep_farray[0] == 0 && alltypes.rep_farray[4] == 0);
TEST(alltypes.has_opt_int32 == false);
TEST(alltypes.has_opt_int64 == false);
TEST(alltypes.has_opt_uint32 == false);
TEST(alltypes.has_opt_uint64 == false);
TEST(alltypes.has_opt_sint32 == false);
TEST(alltypes.has_opt_sint64 == false);
TEST(alltypes.has_opt_bool == false);
TEST(alltypes.has_opt_fixed32 == false);
TEST(alltypes.has_opt_sfixed32 == false);
TEST(alltypes.has_opt_float == false);
TEST(alltypes.has_opt_fixed64 == false);
TEST(alltypes.has_opt_sfixed64 == false);
TEST(alltypes.has_opt_double == false);
TEST(alltypes.has_opt_string == false);
TEST(alltypes.has_opt_bytes == false);
TEST(alltypes.has_opt_submsg == false);
TEST(alltypes.has_opt_enum == false);
TEST(alltypes.has_opt_emptymsg == false);
TEST(alltypes.has_opt_fbytes == false);
TEST(alltypes.which_oneof == 0);
TEST(alltypes.has_opt_non_zero_based_enum == false);
}
TEST(alltypes.end == 1099);
return status == 0;
}
#ifdef __cplusplus
extern "C"
#endif
int main(int argc, char **argv)
{
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
/* Whether to expect the optional values or the default values. */
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
/* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count);
/* Decode and print out the stuff */
if (!check_alltypes(&stream, mode))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
} else {
return 0;
}
}

View File

@@ -0,0 +1,178 @@
/* Attempts to test all the datatypes supported by ProtoBuf.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_encode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
#ifdef __cplusplus
extern "C"
#endif
int main(int argc, char **argv)
{
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Initialize the structure with constants */
AllTypes alltypes = AllTypes_init_zero;
if (mode == 0 || mode == 1)
{
alltypes.req_int32 = -1001;
alltypes.req_int64 = -1002;
alltypes.req_uint32 = 1003;
alltypes.req_uint64 = 1004;
alltypes.req_sint32 = -1005;
alltypes.req_sint64 = -1006;
alltypes.req_bool = true;
alltypes.req_fixed32 = 1008;
alltypes.req_sfixed32 = -1009;
alltypes.req_float = 1010.0f;
alltypes.req_fixed64 = 1011;
alltypes.req_sfixed64 = -1012;
alltypes.req_double = 1013.0;
strcpy(alltypes.req_string, "1014");
alltypes.req_bytes.size = 4;
memcpy(alltypes.req_bytes.bytes, "1015", 4);
strcpy(alltypes.req_submsg.substuff1, "1016");
alltypes.req_submsg.substuff2 = 1016;
alltypes.req_enum = MyEnum_Truth;
memcpy(alltypes.req_fbytes, "1019", 4);
alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = -2001;
alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = -2002;
alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003;
alltypes.rep_uint64_count = 5; alltypes.rep_uint64[4] = 2004;
alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = -2005;
alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = -2006;
alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true;
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32[4] = 2008;
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32[4] = -2009;
alltypes.rep_float_count = 5; alltypes.rep_float[4] = 2010.0f;
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64[4] = 2011;
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64[4] = -2012;
alltypes.rep_double_count = 5; alltypes.rep_double[4] = 2013.0;
alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014");
alltypes.rep_bytes_count = 5; alltypes.rep_bytes[4].size = 4;
memcpy(alltypes.rep_bytes[4].bytes, "2015", 4);
alltypes.rep_submsg_count = 5;
strcpy(alltypes.rep_submsg[4].substuff1, "2016");
alltypes.rep_submsg[4].substuff2 = 2016;
alltypes.rep_submsg[4].has_substuff3 = true;
alltypes.rep_submsg[4].substuff3 = 2016;
alltypes.rep_enum_count = 5; alltypes.rep_enum[4] = MyEnum_Truth;
alltypes.rep_emptymsg_count = 5;
alltypes.rep_fbytes_count = 5;
memcpy(alltypes.rep_fbytes[4], "2019", 4);
alltypes.rep_farray[4] = 2040;
alltypes.rep_farray2[2] = 2095;
alltypes.req_limits.int32_min = INT32_MIN;
alltypes.req_limits.int32_max = INT32_MAX;
alltypes.req_limits.uint32_min = 0;
alltypes.req_limits.uint32_max = UINT32_MAX;
alltypes.req_limits.int64_min = INT64_MIN;
alltypes.req_limits.int64_max = INT64_MAX;
alltypes.req_limits.uint64_min = 0;
alltypes.req_limits.uint64_max = UINT64_MAX;
alltypes.req_limits.enum_min = HugeEnum_Negative;
alltypes.req_limits.enum_max = HugeEnum_Positive;
alltypes.req_limits.largetag = 1001;
alltypes.req_ds8.first = 9991;
alltypes.req_ds8.second = 9992;
alltypes.req_intsizes.req_int8 = -128;
alltypes.req_intsizes.req_uint8 = 255;
alltypes.req_intsizes.req_sint8 = -128;
alltypes.req_intsizes.req_int16 = -32768;
alltypes.req_intsizes.req_uint16 = 65535;
alltypes.req_intsizes.req_sint16 = -32768;
}
if (mode == 1)
{
/* Fill in values for optional fields */
alltypes.has_opt_int32 = true;
alltypes.opt_int32 = 3041;
alltypes.has_opt_int64 = true;
alltypes.opt_int64 = 3042;
alltypes.has_opt_uint32 = true;
alltypes.opt_uint32 = 3043;
alltypes.has_opt_uint64 = true;
alltypes.opt_uint64 = 3044;
alltypes.has_opt_sint32 = true;
alltypes.opt_sint32 = 3045;
alltypes.has_opt_sint64 = true;
alltypes.opt_sint64 = 3046;
alltypes.has_opt_bool = true;
alltypes.opt_bool = true;
alltypes.has_opt_fixed32 = true;
alltypes.opt_fixed32 = 3048;
alltypes.has_opt_sfixed32 = true;
alltypes.opt_sfixed32 = 3049;
alltypes.has_opt_float = true;
alltypes.opt_float = 3050.0f;
alltypes.has_opt_fixed64 = true;
alltypes.opt_fixed64 = 3051;
alltypes.has_opt_sfixed64 = true;
alltypes.opt_sfixed64 = 3052;
alltypes.has_opt_double = true;
alltypes.opt_double = 3053.0;
alltypes.has_opt_string = true;
strcpy(alltypes.opt_string, "3054");
alltypes.has_opt_bytes = true;
alltypes.opt_bytes.size = 4;
memcpy(alltypes.opt_bytes.bytes, "3055", 4);
alltypes.has_opt_submsg = true;
strcpy(alltypes.opt_submsg.substuff1, "3056");
alltypes.opt_submsg.substuff2 = 3056;
alltypes.has_opt_enum = true;
alltypes.opt_enum = MyEnum_Truth;
alltypes.has_opt_emptymsg = true;
alltypes.has_opt_fbytes = true;
memcpy(alltypes.opt_fbytes, "3059", 4);
alltypes.which_oneof = AllTypes_oneof_msg1_tag;
strcpy(alltypes.oneof.oneof_msg1.substuff1, "4059");
alltypes.oneof.oneof_msg1.substuff2 = 4059;
alltypes.has_opt_non_zero_based_enum = true;
alltypes.opt_non_zero_based_enum = NonZeroBasedEnum_Three;
}
alltypes.end = 1099;
{
uint8_t buffer[AllTypes_size];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, AllTypes_fields, &alltypes))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
}
}

View File

@@ -0,0 +1,28 @@
# Test the AllTypes encoding & decoding using callbacks for all fields.
Import("env", "malloc_env")
c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.proto", "#alltypes/alltypes.proto", c)
env.NanopbProto(["alltypes", "alltypes.options"])
enc = env.Program(["encode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
refdec = "$BUILD/alltypes/decode_alltypes$PROGSUFFIX"
# Encode and compare results
env.RunTest(enc)
env.RunTest("decode_alltypes.output", [refdec, "encode_alltypes_callback.output"])
env.RunTest("decode_alltypes_callback.output", [dec, "encode_alltypes_callback.output"])
# Do the same thing with the optional fields present
env.RunTest("optionals.output", enc, ARGS = ['1'])
env.RunTest("optionals.refdecout", [refdec, "optionals.output"], ARGS = ['1'])
env.RunTest("optionals.decout", [dec, "optionals.output"], ARGS = ['1'])
# Try with malloc support also
mallocbin1 = malloc_env.Object("decode_with_malloc.o", "decode_alltypes_callback.c")
mallocbin2 = malloc_env.Object("alltypes_malloc.pb.o", "alltypes.pb.c")
mallocdec = malloc_env.Program("decode_with_malloc", [mallocbin1, mallocbin2, "$COMMON/pb_decode_with_malloc.o", "$COMMON/pb_common_with_malloc.o", "$COMMON/malloc_wrappers.o"])
env.RunTest("decode_with_malloc.output", [mallocdec, "encode_alltypes_callback.output"])

View File

@@ -0,0 +1,10 @@
# Generate all fields as callbacks.
AllTypes.* type:FT_CALLBACK
SubMessage.substuff1 max_size:16
AllTypes.oneof no_unions:true
DescriptorSize8 descriptorsize:DS_8
# With FT_CALLBACK, these options should get ignored
*.*fbytes fixed_length:true max_size:4
*.*farray fixed_count:true max_count:5

View File

@@ -0,0 +1,492 @@
/* Attempts to test all the datatypes supported by ProtoBuf when used as callback fields.
* Note that normally there would be no reason to use callback fields for this,
* because each encoder defined here only gives a single field.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
#define TEST(x) if (!(x)) { \
printf("Test %s failed (in field %d).\n", #x, field->tag); \
return false; \
}
static bool read_varint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
TEST((int64_t)value == (intptr_t)*arg);
return true;
}
static bool read_svarint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int64_t value;
if (!pb_decode_svarint(stream, &value))
return false;
TEST(value == (intptr_t)*arg);
return true;
}
static bool read_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint32_t value;
if (!pb_decode_fixed32(stream, &value))
return false;
TEST(value == *(uint32_t*)*arg);
return true;
}
static bool read_fixed64(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(value == *(uint64_t*)*arg);
return true;
}
static bool read_double(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (sizeof(double) == sizeof(float))
{
float value;
if (!pb_decode_double_as_float(stream, &value))
return false;
TEST(memcmp(&value, *arg, sizeof(float)) == 0);
return true;
}
#endif
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(value == *(uint64_t*)*arg);
return true;
}
static bool read_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint8_t buf[16] = {0};
size_t len = stream->bytes_left;
if (len > sizeof(buf) - 1 || !pb_read(stream, buf, len))
return false;
TEST(strcmp((char*)buf, *arg) == 0);
return true;
}
static bool read_submsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
SubMessage submsg = {""};
SubMessage *ref = *arg;
if (!pb_decode(stream, SubMessage_fields, &submsg))
return false;
TEST(strcmp(submsg.substuff1, ref->substuff1) == 0);
TEST(submsg.substuff2 == ref->substuff2);
TEST(submsg.has_substuff3 == ref->has_substuff3);
TEST(submsg.substuff3 == ref->substuff3);
return true;
}
static bool read_emptymsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
EmptyMessage emptymsg = {0};
return pb_decode(stream, EmptyMessage_fields, &emptymsg);
}
static bool read_repeated_varint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int32_t** expected = (int32_t**)arg;
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_svarint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int32_t** expected = (int32_t**)arg;
int64_t value;
if (!pb_decode_svarint(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint32_t** expected = (uint32_t**)arg;
uint32_t value;
if (!pb_decode_fixed32(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_fixed64(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t** expected = (uint64_t**)arg;
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_double(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (sizeof(double) == sizeof(float))
{
float** expectedf = (float**)arg;
float value;
if (!pb_decode_double_as_float(stream, &value))
return false;
TEST(memcmp(&value, (*expectedf)++, sizeof(float)) == 0);
return true;
}
#endif
uint64_t** expected = (uint64_t**)arg;
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint8_t*** expected = (uint8_t***)arg;
uint8_t buf[16] = {0};
size_t len = stream->bytes_left;
if (len > sizeof(buf) - 1 || !pb_read(stream, buf, len))
return false;
TEST(strcmp((char*)*(*expected)++, (char*)buf) == 0);
return true;
}
static bool read_repeated_submsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
SubMessage** expected = (SubMessage**)arg;
SubMessage submsg = {""};
if (!pb_decode(stream, SubMessage_fields, &submsg))
return false;
TEST(strcmp(submsg.substuff1, (*expected)->substuff1) == 0);
TEST(submsg.substuff2 == (*expected)->substuff2);
TEST(submsg.has_substuff3 == (*expected)->has_substuff3);
TEST(submsg.substuff3 == (*expected)->substuff3);
(*expected)++;
return true;
}
static bool read_limits(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
Limits decoded = {0};
if (!pb_decode(stream, Limits_fields, &decoded))
return false;
TEST(decoded.int32_min == INT32_MIN);
TEST(decoded.int32_max == INT32_MAX);
TEST(decoded.uint32_min == 0);
TEST(decoded.uint32_max == UINT32_MAX);
TEST(decoded.int64_min == INT64_MIN);
TEST(decoded.int64_max == INT64_MAX);
TEST(decoded.uint64_min == 0);
TEST(decoded.uint64_max == UINT64_MAX);
TEST(decoded.enum_min == HugeEnum_Negative);
TEST(decoded.enum_max == HugeEnum_Positive);
TEST(decoded.largetag == 1001);
return true;
}
/* This function is called once from main(), it handles
the decoding and checks the fields. */
bool check_alltypes(pb_istream_t *stream, int mode)
{
/* Values for use from callbacks through pointers. */
bool status;
uint32_t req_fixed32 = 1008;
int32_t req_sfixed32 = -1009;
float req_float = 1010.0f;
uint64_t req_fixed64 = 1011;
int64_t req_sfixed64 = -1012;
double req_double = 1013.0;
SubMessage req_submsg = {"1016", 1016, false, 3};
int32_t rep_int32[5] = {0, 0, 0, 0, -2001};
int32_t rep_int64[5] = {0, 0, 0, 0, -2002};
int32_t rep_uint32[5] = {0, 0, 0, 0, 2003};
int32_t rep_uint64[5] = {0, 0, 0, 0, 2004};
int32_t rep_sint32[5] = {0, 0, 0, 0, -2005};
int32_t rep_sint64[5] = {0, 0, 0, 0, -2006};
int32_t rep_bool[5] = {false, false, false, false, true};
uint32_t rep_fixed32[5] = {0, 0, 0, 0, 2008};
int32_t rep_sfixed32[5] = {0, 0, 0, 0, -2009};
float rep_float[5] = {0, 0, 0, 0, 2010.0f};
uint64_t rep_fixed64[5] = {0, 0, 0, 0, 2011};
int64_t rep_sfixed64[5] = {0, 0, 0, 0, -2012};
double rep_double[5] = {0, 0, 0, 0, 2013.0};
char* rep_string[5] = {"", "", "", "", "2014"};
char* rep_bytes[5] = {"", "", "", "", "2015"};
SubMessage rep_submsg[5] = {{"", 0, 0, 3},
{"", 0, 0, 3},
{"", 0, 0, 3},
{"", 0, 0, 3},
{"2016", 2016, true, 2016}};
int32_t rep_enum[5] = {0, 0, 0, 0, MyEnum_Truth};
uint32_t opt_fixed32 = 3048;
int32_t opt_sfixed32 = 3049;
float opt_float = 3050.0f;
uint64_t opt_fixed64 = 3051;
int64_t opt_sfixed64 = 3052;
double opt_double = 3053.0f;
SubMessage opt_submsg = {"3056", 3056, false, 3};
SubMessage oneof_msg1 = {"4059", 4059, false, 3};
/* Bind callbacks for required fields */
AllTypes alltypes = AllTypes_init_zero;
alltypes.req_int32.funcs.decode = &read_varint;
alltypes.req_int32.arg = (void*)-1001;
alltypes.req_int64.funcs.decode = &read_varint;
alltypes.req_int64.arg = (void*)-1002;
alltypes.req_uint32.funcs.decode = &read_varint;
alltypes.req_uint32.arg = (void*)1003;
alltypes.req_uint32.funcs.decode = &read_varint;
alltypes.req_uint32.arg = (void*)1003;
alltypes.req_uint64.funcs.decode = &read_varint;
alltypes.req_uint64.arg = (void*)1004;
alltypes.req_sint32.funcs.decode = &read_svarint;
alltypes.req_sint32.arg = (void*)-1005;
alltypes.req_sint64.funcs.decode = &read_svarint;
alltypes.req_sint64.arg = (void*)-1006;
alltypes.req_bool.funcs.decode = &read_varint;
alltypes.req_bool.arg = (void*)true;
alltypes.req_fixed32.funcs.decode = &read_fixed32;
alltypes.req_fixed32.arg = &req_fixed32;
alltypes.req_sfixed32.funcs.decode = &read_fixed32;
alltypes.req_sfixed32.arg = &req_sfixed32;
alltypes.req_float.funcs.decode = &read_fixed32;
alltypes.req_float.arg = &req_float;
alltypes.req_fixed64.funcs.decode = &read_fixed64;
alltypes.req_fixed64.arg = &req_fixed64;
alltypes.req_sfixed64.funcs.decode = &read_fixed64;
alltypes.req_sfixed64.arg = &req_sfixed64;
alltypes.req_double.funcs.decode = &read_double;
alltypes.req_double.arg = &req_double;
alltypes.req_string.funcs.decode = &read_string;
alltypes.req_string.arg = "1014";
alltypes.req_bytes.funcs.decode = &read_string;
alltypes.req_bytes.arg = "1015";
alltypes.req_submsg.funcs.decode = &read_submsg;
alltypes.req_submsg.arg = &req_submsg;
alltypes.req_enum.funcs.decode = &read_varint;
alltypes.req_enum.arg = (void*)MyEnum_Truth;
alltypes.req_emptymsg.funcs.decode = &read_emptymsg;
/* Bind callbacks for repeated fields */
alltypes.rep_int32.funcs.decode = &read_repeated_varint;
alltypes.rep_int32.arg = rep_int32;
alltypes.rep_int64.funcs.decode = &read_repeated_varint;
alltypes.rep_int64.arg = rep_int64;
alltypes.rep_uint32.funcs.decode = &read_repeated_varint;
alltypes.rep_uint32.arg = rep_uint32;
alltypes.rep_uint64.funcs.decode = &read_repeated_varint;
alltypes.rep_uint64.arg = rep_uint64;
alltypes.rep_sint32.funcs.decode = &read_repeated_svarint;
alltypes.rep_sint32.arg = rep_sint32;
alltypes.rep_sint64.funcs.decode = &read_repeated_svarint;
alltypes.rep_sint64.arg = rep_sint64;
alltypes.rep_bool.funcs.decode = &read_repeated_varint;
alltypes.rep_bool.arg = rep_bool;
alltypes.rep_fixed32.funcs.decode = &read_repeated_fixed32;
alltypes.rep_fixed32.arg = rep_fixed32;
alltypes.rep_sfixed32.funcs.decode = &read_repeated_fixed32;
alltypes.rep_sfixed32.arg = rep_sfixed32;
alltypes.rep_float.funcs.decode = &read_repeated_fixed32;
alltypes.rep_float.arg = rep_float;
alltypes.rep_fixed64.funcs.decode = &read_repeated_fixed64;
alltypes.rep_fixed64.arg = rep_fixed64;
alltypes.rep_sfixed64.funcs.decode = &read_repeated_fixed64;
alltypes.rep_sfixed64.arg = rep_sfixed64;
alltypes.rep_double.funcs.decode = &read_repeated_double;
alltypes.rep_double.arg = rep_double;
alltypes.rep_string.funcs.decode = &read_repeated_string;
alltypes.rep_string.arg = rep_string;
alltypes.rep_bytes.funcs.decode = &read_repeated_string;
alltypes.rep_bytes.arg = rep_bytes;
alltypes.rep_submsg.funcs.decode = &read_repeated_submsg;
alltypes.rep_submsg.arg = rep_submsg;
alltypes.rep_enum.funcs.decode = &read_repeated_varint;
alltypes.rep_enum.arg = rep_enum;
alltypes.rep_emptymsg.funcs.decode = &read_emptymsg;
alltypes.req_limits.funcs.decode = &read_limits;
alltypes.end.funcs.decode = &read_varint;
alltypes.end.arg = (void*)1099;
/* Bind callbacks for optional fields */
if (mode == 1)
{
alltypes.opt_int32.funcs.decode = &read_varint;
alltypes.opt_int32.arg = (void*)3041;
alltypes.opt_int64.funcs.decode = &read_varint;
alltypes.opt_int64.arg = (void*)3042;
alltypes.opt_uint32.funcs.decode = &read_varint;
alltypes.opt_uint32.arg = (void*)3043;
alltypes.opt_uint64.funcs.decode = &read_varint;
alltypes.opt_uint64.arg = (void*)3044;
alltypes.opt_sint32.funcs.decode = &read_svarint;
alltypes.opt_sint32.arg = (void*)3045;
alltypes.opt_sint64.funcs.decode = &read_svarint;
alltypes.opt_sint64.arg = (void*)3046;
alltypes.opt_bool.funcs.decode = &read_varint;
alltypes.opt_bool.arg = (void*)true;
alltypes.opt_fixed32.funcs.decode = &read_fixed32;
alltypes.opt_fixed32.arg = &opt_fixed32;
alltypes.opt_sfixed32.funcs.decode = &read_fixed32;
alltypes.opt_sfixed32.arg = &opt_sfixed32;
alltypes.opt_float.funcs.decode = &read_fixed32;
alltypes.opt_float.arg = &opt_float;
alltypes.opt_fixed64.funcs.decode = &read_fixed64;
alltypes.opt_fixed64.arg = &opt_fixed64;
alltypes.opt_sfixed64.funcs.decode = &read_fixed64;
alltypes.opt_sfixed64.arg = &opt_sfixed64;
alltypes.opt_double.funcs.decode = &read_double;
alltypes.opt_double.arg = &opt_double;
alltypes.opt_string.funcs.decode = &read_string;
alltypes.opt_string.arg = "3054";
alltypes.opt_bytes.funcs.decode = &read_string;
alltypes.opt_bytes.arg = "3055";
alltypes.opt_submsg.funcs.decode = &read_submsg;
alltypes.opt_submsg.arg = &opt_submsg;
alltypes.opt_enum.funcs.decode = &read_varint;
alltypes.opt_enum.arg = (void*)MyEnum_Truth;
alltypes.opt_emptymsg.funcs.decode = &read_emptymsg;
alltypes.oneof_msg1.funcs.decode = &read_submsg;
alltypes.oneof_msg1.arg = &oneof_msg1;
alltypes.opt_non_zero_based_enum.funcs.decode = &read_varint;
alltypes.opt_non_zero_based_enum.arg = (void *)NonZeroBasedEnum_Three;
}
status = pb_decode(stream, AllTypes_fields, &alltypes);
#ifdef PB_ENABLE_MALLOC
/* Just to check for any interference between pb_release() and callback fields */
pb_release(AllTypes_fields, &alltypes);
#endif
return status;
}
int main(int argc, char **argv)
{
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
/* Whether to expect the optional values or the default values. */
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
/* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count);
/* Decode and print out the stuff */
if (!check_alltypes(&stream, mode))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
} else {
return 0;
}
}

View File

@@ -0,0 +1,491 @@
/* Attempts to test all the datatypes supported by ProtoBuf when used as callback fields.
* Note that normally there would be no reason to use callback fields for this,
* because each encoder defined here only gives a single field.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_encode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
static bool write_varint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, (intptr_t)*arg);
}
static bool write_svarint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, (intptr_t)*arg);
}
static bool write_fixed32(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_fixed32(stream, *arg);
}
static bool write_fixed64(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_double(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (sizeof(double) == sizeof(float))
return pb_encode_tag_for_field(stream, field) &&
pb_encode_float_as_double(stream, *(float*)*arg);
#endif
return pb_encode_tag_for_field(stream, field) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, *arg, strlen(*arg));
}
static bool write_submsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, *arg);
}
static bool write_emptymsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
EmptyMessage emptymsg = {0};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg);
}
static bool write_repeated_varint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, (intptr_t)*arg);
}
static bool write_repeated_svarint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, (intptr_t)*arg);
}
static bool write_repeated_fixed32(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint32_t dummy = 0;
/* Make it a packed field */
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 4) && /* Number of bytes */
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, *arg);
}
static bool write_repeated_fixed64(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint64_t dummy = 0;
/* Make it a packed field */
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 8) && /* Number of bytes */
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_repeated_double(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint64_t dummy = 0;
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (sizeof(double) == sizeof(float))
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 8) && /* Number of bytes */
pb_encode_float_as_double(stream, 0.0f) &&
pb_encode_float_as_double(stream, 0.0f) &&
pb_encode_float_as_double(stream, 0.0f) &&
pb_encode_float_as_double(stream, 0.0f) &&
pb_encode_float_as_double(stream, *(float*)*arg);
#endif
/* Make it a packed field */
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 8) && /* Number of bytes */
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_repeated_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, *arg, strlen(*arg));
}
static bool write_repeated_submsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
SubMessage dummy = {""};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, *arg);
}
static bool write_limits(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
Limits limits = {0};
limits.int32_min = INT32_MIN;
limits.int32_max = INT32_MAX;
limits.uint32_min = 0;
limits.uint32_max = UINT32_MAX;
limits.int64_min = INT64_MIN;
limits.int64_max = INT64_MAX;
limits.uint64_min = 0;
limits.uint64_max = UINT64_MAX;
limits.enum_min = HugeEnum_Negative;
limits.enum_max = HugeEnum_Positive;
limits.largetag = 1001;
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, Limits_fields, &limits);
}
static bool write_ds8(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
DescriptorSize8 ds8 = {9991,9992};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, DescriptorSize8_fields, &ds8);
}
static bool write_intsizes(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
IntSizes intsizes = {-128, 255, -128, -32768, 65535, -32768};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, IntSizes_fields, &intsizes);
}
static bool write_repeated_emptymsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
EmptyMessage emptymsg = {0};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg);
}
static bool write_farray2(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint32_t dummy = 0;
uint32_t value = (uint32_t)(intptr_t)*arg;
/* Make it a packed field */
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 3 * 4) && /* Number of bytes */
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &value);
}
int main(int argc, char **argv)
{
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Values for use from callbacks through pointers. */
uint32_t req_fixed32 = 1008;
int32_t req_sfixed32 = -1009;
float req_float = 1010.0f;
uint64_t req_fixed64 = 1011;
int64_t req_sfixed64 = -1012;
double req_double = 1013.0;
SubMessage req_submsg = {"1016", 1016};
uint32_t rep_fixed32 = 2008;
int32_t rep_sfixed32 = -2009;
float rep_float = 2010.0f;
uint64_t rep_fixed64 = 2011;
int64_t rep_sfixed64 = -2012;
double rep_double = 2013.0;
SubMessage rep_submsg = {"2016", 2016, true, 2016};
uint32_t opt_fixed32 = 3048;
int32_t opt_sfixed32 = 3049;
float opt_float = 3050.0f;
uint64_t opt_fixed64 = 3051;
int64_t opt_sfixed64 = 3052;
double opt_double = 3053.0f;
SubMessage opt_submsg = {"3056", 3056};
SubMessage oneof_msg1 = {"4059", 4059};
/* Bind callbacks for required fields */
AllTypes alltypes = {{{0}}};
alltypes.req_int32.funcs.encode = &write_varint;
alltypes.req_int32.arg = (void*)-1001;
alltypes.req_int64.funcs.encode = &write_varint;
alltypes.req_int64.arg = (void*)-1002;
alltypes.req_uint32.funcs.encode = &write_varint;
alltypes.req_uint32.arg = (void*)1003;
alltypes.req_uint32.funcs.encode = &write_varint;
alltypes.req_uint32.arg = (void*)1003;
alltypes.req_uint64.funcs.encode = &write_varint;
alltypes.req_uint64.arg = (void*)1004;
alltypes.req_sint32.funcs.encode = &write_svarint;
alltypes.req_sint32.arg = (void*)-1005;
alltypes.req_sint64.funcs.encode = &write_svarint;
alltypes.req_sint64.arg = (void*)-1006;
alltypes.req_bool.funcs.encode = &write_varint;
alltypes.req_bool.arg = (void*)true;
alltypes.req_fixed32.funcs.encode = &write_fixed32;
alltypes.req_fixed32.arg = &req_fixed32;
alltypes.req_sfixed32.funcs.encode = &write_fixed32;
alltypes.req_sfixed32.arg = &req_sfixed32;
alltypes.req_float.funcs.encode = &write_fixed32;
alltypes.req_float.arg = &req_float;
alltypes.req_fixed64.funcs.encode = &write_fixed64;
alltypes.req_fixed64.arg = &req_fixed64;
alltypes.req_sfixed64.funcs.encode = &write_fixed64;
alltypes.req_sfixed64.arg = &req_sfixed64;
alltypes.req_double.funcs.encode = &write_double;
alltypes.req_double.arg = &req_double;
alltypes.req_string.funcs.encode = &write_string;
alltypes.req_string.arg = "1014";
alltypes.req_bytes.funcs.encode = &write_string;
alltypes.req_bytes.arg = "1015";
alltypes.req_submsg.funcs.encode = &write_submsg;
alltypes.req_submsg.arg = &req_submsg;
alltypes.req_enum.funcs.encode = &write_varint;
alltypes.req_enum.arg = (void*)MyEnum_Truth;
alltypes.req_emptymsg.funcs.encode = &write_emptymsg;
alltypes.req_fbytes.funcs.encode = &write_string;
alltypes.req_fbytes.arg = "1019";
/* Bind callbacks for repeated fields */
alltypes.rep_int32.funcs.encode = &write_repeated_varint;
alltypes.rep_int32.arg = (void*)-2001;
alltypes.rep_int64.funcs.encode = &write_repeated_varint;
alltypes.rep_int64.arg = (void*)-2002;
alltypes.rep_uint32.funcs.encode = &write_repeated_varint;
alltypes.rep_uint32.arg = (void*)2003;
alltypes.rep_uint64.funcs.encode = &write_repeated_varint;
alltypes.rep_uint64.arg = (void*)2004;
alltypes.rep_sint32.funcs.encode = &write_repeated_svarint;
alltypes.rep_sint32.arg = (void*)-2005;
alltypes.rep_sint64.funcs.encode = &write_repeated_svarint;
alltypes.rep_sint64.arg = (void*)-2006;
alltypes.rep_bool.funcs.encode = &write_repeated_varint;
alltypes.rep_bool.arg = (void*)true;
alltypes.rep_fixed32.funcs.encode = &write_repeated_fixed32;
alltypes.rep_fixed32.arg = &rep_fixed32;
alltypes.rep_sfixed32.funcs.encode = &write_repeated_fixed32;
alltypes.rep_sfixed32.arg = &rep_sfixed32;
alltypes.rep_float.funcs.encode = &write_repeated_fixed32;
alltypes.rep_float.arg = &rep_float;
alltypes.rep_fixed64.funcs.encode = &write_repeated_fixed64;
alltypes.rep_fixed64.arg = &rep_fixed64;
alltypes.rep_sfixed64.funcs.encode = &write_repeated_fixed64;
alltypes.rep_sfixed64.arg = &rep_sfixed64;
alltypes.rep_double.funcs.encode = &write_repeated_double;
alltypes.rep_double.arg = &rep_double;
alltypes.rep_string.funcs.encode = &write_repeated_string;
alltypes.rep_string.arg = "2014";
alltypes.rep_bytes.funcs.encode = &write_repeated_string;
alltypes.rep_bytes.arg = "2015";
alltypes.rep_submsg.funcs.encode = &write_repeated_submsg;
alltypes.rep_submsg.arg = &rep_submsg;
alltypes.rep_enum.funcs.encode = &write_repeated_varint;
alltypes.rep_enum.arg = (void*)MyEnum_Truth;
alltypes.rep_emptymsg.funcs.encode = &write_repeated_emptymsg;
alltypes.rep_fbytes.funcs.encode = &write_repeated_string;
alltypes.rep_fbytes.arg = "2019";
alltypes.rep_farray.funcs.encode = &write_repeated_varint;
alltypes.rep_farray.arg = (void*)2040;
alltypes.rep_farray2.funcs.encode = &write_farray2;
alltypes.rep_farray2.arg = (void*)2095;
alltypes.req_limits.funcs.encode = &write_limits;
alltypes.req_ds8.funcs.encode = &write_ds8;
alltypes.req_intsizes.funcs.encode = &write_intsizes;
/* Bind callbacks for optional fields */
if (mode != 0)
{
alltypes.opt_int32.funcs.encode = &write_varint;
alltypes.opt_int32.arg = (void*)3041;
alltypes.opt_int64.funcs.encode = &write_varint;
alltypes.opt_int64.arg = (void*)3042;
alltypes.opt_uint32.funcs.encode = &write_varint;
alltypes.opt_uint32.arg = (void*)3043;
alltypes.opt_uint64.funcs.encode = &write_varint;
alltypes.opt_uint64.arg = (void*)3044;
alltypes.opt_sint32.funcs.encode = &write_svarint;
alltypes.opt_sint32.arg = (void*)3045;
alltypes.opt_sint64.funcs.encode = &write_svarint;
alltypes.opt_sint64.arg = (void*)3046;
alltypes.opt_bool.funcs.encode = &write_varint;
alltypes.opt_bool.arg = (void*)true;
alltypes.opt_fixed32.funcs.encode = &write_fixed32;
alltypes.opt_fixed32.arg = &opt_fixed32;
alltypes.opt_sfixed32.funcs.encode = &write_fixed32;
alltypes.opt_sfixed32.arg = &opt_sfixed32;
alltypes.opt_float.funcs.encode = &write_fixed32;
alltypes.opt_float.arg = &opt_float;
alltypes.opt_fixed64.funcs.encode = &write_fixed64;
alltypes.opt_fixed64.arg = &opt_fixed64;
alltypes.opt_sfixed64.funcs.encode = &write_fixed64;
alltypes.opt_sfixed64.arg = &opt_sfixed64;
alltypes.opt_double.funcs.encode = &write_double;
alltypes.opt_double.arg = &opt_double;
alltypes.opt_string.funcs.encode = &write_string;
alltypes.opt_string.arg = "3054";
alltypes.opt_bytes.funcs.encode = &write_string;
alltypes.opt_bytes.arg = "3055";
alltypes.opt_submsg.funcs.encode = &write_submsg;
alltypes.opt_submsg.arg = &opt_submsg;
alltypes.opt_enum.funcs.encode = &write_varint;
alltypes.opt_enum.arg = (void*)MyEnum_Truth;
alltypes.opt_emptymsg.funcs.encode = &write_emptymsg;
alltypes.opt_fbytes.funcs.encode = &write_string;
alltypes.opt_fbytes.arg = "3059";
alltypes.oneof_msg1.funcs.encode = &write_submsg;
alltypes.oneof_msg1.arg = &oneof_msg1;
alltypes.opt_non_zero_based_enum.funcs.encode = &write_varint;
alltypes.opt_non_zero_based_enum.arg = (void *)NonZeroBasedEnum_Three;
}
alltypes.end.funcs.encode = &write_varint;
alltypes.end.arg = (void*)1099;
{
uint8_t buffer[2048];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, AllTypes_fields, &alltypes))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
}
}

View File

@@ -0,0 +1,39 @@
# Encode the AllTypes message using pointers for all fields, and verify the
# output against the normal AllTypes test case.
Import("env", "malloc_env")
c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.proto", "#alltypes/alltypes.proto", c)
env.NanopbProto(["alltypes", "alltypes.options"])
enc = malloc_env.Program(["encode_alltypes_pointer.c",
"alltypes.pb.c",
"$COMMON/pb_encode_with_malloc.o",
"$COMMON/pb_common_with_malloc.o",
"$COMMON/malloc_wrappers.o"])
dec = malloc_env.Program(["decode_alltypes_pointer.c",
"alltypes.pb.c",
"$COMMON/pb_decode_with_malloc.o",
"$COMMON/pb_common_with_malloc.o",
"$COMMON/malloc_wrappers.o"])
# Encode and compare results to non-pointer alltypes test case
env.RunTest(enc)
env.Compare(["encode_alltypes_pointer.output", "$BUILD/alltypes/encode_alltypes.output"])
# Decode (under valgrind if available)
kwargs = {}
if env.get("VALGRIND"):
kwargs['COMMAND'] = env['VALGRIND']
kwargs['ARGS'] = ["-q", "--error-exitcode=99", dec[0].abspath]
env.RunTest("decode_alltypes.output", [dec, "encode_alltypes_pointer.output"], **kwargs)
# Do the same thing with the optional fields present
env.RunTest("optionals.output", enc, ARGS = ['1'])
env.Compare(["optionals.output", "$BUILD/alltypes/optionals.output"])
kwargs['ARGS'] = kwargs.get('ARGS', []) + ['1']
env.RunTest("optionals.decout", [dec, "optionals.output"], **kwargs)

View File

@@ -0,0 +1,11 @@
# Generate all fields as pointers.
* type:FT_POINTER
*.static_msg type:FT_STATIC
SubMessage.substuff1 type:FT_STATIC max_size:8
*.*fbytes fixed_length:true max_size:4
*.*farray fixed_count:true max_count:5
*.*farray2 fixed_count:true max_count:3
IntSizes.*int8 int_size:IS_8
IntSizes.*int16 int_size:IS_16
DescriptorSize8 descriptorsize:DS_8

View File

@@ -0,0 +1,200 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
#include "unittests.h"
/* This function is called once from main(), it handles
the decoding and checks the fields. */
bool check_alltypes(pb_istream_t *stream, int mode)
{
int status = 0;
AllTypes alltypes;
/* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes));
alltypes.extensions = 0;
if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false;
TEST(alltypes.req_int32 && *alltypes.req_int32 == -1001);
TEST(alltypes.req_int64 && *alltypes.req_int64 == -1002);
TEST(alltypes.req_uint32 && *alltypes.req_uint32 == 1003);
TEST(alltypes.req_uint64 && *alltypes.req_uint64 == 1004);
TEST(alltypes.req_sint32 && *alltypes.req_sint32 == -1005);
TEST(alltypes.req_sint64 && *alltypes.req_sint64 == -1006);
TEST(alltypes.req_bool && *alltypes.req_bool == true);
TEST(alltypes.req_fixed32 && *alltypes.req_fixed32 == 1008);
TEST(alltypes.req_sfixed32 && *alltypes.req_sfixed32 == -1009);
TEST(alltypes.req_float && *alltypes.req_float == 1010.0f);
TEST(alltypes.req_fixed64 && *alltypes.req_fixed64 == 1011);
TEST(alltypes.req_sfixed64 && *alltypes.req_sfixed64 == -1012);
TEST(alltypes.req_double && *alltypes.req_double == 1013.0f);
TEST(alltypes.req_string && strcmp(alltypes.req_string, "1014") == 0);
TEST(alltypes.req_bytes && alltypes.req_bytes->size == 4);
TEST(alltypes.req_bytes && memcmp(&alltypes.req_bytes->bytes, "1015", 4) == 0);
TEST(alltypes.req_submsg && strcmp(alltypes.req_submsg->substuff1, "1016") == 0);
TEST(alltypes.req_submsg && alltypes.req_submsg->substuff2
&& *alltypes.req_submsg->substuff2 == 1016);
TEST(alltypes.req_enum && *alltypes.req_enum == MyEnum_Truth);
TEST(alltypes.req_fbytes && memcmp(alltypes.req_fbytes, "1019", 4) == 0);
TEST(alltypes.rep_int32_count == 5 && alltypes.rep_int32[4] == -2001 && alltypes.rep_int32[0] == 0);
TEST(alltypes.rep_int64_count == 5 && alltypes.rep_int64[4] == -2002 && alltypes.rep_int64[0] == 0);
TEST(alltypes.rep_uint32_count == 5 && alltypes.rep_uint32[4] == 2003 && alltypes.rep_uint32[0] == 0);
TEST(alltypes.rep_uint64_count == 5 && alltypes.rep_uint64[4] == 2004 && alltypes.rep_uint64[0] == 0);
TEST(alltypes.rep_sint32_count == 5 && alltypes.rep_sint32[4] == -2005 && alltypes.rep_sint32[0] == 0);
TEST(alltypes.rep_sint64_count == 5 && alltypes.rep_sint64[4] == -2006 && alltypes.rep_sint64[0] == 0);
TEST(alltypes.rep_bool_count == 5 && alltypes.rep_bool[4] == true && alltypes.rep_bool[0] == false);
TEST(alltypes.rep_fixed32_count == 5 && alltypes.rep_fixed32[4] == 2008 && alltypes.rep_fixed32[0] == 0);
TEST(alltypes.rep_sfixed32_count == 5 && alltypes.rep_sfixed32[4] == -2009 && alltypes.rep_sfixed32[0] == 0);
TEST(alltypes.rep_float_count == 5 && alltypes.rep_float[4] == 2010.0f && alltypes.rep_float[0] == 0.0f);
TEST(alltypes.rep_fixed64_count == 5 && alltypes.rep_fixed64[4] == 2011 && alltypes.rep_fixed64[0] == 0);
TEST(alltypes.rep_sfixed64_count == 5 && alltypes.rep_sfixed64[4] == -2012 && alltypes.rep_sfixed64[0] == 0);
TEST(alltypes.rep_double_count == 5 && alltypes.rep_double[4] == 2013.0 && alltypes.rep_double[0] == 0.0);
TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0');
TEST(alltypes.rep_bytes_count == 5 && alltypes.rep_bytes[4]->size == 4 && alltypes.rep_bytes[0]->size == 0);
TEST(memcmp(&alltypes.rep_bytes[4]->bytes, "2015", 4) == 0);
TEST(alltypes.rep_submsg_count == 5);
TEST(strcmp(alltypes.rep_submsg[4].substuff1, "2016") == 0 && alltypes.rep_submsg[0].substuff1[0] == '\0');
TEST(*alltypes.rep_submsg[4].substuff2 == 2016 && *alltypes.rep_submsg[0].substuff2 == 0);
TEST(*alltypes.rep_submsg[4].substuff3 == 2016 && alltypes.rep_submsg[0].substuff3 == NULL);
TEST(alltypes.rep_enum_count == 5 && alltypes.rep_enum[4] == MyEnum_Truth && alltypes.rep_enum[0] == MyEnum_Zero);
TEST(alltypes.rep_emptymsg_count == 5);
TEST(alltypes.rep_fbytes_count == 5);
TEST(alltypes.rep_fbytes[0][0] == 0 && alltypes.rep_fbytes[0][3] == 0);
TEST(memcmp(alltypes.rep_fbytes[4], "2019", 4) == 0);
TEST(alltypes.rep_farray && (*alltypes.rep_farray)[0] == 0 && (*alltypes.rep_farray)[4] == 2040);
TEST(alltypes.rep_farray2 && (*alltypes.rep_farray2)[0] == 0 && (*alltypes.rep_farray2)[2] == 2095);
if (mode == 0)
{
/* Expect that optional values are not present */
TEST(alltypes.opt_int32 == NULL);
TEST(alltypes.opt_int64 == NULL);
TEST(alltypes.opt_uint32 == NULL);
TEST(alltypes.opt_uint64 == NULL);
TEST(alltypes.opt_sint32 == NULL);
TEST(alltypes.opt_sint64 == NULL);
TEST(alltypes.opt_bool == NULL);
TEST(alltypes.opt_fixed32 == NULL);
TEST(alltypes.opt_sfixed32 == NULL);
TEST(alltypes.opt_float == NULL);
TEST(alltypes.opt_fixed64 == NULL);
TEST(alltypes.opt_sfixed64 == NULL);
TEST(alltypes.opt_double == NULL);
TEST(alltypes.opt_string == NULL);
TEST(alltypes.opt_bytes == NULL);
TEST(alltypes.opt_submsg == NULL);
TEST(alltypes.opt_enum == NULL);
TEST(alltypes.opt_fbytes == NULL);
TEST(alltypes.which_oneof == 0);
TEST(alltypes.opt_non_zero_based_enum == NULL);
}
else
{
/* Expect filled-in values */
TEST(alltypes.opt_int32 && *alltypes.opt_int32 == 3041);
TEST(alltypes.opt_int64 && *alltypes.opt_int64 == 3042);
TEST(alltypes.opt_uint32 && *alltypes.opt_uint32 == 3043);
TEST(alltypes.opt_uint64 && *alltypes.opt_uint64 == 3044);
TEST(alltypes.opt_sint32 && *alltypes.opt_sint32 == 3045);
TEST(alltypes.opt_sint64 && *alltypes.opt_sint64 == 3046);
TEST(alltypes.opt_bool && *alltypes.opt_bool == true);
TEST(alltypes.opt_fixed32 && *alltypes.opt_fixed32 == 3048);
TEST(alltypes.opt_sfixed32 && *alltypes.opt_sfixed32== 3049);
TEST(alltypes.opt_float && *alltypes.opt_float == 3050.0f);
TEST(alltypes.opt_fixed64 && *alltypes.opt_fixed64 == 3051);
TEST(alltypes.opt_sfixed64 && *alltypes.opt_sfixed64== 3052);
TEST(alltypes.opt_double && *alltypes.opt_double == 3053.0);
TEST(alltypes.opt_string && strcmp(alltypes.opt_string, "3054") == 0);
TEST(alltypes.opt_bytes && alltypes.opt_bytes->size == 4);
TEST(alltypes.opt_bytes && memcmp(&alltypes.opt_bytes->bytes, "3055", 4) == 0);
TEST(alltypes.opt_submsg && strcmp(alltypes.opt_submsg->substuff1, "3056") == 0);
TEST(alltypes.opt_submsg && *alltypes.opt_submsg->substuff2 == 3056);
TEST(alltypes.opt_enum && *alltypes.opt_enum == MyEnum_Truth);
TEST(alltypes.opt_emptymsg);
TEST(alltypes.opt_fbytes && memcmp(alltypes.opt_fbytes, "3059", 4) == 0);
TEST(alltypes.which_oneof == AllTypes_oneof_msg1_tag);
TEST(alltypes.oneof.oneof_msg1 && strcmp(alltypes.oneof.oneof_msg1->substuff1, "4059") == 0);
TEST(alltypes.oneof.oneof_msg1->substuff2 && *alltypes.oneof.oneof_msg1->substuff2 == 4059);
TEST(alltypes.opt_non_zero_based_enum && *alltypes.opt_non_zero_based_enum == NonZeroBasedEnum_Three);
}
TEST(alltypes.req_limits->int32_min && *alltypes.req_limits->int32_min == INT32_MIN);
TEST(alltypes.req_limits->int32_max && *alltypes.req_limits->int32_max == INT32_MAX);
TEST(alltypes.req_limits->uint32_min && *alltypes.req_limits->uint32_min == 0);
TEST(alltypes.req_limits->uint32_max && *alltypes.req_limits->uint32_max == UINT32_MAX);
TEST(alltypes.req_limits->int64_min && *alltypes.req_limits->int64_min == INT64_MIN);
TEST(alltypes.req_limits->int64_max && *alltypes.req_limits->int64_max == INT64_MAX);
TEST(alltypes.req_limits->uint64_min && *alltypes.req_limits->uint64_min == 0);
TEST(alltypes.req_limits->uint64_max && *alltypes.req_limits->uint64_max == UINT64_MAX);
TEST(alltypes.req_limits->enum_min && *alltypes.req_limits->enum_min == HugeEnum_Negative);
TEST(alltypes.req_limits->enum_max && *alltypes.req_limits->enum_max == HugeEnum_Positive);
TEST(alltypes.req_limits->largetag && *alltypes.req_limits->largetag == 1001);
TEST(alltypes.req_ds8);
TEST(alltypes.req_ds8->first && *alltypes.req_ds8->first == 9991);
TEST(alltypes.req_ds8->first && *alltypes.req_ds8->second == 9992);
TEST(alltypes.req_intsizes);
TEST(*alltypes.req_intsizes->req_int8 == -128);
TEST(*alltypes.req_intsizes->req_uint8 == 255);
TEST(*alltypes.req_intsizes->req_sint8 == -128);
TEST(*alltypes.req_intsizes->req_int16 == -32768);
TEST(*alltypes.req_intsizes->req_uint16 == 65535);
TEST(*alltypes.req_intsizes->req_sint16 == -32768);
TEST(alltypes.end && *alltypes.end == 1099);
pb_release(AllTypes_fields, &alltypes);
return status == 0;
}
int main(int argc, char **argv)
{
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
/* Whether to expect the optional values or the default values. */
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
/* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count);
/* Decode and verify the message */
if (!check_alltypes(&stream, mode))
{
fprintf(stderr, "Test failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
else
{
return 0;
}
}

View File

@@ -0,0 +1,227 @@
/* Attempts to test all the datatypes supported by ProtoBuf.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_encode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
int main(int argc, char **argv)
{
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Values for required fields */
int32_t req_int32 = -1001;
int64_t req_int64 = -1002;
uint32_t req_uint32 = 1003;
uint64_t req_uint64 = 1004;
int32_t req_sint32 = -1005;
int64_t req_sint64 = -1006;
bool req_bool = true;
uint32_t req_fixed32 = 1008;
int32_t req_sfixed32 = -1009;
float req_float = 1010.0f;
uint64_t req_fixed64 = 1011;
int64_t req_sfixed64 = -1012;
double req_double = 1013.0;
char* req_string = "1014";
PB_BYTES_ARRAY_T(4) req_bytes = {4, {'1', '0', '1', '5'}};
static int32_t req_substuff = 1016;
SubMessage req_submsg = {"1016", &req_substuff};
MyEnum req_enum = MyEnum_Truth;
EmptyMessage req_emptymsg = {0};
pb_byte_t req_fbytes[4] = {'1', '0', '1', '9'};
int32_t end = 1099;
/* Values for repeated fields */
int32_t rep_int32[5] = {0, 0, 0, 0, -2001};
int64_t rep_int64[5] = {0, 0, 0, 0, -2002};
uint32_t rep_uint32[5] = {0, 0, 0, 0, 2003};
uint64_t rep_uint64[5] = {0, 0, 0, 0, 2004};
int32_t rep_sint32[5] = {0, 0, 0, 0, -2005};
int64_t rep_sint64[5] = {0, 0, 0, 0, -2006};
bool rep_bool[5] = {false, false, false, false, true};
uint32_t rep_fixed32[5] = {0, 0, 0, 0, 2008};
int32_t rep_sfixed32[5] = {0, 0, 0, 0, -2009};
float rep_float[5] = {0, 0, 0, 0, 2010.0f};
uint64_t rep_fixed64[5] = {0, 0, 0, 0, 2011};
int64_t rep_sfixed64[5] = {0, 0, 0, 0, -2012};
double rep_double[5] = {0, 0, 0, 0, 2013.0f};
char* rep_string[5] = {"", "", "", "", "2014"};
static PB_BYTES_ARRAY_T(4) rep_bytes_4 = {4, {'2', '0', '1', '5'}};
pb_bytes_array_t *rep_bytes[5]= {NULL, NULL, NULL, NULL, (pb_bytes_array_t*)&rep_bytes_4};
static int32_t rep_sub2zero = 0;
static int32_t rep_substuff2 = 2016;
static uint32_t rep_substuff3 = 2016;
SubMessage rep_submsg[5] = {{"", &rep_sub2zero},
{"", &rep_sub2zero},
{"", &rep_sub2zero},
{"", &rep_sub2zero},
{"2016", &rep_substuff2, &rep_substuff3}};
MyEnum rep_enum[5] = {0, 0, 0, 0, MyEnum_Truth};
EmptyMessage rep_emptymsg[5] = {{0}, {0}, {0}, {0}, {0}};
pb_byte_t rep_fbytes[5][4] = {{0}, {0}, {0}, {0}, {'2', '0', '1', '9'}};
int32_t rep_farray[5] = {0, 0, 0, 0, 2040};
uint32_t rep_farray2[3] = {0, 0, 2095};
/* Values for optional fields */
int32_t opt_int32 = 3041;
int64_t opt_int64 = 3042;
uint32_t opt_uint32 = 3043;
uint64_t opt_uint64 = 3044;
int32_t opt_sint32 = 3045;
int64_t opt_sint64 = 3046;
bool opt_bool = true;
uint32_t opt_fixed32 = 3048;
int32_t opt_sfixed32 = 3049;
float opt_float = 3050.0f;
uint64_t opt_fixed64 = 3051;
int64_t opt_sfixed64 = 3052;
double opt_double = 3053.0;
char* opt_string = "3054";
PB_BYTES_ARRAY_T(4) opt_bytes = {4, {'3', '0', '5', '5'}};
static int32_t opt_substuff = 3056;
SubMessage opt_submsg = {"3056", &opt_substuff};
MyEnum opt_enum = MyEnum_Truth;
EmptyMessage opt_emptymsg = {0};
pb_byte_t opt_fbytes[4] = {'3', '0', '5', '9'};
static int32_t oneof_substuff = 4059;
SubMessage oneof_msg1 = {"4059", &oneof_substuff};
NonZeroBasedEnum opt_non_zero_based_enum = NonZeroBasedEnum_Three;
/* Values for the Limits message. */
static int32_t int32_min = INT32_MIN;
static int32_t int32_max = INT32_MAX;
static uint32_t uint32_min = 0;
static uint32_t uint32_max = UINT32_MAX;
static int64_t int64_min = INT64_MIN;
static int64_t int64_max = INT64_MAX;
static uint64_t uint64_min = 0;
static uint64_t uint64_max = UINT64_MAX;
static HugeEnum enum_min = HugeEnum_Negative;
static HugeEnum enum_max = HugeEnum_Positive;
static int32_t largetag = 1001;
Limits req_limits = {&int32_min, &int32_max,
&uint32_min, &uint32_max,
&int64_min, &int64_max,
&uint64_min, &uint64_max,
&enum_min, &enum_max,
&largetag};
/* Values for DescriptorSize8 message. */
static int32_t first = 9991;
static int32_t second = 9992;
DescriptorSize8 req_ds8 = {&first, &second};
/* Values for IntSizes message. */
static int8_t req_int8 = -128;
static uint8_t req_uint8 = 255;
static int8_t req_sint8 = -128;
static int16_t req_int16 = -32768;
static uint16_t req_uint16 = 65535;
static int16_t req_sint16 = -32768;
IntSizes req_intsizes = {&req_int8, &req_uint8, &req_sint8,
&req_int16, &req_uint16, &req_sint16};
/* Initialize the message struct with pointers to the fields. */
AllTypes alltypes = {0};
alltypes.req_int32 = &req_int32;
alltypes.req_int64 = &req_int64;
alltypes.req_uint32 = &req_uint32;
alltypes.req_uint64 = &req_uint64;
alltypes.req_sint32 = &req_sint32;
alltypes.req_sint64 = &req_sint64;
alltypes.req_bool = &req_bool;
alltypes.req_fixed32 = &req_fixed32;
alltypes.req_sfixed32 = &req_sfixed32;
alltypes.req_float = &req_float;
alltypes.req_fixed64 = &req_fixed64;
alltypes.req_sfixed64 = &req_sfixed64;
alltypes.req_double = &req_double;
alltypes.req_string = req_string;
alltypes.req_bytes = (pb_bytes_array_t*)&req_bytes;
alltypes.req_submsg = &req_submsg;
alltypes.req_enum = &req_enum;
alltypes.req_emptymsg = &req_emptymsg;
alltypes.req_fbytes = &req_fbytes;
alltypes.req_limits = &req_limits;
alltypes.req_ds8 = &req_ds8;
alltypes.req_intsizes = &req_intsizes;
alltypes.rep_int32_count = 5; alltypes.rep_int32 = rep_int32;
alltypes.rep_int64_count = 5; alltypes.rep_int64 = rep_int64;
alltypes.rep_uint32_count = 5; alltypes.rep_uint32 = rep_uint32;
alltypes.rep_uint64_count = 5; alltypes.rep_uint64 = rep_uint64;
alltypes.rep_sint32_count = 5; alltypes.rep_sint32 = rep_sint32;
alltypes.rep_sint64_count = 5; alltypes.rep_sint64 = rep_sint64;
alltypes.rep_bool_count = 5; alltypes.rep_bool = rep_bool;
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32 = rep_fixed32;
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32 = rep_sfixed32;
alltypes.rep_float_count = 5; alltypes.rep_float = rep_float;
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64 = rep_fixed64;
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64 = rep_sfixed64;
alltypes.rep_double_count = 5; alltypes.rep_double = rep_double;
alltypes.rep_string_count = 5; alltypes.rep_string = rep_string;
alltypes.rep_bytes_count = 5; alltypes.rep_bytes = rep_bytes;
alltypes.rep_submsg_count = 5; alltypes.rep_submsg = rep_submsg;
alltypes.rep_enum_count = 5; alltypes.rep_enum = rep_enum;
alltypes.rep_emptymsg_count = 5; alltypes.rep_emptymsg = rep_emptymsg;
alltypes.rep_fbytes_count = 5; alltypes.rep_fbytes = rep_fbytes;
alltypes.rep_farray = &rep_farray;
alltypes.rep_farray2 = &rep_farray2;
if (mode != 0)
{
/* Fill in values for optional fields */
alltypes.opt_int32 = &opt_int32;
alltypes.opt_int64 = &opt_int64;
alltypes.opt_uint32 = &opt_uint32;
alltypes.opt_uint64 = &opt_uint64;
alltypes.opt_sint32 = &opt_sint32;
alltypes.opt_sint64 = &opt_sint64;
alltypes.opt_bool = &opt_bool;
alltypes.opt_fixed32 = &opt_fixed32;
alltypes.opt_sfixed32 = &opt_sfixed32;
alltypes.opt_float = &opt_float;
alltypes.opt_fixed64 = &opt_fixed64;
alltypes.opt_sfixed64 = &opt_sfixed64;
alltypes.opt_double = &opt_double;
alltypes.opt_string = opt_string;
alltypes.opt_bytes = (pb_bytes_array_t*)&opt_bytes;
alltypes.opt_submsg = &opt_submsg;
alltypes.opt_enum = &opt_enum;
alltypes.opt_emptymsg = &opt_emptymsg;
alltypes.opt_fbytes = &opt_fbytes;
alltypes.which_oneof = AllTypes_oneof_msg1_tag;
alltypes.oneof.oneof_msg1 = &oneof_msg1;
alltypes.opt_non_zero_based_enum = &opt_non_zero_based_enum;
}
alltypes.end = &end;
{
uint8_t buffer[4096];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, AllTypes_fields, &alltypes))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
}
}

View File

@@ -0,0 +1,34 @@
# Version of AllTypes test case for protobuf 3 file format.
Import("env")
env.NanopbProto(["alltypes", "alltypes.options"])
enc = env.Program(["encode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
# Test the round-trip from nanopb encoder to nanopb decoder
env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"])
# Re-encode the data using protoc, and check that the results from nanopb
# match byte-per-byte to the protoc output.
env.Decode("encode_alltypes.output.decoded",
["encode_alltypes.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("encode_alltypes.output.recoded",
["encode_alltypes.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["encode_alltypes.output", "encode_alltypes.output.recoded"])
# Do the same checks with the optional fields present.
env.RunTest("optionals.output", enc, ARGS = ['1'])
env.RunTest("optionals.decout", [dec, "optionals.output"], ARGS = ['1'])
env.Decode("optionals.output.decoded",
["optionals.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("optionals.output.recoded",
["optionals.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["optionals.output", "optionals.output.recoded"])

View File

@@ -0,0 +1,5 @@
* max_size:16
* max_count:5
*.*fbytes fixed_length:true max_size:4
*.req_limits proto3_singular_msgs:true

View File

@@ -0,0 +1,101 @@
syntax = "proto3";
// package name placeholder
message SubMessage {
string substuff1 = 1;
int32 substuff2 = 2;
fixed32 substuff3 = 3;
}
message EmptyMessage {
}
enum HugeEnum {
HE_Zero = 0;
Negative = -2147483647; /* protoc doesn't accept -2147483648 here */
Positive = 2147483647;
}
message Limits {
int32 int32_min = 1;
int32 int32_max = 2;
uint32 uint32_min = 3;
uint32 uint32_max = 4;
int64 int64_min = 5;
int64 int64_max = 6;
uint64 uint64_min = 7;
uint64 uint64_max = 8;
HugeEnum enum_min = 9;
HugeEnum enum_max = 10;
}
enum MyEnum {
Zero = 0;
First = 1;
Second = 2;
Truth = 42;
}
message AllTypes {
int32 sng_int32 = 1;
int64 sng_int64 = 2;
uint32 sng_uint32 = 3;
uint64 sng_uint64 = 4;
sint32 sng_sint32 = 5;
sint64 sng_sint64 = 6;
bool sng_bool = 7;
fixed32 sng_fixed32 = 8;
sfixed32 sng_sfixed32= 9;
float sng_float = 10;
fixed64 sng_fixed64 = 11;
sfixed64 sng_sfixed64= 12;
double sng_double = 13;
string sng_string = 14;
bytes sng_bytes = 15;
SubMessage sng_submsg = 16;
MyEnum sng_enum = 17;
EmptyMessage sng_emptymsg = 18;
bytes sng_fbytes = 19;
repeated int32 rep_int32 = 21 [packed = true];
repeated int64 rep_int64 = 22 [packed = true];
repeated uint32 rep_uint32 = 23 [packed = true];
repeated uint64 rep_uint64 = 24 [packed = true];
repeated sint32 rep_sint32 = 25 [packed = true];
repeated sint64 rep_sint64 = 26 [packed = true];
repeated bool rep_bool = 27 [packed = true];
repeated fixed32 rep_fixed32 = 28 [packed = true];
repeated sfixed32 rep_sfixed32= 29 [packed = true];
repeated float rep_float = 30 [packed = true];
repeated fixed64 rep_fixed64 = 31 [packed = true];
repeated sfixed64 rep_sfixed64= 32 [packed = true];
repeated double rep_double = 33 [packed = true];
repeated string rep_string = 34;
repeated bytes rep_bytes = 35;
repeated SubMessage rep_submsg = 36;
repeated MyEnum rep_enum = 37 [packed = true];
repeated EmptyMessage rep_emptymsg = 38;
repeated bytes rep_fbytes = 39;
oneof oneof
{
SubMessage oneof_msg1 = 60;
EmptyMessage oneof_msg2 = 61;
SubMessage static_msg = 63;
}
// Check that extreme integer values are handled correctly
Limits req_limits = 98;
// Just to make sure that the size of the fields has been calculated
// properly, i.e. otherwise a bug in last field might not be detected.
int32 end = 999;
}

View File

@@ -0,0 +1,166 @@
/* Tests the decoding of all types.
* This is the counterpart of test_encode3.
* Run e.g. ./test_encode3 | ./test_decode3
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
#include "unittests.h"
/* This function is called once from main(), it handles
the decoding and checks the fields. */
bool check_alltypes(pb_istream_t *stream, int mode)
{
int status = 0;
AllTypes alltypes = AllTypes_init_zero;
/* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes));
if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false;
TEST(alltypes.rep_int32_count == 5 && alltypes.rep_int32[4] == -2001 && alltypes.rep_int32[0] == 0);
TEST(alltypes.rep_int64_count == 5 && alltypes.rep_int64[4] == -2002 && alltypes.rep_int64[0] == 0);
TEST(alltypes.rep_uint32_count == 5 && alltypes.rep_uint32[4] == 2003 && alltypes.rep_uint32[0] == 0);
TEST(alltypes.rep_uint64_count == 5 && alltypes.rep_uint64[4] == 2004 && alltypes.rep_uint64[0] == 0);
TEST(alltypes.rep_sint32_count == 5 && alltypes.rep_sint32[4] == -2005 && alltypes.rep_sint32[0] == 0);
TEST(alltypes.rep_sint64_count == 5 && alltypes.rep_sint64[4] == -2006 && alltypes.rep_sint64[0] == 0);
TEST(alltypes.rep_bool_count == 5 && alltypes.rep_bool[4] == true && alltypes.rep_bool[0] == false);
TEST(alltypes.rep_fixed32_count == 5 && alltypes.rep_fixed32[4] == 2008 && alltypes.rep_fixed32[0] == 0);
TEST(alltypes.rep_sfixed32_count == 5 && alltypes.rep_sfixed32[4] == -2009 && alltypes.rep_sfixed32[0] == 0);
TEST(alltypes.rep_float_count == 5 && alltypes.rep_float[4] == 2010.0f && alltypes.rep_float[0] == 0.0f);
TEST(alltypes.rep_fixed64_count == 5 && alltypes.rep_fixed64[4] == 2011 && alltypes.rep_fixed64[0] == 0);
TEST(alltypes.rep_sfixed64_count == 5 && alltypes.rep_sfixed64[4] == -2012 && alltypes.rep_sfixed64[0] == 0);
TEST(alltypes.rep_double_count == 5 && alltypes.rep_double[4] == 2013.0 && alltypes.rep_double[0] == 0.0);
TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0');
TEST(alltypes.rep_bytes_count == 5 && alltypes.rep_bytes[4].size == 4 && alltypes.rep_bytes[0].size == 0);
TEST(memcmp(alltypes.rep_bytes[4].bytes, "2015", 4) == 0);
TEST(alltypes.rep_submsg_count == 5);
TEST(strcmp(alltypes.rep_submsg[4].substuff1, "2016") == 0 && alltypes.rep_submsg[0].substuff1[0] == '\0');
TEST(alltypes.rep_submsg[4].substuff2 == 2016 && alltypes.rep_submsg[0].substuff2 == 0);
TEST(alltypes.rep_submsg[4].substuff3 == 2016 && alltypes.rep_submsg[0].substuff3 == 0);
TEST(alltypes.rep_enum_count == 5 && alltypes.rep_enum[4] == MyEnum_Truth && alltypes.rep_enum[0] == MyEnum_Zero);
TEST(alltypes.rep_emptymsg_count == 5);
TEST(alltypes.rep_fbytes_count == 5);
TEST(alltypes.rep_fbytes[0][0] == 0 && alltypes.rep_fbytes[0][3] == 0);
TEST(memcmp(alltypes.rep_fbytes[4], "2019", 4) == 0);
if (mode == 0)
{
/* Expect default values */
TEST(alltypes.sng_int32 == 0);
TEST(alltypes.sng_int64 == 0);
TEST(alltypes.sng_uint32 == 0);
TEST(alltypes.sng_uint64 == 0);
TEST(alltypes.sng_sint32 == 0);
TEST(alltypes.sng_sint64 == 0);
TEST(alltypes.sng_bool == false);
TEST(alltypes.sng_fixed32 == 0);
TEST(alltypes.sng_sfixed32 == 0);
TEST(alltypes.sng_float == 0.0f);
TEST(alltypes.sng_fixed64 == 0);
TEST(alltypes.sng_sfixed64 == 0);
TEST(alltypes.sng_double == 0.0);
TEST(strcmp(alltypes.sng_string, "") == 0);
TEST(alltypes.sng_bytes.size == 0);
TEST(alltypes.has_sng_submsg == false);
TEST(strcmp(alltypes.sng_submsg.substuff1, "") == 0);
TEST(alltypes.sng_submsg.substuff2 == 0);
TEST(alltypes.sng_submsg.substuff3 == 0);
TEST(alltypes.sng_enum == MyEnum_Zero);
TEST(alltypes.sng_fbytes[0] == 0 &&
alltypes.sng_fbytes[1] == 0 &&
alltypes.sng_fbytes[2] == 0 &&
alltypes.sng_fbytes[3] == 0);
TEST(alltypes.which_oneof == 0);
}
else
{
/* Expect filled-in values */
TEST(alltypes.sng_int32 == 3041);
TEST(alltypes.sng_int64 == 3042);
TEST(alltypes.sng_uint32 == 3043);
TEST(alltypes.sng_uint64 == 3044);
TEST(alltypes.sng_sint32 == 3045);
TEST(alltypes.sng_sint64 == 3046);
TEST(alltypes.sng_bool == true);
TEST(alltypes.sng_fixed32 == 3048);
TEST(alltypes.sng_sfixed32 == 3049);
TEST(alltypes.sng_float == 3050.0f);
TEST(alltypes.sng_fixed64 == 3051);
TEST(alltypes.sng_sfixed64 == 3052);
TEST(alltypes.sng_double == 3053.0);
TEST(strcmp(alltypes.sng_string, "3054") == 0);
TEST(alltypes.sng_bytes.size == 4);
TEST(memcmp(alltypes.sng_bytes.bytes, "3055", 4) == 0);
TEST(alltypes.has_sng_submsg == true);
TEST(strcmp(alltypes.sng_submsg.substuff1, "3056") == 0);
TEST(alltypes.sng_submsg.substuff2 == 3056);
TEST(alltypes.sng_submsg.substuff3 == 0);
TEST(alltypes.sng_enum == MyEnum_Truth);
TEST(memcmp(alltypes.sng_fbytes, "3059", 4) == 0);
TEST(alltypes.which_oneof == AllTypes_oneof_msg1_tag);
TEST(strcmp(alltypes.oneof.oneof_msg1.substuff1, "4059") == 0);
TEST(alltypes.oneof.oneof_msg1.substuff2 == 4059);
}
TEST(alltypes.req_limits.int32_min == INT32_MIN);
TEST(alltypes.req_limits.int32_max == INT32_MAX);
TEST(alltypes.req_limits.uint32_min == 0);
TEST(alltypes.req_limits.uint32_max == UINT32_MAX);
TEST(alltypes.req_limits.int64_min == INT64_MIN);
TEST(alltypes.req_limits.int64_max == INT64_MAX);
TEST(alltypes.req_limits.uint64_min == 0);
TEST(alltypes.req_limits.uint64_max == UINT64_MAX);
TEST(alltypes.req_limits.enum_min == HugeEnum_Negative);
TEST(alltypes.req_limits.enum_max == HugeEnum_Positive);
TEST(alltypes.end == 1099);
return status == 0;
}
int main(int argc, char **argv)
{
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
/* Whether to expect the optional values or the default values. */
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
/* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count);
/* Decode and print out the stuff */
if (!check_alltypes(&stream, mode))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
} else {
return 0;
}
}

View File

@@ -0,0 +1,112 @@
/* Attempts to test all the datatypes supported by ProtoBuf3.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_encode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
int main(int argc, char **argv)
{
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Initialize the structure with constants */
AllTypes alltypes = AllTypes_init_zero;
alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = -2001;
alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = -2002;
alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003;
alltypes.rep_uint64_count = 5; alltypes.rep_uint64[4] = 2004;
alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = -2005;
alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = -2006;
alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true;
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32[4] = 2008;
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32[4] = -2009;
alltypes.rep_float_count = 5; alltypes.rep_float[4] = 2010.0f;
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64[4] = 2011;
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64[4] = -2012;
alltypes.rep_double_count = 5; alltypes.rep_double[4] = 2013.0;
alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014");
alltypes.rep_bytes_count = 5; alltypes.rep_bytes[4].size = 4;
memcpy(alltypes.rep_bytes[4].bytes, "2015", 4);
alltypes.rep_submsg_count = 5;
strcpy(alltypes.rep_submsg[4].substuff1, "2016");
alltypes.rep_submsg[4].substuff2 = 2016;
alltypes.rep_submsg[4].substuff3 = 2016;
alltypes.rep_enum_count = 5; alltypes.rep_enum[4] = MyEnum_Truth;
alltypes.rep_emptymsg_count = 5;
alltypes.rep_fbytes_count = 5;
memcpy(alltypes.rep_fbytes[4], "2019", 4);
alltypes.req_limits.int32_min = INT32_MIN;
alltypes.req_limits.int32_max = INT32_MAX;
alltypes.req_limits.uint32_min = 0;
alltypes.req_limits.uint32_max = UINT32_MAX;
alltypes.req_limits.int64_min = INT64_MIN;
alltypes.req_limits.int64_max = INT64_MAX;
alltypes.req_limits.uint64_min = 0;
alltypes.req_limits.uint64_max = UINT64_MAX;
alltypes.req_limits.enum_min = HugeEnum_Negative;
alltypes.req_limits.enum_max = HugeEnum_Positive;
if (mode != 0)
{
/* Fill in values for singular fields */
alltypes.sng_int32 = 3041;
alltypes.sng_int64 = 3042;
alltypes.sng_uint32 = 3043;
alltypes.sng_uint64 = 3044;
alltypes.sng_sint32 = 3045;
alltypes.sng_sint64 = 3046;
alltypes.sng_bool = true;
alltypes.sng_fixed32 = 3048;
alltypes.sng_sfixed32 = 3049;
alltypes.sng_float = 3050.0f;
alltypes.sng_fixed64 = 3051;
alltypes.sng_sfixed64 = 3052;
alltypes.sng_double = 3053.0;
strcpy(alltypes.sng_string, "3054");
alltypes.sng_bytes.size = 4;
memcpy(alltypes.sng_bytes.bytes, "3055", 4);
alltypes.has_sng_submsg = true;
strcpy(alltypes.sng_submsg.substuff1, "3056");
alltypes.sng_submsg.substuff2 = 3056;
alltypes.sng_enum = MyEnum_Truth;
memcpy(alltypes.sng_fbytes, "3059", 4);
alltypes.which_oneof = AllTypes_oneof_msg1_tag;
strcpy(alltypes.oneof.oneof_msg1.substuff1, "4059");
alltypes.oneof.oneof_msg1.substuff2 = 4059;
}
alltypes.end = 1099;
{
uint8_t buffer[AllTypes_size];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, AllTypes_fields, &alltypes))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
}
}

View File

@@ -0,0 +1,23 @@
# Test the AllTypes encoding & decoding using callbacks for all fields.
Import("env", "malloc_env")
c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.proto", "#alltypes_proto3/alltypes.proto", c)
env.NanopbProto(["alltypes", "alltypes.options"])
enc = env.Program(["encode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_alltypes_callback.c", "alltypes.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
refdec = "$BUILD/alltypes_proto3/decode_alltypes$PROGSUFFIX"
# Encode and compare results
env.RunTest(enc)
env.RunTest("decode_alltypes.output", [refdec, "encode_alltypes_callback.output"])
env.RunTest("decode_alltypes_callback.output", [dec, "encode_alltypes_callback.output"])
# Do the same thing with the optional fields present
env.RunTest("optionals.output", enc, ARGS = ['1'])
env.RunTest("optionals.refdecout", [refdec, "optionals.output"], ARGS = ['1'])
env.RunTest("optionals.decout", [dec, "optionals.output"], ARGS = ['1'])

View File

@@ -0,0 +1,8 @@
# Generate all fields as callbacks.
AllTypes.* type:FT_CALLBACK
SubMessage.substuff1 max_size:16
AllTypes.oneof no_unions:true
# With FT_CALLBACK, these options should get ignored
*.*fbytes fixed_length:true max_size:4

View File

@@ -0,0 +1,422 @@
/* Attempts to test all the datatypes supported by ProtoBuf when used as callback fields.
* Note that normally there would be no reason to use callback fields for this,
* because each encoder defined here only gives a single field.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
#define TEST(x) if (!(x)) { \
printf("Test %s failed (in field %d).\n", #x, field->tag); \
return false; \
}
static bool read_varint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
TEST((int64_t)value == (intptr_t)*arg);
return true;
}
static bool read_svarint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int64_t value;
if (!pb_decode_svarint(stream, &value))
return false;
TEST(value == (intptr_t)*arg);
return true;
}
static bool read_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint32_t value;
if (!pb_decode_fixed32(stream, &value))
return false;
TEST(value == *(uint32_t*)*arg);
return true;
}
static bool read_fixed64(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(value == *(uint64_t*)*arg);
return true;
}
static bool read_double(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (sizeof(double) == sizeof(float))
{
float value;
if (!pb_decode_double_as_float(stream, &value))
return false;
TEST(memcmp(&value, *arg, sizeof(float)) == 0);
return true;
}
#endif
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(value == *(uint64_t*)*arg);
return true;
}
static bool read_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint8_t buf[16] = {0};
size_t len = stream->bytes_left;
if (len > sizeof(buf) - 1 || !pb_read(stream, buf, len))
return false;
TEST(strcmp((char*)buf, *arg) == 0);
return true;
}
static bool read_submsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
SubMessage submsg = {""};
SubMessage *ref = *arg;
if (!pb_decode(stream, SubMessage_fields, &submsg))
return false;
TEST(strcmp(submsg.substuff1, ref->substuff1) == 0);
TEST(submsg.substuff2 == ref->substuff2);
TEST(submsg.substuff3 == ref->substuff3);
return true;
}
static bool read_emptymsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
EmptyMessage emptymsg = {0};
return pb_decode(stream, EmptyMessage_fields, &emptymsg);
}
static bool read_repeated_varint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int32_t** expected = (int32_t**)arg;
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_svarint(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int32_t** expected = (int32_t**)arg;
int64_t value;
if (!pb_decode_svarint(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint32_t** expected = (uint32_t**)arg;
uint32_t value;
if (!pb_decode_fixed32(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_fixed64(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t** expected = (uint64_t**)arg;
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_double(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (sizeof(double) == sizeof(float))
{
float** expectedf = (float**)arg;
float value;
if (!pb_decode_double_as_float(stream, &value))
return false;
TEST(memcmp(&value, (*expectedf)++, sizeof(float)) == 0);
return true;
}
#endif
uint64_t** expected = (uint64_t**)arg;
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
TEST(*(*expected)++ == value);
return true;
}
static bool read_repeated_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint8_t*** expected = (uint8_t***)arg;
uint8_t buf[16] = {0};
size_t len = stream->bytes_left;
if (len > sizeof(buf) - 1 || !pb_read(stream, buf, len))
return false;
TEST(strcmp((char*)*(*expected)++, (char*)buf) == 0);
return true;
}
static bool read_repeated_submsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
SubMessage** expected = (SubMessage**)arg;
SubMessage submsg = {""};
if (!pb_decode(stream, SubMessage_fields, &submsg))
return false;
TEST(strcmp(submsg.substuff1, (*expected)->substuff1) == 0);
TEST(submsg.substuff2 == (*expected)->substuff2);
TEST(submsg.substuff3 == (*expected)->substuff3);
(*expected)++;
return true;
}
static bool read_limits(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
Limits decoded = {0};
if (!pb_decode(stream, Limits_fields, &decoded))
return false;
TEST(decoded.int32_min == INT32_MIN);
TEST(decoded.int32_max == INT32_MAX);
TEST(decoded.uint32_min == 0);
TEST(decoded.uint32_max == UINT32_MAX);
TEST(decoded.int64_min == INT64_MIN);
TEST(decoded.int64_max == INT64_MAX);
TEST(decoded.uint64_min == 0);
TEST(decoded.uint64_max == UINT64_MAX);
TEST(decoded.enum_min == HugeEnum_Negative);
TEST(decoded.enum_max == HugeEnum_Positive);
return true;
}
/* This function is called once from main(), it handles
the decoding and checks the fields. */
bool check_alltypes(pb_istream_t *stream, int mode)
{
/* Values for use from callbacks through pointers. */
bool status;
int32_t rep_int32[5] = {0, 0, 0, 0, -2001};
int32_t rep_int64[5] = {0, 0, 0, 0, -2002};
int32_t rep_uint32[5] = {0, 0, 0, 0, 2003};
int32_t rep_uint64[5] = {0, 0, 0, 0, 2004};
int32_t rep_sint32[5] = {0, 0, 0, 0, -2005};
int32_t rep_sint64[5] = {0, 0, 0, 0, -2006};
int32_t rep_bool[5] = {false, false, false, false, true};
uint32_t rep_fixed32[5] = {0, 0, 0, 0, 2008};
int32_t rep_sfixed32[5] = {0, 0, 0, 0, -2009};
float rep_float[5] = {0, 0, 0, 0, 2010.0f};
uint64_t rep_fixed64[5] = {0, 0, 0, 0, 2011};
int64_t rep_sfixed64[5] = {0, 0, 0, 0, -2012};
double rep_double[5] = {0, 0, 0, 0, 2013.0};
char* rep_string[5] = {"", "", "", "", "2014"};
char* rep_bytes[5] = {"", "", "", "", "2015"};
SubMessage rep_submsg[5] = {{"", 0, 0},
{"", 0, 0},
{"", 0, 0},
{"", 0, 0},
{"2016", 2016, 2016}};
int32_t rep_enum[5] = {0, 0, 0, 0, MyEnum_Truth};
uint32_t sng_fixed32 = 3048;
int32_t sng_sfixed32 = 3049;
float sng_float = 3050.0f;
uint64_t sng_fixed64 = 3051;
int64_t sng_sfixed64 = 3052;
double sng_double = 3053.0f;
SubMessage sng_submsg = {"3056", 3056};
SubMessage oneof_msg1 = {"4059", 4059};
AllTypes alltypes = AllTypes_init_zero;
/* Bind callbacks for repeated fields */
alltypes.rep_int32.funcs.decode = &read_repeated_varint;
alltypes.rep_int32.arg = rep_int32;
alltypes.rep_int64.funcs.decode = &read_repeated_varint;
alltypes.rep_int64.arg = rep_int64;
alltypes.rep_uint32.funcs.decode = &read_repeated_varint;
alltypes.rep_uint32.arg = rep_uint32;
alltypes.rep_uint64.funcs.decode = &read_repeated_varint;
alltypes.rep_uint64.arg = rep_uint64;
alltypes.rep_sint32.funcs.decode = &read_repeated_svarint;
alltypes.rep_sint32.arg = rep_sint32;
alltypes.rep_sint64.funcs.decode = &read_repeated_svarint;
alltypes.rep_sint64.arg = rep_sint64;
alltypes.rep_bool.funcs.decode = &read_repeated_varint;
alltypes.rep_bool.arg = rep_bool;
alltypes.rep_fixed32.funcs.decode = &read_repeated_fixed32;
alltypes.rep_fixed32.arg = rep_fixed32;
alltypes.rep_sfixed32.funcs.decode = &read_repeated_fixed32;
alltypes.rep_sfixed32.arg = rep_sfixed32;
alltypes.rep_float.funcs.decode = &read_repeated_fixed32;
alltypes.rep_float.arg = rep_float;
alltypes.rep_fixed64.funcs.decode = &read_repeated_fixed64;
alltypes.rep_fixed64.arg = rep_fixed64;
alltypes.rep_sfixed64.funcs.decode = &read_repeated_fixed64;
alltypes.rep_sfixed64.arg = rep_sfixed64;
alltypes.rep_double.funcs.decode = &read_repeated_double;
alltypes.rep_double.arg = rep_double;
alltypes.rep_string.funcs.decode = &read_repeated_string;
alltypes.rep_string.arg = rep_string;
alltypes.rep_bytes.funcs.decode = &read_repeated_string;
alltypes.rep_bytes.arg = rep_bytes;
alltypes.rep_submsg.funcs.decode = &read_repeated_submsg;
alltypes.rep_submsg.arg = rep_submsg;
alltypes.rep_enum.funcs.decode = &read_repeated_varint;
alltypes.rep_enum.arg = rep_enum;
alltypes.rep_emptymsg.funcs.decode = &read_emptymsg;
alltypes.req_limits.funcs.decode = &read_limits;
alltypes.end.funcs.decode = &read_varint;
alltypes.end.arg = (void*)1099;
/* Bind callbacks for optional fields */
if (mode == 1)
{
alltypes.sng_int32.funcs.decode = &read_varint;
alltypes.sng_int32.arg = (void*)3041;
alltypes.sng_int64.funcs.decode = &read_varint;
alltypes.sng_int64.arg = (void*)3042;
alltypes.sng_uint32.funcs.decode = &read_varint;
alltypes.sng_uint32.arg = (void*)3043;
alltypes.sng_uint64.funcs.decode = &read_varint;
alltypes.sng_uint64.arg = (void*)3044;
alltypes.sng_sint32.funcs.decode = &read_svarint;
alltypes.sng_sint32.arg = (void*)3045;
alltypes.sng_sint64.funcs.decode = &read_svarint;
alltypes.sng_sint64.arg = (void*)3046;
alltypes.sng_bool.funcs.decode = &read_varint;
alltypes.sng_bool.arg = (void*)true;
alltypes.sng_fixed32.funcs.decode = &read_fixed32;
alltypes.sng_fixed32.arg = &sng_fixed32;
alltypes.sng_sfixed32.funcs.decode = &read_fixed32;
alltypes.sng_sfixed32.arg = &sng_sfixed32;
alltypes.sng_float.funcs.decode = &read_fixed32;
alltypes.sng_float.arg = &sng_float;
alltypes.sng_fixed64.funcs.decode = &read_fixed64;
alltypes.sng_fixed64.arg = &sng_fixed64;
alltypes.sng_sfixed64.funcs.decode = &read_fixed64;
alltypes.sng_sfixed64.arg = &sng_sfixed64;
alltypes.sng_double.funcs.decode = &read_double;
alltypes.sng_double.arg = &sng_double;
alltypes.sng_string.funcs.decode = &read_string;
alltypes.sng_string.arg = "3054";
alltypes.sng_bytes.funcs.decode = &read_string;
alltypes.sng_bytes.arg = "3055";
alltypes.sng_submsg.funcs.decode = &read_submsg;
alltypes.sng_submsg.arg = &sng_submsg;
alltypes.sng_enum.funcs.decode = &read_varint;
alltypes.sng_enum.arg = (void*)MyEnum_Truth;
alltypes.sng_emptymsg.funcs.decode = &read_emptymsg;
alltypes.oneof_msg1.funcs.decode = &read_submsg;
alltypes.oneof_msg1.arg = &oneof_msg1;
}
status = pb_decode(stream, AllTypes_fields, &alltypes);
#ifdef PB_ENABLE_MALLOC
/* Just to check for any interference between pb_release() and callback fields */
pb_release(AllTypes_fields, &alltypes);
#endif
return status;
}
int main(int argc, char **argv)
{
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
/* Whether to expect the optional values or the default values. */
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
/* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count);
/* Decode and print out the stuff */
if (!check_alltypes(&stream, mode))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
} else {
return 0;
}
}

View File

@@ -0,0 +1,380 @@
/* Attempts to test all the datatypes supported by ProtoBuf when used as callback fields.
* Note that normally there would be no reason to use callback fields for this,
* because each encoder defined here only gives a single field.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_encode.h>
#include "alltypes.pb.h"
#include "test_helpers.h"
static bool write_varint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, (intptr_t)*arg);
}
static bool write_svarint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, (intptr_t)*arg);
}
static bool write_fixed32(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_fixed32(stream, *arg);
}
static bool write_fixed64(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_double(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (sizeof(double) == sizeof(float))
return pb_encode_tag_for_field(stream, field) &&
pb_encode_float_as_double(stream, *(float*)*arg);
#endif
return pb_encode_tag_for_field(stream, field) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, *arg, strlen(*arg));
}
static bool write_submsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, *arg);
}
static bool write_emptymsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
EmptyMessage emptymsg = {0};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg);
}
static bool write_repeated_varint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_varint(stream, (intptr_t)*arg);
}
static bool write_repeated_svarint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_svarint(stream, (intptr_t)*arg);
}
static bool write_repeated_fixed32(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint32_t dummy = 0;
/* Make it a packed field */
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 4) && /* Number of bytes */
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, &dummy) &&
pb_encode_fixed32(stream, *arg);
}
static bool write_repeated_fixed64(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint64_t dummy = 0;
/* Make it a packed field */
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 8) && /* Number of bytes */
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_repeated_double(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint64_t dummy = 0;
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (sizeof(double) == sizeof(float))
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 8) && /* Number of bytes */
pb_encode_float_as_double(stream, 0.0f) &&
pb_encode_float_as_double(stream, 0.0f) &&
pb_encode_float_as_double(stream, 0.0f) &&
pb_encode_float_as_double(stream, 0.0f) &&
pb_encode_float_as_double(stream, *(float*)*arg);
#endif
/* Make it a packed field */
return pb_encode_tag(stream, PB_WT_STRING, field->tag) &&
pb_encode_varint(stream, 5 * 8) && /* Number of bytes */
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, &dummy) &&
pb_encode_fixed64(stream, *arg);
}
static bool write_repeated_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
return pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, 0, 0) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_string(stream, *arg, strlen(*arg));
}
static bool write_repeated_submsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
SubMessage dummy = {""};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, &dummy) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, SubMessage_fields, *arg);
}
static bool write_limits(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
Limits limits = {0};
limits.int32_min = INT32_MIN;
limits.int32_max = INT32_MAX;
limits.uint32_min = 0;
limits.uint32_max = UINT32_MAX;
limits.int64_min = INT64_MIN;
limits.int64_max = INT64_MAX;
limits.uint64_min = 0;
limits.uint64_max = UINT64_MAX;
limits.enum_min = HugeEnum_Negative;
limits.enum_max = HugeEnum_Positive;
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, Limits_fields, &limits);
}
static bool write_repeated_emptymsg(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
EmptyMessage emptymsg = {0};
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg) &&
pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, EmptyMessage_fields, &emptymsg);
}
int main(int argc, char **argv)
{
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Values for use from callbacks through pointers. */
uint32_t rep_fixed32 = 2008;
int32_t rep_sfixed32 = -2009;
float rep_float = 2010.0f;
uint64_t rep_fixed64 = 2011;
int64_t rep_sfixed64 = -2012;
double rep_double = 2013.0;
SubMessage rep_submsg = {"2016", 2016, 2016};
uint32_t sng_fixed32 = 3048;
int32_t sng_sfixed32 = 3049;
float sng_float = 3050.0f;
uint64_t sng_fixed64 = 3051;
int64_t sng_sfixed64 = 3052;
double sng_double = 3053.0f;
SubMessage sng_submsg = {"3056", 3056};
SubMessage oneof_msg1 = {"4059", 4059};
AllTypes alltypes = AllTypes_init_zero;
/* Bind callbacks for repeated fields */
alltypes.rep_int32.funcs.encode = &write_repeated_varint;
alltypes.rep_int32.arg = (void*)-2001;
alltypes.rep_int64.funcs.encode = &write_repeated_varint;
alltypes.rep_int64.arg = (void*)-2002;
alltypes.rep_uint32.funcs.encode = &write_repeated_varint;
alltypes.rep_uint32.arg = (void*)2003;
alltypes.rep_uint64.funcs.encode = &write_repeated_varint;
alltypes.rep_uint64.arg = (void*)2004;
alltypes.rep_sint32.funcs.encode = &write_repeated_svarint;
alltypes.rep_sint32.arg = (void*)-2005;
alltypes.rep_sint64.funcs.encode = &write_repeated_svarint;
alltypes.rep_sint64.arg = (void*)-2006;
alltypes.rep_bool.funcs.encode = &write_repeated_varint;
alltypes.rep_bool.arg = (void*)true;
alltypes.rep_fixed32.funcs.encode = &write_repeated_fixed32;
alltypes.rep_fixed32.arg = &rep_fixed32;
alltypes.rep_sfixed32.funcs.encode = &write_repeated_fixed32;
alltypes.rep_sfixed32.arg = &rep_sfixed32;
alltypes.rep_float.funcs.encode = &write_repeated_fixed32;
alltypes.rep_float.arg = &rep_float;
alltypes.rep_fixed64.funcs.encode = &write_repeated_fixed64;
alltypes.rep_fixed64.arg = &rep_fixed64;
alltypes.rep_sfixed64.funcs.encode = &write_repeated_fixed64;
alltypes.rep_sfixed64.arg = &rep_sfixed64;
alltypes.rep_double.funcs.encode = &write_repeated_double;
alltypes.rep_double.arg = &rep_double;
alltypes.rep_string.funcs.encode = &write_repeated_string;
alltypes.rep_string.arg = "2014";
alltypes.rep_bytes.funcs.encode = &write_repeated_string;
alltypes.rep_bytes.arg = "2015";
alltypes.rep_submsg.funcs.encode = &write_repeated_submsg;
alltypes.rep_submsg.arg = &rep_submsg;
alltypes.rep_enum.funcs.encode = &write_repeated_varint;
alltypes.rep_enum.arg = (void*)MyEnum_Truth;
alltypes.rep_emptymsg.funcs.encode = &write_repeated_emptymsg;
alltypes.rep_fbytes.funcs.encode = &write_repeated_string;
alltypes.rep_fbytes.arg = "2019";
alltypes.req_limits.funcs.encode = &write_limits;
/* Bind callbacks for singular fields */
if (mode != 0)
{
alltypes.sng_int32.funcs.encode = &write_varint;
alltypes.sng_int32.arg = (void*)3041;
alltypes.sng_int64.funcs.encode = &write_varint;
alltypes.sng_int64.arg = (void*)3042;
alltypes.sng_uint32.funcs.encode = &write_varint;
alltypes.sng_uint32.arg = (void*)3043;
alltypes.sng_uint64.funcs.encode = &write_varint;
alltypes.sng_uint64.arg = (void*)3044;
alltypes.sng_sint32.funcs.encode = &write_svarint;
alltypes.sng_sint32.arg = (void*)3045;
alltypes.sng_sint64.funcs.encode = &write_svarint;
alltypes.sng_sint64.arg = (void*)3046;
alltypes.sng_bool.funcs.encode = &write_varint;
alltypes.sng_bool.arg = (void*)true;
alltypes.sng_fixed32.funcs.encode = &write_fixed32;
alltypes.sng_fixed32.arg = &sng_fixed32;
alltypes.sng_sfixed32.funcs.encode = &write_fixed32;
alltypes.sng_sfixed32.arg = &sng_sfixed32;
alltypes.sng_float.funcs.encode = &write_fixed32;
alltypes.sng_float.arg = &sng_float;
alltypes.sng_fixed64.funcs.encode = &write_fixed64;
alltypes.sng_fixed64.arg = &sng_fixed64;
alltypes.sng_sfixed64.funcs.encode = &write_fixed64;
alltypes.sng_sfixed64.arg = &sng_sfixed64;
alltypes.sng_double.funcs.encode = &write_double;
alltypes.sng_double.arg = &sng_double;
alltypes.sng_string.funcs.encode = &write_string;
alltypes.sng_string.arg = "3054";
alltypes.sng_bytes.funcs.encode = &write_string;
alltypes.sng_bytes.arg = "3055";
alltypes.sng_submsg.funcs.encode = &write_submsg;
alltypes.sng_submsg.arg = &sng_submsg;
alltypes.sng_enum.funcs.encode = &write_varint;
alltypes.sng_enum.arg = (void*)MyEnum_Truth;
alltypes.sng_emptymsg.funcs.encode = &write_emptymsg;
alltypes.sng_fbytes.funcs.encode = &write_string;
alltypes.sng_fbytes.arg = "3059";
alltypes.oneof_msg1.funcs.encode = &write_submsg;
alltypes.oneof_msg1.arg = &oneof_msg1;
}
alltypes.end.funcs.encode = &write_varint;
alltypes.end.arg = (void*)1099;
{
uint8_t buffer[2048];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, AllTypes_fields, &alltypes))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
}
}

View File

@@ -0,0 +1,19 @@
# Test anonymous_oneof generator option
Import('env')
# Anonymous oneofs are supported by clang and gcc
if 'clang' in env['CC'] or 'gcc' in env['CC']:
env2 = env.Clone()
if '-pedantic' in env2['CFLAGS']:
env2['CFLAGS'].remove('-pedantic')
env2.NanopbProto('oneof')
dec = env2.Program(['decode_oneof.c',
'oneof.pb.c',
'$COMMON/pb_decode.o',
'$COMMON/pb_common.o'])
env2.RunTest("message1.txt", [dec, '$BUILD/oneof/message1.pb'], ARGS = ['1'])
env2.RunTest("message2.txt", [dec, '$BUILD/oneof/message2.pb'], ARGS = ['2'])
env2.RunTest("message3.txt", [dec, '$BUILD/oneof/message3.pb'], ARGS = ['3'])

View File

@@ -0,0 +1,88 @@
/* Decode a message using oneof fields */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_decode.h>
#include "oneof.pb.h"
#include "test_helpers.h"
#include "unittests.h"
/* Test the 'AnonymousOneOfMessage' */
int test_oneof_1(pb_istream_t *stream, int option)
{
AnonymousOneOfMessage msg;
int status = 0;
/* To better catch initialization errors */
memset(&msg, 0xAA, sizeof(msg));
if (!pb_decode(stream, AnonymousOneOfMessage_fields, &msg))
{
printf("Decoding failed: %s\n", PB_GET_ERROR(stream));
return 1;
}
/* Check that the basic fields work normally */
TEST(msg.prefix == 123);
TEST(msg.suffix == 321);
/* Check that we got the right oneof according to command line */
if (option == 1)
{
TEST(msg.which_values == AnonymousOneOfMessage_first_tag);
TEST(msg.first == 999);
}
else if (option == 2)
{
TEST(msg.which_values == AnonymousOneOfMessage_second_tag);
TEST(strcmp(msg.second, "abcd") == 0);
}
else if (option == 3)
{
TEST(msg.which_values == AnonymousOneOfMessage_third_tag);
TEST(msg.third.array[0] == 1);
TEST(msg.third.array[1] == 2);
TEST(msg.third.array[2] == 3);
TEST(msg.third.array[3] == 4);
TEST(msg.third.array[4] == 5);
}
return status;
}
int main(int argc, char **argv)
{
uint8_t buffer[AnonymousOneOfMessage_size];
size_t count;
int option;
if (argc != 2)
{
fprintf(stderr, "Usage: decode_oneof [number]\n");
return 1;
}
option = atoi(argv[1]);
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
if (!feof(stdin))
{
printf("Message does not fit in buffer\n");
return 1;
}
{
int status = 0;
pb_istream_t stream;
stream = pb_istream_from_buffer(buffer, count);
status = test_oneof_1(&stream, option);
if (status != 0)
return status;
}
return 0;
}

View File

@@ -0,0 +1,23 @@
syntax = "proto2";
import 'nanopb.proto';
message SubMessage
{
repeated int32 array = 1 [(nanopb).max_count = 8];
}
/* Oneof in a message with other fields */
message AnonymousOneOfMessage
{
option (nanopb_msgopt).anonymous_oneof = true;
required int32 prefix = 1;
oneof values
{
int32 first = 5;
string second = 6 [(nanopb).max_size = 8];
SubMessage third = 7;
}
required int32 suffix = 99;
}

View File

@@ -0,0 +1,23 @@
# Test usage of Any type
Import("env")
incpath = env.Clone()
incpath.Append(PROTOCPATH = '#any_type')
incpath.Append(CPPPATH = '$BUILD/any_type')
incpath.NanopbProto("anytest")
incpath.NanopbProto(["google/protobuf/any", "google/protobuf/any.options"])
incpath.NanopbProto("google/protobuf/duration")
enc = incpath.Program(["encode_any.c", "anytest.pb.c", "google/protobuf/any.pb.c",
"google/protobuf/duration.pb.c",
"$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = incpath.Program(["decode_any.c", "anytest.pb.c", "google/protobuf/any.pb.c",
"google/protobuf/duration.pb.c",
"$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
env.RunTest(enc)
env.RunTest([dec, "encode_any.output"])

View File

@@ -0,0 +1,27 @@
// This file is an example and test case on handling the Any type in nanopb.
// The Any type is defined in Google-provided any.proto file:
// message Any {
// string type_url = 1;
// bytes value = 2;
// }
//
// The type_url field identifies the type of message, and the message data
// is inside the bytes field.
//
// The encoding follows the basic format of protobuf and doesn't require
// special support to handle. In this example, we just set maximum size for
// the type_url and value fields, and then call pb_decode() again on the value.
//
// This does result in unnecessarily copying the data around, so for larger
// values it is preferable to use callbacks on the fields instead.
syntax = "proto3";
import "google/protobuf/any.proto";
message BaseMessage {
int32 start = 1;
google.protobuf.Any details = 2;
int32 end = 3;
}

View File

@@ -0,0 +1,49 @@
#include <assert.h>
#include <pb_decode.h>
#include <string.h>
#include <stdio.h>
#include "test_helpers.h"
#include "anytest.pb.h"
#include "google/protobuf/duration.pb.h"
int main()
{
BaseMessage msg = BaseMessage_init_zero;
uint8_t buffer[256];
pb_istream_t stream;
size_t count;
bool status;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
stream = pb_istream_from_buffer(buffer, count);
/* Decode the base message */
if (!pb_decode(&stream, BaseMessage_fields, &msg))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
assert(msg.start == 1234);
assert(msg.end == 5678);
/* Decode the Any message if we know the type */
if (strcmp(msg.details.type_url, "type.googleapis.com/google.protobuf.Duration") == 0)
{
google_protobuf_Duration duration = google_protobuf_Duration_init_zero;
stream = pb_istream_from_buffer(msg.details.value.bytes, msg.details.value.size);
status = pb_decode(&stream, google_protobuf_Duration_fields, &duration);
assert(status);
assert(duration.seconds == 99999);
assert(duration.nanos == 100);
return 0;
}
else
{
fprintf(stderr, "Unknown Any type\n");
return 2;
}
}

View File

@@ -0,0 +1,46 @@
#include <assert.h>
#include <pb_encode.h>
#include <string.h>
#include <stdio.h>
#include "test_helpers.h"
#include "anytest.pb.h"
#include "google/protobuf/duration.pb.h"
int main()
{
BaseMessage msg = BaseMessage_init_zero;
google_protobuf_Duration duration = google_protobuf_Duration_init_zero;
uint8_t buffer[256];
pb_ostream_t stream;
bool status;
msg.start = 1234;
msg.end = 5678;
/* Fill in the Any message header */
msg.has_details = true;
strncpy(msg.details.type_url, "type.googleapis.com/google.protobuf.Duration", sizeof(msg.details.type_url));
/* Encode a Duration message inside the Any message. */
duration.seconds = 99999;
duration.nanos = 100;
stream = pb_ostream_from_buffer(msg.details.value.bytes, sizeof(msg.details.value.bytes));
status = pb_encode(&stream, google_protobuf_Duration_fields, &duration);
assert(status);
msg.details.value.size = stream.bytes_written;
/* Then encode the outer message */
stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if (pb_encode(&stream, BaseMessage_fields, &msg))
{
/* Write the result data to stdout */
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0;
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
}

View File

@@ -0,0 +1,2 @@
google.protobuf.Any.type_url max_size:64
google.protobuf.Any.value max_size:64

View File

@@ -0,0 +1,154 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/any";
option java_package = "com.google.protobuf";
option java_outer_classname = "AnyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// `Any` contains an arbitrary serialized protocol buffer message along with a
// URL that describes the type of the serialized message.
//
// Protobuf library provides support to pack/unpack Any values in the form
// of utility functions or additional generated methods of the Any type.
//
// Example 1: Pack and unpack a message in C++.
//
// Foo foo = ...;
// Any any;
// any.PackFrom(foo);
// ...
// if (any.UnpackTo(&foo)) {
// ...
// }
//
// Example 2: Pack and unpack a message in Java.
//
// Foo foo = ...;
// Any any = Any.pack(foo);
// ...
// if (any.is(Foo.class)) {
// foo = any.unpack(Foo.class);
// }
//
// Example 3: Pack and unpack a message in Python.
//
// foo = Foo(...)
// any = Any()
// any.Pack(foo)
// ...
// if any.Is(Foo.DESCRIPTOR):
// any.Unpack(foo)
// ...
//
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := ptypes.MarshalAny(foo)
// ...
// foo := &pb.Foo{}
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/'
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
// name "y.z".
//
//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
// representation of the deserialized, embedded message, with an
// additional field `@type` which contains the type URL. Example:
//
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
//
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
// `value` which holds the custom JSON in addition to the `@type`
// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
//
message Any {
// A URL/resource name that uniquely identifies the type of the serialized
// protocol buffer message. The last segment of the URL's path must represent
// the fully qualified name of the type (as in
// `path/google.protobuf.Duration`). The name should be in a canonical form
// (e.g., leading "." is not accepted).
//
// In practice, teams usually precompile into the binary all types that they
// expect it to use in the context of Any. However, for URLs which use the
// scheme `http`, `https`, or no scheme, one can optionally set up a type
// server that maps type URLs to message definitions as follows:
//
// * If no scheme is provided, `https` is assumed.
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Note: this functionality is not currently available in the official
// protobuf release, and it is not used for type URLs beginning with
// type.googleapis.com.
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
string type_url = 1;
// Must be a valid serialized protocol buffer of the above specified type.
bytes value = 2;
}

View File

@@ -0,0 +1,117 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option cc_enable_arenas = true;
option go_package = "github.com/golang/protobuf/ptypes/duration";
option java_package = "com.google.protobuf";
option java_outer_classname = "DurationProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
// resolution. It is independent of any calendar and concepts like "day"
// or "month". It is related to Timestamp in that the difference between
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
//
// # Examples
//
// Example 1: Compute Duration from two Timestamps in pseudo code.
//
// Timestamp start = ...;
// Timestamp end = ...;
// Duration duration = ...;
//
// duration.seconds = end.seconds - start.seconds;
// duration.nanos = end.nanos - start.nanos;
//
// if (duration.seconds < 0 && duration.nanos > 0) {
// duration.seconds += 1;
// duration.nanos -= 1000000000;
// } else if (durations.seconds > 0 && duration.nanos < 0) {
// duration.seconds -= 1;
// duration.nanos += 1000000000;
// }
//
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
//
// Timestamp start = ...;
// Duration duration = ...;
// Timestamp end = ...;
//
// end.seconds = start.seconds + duration.seconds;
// end.nanos = start.nanos + duration.nanos;
//
// if (end.nanos < 0) {
// end.seconds -= 1;
// end.nanos += 1000000000;
// } else if (end.nanos >= 1000000000) {
// end.seconds += 1;
// end.nanos -= 1000000000;
// }
//
// Example 3: Compute Duration from datetime.timedelta in Python.
//
// td = datetime.timedelta(days=3, minutes=10)
// duration = Duration()
// duration.FromTimedelta(td)
//
// # JSON Mapping
//
// In JSON format, the Duration type is encoded as a string rather than an
// object, where the string ends in the suffix "s" (indicating seconds) and
// is preceded by the number of seconds, with nanoseconds expressed as
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
// microsecond should be expressed in JSON format as "3.000001s".
//
//
message Duration {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
int64 seconds = 1;
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
int32 nanos = 2;
}

View File

@@ -0,0 +1,11 @@
# Check that the old generated .pb.c/.pb.h files are still compatible with the
# current version of nanopb.
Import("env")
enc = env.Program(["encode_legacy.c", "alltypes_legacy.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_legacy.c", "alltypes_legacy.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
env.RunTest(enc)
env.RunTest([dec, "encode_legacy.output"])

View File

@@ -0,0 +1,40 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.0-dev */
#include "alltypes_legacy.h"
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
pb_byte_t SubMessage_DEFAULT[] = {0x0a, 0x01, 0x31, 0x10, 0x02, 0x1d, 0x03, 0x00, 0x00, 0x00, 0x00};
pb_byte_t EmptyMessage_DEFAULT[] = {0x00};
pb_byte_t Limits_DEFAULT[] = {0x08, 0xff, 0xff, 0xff, 0xff, 0x07, 0x10, 0x81, 0x80, 0x80, 0x80, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x18, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x20, 0x00, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x30, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0x38, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x40, 0x00, 0x48, 0xff, 0xff, 0xff, 0xff, 0x07, 0x50, 0x81, 0x80, 0x80, 0x80, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00};
pb_byte_t AllTypes_DEFAULT[] = {0xc8, 0x02, 0xc9, 0x1f, 0xd0, 0x02, 0xca, 0x1f, 0xd8, 0x02, 0xcb, 0x1f, 0xe0, 0x02, 0xcc, 0x1f, 0xe8, 0x02, 0x9a, 0x3f, 0xf0, 0x02, 0x9c, 0x3f, 0xf8, 0x02, 0x00, 0x85, 0x03, 0xd0, 0x0f, 0x00, 0x00, 0x8d, 0x03, 0xd1, 0x0f, 0x00, 0x00, 0x95, 0x03, 0x00, 0x20, 0x7d, 0x45, 0x99, 0x03, 0xd3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x03, 0xd4, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaf, 0x40, 0xb2, 0x03, 0x04, 0x34, 0x30, 0x35, 0x34, 0xba, 0x03, 0x04, 0x34, 0x30, 0x35, 0x35, 0xc8, 0x03, 0x02, 0x00};
PB_BIND(SubMessage, SubMessage, AUTO)
PB_BIND(EmptyMessage, EmptyMessage, AUTO)
PB_BIND(Limits, Limits, AUTO)
PB_BIND(AllTypes, AllTypes, 2)
#ifndef PB_CONVERT_DOUBLE_FLOAT
/* On some platforms (such as AVR), double is really float.
* Using double on these platforms is not directly supported
* by nanopb, but see example_avr_double.
* To get rid of this error, remove any double fields from your .proto.
*/
PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)
#endif
/* @@protoc_insertion_point(eof) */

View File

@@ -0,0 +1,348 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.0-dev */
#ifndef PB_ALLTYPES_LEGACY_H_INCLUDED
#define PB_ALLTYPES_LEGACY_H_INCLUDED
#include <pb.h>
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _HugeEnum {
HugeEnum_Negative = -2147483647,
HugeEnum_Positive = 2147483647
} HugeEnum;
#define _HugeEnum_MIN HugeEnum_Negative
#define _HugeEnum_MAX HugeEnum_Positive
#define _HugeEnum_ARRAYSIZE ((HugeEnum)(HugeEnum_Positive+1))
typedef enum _MyEnum {
MyEnum_Zero = 0,
MyEnum_First = 1,
MyEnum_Second = 2,
MyEnum_Truth = 42
} MyEnum;
#define _MyEnum_MIN MyEnum_Zero
#define _MyEnum_MAX MyEnum_Truth
#define _MyEnum_ARRAYSIZE ((MyEnum)(MyEnum_Truth+1))
/* Struct definitions */
typedef struct _EmptyMessage {
char dummy_field;
/* @@protoc_insertion_point(struct:EmptyMessage) */
} EmptyMessage;
typedef struct _Limits {
int32_t int32_min;
int32_t int32_max;
uint32_t uint32_min;
uint32_t uint32_max;
int64_t int64_min;
int64_t int64_max;
uint64_t uint64_min;
uint64_t uint64_max;
HugeEnum enum_min;
HugeEnum enum_max;
/* @@protoc_insertion_point(struct:Limits) */
} Limits;
typedef struct _SubMessage {
char substuff1[16];
int32_t substuff2;
bool has_substuff3;
uint32_t substuff3;
/* @@protoc_insertion_point(struct:SubMessage) */
} SubMessage;
typedef PB_BYTES_ARRAY_T(16) AllTypes_req_bytes_t;
typedef PB_BYTES_ARRAY_T(16) AllTypes_rep_bytes_t;
typedef PB_BYTES_ARRAY_T(16) AllTypes_opt_bytes_t;
typedef struct _AllTypes {
int32_t req_int32;
int64_t req_int64;
uint32_t req_uint32;
uint64_t req_uint64;
int32_t req_sint32;
int64_t req_sint64;
bool req_bool;
uint32_t req_fixed32;
int32_t req_sfixed32;
float req_float;
uint64_t req_fixed64;
int64_t req_sfixed64;
double req_double;
char req_string[16];
AllTypes_req_bytes_t req_bytes;
SubMessage req_submsg;
MyEnum req_enum;
pb_size_t rep_int32_count;
int32_t rep_int32[5];
pb_size_t rep_int64_count;
int64_t rep_int64[5];
pb_size_t rep_uint32_count;
uint32_t rep_uint32[5];
pb_size_t rep_uint64_count;
uint64_t rep_uint64[5];
pb_size_t rep_sint32_count;
int32_t rep_sint32[5];
pb_size_t rep_sint64_count;
int64_t rep_sint64[5];
pb_size_t rep_bool_count;
bool rep_bool[5];
pb_size_t rep_fixed32_count;
uint32_t rep_fixed32[5];
pb_size_t rep_sfixed32_count;
int32_t rep_sfixed32[5];
pb_size_t rep_float_count;
float rep_float[5];
pb_size_t rep_fixed64_count;
uint64_t rep_fixed64[5];
pb_size_t rep_sfixed64_count;
int64_t rep_sfixed64[5];
pb_size_t rep_double_count;
double rep_double[5];
pb_size_t rep_string_count;
char rep_string[5][16];
pb_size_t rep_bytes_count;
AllTypes_rep_bytes_t rep_bytes[5];
pb_size_t rep_submsg_count;
SubMessage rep_submsg[5];
pb_size_t rep_enum_count;
MyEnum rep_enum[5];
bool has_opt_int32;
int32_t opt_int32;
bool has_opt_int64;
int64_t opt_int64;
bool has_opt_uint32;
uint32_t opt_uint32;
bool has_opt_uint64;
uint64_t opt_uint64;
bool has_opt_sint32;
int32_t opt_sint32;
bool has_opt_sint64;
int64_t opt_sint64;
bool has_opt_bool;
bool opt_bool;
bool has_opt_fixed32;
uint32_t opt_fixed32;
bool has_opt_sfixed32;
int32_t opt_sfixed32;
bool has_opt_float;
float opt_float;
bool has_opt_fixed64;
uint64_t opt_fixed64;
bool has_opt_sfixed64;
int64_t opt_sfixed64;
bool has_opt_double;
double opt_double;
bool has_opt_string;
char opt_string[16];
bool has_opt_bytes;
AllTypes_opt_bytes_t opt_bytes;
bool has_opt_submsg;
SubMessage opt_submsg;
bool has_opt_enum;
MyEnum opt_enum;
int32_t end;
pb_extension_t *extensions;
/* @@protoc_insertion_point(struct:AllTypes) */
} AllTypes;
/* Initializer values for message structs */
#define SubMessage_init_default {"1", 2, false, 3u}
#define EmptyMessage_init_default {0}
#define Limits_init_default {2147483647, -2147483647, 4294967295u, 0u, 9223372036854775807ll, -9223372036854775807ll, 18446744073709551615ull, 0ull, HugeEnum_Positive, HugeEnum_Negative}
#define AllTypes_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", {0, {0}}, SubMessage_init_default, _MyEnum_MIN, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {"", "", "", "", ""}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {SubMessage_init_default, SubMessage_init_default, SubMessage_init_default, SubMessage_init_default, SubMessage_init_default}, 0, {_MyEnum_MIN, _MyEnum_MIN, _MyEnum_MIN, _MyEnum_MIN, _MyEnum_MIN}, false, 4041, false, 4042ll, false, 4043u, false, 4044ull, false, 4045, false, 4046, false, false, false, 4048u, false, 4049, false, 4050, false, 4051ull, false, 4052ll, false, 4053, false, "4054", false, {4, {0x34,0x30,0x35,0x35}}, false, SubMessage_init_default, false, MyEnum_Second, 0, NULL}
#define SubMessage_init_zero {"", 0, false, 0}
#define EmptyMessage_init_zero {0}
#define Limits_init_zero {0, 0, 0, 0, 0, 0, 0, 0, _HugeEnum_MIN, _HugeEnum_MIN}
#define AllTypes_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", {0, {0}}, SubMessage_init_zero, _MyEnum_MIN, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, 0, {"", "", "", "", ""}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {SubMessage_init_zero, SubMessage_init_zero, SubMessage_init_zero, SubMessage_init_zero, SubMessage_init_zero}, 0, {_MyEnum_MIN, _MyEnum_MIN, _MyEnum_MIN, _MyEnum_MIN, _MyEnum_MIN}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, "", false, {0, {0}}, false, SubMessage_init_zero, false, _MyEnum_MIN, 0, NULL}
/* Field tags (for use in manual encoding/decoding) */
#define Limits_int32_min_tag 1
#define Limits_int32_max_tag 2
#define Limits_uint32_min_tag 3
#define Limits_uint32_max_tag 4
#define Limits_int64_min_tag 5
#define Limits_int64_max_tag 6
#define Limits_uint64_min_tag 7
#define Limits_uint64_max_tag 8
#define Limits_enum_min_tag 9
#define Limits_enum_max_tag 10
#define SubMessage_substuff1_tag 1
#define SubMessage_substuff2_tag 2
#define SubMessage_substuff3_tag 3
#define AllTypes_req_int32_tag 1
#define AllTypes_req_int64_tag 2
#define AllTypes_req_uint32_tag 3
#define AllTypes_req_uint64_tag 4
#define AllTypes_req_sint32_tag 5
#define AllTypes_req_sint64_tag 6
#define AllTypes_req_bool_tag 7
#define AllTypes_req_fixed32_tag 8
#define AllTypes_req_sfixed32_tag 9
#define AllTypes_req_float_tag 10
#define AllTypes_req_fixed64_tag 11
#define AllTypes_req_sfixed64_tag 12
#define AllTypes_req_double_tag 13
#define AllTypes_req_string_tag 14
#define AllTypes_req_bytes_tag 15
#define AllTypes_req_submsg_tag 16
#define AllTypes_req_enum_tag 17
#define AllTypes_rep_int32_tag 21
#define AllTypes_rep_int64_tag 22
#define AllTypes_rep_uint32_tag 23
#define AllTypes_rep_uint64_tag 24
#define AllTypes_rep_sint32_tag 25
#define AllTypes_rep_sint64_tag 26
#define AllTypes_rep_bool_tag 27
#define AllTypes_rep_fixed32_tag 28
#define AllTypes_rep_sfixed32_tag 29
#define AllTypes_rep_float_tag 30
#define AllTypes_rep_fixed64_tag 31
#define AllTypes_rep_sfixed64_tag 32
#define AllTypes_rep_double_tag 33
#define AllTypes_rep_string_tag 34
#define AllTypes_rep_bytes_tag 35
#define AllTypes_rep_submsg_tag 36
#define AllTypes_rep_enum_tag 37
#define AllTypes_opt_int32_tag 41
#define AllTypes_opt_int64_tag 42
#define AllTypes_opt_uint32_tag 43
#define AllTypes_opt_uint64_tag 44
#define AllTypes_opt_sint32_tag 45
#define AllTypes_opt_sint64_tag 46
#define AllTypes_opt_bool_tag 47
#define AllTypes_opt_fixed32_tag 48
#define AllTypes_opt_sfixed32_tag 49
#define AllTypes_opt_float_tag 50
#define AllTypes_opt_fixed64_tag 51
#define AllTypes_opt_sfixed64_tag 52
#define AllTypes_opt_double_tag 53
#define AllTypes_opt_string_tag 54
#define AllTypes_opt_bytes_tag 55
#define AllTypes_opt_submsg_tag 56
#define AllTypes_opt_enum_tag 57
#define AllTypes_end_tag 99
/* Struct field encoding specification for nanopb */
#define SubMessage_FIELDLIST(X, a) \
X(a, STATIC, REQUIRED, STRING, substuff1, 1) \
X(a, STATIC, REQUIRED, INT32, substuff2, 2) \
X(a, STATIC, OPTIONAL, FIXED32, substuff3, 3)
#define SubMessage_CALLBACK NULL
#define EmptyMessage_FIELDLIST(X, a) \
#define EmptyMessage_CALLBACK NULL
#define Limits_FIELDLIST(X, a) \
X(a, STATIC, REQUIRED, INT32, int32_min, 1) \
X(a, STATIC, REQUIRED, INT32, int32_max, 2) \
X(a, STATIC, REQUIRED, UINT32, uint32_min, 3) \
X(a, STATIC, REQUIRED, UINT32, uint32_max, 4) \
X(a, STATIC, REQUIRED, INT64, int64_min, 5) \
X(a, STATIC, REQUIRED, INT64, int64_max, 6) \
X(a, STATIC, REQUIRED, UINT64, uint64_min, 7) \
X(a, STATIC, REQUIRED, UINT64, uint64_max, 8) \
X(a, STATIC, REQUIRED, ENUM, enum_min, 9) \
X(a, STATIC, REQUIRED, ENUM, enum_max, 10)
#define Limits_CALLBACK NULL
#define AllTypes_FIELDLIST(X, a) \
X(a, STATIC, REQUIRED, INT32, req_int32, 1) \
X(a, STATIC, REQUIRED, INT64, req_int64, 2) \
X(a, STATIC, REQUIRED, UINT32, req_uint32, 3) \
X(a, STATIC, REQUIRED, UINT64, req_uint64, 4) \
X(a, STATIC, REQUIRED, SINT32, req_sint32, 5) \
X(a, STATIC, REQUIRED, SINT64, req_sint64, 6) \
X(a, STATIC, REQUIRED, BOOL, req_bool, 7) \
X(a, STATIC, REQUIRED, FIXED32, req_fixed32, 8) \
X(a, STATIC, REQUIRED, SFIXED32, req_sfixed32, 9) \
X(a, STATIC, REQUIRED, FLOAT, req_float, 10) \
X(a, STATIC, REQUIRED, FIXED64, req_fixed64, 11) \
X(a, STATIC, REQUIRED, SFIXED64, req_sfixed64, 12) \
X(a, STATIC, REQUIRED, DOUBLE, req_double, 13) \
X(a, STATIC, REQUIRED, STRING, req_string, 14) \
X(a, STATIC, REQUIRED, BYTES, req_bytes, 15) \
X(a, STATIC, REQUIRED, MESSAGE, req_submsg, 16) \
X(a, STATIC, REQUIRED, UENUM, req_enum, 17) \
X(a, STATIC, REPEATED, INT32, rep_int32, 21) \
X(a, STATIC, REPEATED, INT64, rep_int64, 22) \
X(a, STATIC, REPEATED, UINT32, rep_uint32, 23) \
X(a, STATIC, REPEATED, UINT64, rep_uint64, 24) \
X(a, STATIC, REPEATED, SINT32, rep_sint32, 25) \
X(a, STATIC, REPEATED, SINT64, rep_sint64, 26) \
X(a, STATIC, REPEATED, BOOL, rep_bool, 27) \
X(a, STATIC, REPEATED, FIXED32, rep_fixed32, 28) \
X(a, STATIC, REPEATED, SFIXED32, rep_sfixed32, 29) \
X(a, STATIC, REPEATED, FLOAT, rep_float, 30) \
X(a, STATIC, REPEATED, FIXED64, rep_fixed64, 31) \
X(a, STATIC, REPEATED, SFIXED64, rep_sfixed64, 32) \
X(a, STATIC, REPEATED, DOUBLE, rep_double, 33) \
X(a, STATIC, REPEATED, STRING, rep_string, 34) \
X(a, STATIC, REPEATED, BYTES, rep_bytes, 35) \
X(a, STATIC, REPEATED, MESSAGE, rep_submsg, 36) \
X(a, STATIC, REPEATED, UENUM, rep_enum, 37) \
X(a, STATIC, OPTIONAL, INT32, opt_int32, 41) \
X(a, STATIC, OPTIONAL, INT64, opt_int64, 42) \
X(a, STATIC, OPTIONAL, UINT32, opt_uint32, 43) \
X(a, STATIC, OPTIONAL, UINT64, opt_uint64, 44) \
X(a, STATIC, OPTIONAL, SINT32, opt_sint32, 45) \
X(a, STATIC, OPTIONAL, SINT64, opt_sint64, 46) \
X(a, STATIC, OPTIONAL, BOOL, opt_bool, 47) \
X(a, STATIC, OPTIONAL, FIXED32, opt_fixed32, 48) \
X(a, STATIC, OPTIONAL, SFIXED32, opt_sfixed32, 49) \
X(a, STATIC, OPTIONAL, FLOAT, opt_float, 50) \
X(a, STATIC, OPTIONAL, FIXED64, opt_fixed64, 51) \
X(a, STATIC, OPTIONAL, SFIXED64, opt_sfixed64, 52) \
X(a, STATIC, OPTIONAL, DOUBLE, opt_double, 53) \
X(a, STATIC, OPTIONAL, STRING, opt_string, 54) \
X(a, STATIC, OPTIONAL, BYTES, opt_bytes, 55) \
X(a, STATIC, OPTIONAL, MESSAGE, opt_submsg, 56) \
X(a, STATIC, OPTIONAL, UENUM, opt_enum, 57) \
X(a, STATIC, REQUIRED, INT32, end, 99) \
X(a, CALLBACK, OPTIONAL, EXTENSION, extensions, 200)
#define AllTypes_CALLBACK pb_default_field_callback
#define AllTypes_req_submsg_MSGTYPE SubMessage
#define AllTypes_rep_submsg_MSGTYPE SubMessage
#define AllTypes_opt_submsg_MSGTYPE SubMessage
extern const pb_msgdesc_t SubMessage_msg;
extern pb_byte_t SubMessage_default[];
extern const pb_msgdesc_t EmptyMessage_msg;
extern pb_byte_t EmptyMessage_default[];
extern const pb_msgdesc_t Limits_msg;
extern pb_byte_t Limits_default[];
extern const pb_msgdesc_t AllTypes_msg;
extern pb_byte_t AllTypes_default[];
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define SubMessage_fields &SubMessage_msg
#define EmptyMessage_fields &EmptyMessage_msg
#define Limits_fields &Limits_msg
#define AllTypes_fields &AllTypes_msg
/* Maximum encoded size of messages (where known) */
#define SubMessage_size 33
#define EmptyMessage_size 0
#define Limits_size 100
#define AllTypes_size 1320
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif

View File

@@ -0,0 +1,3 @@
* max_size:16
* max_count:5

View File

@@ -0,0 +1,110 @@
syntax = "proto2";
message SubMessage {
required string substuff1 = 1 [default = "1"];
required int32 substuff2 = 2 [default = 2];
optional fixed32 substuff3 = 3 [default = 3];
}
message EmptyMessage {
}
enum HugeEnum {
Negative = -2147483647; /* protoc doesn't accept -2147483648 here */
Positive = 2147483647;
}
message Limits {
required int32 int32_min = 1 [default = 2147483647];
required int32 int32_max = 2 [default = -2147483647];
required uint32 uint32_min = 3 [default = 4294967295];
required uint32 uint32_max = 4 [default = 0];
required int64 int64_min = 5 [default = 9223372036854775807];
required int64 int64_max = 6 [default = -9223372036854775807];
required uint64 uint64_min = 7 [default = 18446744073709551615];
required uint64 uint64_max = 8 [default = 0];
required HugeEnum enum_min = 9 [default = Positive];
required HugeEnum enum_max = 10 [default = Negative];
}
enum MyEnum {
Zero = 0;
First = 1;
Second = 2;
Truth = 42;
}
message AllTypes {
required int32 req_int32 = 1;
required int64 req_int64 = 2;
required uint32 req_uint32 = 3;
required uint64 req_uint64 = 4;
required sint32 req_sint32 = 5;
required sint64 req_sint64 = 6;
required bool req_bool = 7;
required fixed32 req_fixed32 = 8;
required sfixed32 req_sfixed32= 9;
required float req_float = 10;
required fixed64 req_fixed64 = 11;
required sfixed64 req_sfixed64= 12;
required double req_double = 13;
required string req_string = 14;
required bytes req_bytes = 15;
required SubMessage req_submsg = 16;
required MyEnum req_enum = 17;
repeated int32 rep_int32 = 21 [packed = true];
repeated int64 rep_int64 = 22 [packed = true];
repeated uint32 rep_uint32 = 23 [packed = true];
repeated uint64 rep_uint64 = 24 [packed = true];
repeated sint32 rep_sint32 = 25 [packed = true];
repeated sint64 rep_sint64 = 26 [packed = true];
repeated bool rep_bool = 27 [packed = true];
repeated fixed32 rep_fixed32 = 28 [packed = true];
repeated sfixed32 rep_sfixed32= 29 [packed = true];
repeated float rep_float = 30 [packed = true];
repeated fixed64 rep_fixed64 = 31 [packed = true];
repeated sfixed64 rep_sfixed64= 32 [packed = true];
repeated double rep_double = 33 [packed = true];
repeated string rep_string = 34;
repeated bytes rep_bytes = 35;
repeated SubMessage rep_submsg = 36;
repeated MyEnum rep_enum = 37 [packed = true];
optional int32 opt_int32 = 41 [default = 4041];
optional int64 opt_int64 = 42 [default = 4042];
optional uint32 opt_uint32 = 43 [default = 4043];
optional uint64 opt_uint64 = 44 [default = 4044];
optional sint32 opt_sint32 = 45 [default = 4045];
optional sint64 opt_sint64 = 46 [default = 4046];
optional bool opt_bool = 47 [default = false];
optional fixed32 opt_fixed32 = 48 [default = 4048];
optional sfixed32 opt_sfixed32= 49 [default = 4049];
optional float opt_float = 50 [default = 4050];
optional fixed64 opt_fixed64 = 51 [default = 4051];
optional sfixed64 opt_sfixed64= 52 [default = 4052];
optional double opt_double = 53 [default = 4053];
optional string opt_string = 54 [default = "4054"];
optional bytes opt_bytes = 55 [default = "4055"];
optional SubMessage opt_submsg = 56;
optional MyEnum opt_enum = 57 [default = Second];
// Just to make sure that the size of the fields has been calculated
// properly, i.e. otherwise a bug in last field might not be detected.
required int32 end = 99;
extensions 200 to 255;
}

View File

@@ -0,0 +1,196 @@
/* Tests the decoding of all types.
* This is a backwards-compatibility test, using alltypes_legacy.h.
* It is similar to decode_alltypes, but duplicated in order to allow
* decode_alltypes to test any new features introduced later.
*
* Run e.g. ./encode_legacy | ./decode_legacy
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "alltypes_legacy.h"
#include "test_helpers.h"
#include "unittests.h"
/* This function is called once from main(), it handles
the decoding and checks the fields. */
bool check_alltypes(pb_istream_t *stream, int mode)
{
AllTypes alltypes = {0};
int status = 0;
if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false;
TEST(alltypes.req_int32 == -1001);
TEST(alltypes.req_int64 == -1002);
TEST(alltypes.req_uint32 == 1003);
TEST(alltypes.req_uint64 == 1004);
TEST(alltypes.req_sint32 == -1005);
TEST(alltypes.req_sint64 == -1006);
TEST(alltypes.req_bool == true);
TEST(alltypes.req_fixed32 == 1008);
TEST(alltypes.req_sfixed32 == -1009);
TEST(alltypes.req_float == 1010.0f);
TEST(alltypes.req_fixed64 == 1011);
TEST(alltypes.req_sfixed64 == -1012);
TEST(alltypes.req_double == 1013.0f);
TEST(strcmp(alltypes.req_string, "1014") == 0);
TEST(alltypes.req_bytes.size == 4);
TEST(memcmp(alltypes.req_bytes.bytes, "1015", 4) == 0);
TEST(strcmp(alltypes.req_submsg.substuff1, "1016") == 0);
TEST(alltypes.req_submsg.substuff2 == 1016);
TEST(alltypes.req_submsg.substuff3 == 3);
TEST(alltypes.req_enum == MyEnum_Truth);
TEST(alltypes.rep_int32_count == 5 && alltypes.rep_int32[4] == -2001 && alltypes.rep_int32[0] == 0);
TEST(alltypes.rep_int64_count == 5 && alltypes.rep_int64[4] == -2002 && alltypes.rep_int64[0] == 0);
TEST(alltypes.rep_uint32_count == 5 && alltypes.rep_uint32[4] == 2003 && alltypes.rep_uint32[0] == 0);
TEST(alltypes.rep_uint64_count == 5 && alltypes.rep_uint64[4] == 2004 && alltypes.rep_uint64[0] == 0);
TEST(alltypes.rep_sint32_count == 5 && alltypes.rep_sint32[4] == -2005 && alltypes.rep_sint32[0] == 0);
TEST(alltypes.rep_sint64_count == 5 && alltypes.rep_sint64[4] == -2006 && alltypes.rep_sint64[0] == 0);
TEST(alltypes.rep_bool_count == 5 && alltypes.rep_bool[4] == true && alltypes.rep_bool[0] == false);
TEST(alltypes.rep_fixed32_count == 5 && alltypes.rep_fixed32[4] == 2008 && alltypes.rep_fixed32[0] == 0);
TEST(alltypes.rep_sfixed32_count == 5 && alltypes.rep_sfixed32[4] == -2009 && alltypes.rep_sfixed32[0] == 0);
TEST(alltypes.rep_float_count == 5 && alltypes.rep_float[4] == 2010.0f && alltypes.rep_float[0] == 0.0f);
TEST(alltypes.rep_fixed64_count == 5 && alltypes.rep_fixed64[4] == 2011 && alltypes.rep_fixed64[0] == 0);
TEST(alltypes.rep_sfixed64_count == 5 && alltypes.rep_sfixed64[4] == -2012 && alltypes.rep_sfixed64[0] == 0);
TEST(alltypes.rep_double_count == 5 && alltypes.rep_double[4] == 2013.0 && alltypes.rep_double[0] == 0.0);
TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0');
TEST(alltypes.rep_bytes_count == 5 && alltypes.rep_bytes[4].size == 4 && alltypes.rep_bytes[0].size == 0);
TEST(memcmp(alltypes.rep_bytes[4].bytes, "2015", 4) == 0);
TEST(alltypes.rep_submsg_count == 5);
TEST(strcmp(alltypes.rep_submsg[4].substuff1, "2016") == 0 && alltypes.rep_submsg[0].substuff1[0] == '\0');
TEST(alltypes.rep_submsg[4].substuff2 == 2016 && alltypes.rep_submsg[0].substuff2 == 0);
TEST(alltypes.rep_submsg[4].substuff3 == 2016 && alltypes.rep_submsg[0].substuff3 == 3);
TEST(alltypes.rep_enum_count == 5 && alltypes.rep_enum[4] == MyEnum_Truth && alltypes.rep_enum[0] == MyEnum_Zero);
if (mode == 0)
{
/* Expect default values */
TEST(alltypes.has_opt_int32 == false);
TEST(alltypes.opt_int32 == 4041);
TEST(alltypes.has_opt_int64 == false);
TEST(alltypes.opt_int64 == 4042);
TEST(alltypes.has_opt_uint32 == false);
TEST(alltypes.opt_uint32 == 4043);
TEST(alltypes.has_opt_uint64 == false);
TEST(alltypes.opt_uint64 == 4044);
TEST(alltypes.has_opt_sint32 == false);
TEST(alltypes.opt_sint32 == 4045);
TEST(alltypes.has_opt_sint64 == false);
TEST(alltypes.opt_sint64 == 4046);
TEST(alltypes.has_opt_bool == false);
TEST(alltypes.opt_bool == false);
TEST(alltypes.has_opt_fixed32 == false);
TEST(alltypes.opt_fixed32 == 4048);
TEST(alltypes.has_opt_sfixed32 == false);
TEST(alltypes.opt_sfixed32 == 4049);
TEST(alltypes.has_opt_float == false);
TEST(alltypes.opt_float == 4050.0f);
TEST(alltypes.has_opt_fixed64 == false);
TEST(alltypes.opt_fixed64 == 4051);
TEST(alltypes.has_opt_sfixed64 == false);
TEST(alltypes.opt_sfixed64 == 4052);
TEST(alltypes.has_opt_double == false);
TEST(alltypes.opt_double == 4053.0);
TEST(alltypes.has_opt_string == false);
TEST(strcmp(alltypes.opt_string, "4054") == 0);
TEST(alltypes.has_opt_bytes == false);
TEST(alltypes.opt_bytes.size == 4);
TEST(memcmp(alltypes.opt_bytes.bytes, "4055", 4) == 0);
TEST(alltypes.has_opt_submsg == false);
TEST(strcmp(alltypes.opt_submsg.substuff1, "1") == 0);
TEST(alltypes.opt_submsg.substuff2 == 2);
TEST(alltypes.opt_submsg.substuff3 == 3);
TEST(alltypes.has_opt_enum == false);
TEST(alltypes.opt_enum == MyEnum_Second);
}
else
{
/* Expect filled-in values */
TEST(alltypes.has_opt_int32 == true);
TEST(alltypes.opt_int32 == 3041);
TEST(alltypes.has_opt_int64 == true);
TEST(alltypes.opt_int64 == 3042);
TEST(alltypes.has_opt_uint32 == true);
TEST(alltypes.opt_uint32 == 3043);
TEST(alltypes.has_opt_uint64 == true);
TEST(alltypes.opt_uint64 == 3044);
TEST(alltypes.has_opt_sint32 == true);
TEST(alltypes.opt_sint32 == 3045);
TEST(alltypes.has_opt_sint64 == true);
TEST(alltypes.opt_sint64 == 3046);
TEST(alltypes.has_opt_bool == true);
TEST(alltypes.opt_bool == true);
TEST(alltypes.has_opt_fixed32 == true);
TEST(alltypes.opt_fixed32 == 3048);
TEST(alltypes.has_opt_sfixed32 == true);
TEST(alltypes.opt_sfixed32 == 3049);
TEST(alltypes.has_opt_float == true);
TEST(alltypes.opt_float == 3050.0f);
TEST(alltypes.has_opt_fixed64 == true);
TEST(alltypes.opt_fixed64 == 3051);
TEST(alltypes.has_opt_sfixed64 == true);
TEST(alltypes.opt_sfixed64 == 3052);
TEST(alltypes.has_opt_double == true);
TEST(alltypes.opt_double == 3053.0);
TEST(alltypes.has_opt_string == true);
TEST(strcmp(alltypes.opt_string, "3054") == 0);
TEST(alltypes.has_opt_bytes == true);
TEST(alltypes.opt_bytes.size == 4);
TEST(memcmp(alltypes.opt_bytes.bytes, "3055", 4) == 0);
TEST(alltypes.has_opt_submsg == true);
TEST(strcmp(alltypes.opt_submsg.substuff1, "3056") == 0);
TEST(alltypes.opt_submsg.substuff2 == 3056);
TEST(alltypes.opt_submsg.substuff3 == 3);
TEST(alltypes.has_opt_enum == true);
TEST(alltypes.opt_enum == MyEnum_Truth);
}
TEST(alltypes.end == 1099);
return status == 0;
}
int main(int argc, char **argv)
{
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
/* Whether to expect the optional values or the default values. */
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
/* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count);
/* Decode and print out the stuff */
if (!check_alltypes(&stream, mode))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
} else {
return 0;
}
}

View File

@@ -0,0 +1,135 @@
/* Attempts to test all the datatypes supported by ProtoBuf.
* This is a backwards-compatibility test, using alltypes_legacy.h.
* It is similar to encode_alltypes, but duplicated in order to allow
* encode_alltypes to test any new features introduced later.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_encode.h>
#include "alltypes_legacy.h"
#include "test_helpers.h"
int main(int argc, char **argv)
{
int mode = (argc > 1) ? atoi(argv[1]) : 0;
/* Initialize the structure with constants */
AllTypes alltypes = {0};
alltypes.req_int32 = -1001;
alltypes.req_int64 = -1002;
alltypes.req_uint32 = 1003;
alltypes.req_uint64 = 1004;
alltypes.req_sint32 = -1005;
alltypes.req_sint64 = -1006;
alltypes.req_bool = true;
alltypes.req_fixed32 = 1008;
alltypes.req_sfixed32 = -1009;
alltypes.req_float = 1010.0f;
alltypes.req_fixed64 = 1011;
alltypes.req_sfixed64 = -1012;
alltypes.req_double = 1013.0;
strcpy(alltypes.req_string, "1014");
alltypes.req_bytes.size = 4;
memcpy(alltypes.req_bytes.bytes, "1015", 4);
strcpy(alltypes.req_submsg.substuff1, "1016");
alltypes.req_submsg.substuff2 = 1016;
alltypes.req_enum = MyEnum_Truth;
alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = -2001;
alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = -2002;
alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003;
alltypes.rep_uint64_count = 5; alltypes.rep_uint64[4] = 2004;
alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = -2005;
alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = -2006;
alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true;
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32[4] = 2008;
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32[4] = -2009;
alltypes.rep_float_count = 5; alltypes.rep_float[4] = 2010.0f;
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64[4] = 2011;
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64[4] = -2012;
alltypes.rep_double_count = 5; alltypes.rep_double[4] = 2013.0;
alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014");
alltypes.rep_bytes_count = 5; alltypes.rep_bytes[4].size = 4;
memcpy(alltypes.rep_bytes[4].bytes, "2015", 4);
alltypes.rep_submsg_count = 5;
strcpy(alltypes.rep_submsg[4].substuff1, "2016");
alltypes.rep_submsg[4].substuff2 = 2016;
alltypes.rep_submsg[4].has_substuff3 = true;
alltypes.rep_submsg[4].substuff3 = 2016;
alltypes.rep_enum_count = 5; alltypes.rep_enum[4] = MyEnum_Truth;
if (mode != 0)
{
/* Fill in values for optional fields */
alltypes.has_opt_int32 = true;
alltypes.opt_int32 = 3041;
alltypes.has_opt_int64 = true;
alltypes.opt_int64 = 3042;
alltypes.has_opt_uint32 = true;
alltypes.opt_uint32 = 3043;
alltypes.has_opt_uint64 = true;
alltypes.opt_uint64 = 3044;
alltypes.has_opt_sint32 = true;
alltypes.opt_sint32 = 3045;
alltypes.has_opt_sint64 = true;
alltypes.opt_sint64 = 3046;
alltypes.has_opt_bool = true;
alltypes.opt_bool = true;
alltypes.has_opt_fixed32 = true;
alltypes.opt_fixed32 = 3048;
alltypes.has_opt_sfixed32 = true;
alltypes.opt_sfixed32 = 3049;
alltypes.has_opt_float = true;
alltypes.opt_float = 3050.0f;
alltypes.has_opt_fixed64 = true;
alltypes.opt_fixed64 = 3051;
alltypes.has_opt_sfixed64 = true;
alltypes.opt_sfixed64 = 3052;
alltypes.has_opt_double = true;
alltypes.opt_double = 3053.0;
alltypes.has_opt_string = true;
strcpy(alltypes.opt_string, "3054");
alltypes.has_opt_bytes = true;
alltypes.opt_bytes.size = 4;
memcpy(alltypes.opt_bytes.bytes, "3055", 4);
alltypes.has_opt_submsg = true;
strcpy(alltypes.opt_submsg.substuff1, "3056");
alltypes.opt_submsg.substuff2 = 3056;
alltypes.has_opt_enum = true;
alltypes.opt_enum = MyEnum_Truth;
}
alltypes.end = 1099;
{
uint8_t buffer[1024];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, AllTypes_fields, &alltypes))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed!\n");
return 1; /* Failure */
}
}
}

View File

@@ -0,0 +1,12 @@
# Build and run a basic round-trip test using memory buffer encoding.
Import("env")
enc = env.Program(["encode_buffer.c", "$COMMON/person.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_buffer.c", "$COMMON/person.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
env.RunTest(enc)
env.RunTest([dec, "encode_buffer.output"])
env.Decode(["encode_buffer.output", "$COMMON/person.proto"], MESSAGE = "Person")
env.Compare(["decode_buffer.output", "encode_buffer.decoded"])

View File

@@ -0,0 +1,88 @@
/* A very simple decoding test case, using person.proto.
* Produces output compatible with protoc --decode.
* Reads the encoded data from stdin and prints the values
* to stdout as text.
*
* Run e.g. ./test_encode1 | ./test_decode1
*/
#include <stdio.h>
#include <pb_decode.h>
#include "person.pb.h"
#include "test_helpers.h"
/* This function is called once from main(), it handles
the decoding and printing. */
bool print_person(pb_istream_t *stream)
{
int i;
Person person = Person_init_zero;
if (!pb_decode(stream, Person_fields, &person))
return false;
/* Now the decoding is done, rest is just to print stuff out. */
printf("name: \"%s\"\n", person.name);
printf("id: %ld\n", (long)person.id);
if (person.has_email)
printf("email: \"%s\"\n", person.email);
for (i = 0; i < person.phone_count; i++)
{
Person_PhoneNumber *phone = &person.phone[i];
printf("phone {\n");
printf(" number: \"%s\"\n", phone->number);
if (phone->has_type)
{
switch (phone->type)
{
case Person_PhoneType_WORK:
printf(" type: WORK\n");
break;
case Person_PhoneType_HOME:
printf(" type: HOME\n");
break;
case Person_PhoneType_MOBILE:
printf(" type: MOBILE\n");
break;
}
}
printf("}\n");
}
return true;
}
int main()
{
uint8_t buffer[Person_size];
pb_istream_t stream;
size_t count;
/* Read the data into buffer */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
if (!feof(stdin))
{
printf("Message does not fit in buffer\n");
return 1;
}
/* Construct a pb_istream_t for reading from the buffer */
stream = pb_istream_from_buffer(buffer, count);
/* Decode and print out the stuff */
if (!print_person(&stream))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
} else {
return 0;
}
}

View File

@@ -0,0 +1,38 @@
/* A very simple encoding test case using person.proto.
* Just puts constant data in the fields and encodes into
* buffer, which is then written to stdout.
*/
#include <stdio.h>
#include <pb_encode.h>
#include "person.pb.h"
#include "test_helpers.h"
int main()
{
uint8_t buffer[Person_size];
pb_ostream_t stream;
/* Initialize the structure with constants */
Person person = {"Test Person 99", 99, true, "test@person.com",
3, {{"555-12345678", true, Person_PhoneType_MOBILE},
{"99-2342", false, 0},
{"1234-5678", true, Person_PhoneType_WORK},
}};
stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, Person_fields, &person))
{
/* Write the result data to stdout */
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
}

View File

@@ -0,0 +1,12 @@
# Build and run a basic round-trip test using direct stream encoding.
Import("env")
enc = env.Program(["encode_stream.c", "$COMMON/person.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_stream.c", "$COMMON/person.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
env.RunTest(enc)
env.RunTest([dec, "encode_stream.output"])
env.Decode(["encode_stream.output", "$COMMON/person.proto"], MESSAGE = "Person")
env.Compare(["decode_stream.output", "encode_stream.decoded"])

View File

@@ -0,0 +1,87 @@
/* Same as test_decode1 but reads from stdin directly.
*/
#include <stdio.h>
#include <pb_decode.h>
#include "person.pb.h"
#include "test_helpers.h"
/* This function is called once from main(), it handles
the decoding and printing.
Ugly copy-paste from test_decode1.c. */
bool print_person(pb_istream_t *stream)
{
int i;
Person person = Person_init_zero;
if (!pb_decode(stream, Person_fields, &person))
return false;
/* Now the decoding is done, rest is just to print stuff out. */
printf("name: \"%s\"\n", person.name);
printf("id: %ld\n", (long)person.id);
if (person.has_email)
printf("email: \"%s\"\n", person.email);
for (i = 0; i < person.phone_count; i++)
{
Person_PhoneNumber *phone = &person.phone[i];
printf("phone {\n");
printf(" number: \"%s\"\n", phone->number);
if (phone->has_type)
{
switch (phone->type)
{
case Person_PhoneType_WORK:
printf(" type: WORK\n");
break;
case Person_PhoneType_HOME:
printf(" type: HOME\n");
break;
case Person_PhoneType_MOBILE:
printf(" type: MOBILE\n");
break;
}
}
printf("}\n");
}
return true;
}
/* This binds the pb_istream_t to stdin */
bool callback(pb_istream_t *stream, uint8_t *buf, size_t count)
{
FILE *file = (FILE*)stream->state;
size_t len = fread(buf, 1, count, file);
if (len == count)
{
return true;
}
else
{
stream->bytes_left = 0;
return false;
}
}
int main()
{
pb_istream_t stream = {&callback, NULL, SIZE_MAX};
stream.state = stdin;
SET_BINARY_MODE(stdin);
if (!print_person(&stream))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
} else {
return 0;
}
}

View File

@@ -0,0 +1,40 @@
/* Same as test_encode1.c, except writes directly to stdout.
*/
#include <stdio.h>
#include <pb_encode.h>
#include "person.pb.h"
#include "test_helpers.h"
/* This binds the pb_ostream_t into the stdout stream */
bool streamcallback(pb_ostream_t *stream, const uint8_t *buf, size_t count)
{
FILE *file = (FILE*) stream->state;
return fwrite(buf, 1, count, file) == count;
}
int main()
{
/* Initialize the structure with constants */
Person person = {"Test Person 99", 99, true, "test@person.com",
3, {{"555-12345678", true, Person_PhoneType_MOBILE},
{"99-2342", false, 0},
{"1234-5678", true, Person_PhoneType_WORK},
}};
/* Prepare the stream, output goes directly to stdout */
pb_ostream_t stream = {&streamcallback, NULL, SIZE_MAX, 0};
stream.state = stdout;
SET_BINARY_MODE(stdout);
/* Now encode it and check if we succeeded. */
if (pb_encode(&stream, Person_fields, &person))
{
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
}

View File

@@ -0,0 +1,28 @@
# Run the alltypes test case, but compile with PB_BUFFER_ONLY=1
Import("env")
# Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c)
env.Command("alltypes.pb.c", "$BUILD/alltypes/alltypes.pb.c", c)
env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
# Define the compilation options
opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_BUFFER_ONLY': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_bufonly.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_bufonly.o", "$NANOPB/pb_encode.c")
strict.Object("pb_common_bufonly.o", "$NANOPB/pb_common.c")
# Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_bufonly.o", "pb_common_bufonly.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_bufonly.o", "pb_common_bufonly.o"])
env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -0,0 +1,14 @@
# Test the functionality of the callback fields.
Import("env")
env.NanopbProto("callbacks")
enc = env.Program(["encode_callbacks.c", "callbacks.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_callbacks.c", "callbacks.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
env.RunTest(enc)
env.RunTest([dec, "encode_callbacks.output"])
env.Decode(["encode_callbacks.output", "callbacks.proto"], MESSAGE = "TestMessage")
env.Compare(["decode_callbacks.output", "encode_callbacks.decoded"])

View File

@@ -0,0 +1,18 @@
syntax = "proto2";
message SubMessage {
optional string stringvalue = 1;
repeated int32 int32value = 2;
repeated fixed32 fixed32value = 3;
repeated fixed64 fixed64value = 4;
}
message TestMessage {
optional string stringvalue = 1;
repeated int32 int32value = 2;
repeated fixed32 fixed32value = 3;
repeated fixed64 fixed64value = 4;
optional SubMessage submsg = 5;
repeated string repeatedstring = 6;
}

View File

@@ -0,0 +1,97 @@
/* Decoding testcase for callback fields.
* Run e.g. ./test_encode_callbacks | ./test_decode_callbacks
*/
#include <stdio.h>
#include <pb_decode.h>
#include "callbacks.pb.h"
#include "test_helpers.h"
bool print_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint8_t buffer[1024] = {0};
/* We could read block-by-block to avoid the large buffer... */
if (stream->bytes_left > sizeof(buffer) - 1)
return false;
if (!pb_read(stream, buffer, stream->bytes_left))
return false;
/* Print the string, in format comparable with protoc --decode.
* Format comes from the arg defined in main().
*/
printf((char*)*arg, buffer);
return true;
}
bool print_int32(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
printf((char*)*arg, (long)value);
return true;
}
bool print_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint32_t value;
if (!pb_decode_fixed32(stream, &value))
return false;
printf((char*)*arg, (long)value);
return true;
}
bool print_fixed64(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t value;
if (!pb_decode_fixed64(stream, &value))
return false;
printf((char*)*arg, (long)value);
return true;
}
int main()
{
uint8_t buffer[1024];
size_t length;
pb_istream_t stream;
/* Note: empty initializer list initializes the struct with all-0.
* This is recommended so that unused callbacks are set to NULL instead
* of crashing at runtime.
*/
TestMessage testmessage = {{{NULL}}};
SET_BINARY_MODE(stdin);
length = fread(buffer, 1, 1024, stdin);
stream = pb_istream_from_buffer(buffer, length);
testmessage.submsg.stringvalue.funcs.decode = &print_string;
testmessage.submsg.stringvalue.arg = "submsg {\n stringvalue: \"%s\"\n";
testmessage.submsg.int32value.funcs.decode = &print_int32;
testmessage.submsg.int32value.arg = " int32value: %ld\n";
testmessage.submsg.fixed32value.funcs.decode = &print_fixed32;
testmessage.submsg.fixed32value.arg = " fixed32value: %ld\n";
testmessage.submsg.fixed64value.funcs.decode = &print_fixed64;
testmessage.submsg.fixed64value.arg = " fixed64value: %ld\n}\n";
testmessage.stringvalue.funcs.decode = &print_string;
testmessage.stringvalue.arg = "stringvalue: \"%s\"\n";
testmessage.int32value.funcs.decode = &print_int32;
testmessage.int32value.arg = "int32value: %ld\n";
testmessage.fixed32value.funcs.decode = &print_fixed32;
testmessage.fixed32value.arg = "fixed32value: %ld\n";
testmessage.fixed64value.funcs.decode = &print_fixed64;
testmessage.fixed64value.arg = "fixed64value: %ld\n";
testmessage.repeatedstring.funcs.decode = &print_string;
testmessage.repeatedstring.arg = "repeatedstring: \"%s\"\n";
if (!pb_decode(&stream, TestMessage_fields, &testmessage))
return 1;
return 0;
}

View File

@@ -0,0 +1,92 @@
/* Encoding testcase for callback fields */
#include <stdio.h>
#include <string.h>
#include <pb_encode.h>
#include "callbacks.pb.h"
#include "test_helpers.h"
bool encode_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
char *str = "Hello world!";
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}
bool encode_int32(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_varint(stream, 42);
}
bool encode_fixed32(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint32_t value = 42;
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_fixed32(stream, &value);
}
bool encode_fixed64(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
uint64_t value = 42;
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_fixed64(stream, &value);
}
bool encode_repeatedstring(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
char *str[4] = {"Hello world!", "", "Test", "Test2"};
int i;
for (i = 0; i < 4; i++)
{
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!pb_encode_string(stream, (uint8_t*)str[i], strlen(str[i])))
return false;
}
return true;
}
int main()
{
uint8_t buffer[1024];
pb_ostream_t stream;
TestMessage testmessage = {{{NULL}}};
stream = pb_ostream_from_buffer(buffer, 1024);
testmessage.stringvalue.funcs.encode = &encode_string;
testmessage.int32value.funcs.encode = &encode_int32;
testmessage.fixed32value.funcs.encode = &encode_fixed32;
testmessage.fixed64value.funcs.encode = &encode_fixed64;
testmessage.has_submsg = true;
testmessage.submsg.stringvalue.funcs.encode = &encode_string;
testmessage.submsg.int32value.funcs.encode = &encode_int32;
testmessage.submsg.fixed32value.funcs.encode = &encode_fixed32;
testmessage.submsg.fixed64value.funcs.encode = &encode_fixed64;
testmessage.repeatedstring.funcs.encode = &encode_repeatedstring;
if (!pb_encode(&stream, TestMessage_fields, &testmessage))
return 1;
SET_BINARY_MODE(stdout);
if (fwrite(buffer, stream.bytes_written, 1, stdout) != 1)
return 2;
return 0;
}

View File

@@ -0,0 +1,8 @@
# Test comment inclusion from .proto to .pb.h
Import("env")
env.NanopbProto("comments")
env.Object("comments.pb.c")
env.Match(['comments.pb.h', 'comments.expected'])

View File

@@ -0,0 +1,6 @@
Enum1Comment
LeadingEnumComment
ENUMVAL2.*TrailingEnumComment
Message1Comment
member2.*TrailingMemberComment

View File

@@ -0,0 +1,17 @@
syntax = "proto2";
// Message1Comment
message Message1
{
// LeadingMemberComment
required int32 member1 = 1;
required int32 member2 = 2; // TrailingMemberComment
}
// Enum1Comment
enum Enum1
{
// LeadingEnumComment
ENUMVAL1 = 1;
ENUMVAL2 = 2; // TrailingEnumComment
}

View File

@@ -0,0 +1,48 @@
# Build the common files needed by multiple test cases
Import('env')
# Protocol definitions for the encode/decode_unittests
env.NanopbProto("unittestproto")
# Protocol definitions for basic_buffer/stream tests
env.NanopbProto("person")
#--------------------------------------------
# Binaries of the pb_decode.c and pb_encode.c
# These are built using more strict warning flags.
strict = env.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode.o", "$NANOPB/pb_encode.c")
strict.Object("pb_common.o", "$NANOPB/pb_common.c")
#-----------------------------------------------
# Binaries of pb_decode etc. with malloc support
# Uses malloc_wrappers.c to count allocations.
malloc_env = env.Clone()
malloc_env.Append(CPPDEFINES = {'PB_ENABLE_MALLOC': 1,
'PB_SYSTEM_HEADER': '\\"malloc_wrappers_syshdr.h\\"'})
malloc_env.Append(CPPPATH = ["$COMMON"])
if 'SYSHDR' in malloc_env:
malloc_env.Append(CPPDEFINES = {'PB_OLD_SYSHDR': malloc_env['SYSHDR']})
# Disable libmudflap, because it will confuse valgrind
# and other memory leak detection tools.
if '-fmudflap' in env["CCFLAGS"]:
malloc_env["CCFLAGS"].remove("-fmudflap")
malloc_env["LINKFLAGS"].remove("-fmudflap")
malloc_env["LIBS"].remove("mudflap")
malloc_strict = malloc_env.Clone()
malloc_strict.Append(CFLAGS = malloc_strict['CORECFLAGS'])
malloc_strict.Object("pb_decode_with_malloc.o", "$NANOPB/pb_decode.c")
malloc_strict.Object("pb_encode_with_malloc.o", "$NANOPB/pb_encode.c")
malloc_strict.Object("pb_common_with_malloc.o", "$NANOPB/pb_common.c")
malloc_env.Object("malloc_wrappers.o", "malloc_wrappers.c")
malloc_env.Depends("$NANOPB/pb.h", ["malloc_wrappers_syshdr.h", "malloc_wrappers.h"])
Export("malloc_env")

View File

@@ -0,0 +1,189 @@
/* The wrapper functions in this file work like regular malloc() and free(),
* but store check values before and after the allocation. This helps to catch
* any buffer overrun errors in the test cases.
*/
#include "malloc_wrappers.h"
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#define GUARD_SIZE (sizeof(size_t)*3)
#define PREFIX_SIZE (sizeof(size_t)*2)
#define CHECK1 ((size_t)0xDEADBEEF)
#define CHECK2 ((size_t)0x600DCAFE)
#ifndef MAX_ALLOC_BYTES
#define MAX_ALLOC_BYTES 16*1024*1024
#endif
#ifndef DEBUG_MALLOC
#define DEBUG_MALLOC 0
#endif
static size_t g_alloc_count = 0;
static size_t g_alloc_bytes = 0;
static size_t g_max_alloc_bytes = MAX_ALLOC_BYTES;
#ifdef LLVMFUZZER
/* LLVM libsanitizer has a realloc() implementation that always copies
* the whole memory block, even if there would be space to expand it in
* place. This gets pretty slow when fuzzing, so this wrapper limits the
* realloc() calls by rounding allocation size upwards. Real world
* realloc() implementations are hopefully smarter. */
static size_t round_blocksize(size_t size)
{
if (size < 256)
{
return size;
}
else
{
return (size + 1023) / 1024 * 1024;
}
}
#else
static size_t round_blocksize(size_t size)
{
return size;
}
#endif
/* Allocate memory and place check values before and after. */
void* malloc_with_check(size_t size)
{
char *buf = NULL;
if (size <= g_max_alloc_bytes - g_alloc_bytes)
{
buf = malloc(round_blocksize(size + GUARD_SIZE));
}
if (buf)
{
((size_t*)buf)[0] = size;
((size_t*)buf)[1] = CHECK1;
((size_t*)(buf + size))[2] = CHECK2;
g_alloc_count++;
g_alloc_bytes += size;
if (DEBUG_MALLOC) fprintf(stderr, "Alloc 0x%04x/%u\n", (unsigned)(uintptr_t)(buf + PREFIX_SIZE), (unsigned)size);
return buf + PREFIX_SIZE;
}
else
{
if (DEBUG_MALLOC) fprintf(stderr, "malloc(%u) failed\n", (unsigned)size);
return NULL;
}
}
/* Free memory allocated with malloc_with_check() and do the checks. */
void free_with_check(void *mem)
{
if (mem)
{
char *buf = (char*)mem - PREFIX_SIZE;
size_t size = ((size_t*)buf)[0];
if (DEBUG_MALLOC) fprintf(stderr, "Release 0x%04x/%u\n", (unsigned)(uintptr_t)mem, (unsigned)size);
assert(((size_t*)buf)[1] == CHECK1);
assert(((size_t*)(buf + size))[2] == CHECK2);
assert(g_alloc_count > 0);
assert(g_alloc_bytes >= size);
((size_t*)buf)[1] = 0;
((size_t*)(buf + size))[2] = 0;
g_alloc_count--;
g_alloc_bytes -= size;
free(buf);
}
}
/* Reallocate block and check / write guard values */
void* realloc_with_check(void *ptr, size_t size)
{
if (!ptr && size)
{
/* Allocate new block and write guard values */
return malloc_with_check(size);
}
else if (ptr && size)
{
/* Change block size */
char *buf = (char*)ptr - PREFIX_SIZE;
size_t oldsize = ((size_t*)buf)[0];
assert(((size_t*)buf)[1] == CHECK1);
assert(((size_t*)(buf + oldsize))[2] == CHECK2);
assert(g_alloc_count > 0);
assert(g_alloc_bytes >= oldsize);
if (size <= g_max_alloc_bytes - (g_alloc_bytes - oldsize))
{
size_t new_rounded = round_blocksize(size + GUARD_SIZE);
size_t old_rounded = round_blocksize(oldsize + GUARD_SIZE);
if (new_rounded != old_rounded)
{
buf = realloc(buf, new_rounded);
}
}
else
{
buf = NULL;
}
if (!buf)
{
if (DEBUG_MALLOC) fprintf(stderr, "Realloc 0x%04x/%u to %u failed\n", (unsigned)(uintptr_t)ptr, (unsigned)oldsize, (unsigned)size);
return NULL;
}
((size_t*)buf)[0] = size;
((size_t*)buf)[1] = CHECK1;
((size_t*)(buf + size))[2] = CHECK2;
g_alloc_bytes -= oldsize;
g_alloc_bytes += size;
if (DEBUG_MALLOC) fprintf(stderr, "Realloc 0x%04x/%u to 0x%04x/%u\n", (unsigned)(uintptr_t)ptr, (unsigned)oldsize, (unsigned)(uintptr_t)(buf + PREFIX_SIZE), (unsigned)size);
return buf + PREFIX_SIZE;
}
else if (ptr && !size)
{
/* Deallocate */
free_with_check(ptr);
return NULL;
}
else
{
/* No action */
return NULL;
}
}
/* Return total number of allocations not yet released */
size_t get_alloc_count()
{
return g_alloc_count;
}
/* Return allocated size for a pointer returned from malloc(). */
size_t get_allocation_size(const void *mem)
{
char *buf = (char*)mem - PREFIX_SIZE;
return ((size_t*)buf)[0];
}
/* Get total number of allocated bytes */
size_t get_alloc_bytes()
{
return g_alloc_bytes;
}
/* Set limit for allocation size */
void set_max_alloc_bytes(size_t max_bytes)
{
g_max_alloc_bytes = max_bytes;
}
size_t get_max_alloc_bytes()
{
return g_max_alloc_bytes;
}

View File

@@ -0,0 +1,10 @@
#include <stdlib.h>
void* malloc_with_check(size_t size);
void free_with_check(void *mem);
void* realloc_with_check(void *ptr, size_t size);
size_t get_alloc_count();
size_t get_allocation_size(const void *mem);
size_t get_alloc_bytes();
void set_max_alloc_bytes(size_t max_bytes);
size_t get_max_alloc_bytes();

View File

@@ -0,0 +1,15 @@
/* This is just a wrapper in order to get our own malloc wrappers into nanopb core. */
#define pb_realloc(ptr,size) realloc_with_check(ptr,size)
#define pb_free(ptr) free_with_check(ptr)
#ifdef PB_OLD_SYSHDR
#include PB_OLD_SYSHDR
#else
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#endif
#include <malloc_wrappers.h>

View File

@@ -0,0 +1,22 @@
syntax = "proto2";
import "nanopb.proto";
message Person {
required string name = 1 [(nanopb).max_size = 40];
required int32 id = 2;
optional string email = 3 [(nanopb).max_size = 40];
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1 [(nanopb).max_size = 40];
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4 [(nanopb).max_count = 5];
}

View File

@@ -0,0 +1,17 @@
/* Compatibility helpers for the test programs. */
#ifndef _TEST_HELPERS_H_
#define _TEST_HELPERS_H_
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
#define SET_BINARY_MODE(file)
#endif
#endif

View File

@@ -0,0 +1,43 @@
syntax = "proto2";
import 'nanopb.proto';
message IntegerArray {
repeated int32 data = 1 [(nanopb).max_count = 10];
}
message FloatArray {
repeated float data = 1 [(nanopb).max_count = 10];
}
message StringMessage {
required string data = 1 [(nanopb).max_length = 10];
}
message BytesMessage {
required bytes data = 1 [(nanopb).max_size = 16];
}
message CallbackArray {
// We cheat a bit and use this message for testing other types, too.
// Nanopb does not care about the actual defined data type for callback
// fields.
repeated int32 data = 1;
}
message IntegerContainer {
required IntegerArray submsg = 1;
}
message CallbackContainer {
required CallbackArray submsg = 1;
}
message CallbackContainerContainer {
required CallbackContainer submsg = 1;
}
message StringPointerContainer {
repeated string rep_str = 1 [(nanopb).type = FT_POINTER];
}

View File

@@ -0,0 +1,26 @@
#include <stdio.h>
#ifdef UNITTESTS_SHORT_MSGS
/* Short debug messages for platforms with limited memory */
#define COMMENT(x) printf("\n----" x "----\n");
#define TEST(x) \
if (!(x)) { \
fprintf(stderr, "FAIL: Line %d\n", __LINE__); \
status = 1; \
} else { \
printf("OK: Line %d\n", __LINE__); \
}
#else
/* Elaborate debug messages for normal development */
#define COMMENT(x) printf("\n----" x "----\n");
#define TEST(x) \
if (!(x)) { \
fprintf(stderr, "\033[31;1mFAILED:\033[22;39m %s:%d %s\n", __FILE__, __LINE__, #x); \
status = 1; \
} else { \
printf("\033[32;1mOK:\033[22;39m %s\n", #x); \
}
#endif

View File

@@ -0,0 +1,5 @@
# Test functions in pb_common.c
Import('env')
p = env.Program(["common_unittests.c", "$BUILD/alltypes/alltypes.pb.c"])
env.RunTest(p)

View File

@@ -0,0 +1,149 @@
#define PB_VALIDATE_UTF8
#include "pb_common.c"
#include <stdio.h>
#include <string.h>
#include "unittests.h"
#include "../alltypes/alltypes.pb.h"
int main()
{
int status = 0;
{
AllTypes msg;
pb_field_iter_t iter;
COMMENT("Test field iterator logic on AllTypes");
TEST(pb_field_iter_begin(&iter, AllTypes_fields, &msg))
TEST(iter.tag == 1 && iter.pData == &msg.req_int32 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 2 && iter.pData == &msg.req_int64 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 3 && iter.pData == &msg.req_uint32 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 4 && iter.pData == &msg.req_uint64 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 5 && iter.pData == &msg.req_sint32 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 6 && iter.pData == &msg.req_sint64 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 7 && iter.pData == &msg.req_bool && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 8 && iter.pData == &msg.req_fixed32 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 9 && iter.pData == &msg.req_sfixed32 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 10 && iter.pData == &msg.req_float && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 11 && iter.pData == &msg.req_fixed64 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 12 && iter.pData == &msg.req_sfixed64 && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 13 && iter.pData == &msg.req_double && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 14 && iter.pData == &msg.req_string && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 15 && iter.pData == &msg.req_bytes && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 16 && iter.pData == &msg.req_submsg && !iter.pSize
&& iter.submsg_desc == SubMessage_fields)
TEST(pb_field_iter_next(&iter) && iter.tag == 17 && iter.pData == &msg.req_enum && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 18 && iter.pData == &msg.req_emptymsg && !iter.pSize)
TEST(pb_field_iter_next(&iter) && iter.tag == 19 && iter.pData == &msg.req_fbytes && !iter.pSize)
TEST(iter.required_field_index == 18)
TEST(iter.submessage_index == 2)
TEST(pb_field_iter_next(&iter) && iter.tag == 21 && iter.pData == &msg.rep_int32 && iter.pSize == &msg.rep_int32_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 22 && iter.pData == &msg.rep_int64 && iter.pSize == &msg.rep_int64_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 23 && iter.pData == &msg.rep_uint32 && iter.pSize == &msg.rep_uint32_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 24 && iter.pData == &msg.rep_uint64 && iter.pSize == &msg.rep_uint64_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 25 && iter.pData == &msg.rep_sint32 && iter.pSize == &msg.rep_sint32_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 26 && iter.pData == &msg.rep_sint64 && iter.pSize == &msg.rep_sint64_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 27 && iter.pData == &msg.rep_bool && iter.pSize == &msg.rep_bool_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 28 && iter.pData == &msg.rep_fixed32 && iter.pSize == &msg.rep_fixed32_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 29 && iter.pData == &msg.rep_sfixed32 && iter.pSize == &msg.rep_sfixed32_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 30 && iter.pData == &msg.rep_float && iter.pSize == &msg.rep_float_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 31 && iter.pData == &msg.rep_fixed64 && iter.pSize == &msg.rep_fixed64_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 32 && iter.pData == &msg.rep_sfixed64 && iter.pSize == &msg.rep_sfixed64_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 33 && iter.pData == &msg.rep_double && iter.pSize == &msg.rep_double_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 34 && iter.pData == &msg.rep_string && iter.pSize == &msg.rep_string_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 35 && iter.pData == &msg.rep_bytes && iter.pSize == &msg.rep_bytes_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 36 && iter.pData == &msg.rep_submsg && iter.pSize == &msg.rep_submsg_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 37 && iter.pData == &msg.rep_enum && iter.pSize == &msg.rep_enum_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 38 && iter.pData == &msg.rep_emptymsg && iter.pSize == &msg.rep_emptymsg_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 39 && iter.pData == &msg.rep_fbytes && iter.pSize == &msg.rep_fbytes_count)
TEST(pb_field_iter_next(&iter) && iter.tag == 40 && iter.pData == &msg.rep_farray && iter.pSize == &iter.array_size && iter.array_size == 5)
TEST(iter.required_field_index == 19)
TEST(iter.submessage_index == 4)
TEST(pb_field_iter_next(&iter) && iter.tag == 41 && iter.pData == &msg.opt_int32 && iter.pSize == &msg.has_opt_int32 )
TEST(pb_field_iter_next(&iter) && iter.tag == 42 && iter.pData == &msg.opt_int64 && iter.pSize == &msg.has_opt_int64 )
TEST(pb_field_iter_next(&iter) && iter.tag == 43 && iter.pData == &msg.opt_uint32 && iter.pSize == &msg.has_opt_uint32 )
TEST(pb_field_iter_next(&iter) && iter.tag == 44 && iter.pData == &msg.opt_uint64 && iter.pSize == &msg.has_opt_uint64 )
TEST(pb_field_iter_next(&iter) && iter.tag == 45 && iter.pData == &msg.opt_sint32 && iter.pSize == &msg.has_opt_sint32 )
TEST(pb_field_iter_next(&iter) && iter.tag == 46 && iter.pData == &msg.opt_sint64 && iter.pSize == &msg.has_opt_sint64 )
TEST(pb_field_iter_next(&iter) && iter.tag == 47 && iter.pData == &msg.opt_bool && iter.pSize == &msg.has_opt_bool )
TEST(pb_field_iter_next(&iter) && iter.tag == 48 && iter.pData == &msg.opt_fixed32 && iter.pSize == &msg.has_opt_fixed32 )
TEST(pb_field_iter_next(&iter) && iter.tag == 49 && iter.pData == &msg.opt_sfixed32 && iter.pSize == &msg.has_opt_sfixed32)
TEST(pb_field_iter_next(&iter) && iter.tag == 50 && iter.pData == &msg.opt_float && iter.pSize == &msg.has_opt_float )
TEST(pb_field_iter_next(&iter) && iter.tag == 51 && iter.pData == &msg.opt_fixed64 && iter.pSize == &msg.has_opt_fixed64 )
TEST(pb_field_iter_next(&iter) && iter.tag == 52 && iter.pData == &msg.opt_sfixed64 && iter.pSize == &msg.has_opt_sfixed64)
TEST(pb_field_iter_next(&iter) && iter.tag == 53 && iter.pData == &msg.opt_double && iter.pSize == &msg.has_opt_double )
TEST(pb_field_iter_next(&iter) && iter.tag == 54 && iter.pData == &msg.opt_string && iter.pSize == &msg.has_opt_string )
TEST(pb_field_iter_next(&iter) && iter.tag == 55 && iter.pData == &msg.opt_bytes && iter.pSize == &msg.has_opt_bytes )
TEST(pb_field_iter_next(&iter) && iter.tag == 56 && iter.pData == &msg.opt_submsg && iter.pSize == &msg.has_opt_submsg )
TEST(pb_field_iter_next(&iter) && iter.tag == 57 && iter.pData == &msg.opt_enum && iter.pSize == &msg.has_opt_enum )
TEST(pb_field_iter_next(&iter) && iter.tag == 58 && iter.pData == &msg.opt_emptymsg && iter.pSize == &msg.has_opt_emptymsg)
TEST(pb_field_iter_next(&iter) && iter.tag == 59 && iter.pData == &msg.opt_fbytes && iter.pSize == &msg.has_opt_fbytes)
TEST(iter.required_field_index == 19)
TEST(iter.submessage_index == 6)
TEST(pb_field_iter_next(&iter) && iter.tag == 60 && iter.pData == &msg.oneof.oneof_msg1 && iter.pSize == &msg.which_oneof )
TEST(pb_field_iter_next(&iter) && iter.tag == 61 && iter.pData == &msg.oneof.oneof_msg2 && iter.pSize == &msg.which_oneof )
TEST(pb_field_iter_next(&iter) && iter.tag == 62 && iter.pData == &msg.opt_non_zero_based_enum && iter.pSize == &msg.has_opt_non_zero_based_enum)
TEST(pb_field_iter_next(&iter) && iter.tag == 63 && iter.pData == &msg.oneof.static_msg && iter.pSize == &msg.which_oneof )
TEST(iter.required_field_index == 19)
TEST(iter.submessage_index == 8)
TEST(pb_field_iter_next(&iter) && iter.tag == 95 && iter.pData == &msg.rep_farray2 && iter.pSize == &iter.array_size && iter.array_size == 3)
TEST(iter.required_field_index == 19)
TEST(iter.submessage_index == 9)
TEST(pb_field_iter_next(&iter) && iter.tag == 96 && iter.pData == &msg.req_intsizes && !iter.pSize)
TEST(iter.required_field_index == 19)
TEST(iter.submessage_index == 9)
TEST(pb_field_iter_next(&iter) && iter.tag == 97 && iter.pData == &msg.req_ds8 && !iter.pSize)
TEST(iter.required_field_index == 20)
TEST(iter.submessage_index == 10)
TEST(pb_field_iter_next(&iter) && iter.tag == 98 && iter.pData == &msg.req_limits && !iter.pSize)
TEST(iter.required_field_index == 21)
TEST(iter.submessage_index == 11)
TEST(pb_field_iter_next(&iter) && iter.tag == 200 && iter.pData == &msg.extensions && !iter.pSize)
TEST(iter.required_field_index == 22)
TEST(iter.submessage_index == 12)
TEST(pb_field_iter_next(&iter) && iter.tag == 999 && iter.pData == &msg.end && !iter.pSize)
TEST(iter.required_field_index == 22)
TEST(iter.submessage_index == 12)
TEST(!pb_field_iter_next(&iter))
TEST(iter.tag == 1 && iter.pData == &msg.req_int32 && !iter.pSize)
TEST(iter.required_field_index == 0)
TEST(iter.submessage_index == 0)
}
{
COMMENT("Test pb_validate_utf8()");
TEST(pb_validate_utf8("abcdefg"));
TEST(pb_validate_utf8("\xc3\xa4\xc3\xa4\x6b\x6b\xc3\xb6\x6e\x65\x6e\x0a"));
TEST(!pb_validate_utf8("\xc3\xa4\xc3\xa4\x6b\x6b\xb6\xc3\x6e\x65\x6e\x0a"));
TEST(pb_validate_utf8("\xed\x9f\xbf"));
TEST(pb_validate_utf8("\xee\x80\x80"));
TEST(pb_validate_utf8("\xef\xbf\xbd"));
TEST(pb_validate_utf8("\xf4\x8f\xbf\xbf"));
TEST(!pb_validate_utf8("a\x80z"));
TEST(!pb_validate_utf8("a\xbfz"));
TEST(!pb_validate_utf8("a\xfez"));
TEST(!pb_validate_utf8("a\xffz"));
TEST(!pb_validate_utf8("a\xc0\xafz"));
TEST(!pb_validate_utf8("a\xef\xbf\xbez"));
}
if (status != 0)
fprintf(stdout, "\n\nSome tests FAILED!\n");
return status;
}

View File

@@ -0,0 +1,28 @@
Import('env')
import os
base_env = env.Clone()
base_env.Replace(NANOPBFLAGS = '--cpp-descriptor')
base_env.NanopbProtoCpp('message')
# not enabled for "c++03", which fails with "warning: offset of on non-POD type 'TestMessage'"
# 'offsetof' in C++98 requires POD type, C++11 standard relaxes that to standard-layout class.
# see: http://www.cplusplus.com/reference/cstddef/offsetof/
for std in ["c++11", "c++14", "c++17", "c++20"]:
e = base_env.Clone()
e.Append(CXXFLAGS = '-std={}'.format(std))
# Make sure compiler supports this version of C++ before we actually run the
# test.
conf = Configure(e)
compiler_valid = conf.CheckCXX() and conf.CheckCXXHeader('vector')
e = conf.Finish()
if not compiler_valid:
print("Skipping {} test - compiler doesn't support it".format(std))
continue
sources = [ 'cxx_callback_datatype.cpp', 'message.pb.cpp', '$NANOPB/pb_decode.c', '$NANOPB/pb_encode.c', '$NANOPB/pb_common.c' ]
objects = [ e.Object('{}_{}'.format(os.path.basename(s), std), s) for s in sources ]
p = e.Program(target = 'cxx_callback_datatype_{}'.format(std), source = objects)
e.RunTest(p)

View File

@@ -0,0 +1,92 @@
#include "message.pb.hpp"
#include <pb_encode.h>
#include <pb_decode.h>
#include <algorithm>
#include <cstdio>
// See tests/alltypes_callback, tests/oneoff_callback and examples/network_server for more...
bool TestMessage_submessages_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
{
if (ostream != NULL) {
const std::vector<int> &v = *(const std::vector<int> *)field->pData;
for (std::vector<int>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!pb_encode_tag_for_field(ostream, field)) {
return false;
}
SubMessage tmp;
tmp.actual_value = *i;
if (!pb_encode_submessage(ostream, SubMessage_fields, &tmp)) {
return false;
}
}
} else if (istream != NULL) {
std::vector<int> &v = *(std::vector<int> *)field->pData;
SubMessage tmp;
if (!pb_decode(istream, SubMessage_fields, &tmp)) {
return false;
}
v.push_back(tmp.actual_value);
}
return true;
}
extern "C"
bool TestMessage_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
{
if (field->tag == TestMessage_submessages_tag) {
return TestMessage_submessages_callback(istream, ostream, field);
}
return true;
}
extern "C"
int main() {
std::vector<int> source;
source.push_back(5);
source.push_back(4);
source.push_back(3);
source.push_back(2);
source.push_back(1);
std::vector<uint8_t> serialized;
pb_ostream_t sizestream = {0};
pb_encode(&sizestream, TestMessage_fields, &source);
serialized.resize(sizestream.bytes_written);
pb_ostream_t outstream = pb_ostream_from_buffer(&serialized.front(), serialized.size());
if (!pb_encode(&outstream, TestMessage_fields, &source)) {
fprintf(stderr, "Failed to encode: %s\n", PB_GET_ERROR(&outstream));
return 1;
}
std::vector<int> destination;
pb_istream_t instream = pb_istream_from_buffer(&serialized.front(), outstream.bytes_written);
if (!pb_decode(&instream, TestMessage_fields, &destination)) {
fprintf(stderr, "Failed to decode: %s\n", PB_GET_ERROR(&instream));
return 2;
}
if (source != destination) {
fprintf(stderr, "Result does not match\n");
fprintf(stderr, "source(%d): ", (int)source.size());
for (std::vector<int>::iterator i = source.begin(); i != source.end(); ++i)
{
fprintf(stderr, "%d, ", *i);
}
fprintf(stderr, "\nencoded(%d): ", (int)serialized.size());
for (unsigned i = 0; i != std::min(serialized.size(), outstream.bytes_written); ++i) {
fprintf(stderr, "0x%02x ", serialized[i]);
}
fprintf(stderr, "\ndestination(%d): ", (int)destination.size());
for (std::vector<int>::iterator i = destination.begin(); i != destination.end(); ++i)
{
fprintf(stderr, "%d, ", *i);
}
fprintf(stderr, "\n");
return 3;
}
return 0;
}

View File

@@ -0,0 +1,14 @@
syntax = "proto3";
import "nanopb.proto";
option(nanopb_fileopt).include = '<vector>';
message SubMessage {
sint32 actual_value = 1;
}
message TestMessage {
// Instead of std::vector<SubMessage> callback handles wrapping/unwrapping of the int.
repeated SubMessage submessages = 1 [(nanopb).callback_datatype = "std::vector<int>"];
}

View File

@@ -0,0 +1,25 @@
# Test cxx descriptor functionality
Import('env')
base_env = env.Clone()
base_env.Replace(NANOPBFLAGS = '--cpp-descriptor')
base_env.NanopbProto('message')
for std in ["c++03", "c++11", "c++14", "c++17", "c++20"]:
e = base_env.Clone()
e.Append(CXXFLAGS = '-std={}'.format(std))
# Make sure compiler supports this version of C++ before we actually run the
# test.
conf = Configure(e)
compiler_valid = conf.CheckCXX()
e = conf.Finish()
if not compiler_valid:
print("Skipping {} test - compiler doesn't support it".format(std))
continue
o1 = e.Object('message_descriptor_{}'.format(std), 'message_descriptor.cc')
o2 = e.Object('message.pb_{}'.format(std), 'message.pb.c')
p = e.Program([o1, o2])
e.RunTest(p)

View File

@@ -0,0 +1,12 @@
/* Test CPP descriptor generation */
syntax = "proto2";
import "nanopb.proto";
message MyEmptyMessage {
}
message MyNonEmptyMessage {
optional uint32 field = 1;
}

View File

@@ -0,0 +1,29 @@
#include <stdio.h>
#include "message.pb.h"
#include "unittests.h"
extern "C" int main() {
using namespace nanopb;
#if __cplusplus >= 201103L
static_assert(MessageDescriptor<MyEmptyMessage>::fields_array_length == 0,
"Unexpected field length");
static_assert(MessageDescriptor<MyNonEmptyMessage>::fields_array_length == 1,
"Unexpected field length");
#endif // C++11 & newer
int status = 0;
TEST(MessageDescriptor<MyEmptyMessage>::fields_array_length ==
MyEmptyMessage_msg.field_count);
TEST(MessageDescriptor<MyNonEmptyMessage>::fields_array_length ==
MyNonEmptyMessage_msg.field_count);
TEST(MessageDescriptor<MyEmptyMessage>::fields() == MyEmptyMessage_fields);
TEST(MessageDescriptor<MyNonEmptyMessage>::fields() ==
MyNonEmptyMessage_fields);
if (status != 0) fprintf(stdout, "\n\nSome tests FAILED!\n");
return status;
}

View File

@@ -0,0 +1,25 @@
# Run the alltypes test case, but compile it as C++ instead.
# In fact, compile the entire nanopb using C++ compiler.
Import("env")
# This is needed to get INT32_MIN etc. macros defined
env = env.Clone()
env.Append(CPPDEFINES = ['__STDC_LIMIT_MACROS'])
# Copy the files to .cxx extension in order to force C++ build.
c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.cxx", "#../pb_encode.c", c)
env.Command("pb_decode.cxx", "#../pb_decode.c", c)
env.Command("pb_common.cxx", "#../pb_common.c", c)
env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c)
env.Command("alltypes.pb.cxx", "$BUILD/alltypes/alltypes.pb.c", c)
env.Command("encode_alltypes.cxx", "$BUILD/alltypes/encode_alltypes.c", c)
env.Command("decode_alltypes.cxx", "$BUILD/alltypes/decode_alltypes.c", c)
# Now build and run the test normally.
enc = env.Program(["encode_alltypes.cxx", "alltypes.pb.cxx", "pb_encode.cxx", "pb_common.cxx"])
dec = env.Program(["decode_alltypes.cxx", "alltypes.pb.cxx", "pb_decode.cxx", "pb_common.cxx"])
env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -0,0 +1,11 @@
Import("env")
# Encode cyclic messages with callback fields
c = Copy("$TARGET", "$SOURCE")
env.Command("cyclic_callback.proto", "cyclic.proto", c)
env.NanopbProto(["cyclic_callback", "cyclic_callback.options"])
enc_callback = env.Program(["encode_cyclic_callback.c", "cyclic_callback.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])

View File

@@ -0,0 +1,27 @@
// Test structures with cyclic references.
// These can only be handled in pointer/callback mode,
// see associated .options files.
syntax = "proto2";
message TreeNode
{
optional int32 leaf = 1;
optional TreeNode left = 2;
optional TreeNode right = 3;
}
message Dictionary
{
repeated KeyValuePair dictItem = 1;
}
message KeyValuePair
{
required string key = 1;
optional string stringValue = 2;
optional int32 intValue = 3;
optional Dictionary dictValue = 4;
optional TreeNode treeValue = 5;
}

View File

@@ -0,0 +1,6 @@
TreeNode.left type:FT_CALLBACK
TreeNode.right type:FT_CALLBACK
KeyValuePair.key max_size:8
KeyValuePair.stringValue max_size:8
KeyValuePair.treeValue type:FT_CALLBACK

View File

@@ -0,0 +1,148 @@
/* This program parses an input string in a format a bit like JSON:
* {'foobar': 1234, 'xyz': 'abc', 'tree': [[[1, 2], 3], [4, 5]]}
* and encodes it as protobuf
*
* Note: The string parsing here is not in any way intended to be robust
* nor safe against buffer overflows. It is just for this test.
*/
#include <pb_encode.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cyclic_callback.pb.h"
static char *find_end_of_item(char *p)
{
int depth = 0;
do {
if (*p == '[' || *p == '{') depth++;
if (*p == ']' || *p == '}') depth--;
p++;
} while (depth > 0 || (*p != ',' && *p != '}'));
if (*p == '}')
return p; /* End of parent dict */
p++;
while (*p == ' ') p++;
return p;
}
/* Parse a tree in format [[1 2] 3] and encode it directly to protobuf */
static bool encode_tree(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
TreeNode tree = TreeNode_init_zero;
char *p = (char*)*arg;
if (*p == '[')
{
/* This is a tree branch */
p++;
tree.left.funcs.encode = encode_tree;
tree.left.arg = p;
p = find_end_of_item(p);
tree.right.funcs.encode = encode_tree;
tree.right.arg = p;
}
else
{
/* This is a leaf node */
tree.has_leaf = true;
tree.leaf = atoi(p);
}
return pb_encode_tag_for_field(stream, field) &&
pb_encode_submessage(stream, TreeNode_fields, &tree);
}
/* Parse a dictionary in format {'name': value} and encode it directly to protobuf */
static bool encode_dictionary(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
int textlen;
char *p = (char*)*arg;
if (*p == '{') p++;
while (*p != '}')
{
KeyValuePair pair = KeyValuePair_init_zero;
if (*p != '\'')
PB_RETURN_ERROR(stream, "invalid key, missing quote");
p++; /* Starting quote of key */
textlen = strchr(p, '\'') - p;
strncpy(pair.key, p, textlen);
pair.key[textlen] = 0;
p += textlen + 2;
while (*p == ' ') p++;
if (*p == '[')
{
/* Value is a tree */
pair.treeValue.funcs.encode = encode_tree;
pair.treeValue.arg = p;
}
else if (*p == '\'')
{
/* Value is a string */
pair.has_stringValue = true;
p++;
textlen = strchr(p, '\'') - p;
strncpy(pair.stringValue, p, textlen);
pair.stringValue[textlen] = 0;
}
else if (*p == '{')
{
/* Value is a dictionary */
pair.has_dictValue = true;
pair.dictValue.dictItem.funcs.encode = encode_dictionary;
pair.dictValue.dictItem.arg = p;
}
else
{
/* Value is integer */
pair.has_intValue = true;
pair.intValue = atoi(p);
}
p = find_end_of_item(p);
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!pb_encode_submessage(stream, KeyValuePair_fields, &pair))
return false;
}
return true;
}
int main(int argc, char *argv[])
{
uint8_t buffer[256];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
Dictionary dict = Dictionary_init_zero;
if (argc <= 1)
{
fprintf(stderr, "Usage: %s \"{'foobar': 1234, ...}\"\n", argv[0]);
return 1;
}
dict.dictItem.funcs.encode = encode_dictionary;
dict.dictItem.arg = argv[1];
if (!pb_encode(&stream, Dictionary_fields, &dict))
{
fprintf(stderr, "Encoding error: %s\n", PB_GET_ERROR(&stream));
return 1;
}
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0;
}

View File

@@ -0,0 +1,4 @@
Import('env')
p = env.Program(["decode_unittests.c", "$COMMON/unittestproto.pb.c"])
env.RunTest(p)

View File

@@ -0,0 +1,446 @@
/* This includes the whole .c file to get access to static functions. */
#define PB_ENABLE_MALLOC
#include "pb_common.c"
#include "pb_decode.c"
#include <stdio.h>
#include <string.h>
#include "unittests.h"
#include "unittestproto.pb.h"
#define S(x) pb_istream_from_buffer((uint8_t*)x, sizeof(x) - 1)
bool stream_callback(pb_istream_t *stream, uint8_t *buf, size_t count)
{
if (stream->state != NULL)
return false; /* Simulate error */
if (buf != NULL)
memset(buf, 'x', count);
return true;
}
/* Verifies that the stream passed to callback matches the byte array pointed to by arg. */
bool callback_check(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
int i;
uint8_t byte;
pb_bytes_array_t *ref = (pb_bytes_array_t*) *arg;
for (i = 0; i < ref->size; i++)
{
if (!pb_read(stream, &byte, 1))
return false;
if (byte != ref->bytes[i])
return false;
}
return true;
}
int main()
{
int status = 0;
{
uint8_t buffer1[] = "foobartest1234";
uint8_t buffer2[sizeof(buffer1)];
pb_istream_t stream = pb_istream_from_buffer(buffer1, sizeof(buffer1));
COMMENT("Test pb_read and pb_istream_t");
TEST(pb_read(&stream, buffer2, 6))
TEST(memcmp(buffer2, "foobar", 6) == 0)
TEST(stream.bytes_left == sizeof(buffer1) - 6)
TEST(pb_read(&stream, buffer2 + 6, stream.bytes_left))
TEST(memcmp(buffer1, buffer2, sizeof(buffer1)) == 0)
TEST(stream.bytes_left == 0)
TEST(!pb_read(&stream, buffer2, 1))
}
{
uint8_t buffer[20];
pb_istream_t stream = {&stream_callback, NULL, 20};
COMMENT("Test pb_read with custom callback");
TEST(pb_read(&stream, buffer, 5))
TEST(memcmp(buffer, "xxxxx", 5) == 0)
TEST(!pb_read(&stream, buffer, 50))
stream.state = (void*)1; /* Simulated error return from callback */
TEST(!pb_read(&stream, buffer, 5))
stream.state = NULL;
TEST(pb_read(&stream, buffer, 15))
}
{
pb_istream_t s;
uint64_t u;
int64_t i;
COMMENT("Test pb_decode_varint");
TEST((s = S("\x00"), pb_decode_varint(&s, &u) && u == 0));
TEST((s = S("\x01"), pb_decode_varint(&s, &u) && u == 1));
TEST((s = S("\xAC\x02"), pb_decode_varint(&s, &u) && u == 300));
TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint(&s, &u) && u == UINT32_MAX));
TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint(&s, (uint64_t*)&i) && i == UINT32_MAX));
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"),
pb_decode_varint(&s, (uint64_t*)&i) && i == -1));
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"),
pb_decode_varint(&s, &u) && u == UINT64_MAX));
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"),
!pb_decode_varint(&s, &u)));
}
{
pb_istream_t s;
uint32_t u;
COMMENT("Test pb_decode_varint32");
TEST((s = S("\x00"), pb_decode_varint32(&s, &u) && u == 0));
TEST((s = S("\x01"), pb_decode_varint32(&s, &u) && u == 1));
TEST((s = S("\xAC\x02"), pb_decode_varint32(&s, &u) && u == 300));
TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint32(&s, &u) && u == UINT32_MAX));
TEST((s = S("\xFF\xFF\xFF\xFF\x8F\x00"), pb_decode_varint32(&s, &u) && u == UINT32_MAX));
TEST((s = S("\xFF\xFF\xFF\xFF\x10"), !pb_decode_varint32(&s, &u)));
TEST((s = S("\xFF\xFF\xFF\xFF\x40"), !pb_decode_varint32(&s, &u)));
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\x01"), !pb_decode_varint32(&s, &u)));
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x00"), !pb_decode_varint32(&s, &u)));
}
{
pb_istream_t s;
COMMENT("Test pb_skip_varint");
TEST((s = S("\x00""foobar"), pb_skip_varint(&s) && s.bytes_left == 6))
TEST((s = S("\xAC\x02""foobar"), pb_skip_varint(&s) && s.bytes_left == 6))
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01""foobar"),
pb_skip_varint(&s) && s.bytes_left == 6))
TEST((s = S("\xFF"), !pb_skip_varint(&s)))
}
{
pb_istream_t s;
COMMENT("Test pb_skip_string")
TEST((s = S("\x00""foobar"), pb_skip_string(&s) && s.bytes_left == 6))
TEST((s = S("\x04""testfoobar"), pb_skip_string(&s) && s.bytes_left == 6))
TEST((s = S("\x04"), !pb_skip_string(&s)))
TEST((s = S("\xFF"), !pb_skip_string(&s)))
}
{
pb_istream_t s = S("\x01\x00");
pb_field_iter_t f;
uint32_t d;
f.type = PB_LTYPE_VARINT;
f.data_size = sizeof(d);
f.pData = &d;
COMMENT("Test pb_dec_varint using uint32_t")
TEST(pb_dec_varint(&s, &f) && d == 1)
/* Verify that no more than data_size is written. */
d = 0xFFFFFFFF;
f.data_size = 1;
TEST(pb_dec_varint(&s, &f) && (d == 0xFFFFFF00 || d == 0x00FFFFFF))
}
{
pb_istream_t s;
pb_field_iter_t f;
int32_t d;
f.type = PB_LTYPE_SVARINT;
f.data_size = sizeof(d);
f.pData = &d;
COMMENT("Test pb_dec_varint using sint32_t")
TEST((s = S("\x01"), pb_dec_varint(&s, &f) && d == -1))
TEST((s = S("\x02"), pb_dec_varint(&s, &f) && d == 1))
TEST((s = S("\xfe\xff\xff\xff\x0f"), pb_dec_varint(&s, &f) && d == INT32_MAX))
TEST((s = S("\xff\xff\xff\xff\x0f"), pb_dec_varint(&s, &f) && d == INT32_MIN))
}
{
pb_istream_t s;
pb_field_iter_t f;
int64_t d;
f.type = PB_LTYPE_SVARINT;
f.data_size = sizeof(d);
f.pData = &d;
COMMENT("Test pb_dec_varint using sint64_t")
TEST((s = S("\x01"), pb_dec_varint(&s, &f) && d == -1))
TEST((s = S("\x02"), pb_dec_varint(&s, &f) && d == 1))
TEST((s = S("\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"), pb_dec_varint(&s, &f) && d == INT64_MAX))
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"), pb_dec_varint(&s, &f) && d == INT64_MIN))
}
{
pb_istream_t s;
pb_field_iter_t f;
int32_t d;
f.type = PB_LTYPE_SVARINT;
f.data_size = sizeof(d);
f.pData = &d;
COMMENT("Test pb_dec_varint overflow detection using sint32_t");
TEST((s = S("\xfe\xff\xff\xff\x0f"), pb_dec_varint(&s, &f)));
TEST((s = S("\xfe\xff\xff\xff\x10"), !pb_dec_varint(&s, &f)));
TEST((s = S("\xff\xff\xff\xff\x0f"), pb_dec_varint(&s, &f)));
TEST((s = S("\xff\xff\xff\xff\x10"), !pb_dec_varint(&s, &f)));
}
{
pb_istream_t s;
pb_field_iter_t f;
uint32_t d;
f.type = PB_LTYPE_UVARINT;
f.data_size = sizeof(d);
f.pData = &d;
COMMENT("Test pb_dec_varint using uint32_t")
TEST((s = S("\x01"), pb_dec_varint(&s, &f) && d == 1))
TEST((s = S("\x02"), pb_dec_varint(&s, &f) && d == 2))
TEST((s = S("\xff\xff\xff\xff\x0f"), pb_dec_varint(&s, &f) && d == UINT32_MAX))
}
{
pb_istream_t s;
pb_field_iter_t f;
uint64_t d;
f.type = PB_LTYPE_UVARINT;
f.data_size = sizeof(d);
f.pData = &d;
COMMENT("Test pb_dec_varint using uint64_t")
TEST((s = S("\x01"), pb_dec_varint(&s, &f) && d == 1))
TEST((s = S("\x02"), pb_dec_varint(&s, &f) && d == 2))
TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"), pb_dec_varint(&s, &f) && d == UINT64_MAX))
}
{
pb_istream_t s;
pb_field_iter_t f;
uint32_t d;
f.type = PB_LTYPE_UVARINT;
f.data_size = sizeof(d);
f.pData = &d;
COMMENT("Test pb_dec_varint overflow detection using uint32_t");
TEST((s = S("\xff\xff\xff\xff\x0f"), pb_dec_varint(&s, &f)));
TEST((s = S("\xff\xff\xff\xff\x10"), !pb_dec_varint(&s, &f)));
}
{
pb_istream_t s;
float d;
COMMENT("Test pb_dec_fixed using float (failures here may be caused by imperfect rounding)")
TEST((s = S("\x00\x00\x00\x00"), pb_decode_fixed32(&s, &d) && d == 0.0f))
TEST((s = S("\x00\x00\xc6\x42"), pb_decode_fixed32(&s, &d) && d == 99.0f))
TEST((s = S("\x4e\x61\x3c\xcb"), pb_decode_fixed32(&s, &d) && d == -12345678.0f))
d = -12345678.0f;
TEST((s = S("\x00"), !pb_decode_fixed32(&s, &d) && d == -12345678.0f))
}
if (sizeof(double) == 8)
{
pb_istream_t s;
double d;
COMMENT("Test pb_dec_fixed64 using double (failures here may be caused by imperfect rounding)")
TEST((s = S("\x00\x00\x00\x00\x00\x00\x00\x00"), pb_decode_fixed64(&s, &d) && d == 0.0))
TEST((s = S("\x00\x00\x00\x00\x00\xc0\x58\x40"), pb_decode_fixed64(&s, &d) && d == 99.0))
TEST((s = S("\x00\x00\x00\xc0\x29\x8c\x67\xc1"), pb_decode_fixed64(&s, &d) && d == -12345678.0f))
}
{
pb_istream_t s;
struct { pb_size_t size; uint8_t bytes[5]; } d;
pb_field_iter_t f;
f.type = PB_LTYPE_BYTES;
f.data_size = sizeof(d);
f.pData = &d;
COMMENT("Test pb_dec_bytes")
TEST((s = S("\x00"), pb_dec_bytes(&s, &f) && d.size == 0))
TEST((s = S("\x01\xFF"), pb_dec_bytes(&s, &f) && d.size == 1 && d.bytes[0] == 0xFF))
TEST((s = S("\x05xxxxx"), pb_dec_bytes(&s, &f) && d.size == 5))
TEST((s = S("\x05xxxx"), !pb_dec_bytes(&s, &f)))
/* Note: the size limit on bytes-fields is not strictly obeyed, as
* the compiler may add some padding to the struct. Using this padding
* is not a very good thing to do, but it is difficult to avoid when
* we use only a single uint8_t to store the size of the field.
* Therefore this tests against a 10-byte string, while otherwise even
* 6 bytes should error out.
*/
TEST((s = S("\x10xxxxxxxxxx"), !pb_dec_bytes(&s, &f)))
}
{
pb_istream_t s;
pb_field_iter_t f;
char d[5];
f.type = PB_LTYPE_STRING;
f.data_size = sizeof(d);
f.pData = &d;
COMMENT("Test pb_dec_string")
TEST((s = S("\x00"), pb_dec_string(&s, &f) && d[0] == '\0'))
TEST((s = S("\x04xyzz"), pb_dec_string(&s, &f) && strcmp(d, "xyzz") == 0))
TEST((s = S("\x05xyzzy"), !pb_dec_string(&s, &f)))
}
{
pb_istream_t s;
IntegerArray dest;
COMMENT("Testing pb_decode with repeated int32 field")
TEST((s = S(""), pb_decode(&s, IntegerArray_fields, &dest) && dest.data_count == 0))
TEST((s = S("\x08\x01\x08\x02"), pb_decode(&s, IntegerArray_fields, &dest)
&& dest.data_count == 2 && dest.data[0] == 1 && dest.data[1] == 2))
s = S("\x08\x01\x08\x02\x08\x03\x08\x04\x08\x05\x08\x06\x08\x07\x08\x08\x08\x09\x08\x0A");
TEST(pb_decode(&s, IntegerArray_fields, &dest) && dest.data_count == 10 && dest.data[9] == 10)
s = S("\x08\x01\x08\x02\x08\x03\x08\x04\x08\x05\x08\x06\x08\x07\x08\x08\x08\x09\x08\x0A\x08\x0B");
TEST(!pb_decode(&s, IntegerArray_fields, &dest))
}
{
pb_istream_t s;
IntegerArray dest;
COMMENT("Testing pb_decode with packed int32 field")
TEST((s = S("\x0A\x00"), pb_decode(&s, IntegerArray_fields, &dest)
&& dest.data_count == 0))
TEST((s = S("\x0A\x01\x01"), pb_decode(&s, IntegerArray_fields, &dest)
&& dest.data_count == 1 && dest.data[0] == 1))
TEST((s = S("\x0A\x0A\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A"), pb_decode(&s, IntegerArray_fields, &dest)
&& dest.data_count == 10 && dest.data[0] == 1 && dest.data[9] == 10))
TEST((s = S("\x0A\x0B\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B"), !pb_decode(&s, IntegerArray_fields, &dest)))
/* Test invalid wire data */
TEST((s = S("\x0A\xFF"), !pb_decode(&s, IntegerArray_fields, &dest)))
TEST((s = S("\x0A\x01"), !pb_decode(&s, IntegerArray_fields, &dest)))
}
{
pb_istream_t s;
IntegerArray dest;
COMMENT("Testing pb_decode with unknown fields")
TEST((s = S("\x18\x0F\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)
&& dest.data_count == 1 && dest.data[0] == 1))
TEST((s = S("\x19\x00\x00\x00\x00\x00\x00\x00\x00\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)
&& dest.data_count == 1 && dest.data[0] == 1))
TEST((s = S("\x1A\x00\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)
&& dest.data_count == 1 && dest.data[0] == 1))
TEST((s = S("\x1B\x08\x01"), !pb_decode(&s, IntegerArray_fields, &dest)))
TEST((s = S("\x1D\x00\x00\x00\x00\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)
&& dest.data_count == 1 && dest.data[0] == 1))
}
{
pb_istream_t s;
CallbackArray dest;
struct { pb_size_t size; uint8_t bytes[10]; } ref;
dest.data.funcs.decode = &callback_check;
dest.data.arg = &ref;
COMMENT("Testing pb_decode with callbacks")
/* Single varint */
ref.size = 1; ref.bytes[0] = 0x55;
TEST((s = S("\x08\x55"), pb_decode(&s, CallbackArray_fields, &dest)))
/* Packed varint */
ref.size = 3; ref.bytes[0] = ref.bytes[1] = ref.bytes[2] = 0x55;
TEST((s = S("\x0A\x03\x55\x55\x55"), pb_decode(&s, CallbackArray_fields, &dest)))
/* Packed varint with loop */
ref.size = 1; ref.bytes[0] = 0x55;
TEST((s = S("\x0A\x03\x55\x55\x55"), pb_decode(&s, CallbackArray_fields, &dest)))
/* Single fixed32 */
ref.size = 4; ref.bytes[0] = ref.bytes[1] = ref.bytes[2] = ref.bytes[3] = 0xAA;
TEST((s = S("\x0D\xAA\xAA\xAA\xAA"), pb_decode(&s, CallbackArray_fields, &dest)))
/* Single fixed64 */
ref.size = 8; memset(ref.bytes, 0xAA, 8);
TEST((s = S("\x09\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"), pb_decode(&s, CallbackArray_fields, &dest)))
/* Unsupported field type */
TEST((s = S("\x0B\x00"), !pb_decode(&s, CallbackArray_fields, &dest)))
/* Just make sure that our test function works */
ref.size = 1; ref.bytes[0] = 0x56;
TEST((s = S("\x08\x55"), !pb_decode(&s, CallbackArray_fields, &dest)))
}
{
pb_istream_t s;
IntegerArray dest;
COMMENT("Testing pb_decode message termination")
TEST((s = S(""), pb_decode(&s, IntegerArray_fields, &dest)))
TEST((s = S("\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)))
TEST((s = S("\x08"), !pb_decode(&s, IntegerArray_fields, &dest)))
}
{
pb_istream_t s;
IntegerArray dest;
COMMENT("Testing pb_decode_ex null termination")
TEST((s = S("\x00"), pb_decode_ex(&s, IntegerArray_fields, &dest, PB_DECODE_NULLTERMINATED)))
TEST((s = S("\x08\x01\x00"), pb_decode_ex(&s, IntegerArray_fields, &dest, PB_DECODE_NULLTERMINATED)))
}
{
pb_istream_t s;
IntegerArray dest;
COMMENT("Testing pb_decode with invalid tag numbers")
TEST((s = S("\x9f\xea"), !pb_decode(&s, IntegerArray_fields, &dest)));
TEST((s = S("\x00"), !pb_decode(&s, IntegerArray_fields, &dest)));
}
{
pb_istream_t s;
IntegerContainer dest = {{0}};
COMMENT("Testing pb_decode_delimited")
TEST((s = S("\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"),
pb_decode_delimited(&s, IntegerContainer_fields, &dest)) &&
dest.submsg.data_count == 5)
}
{
pb_istream_t s = {0};
void *data = NULL;
COMMENT("Testing allocate_field")
TEST(allocate_field(&s, &data, 10, 10) && data != NULL);
TEST(allocate_field(&s, &data, 10, 20) && data != NULL);
{
void *oldvalue = data;
size_t very_big = (size_t)-1;
size_t somewhat_big = very_big / 2 + 1;
size_t not_so_big = (size_t)1 << (4 * sizeof(size_t));
TEST(!allocate_field(&s, &data, very_big, 2) && data == oldvalue);
TEST(!allocate_field(&s, &data, somewhat_big, 2) && data == oldvalue);
TEST(!allocate_field(&s, &data, not_so_big, not_so_big) && data == oldvalue);
}
pb_free(data);
}
if (status != 0)
fprintf(stdout, "\n\nSome tests FAILED!\n");
return status;
}

View File

@@ -0,0 +1,17 @@
Docker files
------------
This folder contains docker files that are used in testing nanopb automatically
on various platforms.
By default they take the newest master branch code from github.
To build tests for a single target, use for example:
docker build ubuntu1804
To build tests for all targets, use:
./build_all.sh

View File

@@ -0,0 +1,8 @@
#!/bin/bash -e
# Run all targets
for file in `ls */Dockerfile`
do echo -e "\n\n\n---------------------------------------- Building image for" $file " -------------------------------------------\n\n\n"
docker build $(dirname $file)
done

View File

@@ -0,0 +1,15 @@
FROM ubuntu:bionic
RUN apt -y update
RUN apt -y upgrade
RUN apt -y dist-upgrade
RUN apt -y autoremove
RUN apt -y install --fix-missing
RUN apt -y install apt-utils
RUN apt -y install git scons build-essential g++
RUN apt -y install protobuf-compiler python3-protobuf python3
RUN git clone https://github.com/nanopb/nanopb.git
RUN cd nanopb/tests && scons

View File

@@ -0,0 +1,16 @@
FROM ubuntu:focal
RUN apt -y update
RUN apt -y upgrade
RUN apt -y dist-upgrade
RUN apt -y autoremove
RUN apt -y install --fix-missing
RUN apt -y install apt-utils
RUN apt -y install git scons build-essential g++
RUN apt -y install protobuf-compiler python3.8 python3-protobuf
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.8 1 && update-alternatives --set python /usr/bin/python3.8
RUN git clone https://github.com/nanopb/nanopb.git
RUN cd nanopb/tests && scons

View File

@@ -0,0 +1,28 @@
# Run the alltypes test case, but compile with PB_ENCODE_ARRAYS_UNPACKED=1
Import("env")
# Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE")
env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c)
env.Command("alltypes.pb.c", "$BUILD/alltypes/alltypes.pb.c", c)
env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
# Define the compilation options
opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_ENCODE_ARRAYS_UNPACKED': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_unpacked.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_unpacked.o", "$NANOPB/pb_encode.c")
strict.Object("pb_common_unpacked.o", "$NANOPB/pb_common.c")
# Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_unpacked.o", "pb_common_unpacked.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_unpacked.o", "pb_common_unpacked.o"])
env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -0,0 +1,5 @@
# Build and run the stand-alone unit tests for the nanopb encoder part.
Import('env')
p = env.Program(["encode_unittests.c", "$COMMON/unittestproto.pb.c"])
env.RunTest(p)

View File

@@ -0,0 +1,429 @@
/* This includes the whole .c file to get access to static functions. */
#include "pb_common.c"
#include "pb_encode.c"
#include <stdio.h>
#include <string.h>
#include "unittests.h"
#include "unittestproto.pb.h"
bool streamcallback(pb_ostream_t *stream, const uint8_t *buf, size_t count)
{
/* Allow only 'x' to be written */
while (count--)
{
if (*buf++ != 'x')
return false;
}
return true;
}
bool fieldcallback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
int value = 0x55;
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_varint(stream, value);
}
bool crazyfieldcallback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
/* This callback writes different amount of data the second time. */
uint32_t *state = (uint32_t*)arg;
*state <<= 8;
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_varint(stream, *state);
}
/* Check that expression x writes data y.
* Y is a string, which may contain null bytes. Null terminator is ignored.
*/
#define WRITES(x, y) \
memset(buffer, 0xAA, sizeof(buffer)), \
s = pb_ostream_from_buffer(buffer, sizeof(buffer)), \
(x) && \
memcmp(buffer, y, sizeof(y) - 1) == 0 && \
buffer[sizeof(y) - 1] == 0xAA
int main()
{
int status = 0;
{
uint8_t buffer1[] = "foobartest1234";
uint8_t buffer2[sizeof(buffer1)];
pb_ostream_t stream = pb_ostream_from_buffer(buffer2, sizeof(buffer1));
COMMENT("Test pb_write and pb_ostream_t");
TEST(pb_write(&stream, buffer1, sizeof(buffer1)));
TEST(memcmp(buffer1, buffer2, sizeof(buffer1)) == 0);
TEST(!pb_write(&stream, buffer1, 1));
TEST(stream.bytes_written == sizeof(buffer1));
}
{
uint8_t buffer1[] = "xxxxxxx";
pb_ostream_t stream = {&streamcallback, 0, SIZE_MAX, 0};
COMMENT("Test pb_write with custom callback");
TEST(pb_write(&stream, buffer1, 5));
buffer1[0] = 'a';
TEST(!pb_write(&stream, buffer1, 5));
}
{
uint8_t buffer[30];
pb_ostream_t s;
COMMENT("Test pb_encode_varint")
TEST(WRITES(pb_encode_varint(&s, 0), "\0"));
TEST(WRITES(pb_encode_varint(&s, 1), "\1"));
TEST(WRITES(pb_encode_varint(&s, 0x7F), "\x7F"));
TEST(WRITES(pb_encode_varint(&s, 0x80), "\x80\x01"));
TEST(WRITES(pb_encode_varint(&s, UINT32_MAX), "\xFF\xFF\xFF\xFF\x0F"));
TEST(WRITES(pb_encode_varint(&s, UINT64_MAX), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
}
{
uint8_t buffer[50];
pb_ostream_t s;
COMMENT("Test pb_encode_varint 32-bit fast path")
TEST(WRITES(pb_encode_varint(&s, 0x00000000), "\x00"));
TEST(WRITES(pb_encode_varint(&s, 0x00000001), "\x01"));
TEST(WRITES(pb_encode_varint(&s, 0x0000007F), "\x7F"));
TEST(WRITES(pb_encode_varint(&s, 0x00000080), "\x80\x01"));
TEST(WRITES(pb_encode_varint(&s, 0x00000191), "\x91\x03"));
TEST(WRITES(pb_encode_varint(&s, 0x00003FFF), "\xFF\x7F"));
TEST(WRITES(pb_encode_varint(&s, 0x00004000), "\x80\x80\x01"));
TEST(WRITES(pb_encode_varint(&s, 0x0000D111), "\x91\xA2\x03"));
TEST(WRITES(pb_encode_varint(&s, 0x001FFFFF), "\xFF\xFF\x7F"));
TEST(WRITES(pb_encode_varint(&s, 0x00200000), "\x80\x80\x80\x01"));
TEST(WRITES(pb_encode_varint(&s, 0x00711111), "\x91\xA2\xC4\x03"));
TEST(WRITES(pb_encode_varint(&s, 0x0FFFFFFF), "\xFF\xFF\xFF\x7F"));
TEST(WRITES(pb_encode_varint(&s, 0x10000000), "\x80\x80\x80\x80\x01"));
TEST(WRITES(pb_encode_varint(&s, 0x31111111), "\x91\xA2\xC4\x88\x03"));
TEST(WRITES(pb_encode_varint(&s, UINT32_MAX), "\xFF\xFF\xFF\xFF\x0F"));
}
{
uint8_t buffer[50];
pb_ostream_t s;
COMMENT("Test pb_encode_svarint 32-bit fast path")
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00000000), "\x00"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xFFFFFFFF), "\x01"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x0000003F), "\x7E"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xFFFFFFC0), "\x7F"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00000040), "\x80\x01"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00001FFF), "\xFE\x7F"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xFFFFE000), "\xFF\x7F"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00002000), "\x80\x80\x01"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x000FFFFF), "\xFE\xFF\x7F"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xFFF00000), "\xFF\xFF\x7F"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00100000), "\x80\x80\x80\x01"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x07FFFFFF), "\xFE\xFF\xFF\x7F"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xF8000000), "\xFF\xFF\xFF\x7F"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x08000000), "\x80\x80\x80\x80\x01"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x7FFFFFFF), "\xFE\xFF\xFF\xFF\x0F"));
TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x80000000), "\xFF\xFF\xFF\xFF\x0F"));
}
{
uint8_t buffer[30];
pb_ostream_t s;
COMMENT("Test pb_encode_tag")
TEST(WRITES(pb_encode_tag(&s, PB_WT_STRING, 5), "\x2A"));
TEST(WRITES(pb_encode_tag(&s, PB_WT_VARINT, 99), "\x98\x06"));
}
{
uint8_t buffer[30];
pb_ostream_t s;
pb_field_iter_t field;
field.tag = 10;
COMMENT("Test pb_encode_tag_for_field")
field.type = PB_LTYPE_SVARINT;
TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x50"));
field.type = PB_LTYPE_FIXED64;
TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x51"));
field.type = PB_LTYPE_STRING;
TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x52"));
field.type = PB_LTYPE_FIXED32;
TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x55"));
}
{
uint8_t buffer[30];
pb_ostream_t s;
COMMENT("Test pb_encode_string")
TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"abcd", 4), "\x04""abcd"));
TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"abcd\x00", 5), "\x05""abcd\x00"));
TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"", 0), "\x00"));
}
{
uint8_t buffer[30];
pb_ostream_t s;
uint8_t value = 1;
int32_t max = INT32_MAX;
int32_t min = INT32_MIN;
int64_t lmax = INT64_MAX;
int64_t lmin = INT64_MIN;
pb_field_iter_t field;
COMMENT("Test pb_enc_varint and pb_enc_svarint")
field.type = PB_LTYPE_VARINT;
field.data_size = sizeof(value);
field.pData = &value;
TEST(WRITES(pb_enc_varint(&s, &field), "\x01"));
field.type = PB_LTYPE_SVARINT;
field.data_size = sizeof(max);
field.pData = &max;
TEST(WRITES(pb_enc_varint(&s, &field), "\xfe\xff\xff\xff\x0f"));
field.type = PB_LTYPE_SVARINT;
field.data_size = sizeof(min);
field.pData = &min;
TEST(WRITES(pb_enc_varint(&s, &field), "\xff\xff\xff\xff\x0f"));
field.type = PB_LTYPE_SVARINT;
field.data_size = sizeof(lmax);
field.pData = &lmax;
TEST(WRITES(pb_enc_varint(&s, &field), "\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
field.type = PB_LTYPE_SVARINT;
field.data_size = sizeof(lmin);
field.pData = &lmin;
TEST(WRITES(pb_enc_varint(&s, &field), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
}
{
uint8_t buffer[30];
pb_ostream_t s;
float fvalue;
double dvalue;
pb_field_iter_t field;
COMMENT("Test pb_enc_fixed using float")
field.type = PB_LTYPE_FIXED32;
field.data_size = sizeof(fvalue);
field.pData = &fvalue;
fvalue = 0.0f;
TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\x00\x00"))
fvalue = 99.0f;
TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\xc6\x42"))
fvalue = -12345678.0f;
TEST(WRITES(pb_enc_fixed(&s, &field), "\x4e\x61\x3c\xcb"))
COMMENT("Test pb_enc_fixed using double")
field.type = PB_LTYPE_FIXED64;
field.data_size = sizeof(dvalue);
field.pData = &dvalue;
dvalue = 0.0;
TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\x00\x00\x00\x00\x00\x00"))
dvalue = 99.0;
TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\x00\x00\x00\xc0\x58\x40"))
dvalue = -12345678.0;
TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\x00\xc0\x29\x8c\x67\xc1"))
}
{
uint8_t buffer[30];
pb_ostream_t s;
struct { pb_size_t size; uint8_t bytes[5]; } value = {5, {'x', 'y', 'z', 'z', 'y'}};
pb_field_iter_t field;
pb_field_iter_begin(&field, BytesMessage_fields, &value);
COMMENT("Test pb_enc_bytes")
TEST(WRITES(pb_enc_bytes(&s, &field), "\x05xyzzy"))
value.size = 0;
TEST(WRITES(pb_enc_bytes(&s, &field), "\x00"))
}
{
uint8_t buffer[30];
pb_ostream_t s;
char value[30] = "xyzzy";
pb_field_iter_t field;
pb_field_iter_begin(&field, StringMessage_fields, &value);
COMMENT("Test pb_enc_string")
TEST(WRITES(pb_enc_string(&s, &field), "\x05xyzzy"))
value[0] = '\0';
TEST(WRITES(pb_enc_string(&s, &field), "\x00"))
memset(value, 'x', 10);
value[10] = '\0';
TEST(WRITES(pb_enc_string(&s, &field), "\x0Axxxxxxxxxx"))
}
{
uint8_t buffer[10];
pb_ostream_t s;
IntegerArray msg = {5, {1, 2, 3, 4, 5}};
COMMENT("Test pb_encode with int32 array")
TEST(WRITES(pb_encode(&s, IntegerArray_fields, &msg), "\x0A\x05\x01\x02\x03\x04\x05"))
msg.data_count = 0;
TEST(WRITES(pb_encode(&s, IntegerArray_fields, &msg), ""))
msg.data_count = 10;
TEST(!pb_encode(&s, IntegerArray_fields, &msg))
}
{
uint8_t buffer[10];
pb_ostream_t s;
FloatArray msg = {1, {99.0f}};
COMMENT("Test pb_encode with float array")
TEST(WRITES(pb_encode(&s, FloatArray_fields, &msg),
"\x0A\x04\x00\x00\xc6\x42"))
msg.data_count = 0;
TEST(WRITES(pb_encode(&s, FloatArray_fields, &msg), ""))
msg.data_count = 3;
TEST(!pb_encode(&s, FloatArray_fields, &msg))
}
{
uint8_t buffer[50];
pb_ostream_t s;
FloatArray msg = {1, {99.0f}};
COMMENT("Test array size limit in pb_encode")
s = pb_ostream_from_buffer(buffer, sizeof(buffer));
TEST((msg.data_count = 10) && pb_encode(&s, FloatArray_fields, &msg))
s = pb_ostream_from_buffer(buffer, sizeof(buffer));
TEST((msg.data_count = 11) && !pb_encode(&s, FloatArray_fields, &msg))
}
{
uint8_t buffer[10];
pb_ostream_t s;
CallbackArray msg;
msg.data.funcs.encode = &fieldcallback;
COMMENT("Test pb_encode with callback field.")
TEST(WRITES(pb_encode(&s, CallbackArray_fields, &msg), "\x08\x55"))
}
{
uint8_t buffer[10];
pb_ostream_t s;
IntegerContainer msg = {{5, {1,2,3,4,5}}};
COMMENT("Test pb_encode with packed array in a submessage.")
TEST(WRITES(pb_encode(&s, IntegerContainer_fields, &msg),
"\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"))
}
{
uint8_t buffer[32];
pb_ostream_t s;
BytesMessage msg = {{3, "xyz"}};
COMMENT("Test pb_encode with bytes message.")
TEST(WRITES(pb_encode(&s, BytesMessage_fields, &msg),
"\x0A\x03xyz"))
msg.data.size = 17; /* More than maximum */
TEST(!pb_encode(&s, BytesMessage_fields, &msg))
}
{
uint8_t buffer[20];
pb_ostream_t s;
IntegerContainer msg = {{5, {1,2,3,4,5}}};
COMMENT("Test pb_encode_delimited.")
TEST(WRITES(pb_encode_delimited(&s, IntegerContainer_fields, &msg),
"\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"))
}
{
IntegerContainer msg = {{5, {1,2,3,4,5}}};
size_t size;
COMMENT("Test pb_get_encoded_size.")
TEST(pb_get_encoded_size(&size, IntegerContainer_fields, &msg) &&
size == 9);
}
{
uint8_t buffer[10];
pb_ostream_t s;
CallbackContainer msg;
CallbackContainerContainer msg2;
uint32_t state = 1;
msg.submsg.data.funcs.encode = &fieldcallback;
msg2.submsg.submsg.data.funcs.encode = &fieldcallback;
COMMENT("Test pb_encode with callback field in a submessage.")
TEST(WRITES(pb_encode(&s, CallbackContainer_fields, &msg), "\x0A\x02\x08\x55"))
TEST(WRITES(pb_encode(&s, CallbackContainerContainer_fields, &msg2),
"\x0A\x04\x0A\x02\x08\x55"))
/* Misbehaving callback: varying output between calls */
msg.submsg.data.funcs.encode = &crazyfieldcallback;
msg.submsg.data.arg = &state;
msg2.submsg.submsg.data.funcs.encode = &crazyfieldcallback;
msg2.submsg.submsg.data.arg = &state;
TEST(!pb_encode(&s, CallbackContainer_fields, &msg))
state = 1;
TEST(!pb_encode(&s, CallbackContainerContainer_fields, &msg2))
}
{
uint8_t buffer[StringMessage_size];
pb_ostream_t s;
StringMessage msg = {"0123456789"};
s = pb_ostream_from_buffer(buffer, sizeof(buffer));
COMMENT("Test that StringMessage_size is correct")
TEST(pb_encode(&s, StringMessage_fields, &msg));
TEST(s.bytes_written == StringMessage_size);
}
{
uint8_t buffer[128];
pb_ostream_t s;
StringPointerContainer msg = StringPointerContainer_init_zero;
char *strs[1] = {NULL};
char zstr[] = "Z";
COMMENT("Test string pointer encoding.");
msg.rep_str = strs;
msg.rep_str_count = 1;
TEST(WRITES(pb_encode(&s, StringPointerContainer_fields, &msg), "\x0a\x00"))
strs[0] = zstr;
TEST(WRITES(pb_encode(&s, StringPointerContainer_fields, &msg), "\x0a\x01Z"))
}
if (status != 0)
fprintf(stdout, "\n\nSome tests FAILED!\n");
return status;
}

View File

@@ -0,0 +1,8 @@
# Test that different sizes of enum fields are properly encoded and decoded.
Import('env')
env.NanopbProto('enumminmax')
p = env.Program(["enumminmax_unittests.c",])
env.RunTest(p)

View File

@@ -0,0 +1,22 @@
/* Test out-of-order enum values.
*/
syntax = "proto3";
enum Language {
UNKNOWN = 0;
ENGLISH_EN_GB = 12;
ENGLISH_EN_US = 1;
FRENCH_FR_FR = 2;
ITALIAN_IT_IT = 3;
GERMAN_DE_DE = 4;
SPANISH_ES_AR = 13;
SPANISH_ES_ES = 5;
SPANISH_ES_MX = 14;
SWEDISH_SV_SE = 6;
DUTCH_NL_NL = 7;
KOREAN_KO_KR = 8;
JAPANESE_JA_JP = 9;
CHINESE_SIMPLIFIED_ZH_CN = 10;
CHINESE_TRADITIONAL_ZH_TW = 11;
}

View File

@@ -0,0 +1,16 @@
#include "unittests.h"
#include "enumminmax.pb.h"
int main()
{
int status = 0;
COMMENT("Verify min/max on unsorted enum");
{
TEST(_Language_MIN == Language_UNKNOWN);
TEST(_Language_MAX == Language_SPANISH_ES_MX);
TEST(_Language_ARRAYSIZE == (Language_SPANISH_ES_MX+1));
}
return status;
}

View File

@@ -0,0 +1,12 @@
# Test that different sizes of enum fields are properly encoded and decoded.
Import('env')
env.NanopbProto('enumsizes')
p = env.Program(["enumsizes_unittests.c",
"enumsizes.pb.c",
"$COMMON/pb_encode.o",
"$COMMON/pb_decode.o",
"$COMMON/pb_common.o"])
env.RunTest(p)

View File

@@ -0,0 +1,86 @@
/* Test handling of enums with different value ranges.
* Depending on compiler and the packed_enum setting, the datatypes
* for enums can be either signed or unsigned. In past this has caused
* a bit of a problem for the encoder/decoder (issue #164).
*/
syntax = "proto2";
import 'nanopb.proto';
option (nanopb_fileopt).long_names = false;
enum UnpackedUint8 {
option (nanopb_enumopt).packed_enum = false;
UU8_MIN = 0;
UU8_MAX = 255;
}
enum PackedUint8 {
option (nanopb_enumopt).packed_enum = true;
PU8_MIN = 0;
PU8_MAX = 255;
}
enum UnpackedInt8 {
option (nanopb_enumopt).packed_enum = false;
UI8_MIN = -128;
UI8_MAX = 127;
}
enum PackedInt8 {
option (nanopb_enumopt).packed_enum = true;
PI8_MIN = -128;
PI8_MAX = 127;
}
enum UnpackedUint16 {
option (nanopb_enumopt).packed_enum = false;
UU16_MIN = 0;
UU16_MAX = 65535;
}
enum PackedUint16 {
option (nanopb_enumopt).packed_enum = true;
PU16_MIN = 0;
PU16_MAX = 65535;
}
enum UnpackedInt16 {
option (nanopb_enumopt).packed_enum = false;
UI16_MIN = -32768;
UI16_MAX = 32767;
}
enum PackedInt16 {
option (nanopb_enumopt).packed_enum = true;
PI16_MIN = -32768;
PI16_MAX = 32767;
}
/* Protobuf supports enums up to 32 bits.
* The 32 bit case is covered by HugeEnum in the alltypes test.
*/
message PackedEnums {
required PackedUint8 u8_min = 1;
required PackedUint8 u8_max = 2;
required PackedInt8 i8_min = 3;
required PackedInt8 i8_max = 4;
required PackedUint16 u16_min = 5;
required PackedUint16 u16_max = 6;
required PackedInt16 i16_min = 7;
required PackedInt16 i16_max = 8;
}
message UnpackedEnums {
required UnpackedUint8 u8_min = 1;
required UnpackedUint8 u8_max = 2;
required UnpackedInt8 i8_min = 3;
required UnpackedInt8 i8_max = 4;
required UnpackedUint16 u16_min = 5;
required UnpackedUint16 u16_max = 6;
required UnpackedInt16 i16_min = 7;
required UnpackedInt16 i16_max = 8;
}

View File

@@ -0,0 +1,72 @@
#include <stdio.h>
#include <string.h>
#include <pb_decode.h>
#include <pb_encode.h>
#include "unittests.h"
#include "enumsizes.pb.h"
int main()
{
int status = 0;
UnpackedEnums msg1 = {
UU8_MIN, UU8_MAX,
UI8_MIN, UI8_MAX,
UU16_MIN, UU16_MAX,
UI16_MIN, UI16_MAX,
};
PackedEnums msg2;
UnpackedEnums msg3;
uint8_t buf[256];
size_t msgsize;
COMMENT("Step 1: unpacked enums -> protobuf");
{
pb_ostream_t s = pb_ostream_from_buffer(buf, sizeof(buf));
TEST(pb_encode(&s, UnpackedEnums_fields, &msg1));
msgsize = s.bytes_written;
}
COMMENT("Step 2: protobuf -> packed enums");
{
pb_istream_t s = pb_istream_from_buffer(buf, msgsize);
TEST(pb_decode(&s, PackedEnums_fields, &msg2));
TEST(msg1.u8_min == (int)msg2.u8_min);
TEST(msg1.u8_max == (int)msg2.u8_max);
TEST(msg1.i8_min == (int)msg2.i8_min);
TEST(msg1.i8_max == (int)msg2.i8_max);
TEST(msg1.u16_min == (int)msg2.u16_min);
TEST(msg1.u16_max == (int)msg2.u16_max);
TEST(msg1.i16_min == (int)msg2.i16_min);
TEST(msg1.i16_max == (int)msg2.i16_max);
}
COMMENT("Step 3: packed enums -> protobuf");
{
pb_ostream_t s = pb_ostream_from_buffer(buf, sizeof(buf));
TEST(pb_encode(&s, PackedEnums_fields, &msg2));
msgsize = s.bytes_written;
}
COMMENT("Step 4: protobuf -> unpacked enums");
{
pb_istream_t s = pb_istream_from_buffer(buf, msgsize);
TEST(pb_decode(&s, UnpackedEnums_fields, &msg3));
TEST(msg1.u8_min == (int)msg3.u8_min);
TEST(msg1.u8_max == (int)msg3.u8_max);
TEST(msg1.i8_min == (int)msg3.i8_min);
TEST(msg1.i8_max == (int)msg3.i8_max);
TEST(msg1.u16_min == (int)msg2.u16_min);
TEST(msg1.u16_max == (int)msg2.u16_max);
TEST(msg1.i16_min == (int)msg2.i16_min);
TEST(msg1.i16_max == (int)msg2.i16_max);
}
if (status != 0)
fprintf(stdout, "\n\nSome tests FAILED!\n");
return status;
}

View File

@@ -0,0 +1,7 @@
# Test enum to string functionality
Import('env')
env.NanopbProto("enum.proto")
p = env.Program(["enum_to_string.c", "enum.pb.c"])
env.RunTest(p)

View File

@@ -0,0 +1,19 @@
/* Test enum to string function generation */
syntax = "proto2";
import "nanopb.proto";
option (nanopb_fileopt).enum_to_string = true;
enum MyEnum {
VALUE1 = 1;
VALUE2 = 2;
VALUE15 = 15;
}
enum MyShortNameEnum {
option (nanopb_enumopt).long_names = false;
MSNE_VALUE256 = 256;
}

View File

@@ -0,0 +1,19 @@
#include <stdio.h>
#include "unittests.h"
#include "enum.pb.h"
int main()
{
int status = 0;
TEST(strcmp(MyEnum_name(MyEnum_VALUE1), "VALUE1") == 0);
TEST(strcmp(MyEnum_name(MyEnum_VALUE2), "VALUE2") == 0);
TEST(strcmp(MyEnum_name(MyEnum_VALUE15), "VALUE15") == 0);
TEST(strcmp(MyShortNameEnum_name(MSNE_VALUE256), "MSNE_VALUE256") == 0);
TEST(strcmp(MyShortNameEnum_name(9999), "unknown") == 0);
if (status != 0)
fprintf(stdout, "\n\nSome tests FAILED!\n");
return status;
}

View File

@@ -0,0 +1,16 @@
# Test the support for extension fields.
Import("env")
# We use the files from the alltypes test case
incpath = env.Clone()
incpath.Append(PROTOCPATH = '$BUILD/alltypes')
incpath.Append(CPPPATH = '$BUILD/alltypes')
incpath.NanopbProto(["extensions", "extensions.options"])
enc = incpath.Program(["encode_extensions.c", "extensions.pb.c", "$BUILD/alltypes/alltypes.pb$OBJSUFFIX", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = incpath.Program(["decode_extensions.c", "extensions.pb.c", "$BUILD/alltypes/alltypes.pb$OBJSUFFIX", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
env.RunTest(enc)
env.RunTest([dec, "encode_extensions.output"])

View File

@@ -0,0 +1,57 @@
/* Test decoding of extension fields. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include "alltypes.pb.h"
#include "extensions.pb.h"
#include "test_helpers.h"
#include "unittests.h"
int main(int argc, char **argv)
{
uint8_t buffer[1024];
size_t count;
pb_istream_t stream;
int status = 0;
AllTypes alltypes = AllTypes_init_zero;
int32_t extensionfield1;
pb_extension_t ext1 = pb_extension_init_zero;
ExtensionMessage extensionfield2 = ExtensionMessage_init_zero;
pb_extension_t ext2 = pb_extension_init_zero;
/* Read the message data */
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
stream = pb_istream_from_buffer(buffer, count);
/* Add the extensions */
alltypes.extensions = &ext1;
ext1.type = &AllTypes_extensionfield1;
ext1.dest = &extensionfield1;
ext1.next = &ext2;
ext2.type = &ExtensionMessage_AllTypes_extensionfield2;
ext2.dest = &extensionfield2;
ext2.next = NULL;
/* Decode the message */
if (!pb_decode(&stream, AllTypes_fields, &alltypes))
{
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
/* Check that the extensions decoded properly */
TEST(ext1.found)
TEST(extensionfield1 == 12345)
TEST(ext2.found)
TEST(strcmp(extensionfield2.test1, "test") == 0)
TEST(extensionfield2.test2 == 54321)
return status;
}

View File

@@ -0,0 +1,54 @@
/* Tests extension fields.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_encode.h>
#include "alltypes.pb.h"
#include "extensions.pb.h"
#include "test_helpers.h"
int main(int argc, char **argv)
{
uint8_t buffer[1024];
pb_ostream_t stream;
AllTypes alltypes = {0};
int32_t extensionfield1 = 12345;
pb_extension_t ext1 = pb_extension_init_zero;
ExtensionMessage extensionfield2 = {"test", 54321};
pb_extension_t ext2 = pb_extension_init_zero;
/* Set up the extensions */
alltypes.extensions = &ext1;
ext1.type = &AllTypes_extensionfield1;
ext1.dest = &extensionfield1;
ext1.next = &ext2;
ext2.type = &ExtensionMessage_AllTypes_extensionfield2;
ext2.dest = &extensionfield2;
ext2.next = NULL;
/* Set up the output stream */
stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Now encode the message and check if we succeeded. */
if (pb_encode(&stream, AllTypes_fields, &alltypes))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1; /* Failure */
}
/* Check that the field tags are properly generated */
(void)AllTypes_extensionfield1_tag;
(void)ExtensionMessage_AllTypes_extensionfield2_tag;
}

View File

@@ -0,0 +1 @@
* max_size:16

View File

@@ -0,0 +1,19 @@
syntax = "proto2";
import 'alltypes.proto';
extend AllTypes {
optional int32 AllTypes_extensionfield1 = 255 [default = 5];
}
message ExtensionMessage {
extend AllTypes {
optional ExtensionMessage AllTypes_extensionfield2 = 254;
// required ExtensionMessage AllTypes_extensionfield3 = 253; // No longer allowed by protobuf 3
repeated ExtensionMessage AllTypes_extensionfield4 = 252;
}
required string test1 = 1;
required int32 test2 = 2;
}

View File

@@ -0,0 +1,16 @@
# Test that the decoder properly handles unknown fields in the input.
Import("env")
dec = env.GetBuildPath('$BUILD/basic_buffer/${PROGPREFIX}decode_buffer${PROGSUFFIX}')
env.RunTest('person_with_extra_field.output', [dec, "person_with_extra_field.pb"])
env.Compare(["person_with_extra_field.output", "person_with_extra_field.expected"])
dec = env.GetBuildPath('$BUILD/basic_stream/${PROGPREFIX}decode_stream${PROGSUFFIX}')
env.RunTest('person_with_extra_field_stream.output', [dec, "person_with_extra_field.pb"])
env.Compare(["person_with_extra_field_stream.output", "person_with_extra_field.expected"])
# This uses the backwards compatibility alltypes test, so that
# alltypes_with_extra_fields.pb doesn't have to be remade so often.
dec2 = env.GetBuildPath('$BUILD/backwards_compatibility/${PROGPREFIX}decode_legacy${PROGSUFFIX}')
env.RunTest('alltypes_with_extra_fields.output', [dec2, 'alltypes_with_extra_fields.pb'])

Some files were not shown because too many files have changed in this diff Show More