diff options
-rw-r--r-- | docs/concepts.rst | 2 | ||||
-rw-r--r-- | tests/Makefile | 9 | ||||
-rw-r--r-- | tests/callbacks.proto | 16 | ||||
-rw-r--r-- | tests/test_decode1.c | 4 | ||||
-rw-r--r-- | tests/test_decode_callbacks.c | 44 | ||||
-rw-r--r-- | tests/test_encode1.c | 4 | ||||
-rw-r--r-- | tests/test_encode_callbacks.c | 33 |
7 files changed, 109 insertions, 3 deletions
diff --git a/docs/concepts.rst b/docs/concepts.rst index e607640..c4e5476 100644 --- a/docs/concepts.rst +++ b/docs/concepts.rst @@ -201,7 +201,7 @@ Decoding callbacks bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); -When decoding, the callback receives a length-limited substring that reads the contents of a single field. The field tag has already been read. +When decoding, the callback receives a length-limited substring that reads the contents of a single field. The field tag has already been read. For *string* and *bytes*, the length value has already been parsed, and is available at *stream->bytes_left*. The callback will be called multiple times for repeated fields. For packed fields, you can either read multiple values until the stream ends, or leave it to `pb_decode`_ to call your function over and over until all values have been read. diff --git a/tests/Makefile b/tests/Makefile index 807da64..30bce64 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ CFLAGS=-ansi -Wall -Werror -I .. -g -O0 --coverage LDFLAGS=--coverage -DEPS=../pb_decode.h ../pb_encode.h ../pb.h person.pb.h unittests.h unittestproto.pb.h +DEPS=../pb_decode.h ../pb_encode.h ../pb.h person.pb.h callbacks.pb.h unittests.h unittestproto.pb.h TESTS=test_decode1 test_encode1 decode_unittests encode_unittests all: $(TESTS) run_unittests breakpoints @@ -19,6 +19,8 @@ pb_decode.o: ../pb_decode.c $(DEPS) test_decode1: test_decode1.o pb_decode.o person.pb.o test_encode1: test_encode1.o pb_encode.o person.pb.o +test_decode_callbacks: test_decode_callbacks.o pb_decode.o callbacks.pb.o +test_encode_callbacks: test_encode_callbacks.o pb_encode.o callbacks.pb.o decode_unittests: decode_unittests.o pb_decode.o unittestproto.pb.o encode_unittests: encode_unittests.o pb_encode.o unittestproto.pb.o @@ -35,7 +37,7 @@ coverage: run_unittests gcov pb_encode.gcda gcov pb_decode.gcda -run_unittests: decode_unittests encode_unittests test_encode1 test_decode1 +run_unittests: decode_unittests encode_unittests test_encode1 test_decode1 test_encode_callbacks test_decode_callbacks rm -f *.gcda ./decode_unittests > /dev/null @@ -43,6 +45,9 @@ run_unittests: decode_unittests encode_unittests test_encode1 test_decode1 [ "`./test_encode1 | ./test_decode1`" = \ "`./test_encode1 | protoc --decode=Person -I. -I../generator -I/usr/include person.proto`" ] + + [ "`./test_encode_callbacks | ./test_decode_callbacks`" = \ + "`./test_encode_callbacks | protoc --decode=TestMessage callbacks.proto`" ] run_fuzztest: test_decode1 bash -c 'I=1; while cat /dev/urandom | ./test_decode1 > /dev/null; do I=$$(($$I+1)); echo -en "\r$$I"; done' diff --git a/tests/callbacks.proto b/tests/callbacks.proto new file mode 100644 index 0000000..7bc7900 --- /dev/null +++ b/tests/callbacks.proto @@ -0,0 +1,16 @@ +/* Todo: write tests for the rest of these fields, currently only stringvalue + * is tested. + */ + +message SubMessage { + optional int32 int32value = 1; +} + +message TestMessage { + optional string stringvalue = 1; + optional int32 int32value = 2; + optional fixed32 fixed32value = 3; + optional fixed64 fixed64value = 4; + optional SubMessage submsg = 5; +} + diff --git a/tests/test_decode1.c b/tests/test_decode1.c index b46d0d5..d0cc427 100644 --- a/tests/test_decode1.c +++ b/tests/test_decode1.c @@ -1,3 +1,7 @@ +/* A very simple decoding test case, using person.proto. + * Produces output compatible with protoc --decode. + */ + #include <stdio.h> #include <pb_decode.h> #include "person.pb.h" diff --git a/tests/test_decode_callbacks.c b/tests/test_decode_callbacks.c new file mode 100644 index 0000000..1c8d43a --- /dev/null +++ b/tests/test_decode_callbacks.c @@ -0,0 +1,44 @@ +/* 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" + +bool print_string(pb_istream_t *stream, const pb_field_t *field, void *arg) +{ + uint8_t buffer[1024]; + + /* We could read block-by-block to avoid the large buffer... */ + if (stream->bytes_left > sizeof(buffer)) + return false; + + if (!pb_read(stream, buffer, stream->bytes_left)) + return false; + + /* Print the string, in format comparable with protoc --decode. */ + printf("%s: \"%s\"\n", (char*)arg, buffer); + return true; +} + +int main() +{ + uint8_t buffer[1024]; + size_t length = fread(buffer, 1, 1024, stdin); + pb_istream_t stream = pb_istream_from_buffer(buffer, length); + + /* 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 = {}; + + testmessage.stringvalue.funcs.decode = &print_string; + testmessage.stringvalue.arg = "stringvalue"; + + if (!pb_decode(&stream, TestMessage_fields, &testmessage)) + return 1; + + return 0; +}
\ No newline at end of file diff --git a/tests/test_encode1.c b/tests/test_encode1.c index 412a271..df1ec4f 100644 --- a/tests/test_encode1.c +++ b/tests/test_encode1.c @@ -1,3 +1,7 @@ +/* A very simple encoding test case using person.proto. + * Just puts constant data in the fields. + */ + #include <stdio.h> #include <pb_encode.h> #include "person.pb.h" diff --git a/tests/test_encode_callbacks.c b/tests/test_encode_callbacks.c new file mode 100644 index 0000000..da2ee28 --- /dev/null +++ b/tests/test_encode_callbacks.c @@ -0,0 +1,33 @@ +/* Encoding testcase for callback fields */ + +#include <stdio.h> +#include <string.h> +#include <pb_encode.h> +#include "callbacks.pb.h" + +bool encode_string(pb_ostream_t *stream, const pb_field_t *field, const void *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)); +} + +int main() +{ + uint8_t buffer[1024]; + pb_ostream_t stream = pb_ostream_from_buffer(buffer, 1024); + TestMessage testmessage = {}; + + testmessage.stringvalue.funcs.encode = &encode_string; + + if (!pb_encode(&stream, TestMessage_fields, &testmessage)) + return 1; + + if (fwrite(buffer, stream.bytes_written, 1, stdout) != 1) + return 2; + + return 0; +} |