Line data Source code
1 : /* This includes the whole .c file to get access to static functions. */
2 : #define PB_ENABLE_MALLOC
3 : #include "pb_common.c"
4 : #include "pb_decode.c"
5 :
6 : #include <stdio.h>
7 : #include <string.h>
8 : #include "unittests.h"
9 : #include "unittestproto.pb.h"
10 :
11 : #define S(x) pb_istream_from_buffer((uint8_t*)x, sizeof(x) - 1)
12 :
13 3 : bool stream_callback(pb_istream_t *stream, uint8_t *buf, size_t count)
14 : {
15 3 : if (stream->state != NULL)
16 1 : return false; /* Simulate error */
17 :
18 2 : if (buf != NULL)
19 2 : memset(buf, 'x', count);
20 2 : return true;
21 : }
22 :
23 : /* Verifies that the stream passed to callback matches the byte array pointed to by arg. */
24 8 : bool callback_check(pb_istream_t *stream, const pb_field_t *field, void **arg)
25 : {
26 : int i;
27 : uint8_t byte;
28 8 : pb_bytes_array_t *ref = (pb_bytes_array_t*) *arg;
29 :
30 27 : for (i = 0; i < ref->size; i++)
31 : {
32 20 : if (!pb_read(stream, &byte, 1))
33 0 : return false;
34 :
35 20 : if (byte != ref->bytes[i])
36 1 : return false;
37 : }
38 :
39 7 : return true;
40 : }
41 :
42 1 : int main()
43 : {
44 1 : int status = 0;
45 :
46 : {
47 1 : uint8_t buffer1[] = "foobartest1234";
48 : uint8_t buffer2[sizeof(buffer1)];
49 1 : pb_istream_t stream = pb_istream_from_buffer(buffer1, sizeof(buffer1));
50 :
51 1 : COMMENT("Test pb_read and pb_istream_t");
52 1 : TEST(pb_read(&stream, buffer2, 6))
53 1 : TEST(memcmp(buffer2, "foobar", 6) == 0)
54 1 : TEST(stream.bytes_left == sizeof(buffer1) - 6)
55 1 : TEST(pb_read(&stream, buffer2 + 6, stream.bytes_left))
56 1 : TEST(memcmp(buffer1, buffer2, sizeof(buffer1)) == 0)
57 1 : TEST(stream.bytes_left == 0)
58 1 : TEST(!pb_read(&stream, buffer2, 1))
59 : }
60 :
61 : {
62 : uint8_t buffer[20];
63 1 : pb_istream_t stream = {&stream_callback, NULL, 20};
64 :
65 1 : COMMENT("Test pb_read with custom callback");
66 1 : TEST(pb_read(&stream, buffer, 5))
67 1 : TEST(memcmp(buffer, "xxxxx", 5) == 0)
68 1 : TEST(!pb_read(&stream, buffer, 50))
69 1 : stream.state = (void*)1; /* Simulated error return from callback */
70 1 : TEST(!pb_read(&stream, buffer, 5))
71 1 : stream.state = NULL;
72 1 : TEST(pb_read(&stream, buffer, 15))
73 : }
74 :
75 : {
76 : pb_istream_t s;
77 : uint64_t u;
78 : int64_t i;
79 :
80 1 : COMMENT("Test pb_decode_varint");
81 1 : TEST((s = S("\x00"), pb_decode_varint(&s, &u) && u == 0));
82 1 : TEST((s = S("\x01"), pb_decode_varint(&s, &u) && u == 1));
83 1 : TEST((s = S("\xAC\x02"), pb_decode_varint(&s, &u) && u == 300));
84 1 : TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint(&s, &u) && u == UINT32_MAX));
85 1 : TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint(&s, (uint64_t*)&i) && i == UINT32_MAX));
86 1 : TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"),
87 : pb_decode_varint(&s, (uint64_t*)&i) && i == -1));
88 1 : TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"),
89 : pb_decode_varint(&s, &u) && u == UINT64_MAX));
90 1 : TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"),
91 : !pb_decode_varint(&s, &u)));
92 : }
93 :
94 : {
95 : pb_istream_t s;
96 : uint32_t u;
97 :
98 1 : COMMENT("Test pb_decode_varint32");
99 1 : TEST((s = S("\x00"), pb_decode_varint32(&s, &u) && u == 0));
100 1 : TEST((s = S("\x01"), pb_decode_varint32(&s, &u) && u == 1));
101 1 : TEST((s = S("\xAC\x02"), pb_decode_varint32(&s, &u) && u == 300));
102 1 : TEST((s = S("\xFF\xFF\xFF\xFF\x0F"), pb_decode_varint32(&s, &u) && u == UINT32_MAX));
103 1 : TEST((s = S("\xFF\xFF\xFF\xFF\x8F\x00"), pb_decode_varint32(&s, &u) && u == UINT32_MAX));
104 1 : TEST((s = S("\xFF\xFF\xFF\xFF\x10"), !pb_decode_varint32(&s, &u)));
105 1 : TEST((s = S("\xFF\xFF\xFF\xFF\x40"), !pb_decode_varint32(&s, &u)));
106 1 : TEST((s = S("\xFF\xFF\xFF\xFF\xFF\x01"), !pb_decode_varint32(&s, &u)));
107 1 : TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x00"), !pb_decode_varint32(&s, &u)));
108 : }
109 :
110 : {
111 : pb_istream_t s;
112 1 : COMMENT("Test pb_skip_varint");
113 1 : TEST((s = S("\x00""foobar"), pb_skip_varint(&s) && s.bytes_left == 6))
114 1 : TEST((s = S("\xAC\x02""foobar"), pb_skip_varint(&s) && s.bytes_left == 6))
115 1 : TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01""foobar"),
116 : pb_skip_varint(&s) && s.bytes_left == 6))
117 1 : TEST((s = S("\xFF"), !pb_skip_varint(&s)))
118 : }
119 :
120 : {
121 : pb_istream_t s;
122 1 : COMMENT("Test pb_skip_string")
123 1 : TEST((s = S("\x00""foobar"), pb_skip_string(&s) && s.bytes_left == 6))
124 1 : TEST((s = S("\x04""testfoobar"), pb_skip_string(&s) && s.bytes_left == 6))
125 1 : TEST((s = S("\x04"), !pb_skip_string(&s)))
126 1 : TEST((s = S("\xFF"), !pb_skip_string(&s)))
127 : }
128 :
129 : {
130 1 : pb_istream_t s = S("\x01\x00");
131 : pb_field_iter_t f;
132 : uint32_t d;
133 :
134 1 : f.type = PB_LTYPE_VARINT;
135 1 : f.data_size = sizeof(d);
136 1 : f.pData = &d;
137 :
138 1 : COMMENT("Test pb_dec_varint using uint32_t")
139 1 : TEST(pb_dec_varint(&s, &f) && d == 1)
140 :
141 : /* Verify that no more than data_size is written. */
142 1 : d = 0xFFFFFFFF;
143 1 : f.data_size = 1;
144 1 : TEST(pb_dec_varint(&s, &f) && (d == 0xFFFFFF00 || d == 0x00FFFFFF))
145 : }
146 :
147 : {
148 : pb_istream_t s;
149 : pb_field_iter_t f;
150 : int32_t d;
151 :
152 1 : f.type = PB_LTYPE_SVARINT;
153 1 : f.data_size = sizeof(d);
154 1 : f.pData = &d;
155 :
156 1 : COMMENT("Test pb_dec_varint using sint32_t")
157 1 : TEST((s = S("\x01"), pb_dec_varint(&s, &f) && d == -1))
158 1 : TEST((s = S("\x02"), pb_dec_varint(&s, &f) && d == 1))
159 1 : TEST((s = S("\xfe\xff\xff\xff\x0f"), pb_dec_varint(&s, &f) && d == INT32_MAX))
160 1 : TEST((s = S("\xff\xff\xff\xff\x0f"), pb_dec_varint(&s, &f) && d == INT32_MIN))
161 : }
162 :
163 : {
164 : pb_istream_t s;
165 : pb_field_iter_t f;
166 : int64_t d;
167 :
168 1 : f.type = PB_LTYPE_SVARINT;
169 1 : f.data_size = sizeof(d);
170 1 : f.pData = &d;
171 :
172 1 : COMMENT("Test pb_dec_varint using sint64_t")
173 1 : TEST((s = S("\x01"), pb_dec_varint(&s, &f) && d == -1))
174 1 : TEST((s = S("\x02"), pb_dec_varint(&s, &f) && d == 1))
175 1 : TEST((s = S("\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"), pb_dec_varint(&s, &f) && d == INT64_MAX))
176 1 : TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"), pb_dec_varint(&s, &f) && d == INT64_MIN))
177 : }
178 :
179 : {
180 : pb_istream_t s;
181 : pb_field_iter_t f;
182 : int32_t d;
183 :
184 1 : f.type = PB_LTYPE_SVARINT;
185 1 : f.data_size = sizeof(d);
186 1 : f.pData = &d;
187 :
188 1 : COMMENT("Test pb_dec_varint overflow detection using sint32_t");
189 1 : TEST((s = S("\xfe\xff\xff\xff\x0f"), pb_dec_varint(&s, &f)));
190 1 : TEST((s = S("\xfe\xff\xff\xff\x10"), !pb_dec_varint(&s, &f)));
191 1 : TEST((s = S("\xff\xff\xff\xff\x0f"), pb_dec_varint(&s, &f)));
192 1 : TEST((s = S("\xff\xff\xff\xff\x10"), !pb_dec_varint(&s, &f)));
193 : }
194 :
195 : {
196 : pb_istream_t s;
197 : pb_field_iter_t f;
198 : uint32_t d;
199 :
200 1 : f.type = PB_LTYPE_UVARINT;
201 1 : f.data_size = sizeof(d);
202 1 : f.pData = &d;
203 :
204 1 : COMMENT("Test pb_dec_varint using uint32_t")
205 1 : TEST((s = S("\x01"), pb_dec_varint(&s, &f) && d == 1))
206 1 : TEST((s = S("\x02"), pb_dec_varint(&s, &f) && d == 2))
207 1 : TEST((s = S("\xff\xff\xff\xff\x0f"), pb_dec_varint(&s, &f) && d == UINT32_MAX))
208 : }
209 :
210 : {
211 : pb_istream_t s;
212 : pb_field_iter_t f;
213 : uint64_t d;
214 :
215 1 : f.type = PB_LTYPE_UVARINT;
216 1 : f.data_size = sizeof(d);
217 1 : f.pData = &d;
218 :
219 1 : COMMENT("Test pb_dec_varint using uint64_t")
220 1 : TEST((s = S("\x01"), pb_dec_varint(&s, &f) && d == 1))
221 1 : TEST((s = S("\x02"), pb_dec_varint(&s, &f) && d == 2))
222 1 : TEST((s = S("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"), pb_dec_varint(&s, &f) && d == UINT64_MAX))
223 : }
224 :
225 : {
226 : pb_istream_t s;
227 : pb_field_iter_t f;
228 : uint32_t d;
229 :
230 1 : f.type = PB_LTYPE_UVARINT;
231 1 : f.data_size = sizeof(d);
232 1 : f.pData = &d;
233 :
234 1 : COMMENT("Test pb_dec_varint overflow detection using uint32_t");
235 1 : TEST((s = S("\xff\xff\xff\xff\x0f"), pb_dec_varint(&s, &f)));
236 1 : TEST((s = S("\xff\xff\xff\xff\x10"), !pb_dec_varint(&s, &f)));
237 : }
238 :
239 : {
240 : pb_istream_t s;
241 : float d;
242 :
243 1 : COMMENT("Test pb_dec_fixed using float (failures here may be caused by imperfect rounding)")
244 1 : TEST((s = S("\x00\x00\x00\x00"), pb_decode_fixed32(&s, &d) && d == 0.0f))
245 1 : TEST((s = S("\x00\x00\xc6\x42"), pb_decode_fixed32(&s, &d) && d == 99.0f))
246 1 : TEST((s = S("\x4e\x61\x3c\xcb"), pb_decode_fixed32(&s, &d) && d == -12345678.0f))
247 1 : d = -12345678.0f;
248 1 : TEST((s = S("\x00"), !pb_decode_fixed32(&s, &d) && d == -12345678.0f))
249 : }
250 :
251 : if (sizeof(double) == 8)
252 : {
253 : pb_istream_t s;
254 : double d;
255 :
256 1 : COMMENT("Test pb_dec_fixed64 using double (failures here may be caused by imperfect rounding)")
257 1 : TEST((s = S("\x00\x00\x00\x00\x00\x00\x00\x00"), pb_decode_fixed64(&s, &d) && d == 0.0))
258 1 : TEST((s = S("\x00\x00\x00\x00\x00\xc0\x58\x40"), pb_decode_fixed64(&s, &d) && d == 99.0))
259 1 : TEST((s = S("\x00\x00\x00\xc0\x29\x8c\x67\xc1"), pb_decode_fixed64(&s, &d) && d == -12345678.0f))
260 : }
261 :
262 : {
263 : pb_istream_t s;
264 : struct { pb_size_t size; uint8_t bytes[5]; } d;
265 : pb_field_iter_t f;
266 :
267 1 : f.type = PB_LTYPE_BYTES;
268 1 : f.data_size = sizeof(d);
269 1 : f.pData = &d;
270 :
271 1 : COMMENT("Test pb_dec_bytes")
272 1 : TEST((s = S("\x00"), pb_dec_bytes(&s, &f) && d.size == 0))
273 1 : TEST((s = S("\x01\xFF"), pb_dec_bytes(&s, &f) && d.size == 1 && d.bytes[0] == 0xFF))
274 1 : TEST((s = S("\x05xxxxx"), pb_dec_bytes(&s, &f) && d.size == 5))
275 1 : TEST((s = S("\x05xxxx"), !pb_dec_bytes(&s, &f)))
276 :
277 : /* Note: the size limit on bytes-fields is not strictly obeyed, as
278 : * the compiler may add some padding to the struct. Using this padding
279 : * is not a very good thing to do, but it is difficult to avoid when
280 : * we use only a single uint8_t to store the size of the field.
281 : * Therefore this tests against a 10-byte string, while otherwise even
282 : * 6 bytes should error out.
283 : */
284 1 : TEST((s = S("\x10xxxxxxxxxx"), !pb_dec_bytes(&s, &f)))
285 : }
286 :
287 : {
288 : pb_istream_t s;
289 : pb_field_iter_t f;
290 : char d[5];
291 :
292 1 : f.type = PB_LTYPE_STRING;
293 1 : f.data_size = sizeof(d);
294 1 : f.pData = &d;
295 :
296 1 : COMMENT("Test pb_dec_string")
297 1 : TEST((s = S("\x00"), pb_dec_string(&s, &f) && d[0] == '\0'))
298 1 : TEST((s = S("\x04xyzz"), pb_dec_string(&s, &f) && strcmp(d, "xyzz") == 0))
299 1 : TEST((s = S("\x05xyzzy"), !pb_dec_string(&s, &f)))
300 : }
301 :
302 : {
303 : pb_istream_t s;
304 : IntegerArray dest;
305 :
306 1 : COMMENT("Testing pb_decode with repeated int32 field")
307 1 : TEST((s = S(""), pb_decode(&s, IntegerArray_fields, &dest) && dest.data_count == 0))
308 1 : TEST((s = S("\x08\x01\x08\x02"), pb_decode(&s, IntegerArray_fields, &dest)
309 : && dest.data_count == 2 && dest.data[0] == 1 && dest.data[1] == 2))
310 1 : s = S("\x08\x01\x08\x02\x08\x03\x08\x04\x08\x05\x08\x06\x08\x07\x08\x08\x08\x09\x08\x0A");
311 1 : TEST(pb_decode(&s, IntegerArray_fields, &dest) && dest.data_count == 10 && dest.data[9] == 10)
312 1 : s = S("\x08\x01\x08\x02\x08\x03\x08\x04\x08\x05\x08\x06\x08\x07\x08\x08\x08\x09\x08\x0A\x08\x0B");
313 1 : TEST(!pb_decode(&s, IntegerArray_fields, &dest))
314 : }
315 :
316 : {
317 : pb_istream_t s;
318 : IntegerArray dest;
319 :
320 1 : COMMENT("Testing pb_decode with packed int32 field")
321 1 : TEST((s = S("\x0A\x00"), pb_decode(&s, IntegerArray_fields, &dest)
322 : && dest.data_count == 0))
323 1 : TEST((s = S("\x0A\x01\x01"), pb_decode(&s, IntegerArray_fields, &dest)
324 : && dest.data_count == 1 && dest.data[0] == 1))
325 1 : TEST((s = S("\x0A\x0A\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A"), pb_decode(&s, IntegerArray_fields, &dest)
326 : && dest.data_count == 10 && dest.data[0] == 1 && dest.data[9] == 10))
327 1 : TEST((s = S("\x0A\x0B\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B"), !pb_decode(&s, IntegerArray_fields, &dest)))
328 :
329 : /* Test invalid wire data */
330 1 : TEST((s = S("\x0A\xFF"), !pb_decode(&s, IntegerArray_fields, &dest)))
331 1 : TEST((s = S("\x0A\x01"), !pb_decode(&s, IntegerArray_fields, &dest)))
332 : }
333 :
334 : {
335 : pb_istream_t s;
336 : IntegerArray dest;
337 :
338 1 : COMMENT("Testing pb_decode with unknown fields")
339 1 : TEST((s = S("\x18\x0F\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)
340 : && dest.data_count == 1 && dest.data[0] == 1))
341 1 : TEST((s = S("\x19\x00\x00\x00\x00\x00\x00\x00\x00\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)
342 : && dest.data_count == 1 && dest.data[0] == 1))
343 1 : TEST((s = S("\x1A\x00\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)
344 : && dest.data_count == 1 && dest.data[0] == 1))
345 1 : TEST((s = S("\x1B\x08\x01"), !pb_decode(&s, IntegerArray_fields, &dest)))
346 1 : TEST((s = S("\x1D\x00\x00\x00\x00\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)
347 : && dest.data_count == 1 && dest.data[0] == 1))
348 : }
349 :
350 : {
351 : pb_istream_t s;
352 : CallbackArray dest;
353 : struct { pb_size_t size; uint8_t bytes[10]; } ref;
354 1 : dest.data.funcs.decode = &callback_check;
355 1 : dest.data.arg = &ref;
356 :
357 1 : COMMENT("Testing pb_decode with callbacks")
358 : /* Single varint */
359 1 : ref.size = 1; ref.bytes[0] = 0x55;
360 1 : TEST((s = S("\x08\x55"), pb_decode(&s, CallbackArray_fields, &dest)))
361 : /* Packed varint */
362 1 : ref.size = 3; ref.bytes[0] = ref.bytes[1] = ref.bytes[2] = 0x55;
363 1 : TEST((s = S("\x0A\x03\x55\x55\x55"), pb_decode(&s, CallbackArray_fields, &dest)))
364 : /* Packed varint with loop */
365 1 : ref.size = 1; ref.bytes[0] = 0x55;
366 1 : TEST((s = S("\x0A\x03\x55\x55\x55"), pb_decode(&s, CallbackArray_fields, &dest)))
367 : /* Single fixed32 */
368 1 : ref.size = 4; ref.bytes[0] = ref.bytes[1] = ref.bytes[2] = ref.bytes[3] = 0xAA;
369 1 : TEST((s = S("\x0D\xAA\xAA\xAA\xAA"), pb_decode(&s, CallbackArray_fields, &dest)))
370 : /* Single fixed64 */
371 1 : ref.size = 8; memset(ref.bytes, 0xAA, 8);
372 1 : TEST((s = S("\x09\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"), pb_decode(&s, CallbackArray_fields, &dest)))
373 : /* Unsupported field type */
374 1 : TEST((s = S("\x0B\x00"), !pb_decode(&s, CallbackArray_fields, &dest)))
375 :
376 : /* Just make sure that our test function works */
377 1 : ref.size = 1; ref.bytes[0] = 0x56;
378 1 : TEST((s = S("\x08\x55"), !pb_decode(&s, CallbackArray_fields, &dest)))
379 : }
380 :
381 : {
382 : pb_istream_t s;
383 : IntegerArray dest;
384 :
385 1 : COMMENT("Testing pb_decode message termination")
386 1 : TEST((s = S(""), pb_decode(&s, IntegerArray_fields, &dest)))
387 1 : TEST((s = S("\x08\x01"), pb_decode(&s, IntegerArray_fields, &dest)))
388 1 : TEST((s = S("\x08"), !pb_decode(&s, IntegerArray_fields, &dest)))
389 : }
390 :
391 : {
392 : pb_istream_t s;
393 : IntegerArray dest;
394 :
395 1 : COMMENT("Testing pb_decode_ex null termination")
396 :
397 1 : TEST((s = S("\x00"), pb_decode_ex(&s, IntegerArray_fields, &dest, PB_DECODE_NULLTERMINATED)))
398 1 : TEST((s = S("\x08\x01\x00"), pb_decode_ex(&s, IntegerArray_fields, &dest, PB_DECODE_NULLTERMINATED)))
399 : }
400 :
401 : {
402 : pb_istream_t s;
403 : IntegerArray dest;
404 :
405 1 : COMMENT("Testing pb_decode with invalid tag numbers")
406 1 : TEST((s = S("\x9f\xea"), !pb_decode(&s, IntegerArray_fields, &dest)));
407 1 : TEST((s = S("\x00"), !pb_decode(&s, IntegerArray_fields, &dest)));
408 : }
409 :
410 : {
411 : pb_istream_t s;
412 1 : IntegerContainer dest = {{0}};
413 :
414 1 : COMMENT("Testing pb_decode_delimited")
415 1 : TEST((s = S("\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"),
416 : pb_decode_delimited(&s, IntegerContainer_fields, &dest)) &&
417 : dest.submsg.data_count == 5)
418 : }
419 :
420 : {
421 1 : pb_istream_t s = {0};
422 1 : void *data = NULL;
423 :
424 1 : COMMENT("Testing allocate_field")
425 1 : TEST(allocate_field(&s, &data, 10, 10) && data != NULL);
426 1 : TEST(allocate_field(&s, &data, 10, 20) && data != NULL);
427 :
428 : {
429 1 : void *oldvalue = data;
430 1 : size_t very_big = (size_t)-1;
431 1 : size_t somewhat_big = very_big / 2 + 1;
432 1 : size_t not_so_big = (size_t)1 << (4 * sizeof(size_t));
433 :
434 1 : TEST(!allocate_field(&s, &data, very_big, 2) && data == oldvalue);
435 1 : TEST(!allocate_field(&s, &data, somewhat_big, 2) && data == oldvalue);
436 1 : TEST(!allocate_field(&s, &data, not_so_big, not_so_big) && data == oldvalue);
437 : }
438 :
439 1 : pb_free(data);
440 : }
441 :
442 1 : if (status != 0)
443 0 : fprintf(stdout, "\n\nSome tests FAILED!\n");
444 :
445 1 : return status;
446 : }
|