Tests for callback fields
authorPetteri Aimonen <jpa@npb.mail.kapsi.fi>
Mon, 12 Sep 2011 18:53:33 +0000 (18:53 +0000)
committerPetteri Aimonen <jpa@npb.mail.kapsi.fi>
Mon, 12 Sep 2011 18:53:33 +0000 (18:53 +0000)
git-svn-id: https://svn.kapsi.fi/jpa/nanopb@974 e3a754e5-d11d-0410-8d38-ebb782a927b9

docs/concepts.rst
tests/Makefile
tests/callbacks.proto [new file with mode: 0644]
tests/test_decode1.c
tests/test_decode_callbacks.c [new file with mode: 0644]
tests/test_encode1.c
tests/test_encode_callbacks.c [new file with mode: 0644]

index e607640..c4e5476 100644 (file)
@@ -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.
 
index 807da64..30bce64 100644 (file)
@@ -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 (file)
index 0000000..7bc7900
--- /dev/null
@@ -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;
+}
+
index b46d0d5..d0cc427 100644 (file)
@@ -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 (file)
index 0000000..1c8d43a
--- /dev/null
@@ -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
index 412a271..df1ec4f 100644 (file)
@@ -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 (file)
index 0000000..da2ee28
--- /dev/null
@@ -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;
+}