Fuzztest: include callback fields in test
diff --git a/tests/fuzztest/SConscript b/tests/fuzztest/SConscript
index 3280f75..91ecee0 100644
--- a/tests/fuzztest/SConscript
+++ b/tests/fuzztest/SConscript
@@ -18,8 +18,8 @@
 env.Command("alltypes_pointer.proto", "#alltypes/alltypes.proto",
             lambda target, source, env: set_pkgname(source[0], target[0], 'alltypes_pointer'))
 
-p1 = env.NanopbProto(["alltypes_pointer", "alltypes_pointer.options"])
-p2 = env.NanopbProto(["alltypes_static", "alltypes_static.options"])
+env.NanopbProto(["alltypes_pointer", "alltypes_pointer.options"])
+env.NanopbProto(["alltypes_static", "alltypes_static.options"])
 
 # Do the same for proto3 versions
 env.Command("alltypes_proto3_static.proto", "#alltypes_proto3/alltypes.proto",
@@ -27,8 +27,13 @@
 env.Command("alltypes_proto3_pointer.proto", "#alltypes_proto3/alltypes.proto",
             lambda target, source, env: set_pkgname(source[0], target[0], 'alltypes_proto3_pointer'))
 
-p1 = env.NanopbProto(["alltypes_proto3_pointer", "alltypes_proto3_pointer.options"])
-p2 = env.NanopbProto(["alltypes_proto3_static", "alltypes_proto3_static.options"])
+env.NanopbProto(["alltypes_proto3_pointer", "alltypes_proto3_pointer.options"])
+env.NanopbProto(["alltypes_proto3_static", "alltypes_proto3_static.options"])
+
+# And also a callback version
+env.Command("alltypes_callback.proto", "#alltypes/alltypes.proto",
+            lambda target, source, env: set_pkgname(source[0], target[0], 'alltypes_callback'))
+env.NanopbProto(["alltypes_callback", "alltypes_callback.options"])
 
 fuzz = malloc_env.Program(["fuzztest.c",
                     "random_data.c",
@@ -36,6 +41,7 @@
                     "flakystream.c",
                     "alltypes_pointer.pb.c",
                     "alltypes_static.pb.c",
+                    "alltypes_callback.pb.c",
                     "alltypes_proto3_pointer.pb.c",
                     "alltypes_proto3_static.pb.c",
                     "$COMMON/pb_encode_with_malloc.o",
diff --git a/tests/fuzztest/alltypes_proto3_pointer.options b/tests/fuzztest/alltypes_proto3_pointer.options
index ddd7934..e495787 100644
--- a/tests/fuzztest/alltypes_proto3_pointer.options
+++ b/tests/fuzztest/alltypes_proto3_pointer.options
@@ -1,5 +1,3 @@
 * type:FT_POINTER
 *.*fbytes fixed_length:true max_size:4
 *.req_limits proto3_singular_msgs:true
-*.*farray fixed_count:true max_count:5
-*.DescriptorSize8 descriptorsize:DS_8
diff --git a/tests/fuzztest/alltypes_proto3_static.options b/tests/fuzztest/alltypes_proto3_static.options
index 305837b..b90eb38 100644
--- a/tests/fuzztest/alltypes_proto3_static.options
+++ b/tests/fuzztest/alltypes_proto3_static.options
@@ -2,5 +2,3 @@
 * max_count:8
 *.*fbytes fixed_length:true max_size:4
 *.req_limits proto3_singular_msgs:true
-*.*farray fixed_count:true max_count:5
-*.DescriptorSize8 descriptorsize:DS_8
diff --git a/tests/fuzztest/fuzztest.c b/tests/fuzztest/fuzztest.c
index 1a4a7d2..2cbe05a 100644
--- a/tests/fuzztest/fuzztest.c
+++ b/tests/fuzztest/fuzztest.c
@@ -20,6 +20,7 @@
 #include "test_helpers.h"
 #include "alltypes_static.pb.h"
 #include "alltypes_pointer.pb.h"
+#include "alltypes_callback.pb.h"
 #include "alltypes_proto3_static.pb.h"
 #include "alltypes_proto3_pointer.pb.h"
 
@@ -90,6 +91,50 @@
     return status;
 }
 
+static int g_sentinel;
+
+static bool field_callback(pb_istream_t *stream, const pb_field_t *field, void **arg)
+{
+    assert(*arg == &g_sentinel);
+    return pb_read(stream, NULL, stream->bytes_left);
+}
+
+static bool do_callback_decode(const uint8_t *buffer, size_t msglen, bool assert_success)
+{
+    bool status;
+    pb_istream_t stream;
+    size_t initial_alloc_count = get_alloc_count();
+    alltypes_callback_AllTypes *msg = malloc_with_check(sizeof(alltypes_callback_AllTypes));
+
+    memset(msg, 0, sizeof(alltypes_callback_AllTypes));
+    stream = pb_istream_from_buffer(buffer, msglen);
+
+    msg->rep_int32.funcs.decode = &field_callback;
+    msg->rep_int32.arg = &g_sentinel;
+    msg->rep_string.funcs.decode = &field_callback;
+    msg->rep_string.arg = &g_sentinel;
+    msg->rep_farray.funcs.decode = &field_callback;
+    msg->rep_farray.arg = &g_sentinel;
+    msg->req_limits.int64_min.funcs.decode = &field_callback;
+    msg->req_limits.int64_min.arg = &g_sentinel;
+    msg->cb_oneof.funcs.decode = &field_callback;
+    msg->cb_oneof.arg = &g_sentinel;
+
+    status = pb_decode(&stream, alltypes_callback_AllTypes_fields, msg);
+
+    if (assert_success)
+    {
+        if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream));
+        assert(status);
+    }
+
+    pb_release(alltypes_callback_AllTypes_fields, msg);
+    free_with_check(msg);
+    assert(get_alloc_count() == initial_alloc_count);
+
+    return status;
+}
+
 /* Do a decode -> encode -> decode -> encode roundtrip */
 static void do_roundtrip(const uint8_t *buffer, size_t msglen, size_t structsize, const pb_msgdesc_t *msgtype)
 {
@@ -183,6 +228,9 @@
         /* Test successful decoding also when using a stream */
         do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, true);
         do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, true);
+
+        /* Test callbacks */
+        do_callback_decode(data, size, true);
     }
     else if (do_decode(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, expect_valid))
     {
@@ -215,6 +263,9 @@
     do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_DELIMITED, false);
     do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NULLTERMINATED, false);
 
+    /* Test callbacks also when message is not valid */
+    do_callback_decode(data, size, false);
+
     assert(get_alloc_count() == initial_alloc_count);
 }