Line data Source code
1 : /* Attempts to test all the datatypes supported by ProtoBuf when used as callback fields.
2 : * Note that normally there would be no reason to use callback fields for this,
3 : * because each encoder defined here only gives a single field.
4 : */
5 :
6 : #include <stdio.h>
7 : #include <string.h>
8 : #include <stdlib.h>
9 : #include <pb_decode.h>
10 : #include "alltypes.pb.h"
11 : #include "test_helpers.h"
12 :
13 : #define TEST(x) if (!(x)) { \
14 : printf("Test %s failed (in field %d).\n", #x, field->tag); \
15 : return false; \
16 : }
17 :
18 28 : static bool read_varint(pb_istream_t *stream, const pb_field_t *field, void **arg)
19 : {
20 : uint64_t value;
21 28 : if (!pb_decode_varint(stream, &value))
22 0 : return false;
23 :
24 28 : TEST((int64_t)value == (intptr_t)*arg);
25 28 : return true;
26 : }
27 :
28 8 : static bool read_svarint(pb_istream_t *stream, const pb_field_t *field, void **arg)
29 : {
30 : int64_t value;
31 8 : if (!pb_decode_svarint(stream, &value))
32 0 : return false;
33 :
34 8 : TEST(value == (intptr_t)*arg);
35 8 : return true;
36 : }
37 :
38 12 : static bool read_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg)
39 : {
40 : uint32_t value;
41 12 : if (!pb_decode_fixed32(stream, &value))
42 0 : return false;
43 :
44 12 : TEST(value == *(uint32_t*)*arg);
45 12 : return true;
46 : }
47 :
48 8 : static bool read_fixed64(pb_istream_t *stream, const pb_field_t *field, void **arg)
49 : {
50 : uint64_t value;
51 8 : if (!pb_decode_fixed64(stream, &value))
52 0 : return false;
53 :
54 8 : TEST(value == *(uint64_t*)*arg);
55 8 : return true;
56 : }
57 :
58 4 : static bool read_double(pb_istream_t *stream, const pb_field_t *field, void **arg)
59 : {
60 : #ifdef PB_CONVERT_DOUBLE_FLOAT
61 : if (sizeof(double) == sizeof(float))
62 : {
63 : float value;
64 : if (!pb_decode_double_as_float(stream, &value))
65 : return false;
66 :
67 : TEST(memcmp(&value, *arg, sizeof(float)) == 0);
68 : return true;
69 : }
70 : #endif
71 :
72 : uint64_t value;
73 4 : if (!pb_decode_fixed64(stream, &value))
74 0 : return false;
75 :
76 4 : TEST(value == *(uint64_t*)*arg);
77 4 : return true;
78 : }
79 :
80 8 : static bool read_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
81 : {
82 8 : uint8_t buf[16] = {0};
83 8 : size_t len = stream->bytes_left;
84 :
85 8 : if (len > sizeof(buf) - 1 || !pb_read(stream, buf, len))
86 0 : return false;
87 :
88 8 : TEST(strcmp((char*)buf, *arg) == 0);
89 8 : return true;
90 : }
91 :
92 5 : static bool read_submsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
93 : {
94 5 : SubMessage submsg = {""};
95 5 : SubMessage *ref = *arg;
96 :
97 5 : if (!pb_decode(stream, SubMessage_fields, &submsg))
98 0 : return false;
99 :
100 5 : TEST(strcmp(submsg.substuff1, ref->substuff1) == 0);
101 5 : TEST(submsg.substuff2 == ref->substuff2);
102 5 : TEST(submsg.has_substuff3 == ref->has_substuff3);
103 5 : TEST(submsg.substuff3 == ref->substuff3);
104 5 : return true;
105 : }
106 :
107 19 : static bool read_emptymsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
108 : {
109 19 : EmptyMessage emptymsg = {0};
110 19 : return pb_decode(stream, EmptyMessage_fields, &emptymsg);
111 : }
112 :
113 90 : static bool read_repeated_varint(pb_istream_t *stream, const pb_field_t *field, void **arg)
114 : {
115 90 : int32_t** expected = (int32_t**)arg;
116 : uint64_t value;
117 90 : if (!pb_decode_varint(stream, &value))
118 0 : return false;
119 :
120 90 : TEST(*(*expected)++ == value);
121 90 : return true;
122 : }
123 :
124 30 : static bool read_repeated_svarint(pb_istream_t *stream, const pb_field_t *field, void **arg)
125 : {
126 30 : int32_t** expected = (int32_t**)arg;
127 : int64_t value;
128 30 : if (!pb_decode_svarint(stream, &value))
129 0 : return false;
130 :
131 30 : TEST(*(*expected)++ == value);
132 30 : return true;
133 : }
134 :
135 45 : static bool read_repeated_fixed32(pb_istream_t *stream, const pb_field_t *field, void **arg)
136 : {
137 45 : uint32_t** expected = (uint32_t**)arg;
138 : uint32_t value;
139 45 : if (!pb_decode_fixed32(stream, &value))
140 0 : return false;
141 :
142 45 : TEST(*(*expected)++ == value);
143 45 : return true;
144 : }
145 :
146 30 : static bool read_repeated_fixed64(pb_istream_t *stream, const pb_field_t *field, void **arg)
147 : {
148 30 : uint64_t** expected = (uint64_t**)arg;
149 : uint64_t value;
150 30 : if (!pb_decode_fixed64(stream, &value))
151 0 : return false;
152 :
153 30 : TEST(*(*expected)++ == value);
154 30 : return true;
155 : }
156 :
157 15 : static bool read_repeated_double(pb_istream_t *stream, const pb_field_t *field, void **arg)
158 : {
159 : #ifdef PB_CONVERT_DOUBLE_FLOAT
160 : if (sizeof(double) == sizeof(float))
161 : {
162 : float** expectedf = (float**)arg;
163 : float value;
164 : if (!pb_decode_double_as_float(stream, &value))
165 : return false;
166 :
167 : TEST(memcmp(&value, (*expectedf)++, sizeof(float)) == 0);
168 : return true;
169 : }
170 : #endif
171 :
172 15 : uint64_t** expected = (uint64_t**)arg;
173 : uint64_t value;
174 15 : if (!pb_decode_fixed64(stream, &value))
175 0 : return false;
176 :
177 15 : TEST(*(*expected)++ == value);
178 15 : return true;
179 : }
180 :
181 30 : static bool read_repeated_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
182 : {
183 30 : uint8_t*** expected = (uint8_t***)arg;
184 30 : uint8_t buf[16] = {0};
185 30 : size_t len = stream->bytes_left;
186 :
187 30 : if (len > sizeof(buf) - 1 || !pb_read(stream, buf, len))
188 0 : return false;
189 :
190 30 : TEST(strcmp((char*)*(*expected)++, (char*)buf) == 0);
191 30 : return true;
192 : }
193 :
194 15 : static bool read_repeated_submsg(pb_istream_t *stream, const pb_field_t *field, void **arg)
195 : {
196 15 : SubMessage** expected = (SubMessage**)arg;
197 15 : SubMessage submsg = {""};
198 15 : if (!pb_decode(stream, SubMessage_fields, &submsg))
199 0 : return false;
200 :
201 15 : TEST(strcmp(submsg.substuff1, (*expected)->substuff1) == 0);
202 15 : TEST(submsg.substuff2 == (*expected)->substuff2);
203 15 : TEST(submsg.has_substuff3 == (*expected)->has_substuff3);
204 15 : TEST(submsg.substuff3 == (*expected)->substuff3);
205 15 : (*expected)++;
206 :
207 15 : return true;
208 : }
209 :
210 3 : static bool read_limits(pb_istream_t *stream, const pb_field_t *field, void **arg)
211 : {
212 3 : Limits decoded = {0};
213 3 : if (!pb_decode(stream, Limits_fields, &decoded))
214 0 : return false;
215 :
216 3 : TEST(decoded.int32_min == INT32_MIN);
217 3 : TEST(decoded.int32_max == INT32_MAX);
218 3 : TEST(decoded.uint32_min == 0);
219 3 : TEST(decoded.uint32_max == UINT32_MAX);
220 3 : TEST(decoded.int64_min == INT64_MIN);
221 3 : TEST(decoded.int64_max == INT64_MAX);
222 3 : TEST(decoded.uint64_min == 0);
223 3 : TEST(decoded.uint64_max == UINT64_MAX);
224 3 : TEST(decoded.enum_min == HugeEnum_Negative);
225 3 : TEST(decoded.enum_max == HugeEnum_Positive);
226 3 : TEST(decoded.largetag == 1001);
227 :
228 3 : return true;
229 : }
230 :
231 : /* This function is called once from main(), it handles
232 : the decoding and checks the fields. */
233 3 : bool check_alltypes(pb_istream_t *stream, int mode)
234 : {
235 : /* Values for use from callbacks through pointers. */
236 : bool status;
237 3 : uint32_t req_fixed32 = 1008;
238 3 : int32_t req_sfixed32 = -1009;
239 3 : float req_float = 1010.0f;
240 3 : uint64_t req_fixed64 = 1011;
241 3 : int64_t req_sfixed64 = -1012;
242 3 : double req_double = 1013.0;
243 3 : SubMessage req_submsg = {"1016", 1016, false, 3};
244 :
245 3 : int32_t rep_int32[5] = {0, 0, 0, 0, -2001};
246 3 : int32_t rep_int64[5] = {0, 0, 0, 0, -2002};
247 3 : int32_t rep_uint32[5] = {0, 0, 0, 0, 2003};
248 3 : int32_t rep_uint64[5] = {0, 0, 0, 0, 2004};
249 3 : int32_t rep_sint32[5] = {0, 0, 0, 0, -2005};
250 3 : int32_t rep_sint64[5] = {0, 0, 0, 0, -2006};
251 3 : int32_t rep_bool[5] = {false, false, false, false, true};
252 3 : uint32_t rep_fixed32[5] = {0, 0, 0, 0, 2008};
253 3 : int32_t rep_sfixed32[5] = {0, 0, 0, 0, -2009};
254 3 : float rep_float[5] = {0, 0, 0, 0, 2010.0f};
255 3 : uint64_t rep_fixed64[5] = {0, 0, 0, 0, 2011};
256 3 : int64_t rep_sfixed64[5] = {0, 0, 0, 0, -2012};
257 3 : double rep_double[5] = {0, 0, 0, 0, 2013.0};
258 3 : char* rep_string[5] = {"", "", "", "", "2014"};
259 3 : char* rep_bytes[5] = {"", "", "", "", "2015"};
260 3 : SubMessage rep_submsg[5] = {{"", 0, 0, 3},
261 : {"", 0, 0, 3},
262 : {"", 0, 0, 3},
263 : {"", 0, 0, 3},
264 : {"2016", 2016, true, 2016}};
265 3 : int32_t rep_enum[5] = {0, 0, 0, 0, MyEnum_Truth};
266 :
267 3 : uint32_t opt_fixed32 = 3048;
268 3 : int32_t opt_sfixed32 = 3049;
269 3 : float opt_float = 3050.0f;
270 3 : uint64_t opt_fixed64 = 3051;
271 3 : int64_t opt_sfixed64 = 3052;
272 3 : double opt_double = 3053.0f;
273 3 : SubMessage opt_submsg = {"3056", 3056, false, 3};
274 :
275 3 : SubMessage oneof_msg1 = {"4059", 4059, false, 3};
276 :
277 : /* Bind callbacks for required fields */
278 3 : AllTypes alltypes = AllTypes_init_zero;
279 :
280 3 : alltypes.req_int32.funcs.decode = &read_varint;
281 3 : alltypes.req_int32.arg = (void*)-1001;
282 :
283 3 : alltypes.req_int64.funcs.decode = &read_varint;
284 3 : alltypes.req_int64.arg = (void*)-1002;
285 :
286 3 : alltypes.req_uint32.funcs.decode = &read_varint;
287 3 : alltypes.req_uint32.arg = (void*)1003;
288 :
289 3 : alltypes.req_uint32.funcs.decode = &read_varint;
290 3 : alltypes.req_uint32.arg = (void*)1003;
291 :
292 3 : alltypes.req_uint64.funcs.decode = &read_varint;
293 3 : alltypes.req_uint64.arg = (void*)1004;
294 :
295 3 : alltypes.req_sint32.funcs.decode = &read_svarint;
296 3 : alltypes.req_sint32.arg = (void*)-1005;
297 :
298 3 : alltypes.req_sint64.funcs.decode = &read_svarint;
299 3 : alltypes.req_sint64.arg = (void*)-1006;
300 :
301 3 : alltypes.req_bool.funcs.decode = &read_varint;
302 3 : alltypes.req_bool.arg = (void*)true;
303 :
304 3 : alltypes.req_fixed32.funcs.decode = &read_fixed32;
305 3 : alltypes.req_fixed32.arg = &req_fixed32;
306 :
307 3 : alltypes.req_sfixed32.funcs.decode = &read_fixed32;
308 3 : alltypes.req_sfixed32.arg = &req_sfixed32;
309 :
310 3 : alltypes.req_float.funcs.decode = &read_fixed32;
311 3 : alltypes.req_float.arg = &req_float;
312 :
313 3 : alltypes.req_fixed64.funcs.decode = &read_fixed64;
314 3 : alltypes.req_fixed64.arg = &req_fixed64;
315 :
316 3 : alltypes.req_sfixed64.funcs.decode = &read_fixed64;
317 3 : alltypes.req_sfixed64.arg = &req_sfixed64;
318 :
319 3 : alltypes.req_double.funcs.decode = &read_double;
320 3 : alltypes.req_double.arg = &req_double;
321 :
322 3 : alltypes.req_string.funcs.decode = &read_string;
323 3 : alltypes.req_string.arg = "1014";
324 :
325 3 : alltypes.req_bytes.funcs.decode = &read_string;
326 3 : alltypes.req_bytes.arg = "1015";
327 :
328 3 : alltypes.req_submsg.funcs.decode = &read_submsg;
329 3 : alltypes.req_submsg.arg = &req_submsg;
330 :
331 3 : alltypes.req_enum.funcs.decode = &read_varint;
332 3 : alltypes.req_enum.arg = (void*)MyEnum_Truth;
333 :
334 3 : alltypes.req_emptymsg.funcs.decode = &read_emptymsg;
335 :
336 : /* Bind callbacks for repeated fields */
337 3 : alltypes.rep_int32.funcs.decode = &read_repeated_varint;
338 3 : alltypes.rep_int32.arg = rep_int32;
339 :
340 3 : alltypes.rep_int64.funcs.decode = &read_repeated_varint;
341 3 : alltypes.rep_int64.arg = rep_int64;
342 :
343 3 : alltypes.rep_uint32.funcs.decode = &read_repeated_varint;
344 3 : alltypes.rep_uint32.arg = rep_uint32;
345 :
346 3 : alltypes.rep_uint64.funcs.decode = &read_repeated_varint;
347 3 : alltypes.rep_uint64.arg = rep_uint64;
348 :
349 3 : alltypes.rep_sint32.funcs.decode = &read_repeated_svarint;
350 3 : alltypes.rep_sint32.arg = rep_sint32;
351 :
352 3 : alltypes.rep_sint64.funcs.decode = &read_repeated_svarint;
353 3 : alltypes.rep_sint64.arg = rep_sint64;
354 :
355 3 : alltypes.rep_bool.funcs.decode = &read_repeated_varint;
356 3 : alltypes.rep_bool.arg = rep_bool;
357 :
358 3 : alltypes.rep_fixed32.funcs.decode = &read_repeated_fixed32;
359 3 : alltypes.rep_fixed32.arg = rep_fixed32;
360 :
361 3 : alltypes.rep_sfixed32.funcs.decode = &read_repeated_fixed32;
362 3 : alltypes.rep_sfixed32.arg = rep_sfixed32;
363 :
364 3 : alltypes.rep_float.funcs.decode = &read_repeated_fixed32;
365 3 : alltypes.rep_float.arg = rep_float;
366 :
367 3 : alltypes.rep_fixed64.funcs.decode = &read_repeated_fixed64;
368 3 : alltypes.rep_fixed64.arg = rep_fixed64;
369 :
370 3 : alltypes.rep_sfixed64.funcs.decode = &read_repeated_fixed64;
371 3 : alltypes.rep_sfixed64.arg = rep_sfixed64;
372 :
373 3 : alltypes.rep_double.funcs.decode = &read_repeated_double;
374 3 : alltypes.rep_double.arg = rep_double;
375 :
376 3 : alltypes.rep_string.funcs.decode = &read_repeated_string;
377 3 : alltypes.rep_string.arg = rep_string;
378 :
379 3 : alltypes.rep_bytes.funcs.decode = &read_repeated_string;
380 3 : alltypes.rep_bytes.arg = rep_bytes;
381 :
382 3 : alltypes.rep_submsg.funcs.decode = &read_repeated_submsg;
383 3 : alltypes.rep_submsg.arg = rep_submsg;
384 :
385 3 : alltypes.rep_enum.funcs.decode = &read_repeated_varint;
386 3 : alltypes.rep_enum.arg = rep_enum;
387 :
388 3 : alltypes.rep_emptymsg.funcs.decode = &read_emptymsg;
389 :
390 3 : alltypes.req_limits.funcs.decode = &read_limits;
391 :
392 3 : alltypes.end.funcs.decode = &read_varint;
393 3 : alltypes.end.arg = (void*)1099;
394 :
395 : /* Bind callbacks for optional fields */
396 3 : if (mode == 1)
397 : {
398 1 : alltypes.opt_int32.funcs.decode = &read_varint;
399 1 : alltypes.opt_int32.arg = (void*)3041;
400 :
401 1 : alltypes.opt_int64.funcs.decode = &read_varint;
402 1 : alltypes.opt_int64.arg = (void*)3042;
403 :
404 1 : alltypes.opt_uint32.funcs.decode = &read_varint;
405 1 : alltypes.opt_uint32.arg = (void*)3043;
406 :
407 1 : alltypes.opt_uint64.funcs.decode = &read_varint;
408 1 : alltypes.opt_uint64.arg = (void*)3044;
409 :
410 1 : alltypes.opt_sint32.funcs.decode = &read_svarint;
411 1 : alltypes.opt_sint32.arg = (void*)3045;
412 :
413 1 : alltypes.opt_sint64.funcs.decode = &read_svarint;
414 1 : alltypes.opt_sint64.arg = (void*)3046;
415 :
416 1 : alltypes.opt_bool.funcs.decode = &read_varint;
417 1 : alltypes.opt_bool.arg = (void*)true;
418 :
419 1 : alltypes.opt_fixed32.funcs.decode = &read_fixed32;
420 1 : alltypes.opt_fixed32.arg = &opt_fixed32;
421 :
422 1 : alltypes.opt_sfixed32.funcs.decode = &read_fixed32;
423 1 : alltypes.opt_sfixed32.arg = &opt_sfixed32;
424 :
425 1 : alltypes.opt_float.funcs.decode = &read_fixed32;
426 1 : alltypes.opt_float.arg = &opt_float;
427 :
428 1 : alltypes.opt_fixed64.funcs.decode = &read_fixed64;
429 1 : alltypes.opt_fixed64.arg = &opt_fixed64;
430 :
431 1 : alltypes.opt_sfixed64.funcs.decode = &read_fixed64;
432 1 : alltypes.opt_sfixed64.arg = &opt_sfixed64;
433 :
434 1 : alltypes.opt_double.funcs.decode = &read_double;
435 1 : alltypes.opt_double.arg = &opt_double;
436 :
437 1 : alltypes.opt_string.funcs.decode = &read_string;
438 1 : alltypes.opt_string.arg = "3054";
439 :
440 1 : alltypes.opt_bytes.funcs.decode = &read_string;
441 1 : alltypes.opt_bytes.arg = "3055";
442 :
443 1 : alltypes.opt_submsg.funcs.decode = &read_submsg;
444 1 : alltypes.opt_submsg.arg = &opt_submsg;
445 :
446 1 : alltypes.opt_enum.funcs.decode = &read_varint;
447 1 : alltypes.opt_enum.arg = (void*)MyEnum_Truth;
448 :
449 1 : alltypes.opt_emptymsg.funcs.decode = &read_emptymsg;
450 :
451 1 : alltypes.oneof_msg1.funcs.decode = &read_submsg;
452 1 : alltypes.oneof_msg1.arg = &oneof_msg1;
453 :
454 1 : alltypes.opt_non_zero_based_enum.funcs.decode = &read_varint;
455 1 : alltypes.opt_non_zero_based_enum.arg = (void *)NonZeroBasedEnum_Three;
456 : }
457 :
458 3 : status = pb_decode(stream, AllTypes_fields, &alltypes);
459 :
460 : #ifdef PB_ENABLE_MALLOC
461 : /* Just to check for any interference between pb_release() and callback fields */
462 1 : pb_release(AllTypes_fields, &alltypes);
463 : #endif
464 :
465 3 : return status;
466 : }
467 :
468 3 : int main(int argc, char **argv)
469 : {
470 : uint8_t buffer[1024];
471 : size_t count;
472 : pb_istream_t stream;
473 :
474 : /* Whether to expect the optional values or the default values. */
475 3 : int mode = (argc > 1) ? atoi(argv[1]) : 0;
476 :
477 : /* Read the data into buffer */
478 : SET_BINARY_MODE(stdin);
479 3 : count = fread(buffer, 1, sizeof(buffer), stdin);
480 :
481 : /* Construct a pb_istream_t for reading from the buffer */
482 3 : stream = pb_istream_from_buffer(buffer, count);
483 :
484 : /* Decode and print out the stuff */
485 3 : if (!check_alltypes(&stream, mode))
486 : {
487 0 : printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
488 0 : return 1;
489 : } else {
490 3 : return 0;
491 : }
492 : }
|