1 /* This includes the whole .c file to get access to static functions. */
2 #include "pb_common.c"
3 #include "pb_encode.c"
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include "unittests.h"
8 #include "unittestproto.pb.h"
9 
streamcallback(pb_ostream_t * stream,const uint8_t * buf,size_t count)10 bool streamcallback(pb_ostream_t *stream, const uint8_t *buf, size_t count)
11 {
12     /* Allow only 'x' to be written */
13     while (count--)
14     {
15         if (*buf++ != 'x')
16             return false;
17     }
18     return true;
19 }
20 
fieldcallback(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)21 bool fieldcallback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
22 {
23     int value = 0x55;
24     if (!pb_encode_tag_for_field(stream, field))
25         return false;
26     return pb_encode_varint(stream, value);
27 }
28 
crazyfieldcallback(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)29 bool crazyfieldcallback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
30 {
31     /* This callback writes different amount of data the second time. */
32     uint32_t *state = (uint32_t*)arg;
33     *state <<= 8;
34     if (!pb_encode_tag_for_field(stream, field))
35         return false;
36     return pb_encode_varint(stream, *state);
37 }
38 
39 /* Check that expression x writes data y.
40  * Y is a string, which may contain null bytes. Null terminator is ignored.
41  */
42 #define WRITES(x, y) \
43 memset(buffer, 0xAA, sizeof(buffer)), \
44 s = pb_ostream_from_buffer(buffer, sizeof(buffer)), \
45 (x) && \
46 memcmp(buffer, y, sizeof(y) - 1) == 0 && \
47 buffer[sizeof(y) - 1] == 0xAA
48 
main()49 int main()
50 {
51     int status = 0;
52 
53     {
54         uint8_t buffer1[] = "foobartest1234";
55         uint8_t buffer2[sizeof(buffer1)];
56         pb_ostream_t stream = pb_ostream_from_buffer(buffer2, sizeof(buffer1));
57 
58         COMMENT("Test pb_write and pb_ostream_t");
59         TEST(pb_write(&stream, buffer1, sizeof(buffer1)));
60         TEST(memcmp(buffer1, buffer2, sizeof(buffer1)) == 0);
61         TEST(!pb_write(&stream, buffer1, 1));
62         TEST(stream.bytes_written == sizeof(buffer1));
63     }
64 
65     {
66         uint8_t buffer1[] = "xxxxxxx";
67         pb_ostream_t stream = {&streamcallback, 0, SIZE_MAX, 0};
68 
69         COMMENT("Test pb_write with custom callback");
70         TEST(pb_write(&stream, buffer1, 5));
71         buffer1[0] = 'a';
72         TEST(!pb_write(&stream, buffer1, 5));
73     }
74 
75     {
76         uint8_t buffer[30];
77         pb_ostream_t s;
78 
79         COMMENT("Test pb_encode_varint")
80         TEST(WRITES(pb_encode_varint(&s, 0), "\0"));
81         TEST(WRITES(pb_encode_varint(&s, 1), "\1"));
82         TEST(WRITES(pb_encode_varint(&s, 0x7F), "\x7F"));
83         TEST(WRITES(pb_encode_varint(&s, 0x80), "\x80\x01"));
84         TEST(WRITES(pb_encode_varint(&s, UINT32_MAX), "\xFF\xFF\xFF\xFF\x0F"));
85         TEST(WRITES(pb_encode_varint(&s, UINT64_MAX), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
86     }
87 
88     {
89         uint8_t buffer[50];
90         pb_ostream_t s;
91 
92         COMMENT("Test pb_encode_varint 32-bit fast path")
93         TEST(WRITES(pb_encode_varint(&s, 0x00000000), "\x00"));
94         TEST(WRITES(pb_encode_varint(&s, 0x00000001), "\x01"));
95         TEST(WRITES(pb_encode_varint(&s, 0x0000007F), "\x7F"));
96         TEST(WRITES(pb_encode_varint(&s, 0x00000080), "\x80\x01"));
97         TEST(WRITES(pb_encode_varint(&s, 0x00000191), "\x91\x03"));
98         TEST(WRITES(pb_encode_varint(&s, 0x00003FFF), "\xFF\x7F"));
99         TEST(WRITES(pb_encode_varint(&s, 0x00004000), "\x80\x80\x01"));
100         TEST(WRITES(pb_encode_varint(&s, 0x0000D111), "\x91\xA2\x03"));
101         TEST(WRITES(pb_encode_varint(&s, 0x001FFFFF), "\xFF\xFF\x7F"));
102         TEST(WRITES(pb_encode_varint(&s, 0x00200000), "\x80\x80\x80\x01"));
103         TEST(WRITES(pb_encode_varint(&s, 0x00711111), "\x91\xA2\xC4\x03"));
104         TEST(WRITES(pb_encode_varint(&s, 0x0FFFFFFF), "\xFF\xFF\xFF\x7F"));
105         TEST(WRITES(pb_encode_varint(&s, 0x10000000), "\x80\x80\x80\x80\x01"));
106         TEST(WRITES(pb_encode_varint(&s, 0x31111111), "\x91\xA2\xC4\x88\x03"));
107         TEST(WRITES(pb_encode_varint(&s, UINT32_MAX), "\xFF\xFF\xFF\xFF\x0F"));
108     }
109 
110     {
111         uint8_t buffer[50];
112         pb_ostream_t s;
113 
114         COMMENT("Test pb_encode_svarint 32-bit fast path")
115         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00000000), "\x00"));
116         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xFFFFFFFF), "\x01"));
117         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x0000003F), "\x7E"));
118         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xFFFFFFC0), "\x7F"));
119         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00000040), "\x80\x01"));
120         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00001FFF), "\xFE\x7F"));
121         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xFFFFE000), "\xFF\x7F"));
122         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00002000), "\x80\x80\x01"));
123         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x000FFFFF), "\xFE\xFF\x7F"));
124         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xFFF00000), "\xFF\xFF\x7F"));
125         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x00100000), "\x80\x80\x80\x01"));
126         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x07FFFFFF), "\xFE\xFF\xFF\x7F"));
127         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0xF8000000), "\xFF\xFF\xFF\x7F"));
128         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x08000000), "\x80\x80\x80\x80\x01"));
129         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x7FFFFFFF), "\xFE\xFF\xFF\xFF\x0F"));
130         TEST(WRITES(pb_encode_svarint(&s, (int32_t)0x80000000), "\xFF\xFF\xFF\xFF\x0F"));
131     }
132 
133     {
134         uint8_t buffer[30];
135         pb_ostream_t s;
136 
137         COMMENT("Test pb_encode_tag")
138         TEST(WRITES(pb_encode_tag(&s, PB_WT_STRING, 5), "\x2A"));
139         TEST(WRITES(pb_encode_tag(&s, PB_WT_VARINT, 99), "\x98\x06"));
140     }
141 
142     {
143         uint8_t buffer[30];
144         pb_ostream_t s;
145         pb_field_iter_t field;
146         field.tag = 10;
147 
148         COMMENT("Test pb_encode_tag_for_field")
149         field.type = PB_LTYPE_SVARINT;
150         TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x50"));
151 
152         field.type = PB_LTYPE_FIXED64;
153         TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x51"));
154 
155         field.type = PB_LTYPE_STRING;
156         TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x52"));
157 
158         field.type = PB_LTYPE_FIXED32;
159         TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x55"));
160     }
161 
162     {
163         uint8_t buffer[30];
164         pb_ostream_t s;
165 
166         COMMENT("Test pb_encode_string")
167         TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"abcd", 4), "\x04""abcd"));
168         TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"abcd\x00", 5), "\x05""abcd\x00"));
169         TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"", 0), "\x00"));
170     }
171 
172     {
173         uint8_t buffer[30];
174         pb_ostream_t s;
175         uint8_t value = 1;
176         int32_t max = INT32_MAX;
177         int32_t min = INT32_MIN;
178         int64_t lmax = INT64_MAX;
179         int64_t lmin = INT64_MIN;
180         pb_field_iter_t field;
181 
182         COMMENT("Test pb_enc_varint and pb_enc_svarint")
183         field.type = PB_LTYPE_VARINT;
184         field.data_size = sizeof(value);
185         field.pData = &value;
186         TEST(WRITES(pb_enc_varint(&s, &field), "\x01"));
187 
188         field.type = PB_LTYPE_SVARINT;
189         field.data_size = sizeof(max);
190         field.pData = &max;
191         TEST(WRITES(pb_enc_varint(&s, &field), "\xfe\xff\xff\xff\x0f"));
192 
193         field.type = PB_LTYPE_SVARINT;
194         field.data_size = sizeof(min);
195         field.pData = &min;
196         TEST(WRITES(pb_enc_varint(&s, &field), "\xff\xff\xff\xff\x0f"));
197 
198         field.type = PB_LTYPE_SVARINT;
199         field.data_size = sizeof(lmax);
200         field.pData = &lmax;
201         TEST(WRITES(pb_enc_varint(&s, &field), "\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
202 
203         field.type = PB_LTYPE_SVARINT;
204         field.data_size = sizeof(lmin);
205         field.pData = &lmin;
206         TEST(WRITES(pb_enc_varint(&s, &field), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
207     }
208 
209     {
210         uint8_t buffer[30];
211         pb_ostream_t s;
212         float fvalue;
213         double dvalue;
214         pb_field_iter_t field;
215 
216         COMMENT("Test pb_enc_fixed using float")
217         field.type = PB_LTYPE_FIXED32;
218         field.data_size = sizeof(fvalue);
219         field.pData = &fvalue;
220         fvalue = 0.0f;
221         TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\x00\x00"))
222         fvalue = 99.0f;
223         TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\xc6\x42"))
224         fvalue = -12345678.0f;
225         TEST(WRITES(pb_enc_fixed(&s, &field), "\x4e\x61\x3c\xcb"))
226 
227         COMMENT("Test pb_enc_fixed using double")
228         field.type = PB_LTYPE_FIXED64;
229         field.data_size = sizeof(dvalue);
230         field.pData = &dvalue;
231         dvalue = 0.0;
232         TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\x00\x00\x00\x00\x00\x00"))
233         dvalue = 99.0;
234         TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\x00\x00\x00\xc0\x58\x40"))
235         dvalue = -12345678.0;
236         TEST(WRITES(pb_enc_fixed(&s, &field), "\x00\x00\x00\xc0\x29\x8c\x67\xc1"))
237     }
238 
239     {
240         uint8_t buffer[30];
241         pb_ostream_t s;
242         struct { pb_size_t size; uint8_t bytes[5]; } value = {5, {'x', 'y', 'z', 'z', 'y'}};
243         pb_field_iter_t field;
244         pb_field_iter_begin(&field, BytesMessage_fields, &value);
245 
246         COMMENT("Test pb_enc_bytes")
247         TEST(WRITES(pb_enc_bytes(&s, &field), "\x05xyzzy"))
248         value.size = 0;
249         TEST(WRITES(pb_enc_bytes(&s, &field), "\x00"))
250     }
251 
252     {
253         uint8_t buffer[30];
254         pb_ostream_t s;
255         char value[30] = "xyzzy";
256         pb_field_iter_t field;
257         pb_field_iter_begin(&field, StringMessage_fields, &value);
258 
259         COMMENT("Test pb_enc_string")
260         TEST(WRITES(pb_enc_string(&s, &field), "\x05xyzzy"))
261         value[0] = '\0';
262         TEST(WRITES(pb_enc_string(&s, &field), "\x00"))
263         memset(value, 'x', 10);
264         value[10] = '\0';
265         TEST(WRITES(pb_enc_string(&s, &field), "\x0Axxxxxxxxxx"))
266     }
267 
268     {
269         uint8_t buffer[10];
270         pb_ostream_t s;
271         IntegerArray msg = {5, {1, 2, 3, 4, 5}};
272 
273         COMMENT("Test pb_encode with int32 array")
274 
275         TEST(WRITES(pb_encode(&s, IntegerArray_fields, &msg), "\x0A\x05\x01\x02\x03\x04\x05"))
276 
277         msg.data_count = 0;
278         TEST(WRITES(pb_encode(&s, IntegerArray_fields, &msg), ""))
279 
280         msg.data_count = 10;
281         TEST(!pb_encode(&s, IntegerArray_fields, &msg))
282     }
283 
284     {
285         uint8_t buffer[10];
286         pb_ostream_t s;
287         FloatArray msg = {1, {99.0f}};
288 
289         COMMENT("Test pb_encode with float array")
290 
291         TEST(WRITES(pb_encode(&s, FloatArray_fields, &msg),
292                     "\x0A\x04\x00\x00\xc6\x42"))
293 
294         msg.data_count = 0;
295         TEST(WRITES(pb_encode(&s, FloatArray_fields, &msg), ""))
296 
297         msg.data_count = 3;
298         TEST(!pb_encode(&s, FloatArray_fields, &msg))
299     }
300 
301     {
302         uint8_t buffer[50];
303         pb_ostream_t s;
304         FloatArray msg = {1, {99.0f}};
305 
306         COMMENT("Test array size limit in pb_encode")
307 
308         s = pb_ostream_from_buffer(buffer, sizeof(buffer));
309         TEST((msg.data_count = 10) && pb_encode(&s, FloatArray_fields, &msg))
310 
311         s = pb_ostream_from_buffer(buffer, sizeof(buffer));
312         TEST((msg.data_count = 11) && !pb_encode(&s, FloatArray_fields, &msg))
313     }
314 
315     {
316         uint8_t buffer[10];
317         pb_ostream_t s;
318         CallbackArray msg;
319 
320         msg.data.funcs.encode = &fieldcallback;
321 
322         COMMENT("Test pb_encode with callback field.")
323         TEST(WRITES(pb_encode(&s, CallbackArray_fields, &msg), "\x08\x55"))
324     }
325 
326     {
327         uint8_t buffer[10];
328         pb_ostream_t s;
329         IntegerContainer msg = {{5, {1,2,3,4,5}}};
330 
331         COMMENT("Test pb_encode with packed array in a submessage.")
332         TEST(WRITES(pb_encode(&s, IntegerContainer_fields, &msg),
333                     "\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"))
334     }
335 
336     {
337         uint8_t buffer[32];
338         pb_ostream_t s;
339         BytesMessage msg = {{3, "xyz"}};
340 
341         COMMENT("Test pb_encode with bytes message.")
342         TEST(WRITES(pb_encode(&s, BytesMessage_fields, &msg),
343                     "\x0A\x03xyz"))
344 
345         msg.data.size = 17; /* More than maximum */
346         TEST(!pb_encode(&s, BytesMessage_fields, &msg))
347     }
348 
349 
350     {
351         uint8_t buffer[20];
352         pb_ostream_t s;
353         IntegerContainer msg = {{5, {1,2,3,4,5}}};
354 
355         COMMENT("Test pb_encode_delimited.")
356         TEST(WRITES(pb_encode_delimited(&s, IntegerContainer_fields, &msg),
357                     "\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"))
358     }
359 
360     {
361         IntegerContainer msg = {{5, {1,2,3,4,5}}};
362         size_t size;
363 
364         COMMENT("Test pb_get_encoded_size.")
365         TEST(pb_get_encoded_size(&size, IntegerContainer_fields, &msg) &&
366              size == 9);
367     }
368 
369     {
370         uint8_t buffer[10];
371         pb_ostream_t s;
372         CallbackContainer msg;
373         CallbackContainerContainer msg2;
374         uint32_t state = 1;
375 
376         msg.submsg.data.funcs.encode = &fieldcallback;
377         msg2.submsg.submsg.data.funcs.encode = &fieldcallback;
378 
379         COMMENT("Test pb_encode with callback field in a submessage.")
380         TEST(WRITES(pb_encode(&s, CallbackContainer_fields, &msg), "\x0A\x02\x08\x55"))
381         TEST(WRITES(pb_encode(&s, CallbackContainerContainer_fields, &msg2),
382                     "\x0A\x04\x0A\x02\x08\x55"))
383 
384         /* Misbehaving callback: varying output between calls */
385         msg.submsg.data.funcs.encode = &crazyfieldcallback;
386         msg.submsg.data.arg = &state;
387         msg2.submsg.submsg.data.funcs.encode = &crazyfieldcallback;
388         msg2.submsg.submsg.data.arg = &state;
389 
390         TEST(!pb_encode(&s, CallbackContainer_fields, &msg))
391         state = 1;
392         TEST(!pb_encode(&s, CallbackContainerContainer_fields, &msg2))
393     }
394 
395     {
396         uint8_t buffer[StringMessage_size];
397         pb_ostream_t s;
398         StringMessage msg = {"0123456789"};
399 
400         s = pb_ostream_from_buffer(buffer, sizeof(buffer));
401 
402         COMMENT("Test that StringMessage_size is correct")
403 
404         TEST(pb_encode(&s, StringMessage_fields, &msg));
405         TEST(s.bytes_written == StringMessage_size);
406     }
407 
408     {
409         uint8_t buffer[128];
410         pb_ostream_t s;
411         StringPointerContainer msg = StringPointerContainer_init_zero;
412         char *strs[1] = {NULL};
413         char zstr[] = "Z";
414 
415         COMMENT("Test string pointer encoding.");
416 
417         msg.rep_str = strs;
418         msg.rep_str_count = 1;
419         TEST(WRITES(pb_encode(&s, StringPointerContainer_fields, &msg), "\x0a\x00"))
420 
421         strs[0] = zstr;
422         TEST(WRITES(pb_encode(&s, StringPointerContainer_fields, &msg), "\x0a\x01Z"))
423     }
424 
425     if (status != 0)
426         fprintf(stdout, "\n\nSome tests FAILED!\n");
427 
428     return status;
429 }
430