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);
 
 
     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.
 
 
 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
 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
 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_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
 
 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
 
        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
        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_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'
 
 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"
 #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"
 #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;
+}