diff options
-rwxr-xr-x | generator/nanopb_generator.py | 16 | ||||
-rw-r--r-- | pb.h | 4 | ||||
-rw-r--r-- | tests/anonymous_oneof/SConscript | 29 | ||||
-rw-r--r-- | tests/anonymous_oneof/decode_oneof.c | 88 | ||||
-rw-r--r-- | tests/anonymous_oneof/oneof.proto | 23 |
5 files changed, 153 insertions, 7 deletions
diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py index a21257b5..13217462 100755 --- a/generator/nanopb_generator.py +++ b/generator/nanopb_generator.py @@ -492,6 +492,9 @@ class Field: return result + def get_last_field_name(self): + return self.name + def largest_field_value(self): '''Determine if this field needs 16bit or 32bit pb_field_t structure to compile properly. Returns numeric value or a C-expression for assert.''' @@ -704,12 +707,18 @@ class OneOf(Field): return None def tags(self): - return '\n'.join([f.tags() for f in self.fields]) + return ''.join([f.tags() for f in self.fields]) def pb_field_t(self, prev_field_name): result = ',\n'.join([f.pb_field_t(prev_field_name) for f in self.fields]) return result + def get_last_field_name(self): + if self.anonymous: + return self.fields[-1].name + else: + return self.name + '.' + self.fields[-1].name + def largest_field_value(self): largest = FieldMaxSize() for f in self.fields: @@ -860,10 +869,7 @@ class Message: for field in self.ordered_fields: result += field.pb_field_t(prev) result += ',\n' - if isinstance(field, OneOf): - prev = field.name + '.' + field.fields[-1].name - else: - prev = field.name + prev = field.get_last_field_name() result += ' PB_LAST_FIELD\n};' return result @@ -518,7 +518,7 @@ struct pb_extension_s { pb_membersize(st, u.m[0]), 0, ptr} #define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ - PB_ ## ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_ONEOF_ ## allocation(union_name, tag, message, field, \ PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \ PB_LTYPE_MAP_ ## type, ptr) @@ -533,7 +533,7 @@ struct pb_extension_s { pb_membersize(st, m[0]), 0, ptr} #define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ - PB_ ## ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \ PB_DATAOFFSET_ ## placement(message, field, prevfield), \ PB_LTYPE_MAP_ ## type, ptr) diff --git a/tests/anonymous_oneof/SConscript b/tests/anonymous_oneof/SConscript new file mode 100644 index 00000000..8f634bd7 --- /dev/null +++ b/tests/anonymous_oneof/SConscript @@ -0,0 +1,29 @@ +# Test anonymous_oneof generator option + +Import('env') + +import re + +match = None +if 'PROTOC_VERSION' in env: + match = re.search('([0-9]+).([0-9]+).([0-9]+)', env['PROTOC_VERSION']) + +if match: + version = map(int, match.groups()) + +# Oneof is supported by protoc >= 2.6.0 +if env.GetOption('clean') or (match and (version[0] > 2 or (version[0] == 2 and version[1] >= 6))): + # Anonymous oneofs are supported by clang and gcc + if 'clang' in env['CC'] or 'gcc' in env['CC']: + env2 = env.Clone() + env2.Append(CFLAGS = "-Wno-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']) diff --git a/tests/anonymous_oneof/decode_oneof.c b/tests/anonymous_oneof/decode_oneof.c new file mode 100644 index 00000000..0f774dbc --- /dev/null +++ b/tests/anonymous_oneof/decode_oneof.c @@ -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; +} diff --git a/tests/anonymous_oneof/oneof.proto b/tests/anonymous_oneof/oneof.proto new file mode 100644 index 00000000..d56285c0 --- /dev/null +++ b/tests/anonymous_oneof/oneof.proto @@ -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; +} + |