Home | History | Annotate | Download | only in encode_unittests
      1 /* This includes the whole .c file to get access to static functions. */
      2 #include "pb_encode.c"
      3 
      4 #include <stdio.h>
      5 #include <string.h>
      6 #include "unittests.h"
      7 #include "unittestproto.pb.h"
      8 
      9 bool streamcallback(pb_ostream_t *stream, const uint8_t *buf, size_t count)
     10 {
     11     /* Allow only 'x' to be written */
     12     while (count--)
     13     {
     14         if (*buf++ != 'x')
     15             return false;
     16     }
     17     return true;
     18 }
     19 
     20 bool fieldcallback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
     21 {
     22     int value = 0x55;
     23     if (!pb_encode_tag_for_field(stream, field))
     24         return false;
     25     return pb_encode_varint(stream, value);
     26 }
     27 
     28 bool crazyfieldcallback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
     29 {
     30     /* This callback writes different amount of data the second time. */
     31     uint32_t *state = (uint32_t*)arg;
     32     *state <<= 8;
     33     if (!pb_encode_tag_for_field(stream, field))
     34         return false;
     35     return pb_encode_varint(stream, *state);
     36 }
     37 
     38 /* Check that expression x writes data y.
     39  * Y is a string, which may contain null bytes. Null terminator is ignored.
     40  */
     41 #define WRITES(x, y) \
     42 memset(buffer, 0xAA, sizeof(buffer)), \
     43 s = pb_ostream_from_buffer(buffer, sizeof(buffer)), \
     44 (x) && \
     45 memcmp(buffer, y, sizeof(y) - 1) == 0 && \
     46 buffer[sizeof(y) - 1] == 0xAA
     47 
     48 int main()
     49 {
     50     int status = 0;
     51 
     52     {
     53         uint8_t buffer1[] = "foobartest1234";
     54         uint8_t buffer2[sizeof(buffer1)];
     55         pb_ostream_t stream = pb_ostream_from_buffer(buffer2, sizeof(buffer1));
     56 
     57         COMMENT("Test pb_write and pb_ostream_t");
     58         TEST(pb_write(&stream, buffer1, sizeof(buffer1)));
     59         TEST(memcmp(buffer1, buffer2, sizeof(buffer1)) == 0);
     60         TEST(!pb_write(&stream, buffer1, 1));
     61         TEST(stream.bytes_written == sizeof(buffer1));
     62     }
     63 
     64     {
     65         uint8_t buffer1[] = "xxxxxxx";
     66         pb_ostream_t stream = {&streamcallback, 0, SIZE_MAX, 0};
     67 
     68         COMMENT("Test pb_write with custom callback");
     69         TEST(pb_write(&stream, buffer1, 5));
     70         buffer1[0] = 'a';
     71         TEST(!pb_write(&stream, buffer1, 5));
     72     }
     73 
     74     {
     75         uint8_t buffer[30];
     76         pb_ostream_t s;
     77 
     78         COMMENT("Test pb_encode_varint")
     79         TEST(WRITES(pb_encode_varint(&s, 0), "\0"));
     80         TEST(WRITES(pb_encode_varint(&s, 1), "\1"));
     81         TEST(WRITES(pb_encode_varint(&s, 0x7F), "\x7F"));
     82         TEST(WRITES(pb_encode_varint(&s, 0x80), "\x80\x01"));
     83         TEST(WRITES(pb_encode_varint(&s, UINT32_MAX), "\xFF\xFF\xFF\xFF\x0F"));
     84         TEST(WRITES(pb_encode_varint(&s, UINT64_MAX), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
     85     }
     86 
     87     {
     88         uint8_t buffer[30];
     89         pb_ostream_t s;
     90 
     91         COMMENT("Test pb_encode_tag")
     92         TEST(WRITES(pb_encode_tag(&s, PB_WT_STRING, 5), "\x2A"));
     93         TEST(WRITES(pb_encode_tag(&s, PB_WT_VARINT, 99), "\x98\x06"));
     94     }
     95 
     96     {
     97         uint8_t buffer[30];
     98         pb_ostream_t s;
     99         pb_field_t field = {10, PB_LTYPE_SVARINT};
    100 
    101         COMMENT("Test pb_encode_tag_for_field")
    102         TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x50"));
    103 
    104         field.type = PB_LTYPE_FIXED64;
    105         TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x51"));
    106 
    107         field.type = PB_LTYPE_STRING;
    108         TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x52"));
    109 
    110         field.type = PB_LTYPE_FIXED32;
    111         TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x55"));
    112     }
    113 
    114     {
    115         uint8_t buffer[30];
    116         pb_ostream_t s;
    117 
    118         COMMENT("Test pb_encode_string")
    119         TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"abcd", 4), "\x04""abcd"));
    120         TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"abcd\x00", 5), "\x05""abcd\x00"));
    121         TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"", 0), "\x00"));
    122     }
    123 
    124     {
    125         uint8_t buffer[30];
    126         pb_ostream_t s;
    127         uint8_t value = 1;
    128         int32_t max = INT32_MAX;
    129         int32_t min = INT32_MIN;
    130         int64_t lmax = INT64_MAX;
    131         int64_t lmin = INT64_MIN;
    132         pb_field_t field = {1, PB_LTYPE_VARINT, 0, 0, sizeof(value)};
    133 
    134         COMMENT("Test pb_enc_varint and pb_enc_svarint")
    135         TEST(WRITES(pb_enc_varint(&s, &field, &value), "\x01"));
    136 
    137         field.data_size = sizeof(max);
    138         TEST(WRITES(pb_enc_svarint(&s, &field, &max), "\xfe\xff\xff\xff\x0f"));
    139         TEST(WRITES(pb_enc_svarint(&s, &field, &min), "\xff\xff\xff\xff\x0f"));
    140 
    141         field.data_size = sizeof(lmax);
    142         TEST(WRITES(pb_enc_svarint(&s, &field, &lmax), "\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
    143         TEST(WRITES(pb_enc_svarint(&s, &field, &lmin), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"));
    144     }
    145 
    146     {
    147         uint8_t buffer[30];
    148         pb_ostream_t s;
    149         float fvalue;
    150         double dvalue;
    151 
    152         COMMENT("Test pb_enc_fixed32 using float")
    153         fvalue = 0.0f;
    154         TEST(WRITES(pb_enc_fixed32(&s, NULL, &fvalue), "\x00\x00\x00\x00"))
    155         fvalue = 99.0f;
    156         TEST(WRITES(pb_enc_fixed32(&s, NULL, &fvalue), "\x00\x00\xc6\x42"))
    157         fvalue = -12345678.0f;
    158         TEST(WRITES(pb_enc_fixed32(&s, NULL, &fvalue), "\x4e\x61\x3c\xcb"))
    159 
    160         COMMENT("Test pb_enc_fixed64 using double")
    161         dvalue = 0.0;
    162         TEST(WRITES(pb_enc_fixed64(&s, NULL, &dvalue), "\x00\x00\x00\x00\x00\x00\x00\x00"))
    163         dvalue = 99.0;
    164         TEST(WRITES(pb_enc_fixed64(&s, NULL, &dvalue), "\x00\x00\x00\x00\x00\xc0\x58\x40"))
    165         dvalue = -12345678.0;
    166         TEST(WRITES(pb_enc_fixed64(&s, NULL, &dvalue), "\x00\x00\x00\xc0\x29\x8c\x67\xc1"))
    167     }
    168 
    169     {
    170         uint8_t buffer[30];
    171         pb_ostream_t s;
    172         struct { size_t size; uint8_t bytes[5]; } value = {5, {'x', 'y', 'z', 'z', 'y'}};
    173 
    174         COMMENT("Test pb_enc_bytes")
    175         TEST(WRITES(pb_enc_bytes(&s, &BytesMessage_fields[0], &value), "\x05xyzzy"))
    176         value.size = 0;
    177         TEST(WRITES(pb_enc_bytes(&s, &BytesMessage_fields[0], &value), "\x00"))
    178     }
    179 
    180     {
    181         uint8_t buffer[30];
    182         pb_ostream_t s;
    183         char value[30] = "xyzzy";
    184 
    185         COMMENT("Test pb_enc_string")
    186         TEST(WRITES(pb_enc_string(&s, &StringMessage_fields[0], &value), "\x05xyzzy"))
    187         value[0] = '\0';
    188         TEST(WRITES(pb_enc_string(&s, &StringMessage_fields[0], &value), "\x00"))
    189         memset(value, 'x', 30);
    190         TEST(WRITES(pb_enc_string(&s, &StringMessage_fields[0], &value), "\x0Axxxxxxxxxx"))
    191     }
    192 
    193     {
    194         uint8_t buffer[10];
    195         pb_ostream_t s;
    196         IntegerArray msg = {5, {1, 2, 3, 4, 5}};
    197 
    198         COMMENT("Test pb_encode with int32 array")
    199 
    200         TEST(WRITES(pb_encode(&s, IntegerArray_fields, &msg), "\x0A\x05\x01\x02\x03\x04\x05"))
    201 
    202         msg.data_count = 0;
    203         TEST(WRITES(pb_encode(&s, IntegerArray_fields, &msg), ""))
    204 
    205         msg.data_count = 10;
    206         TEST(!pb_encode(&s, IntegerArray_fields, &msg))
    207     }
    208 
    209     {
    210         uint8_t buffer[10];
    211         pb_ostream_t s;
    212         FloatArray msg = {1, {99.0f}};
    213 
    214         COMMENT("Test pb_encode with float array")
    215 
    216         TEST(WRITES(pb_encode(&s, FloatArray_fields, &msg),
    217                     "\x0A\x04\x00\x00\xc6\x42"))
    218 
    219         msg.data_count = 0;
    220         TEST(WRITES(pb_encode(&s, FloatArray_fields, &msg), ""))
    221 
    222         msg.data_count = 3;
    223         TEST(!pb_encode(&s, FloatArray_fields, &msg))
    224     }
    225 
    226     {
    227         uint8_t buffer[50];
    228         pb_ostream_t s;
    229         FloatArray msg = {1, {99.0f}};
    230 
    231         COMMENT("Test array size limit in pb_encode")
    232 
    233         s = pb_ostream_from_buffer(buffer, sizeof(buffer));
    234         TEST((msg.data_count = 10) && pb_encode(&s, FloatArray_fields, &msg))
    235 
    236         s = pb_ostream_from_buffer(buffer, sizeof(buffer));
    237         TEST((msg.data_count = 11) && !pb_encode(&s, FloatArray_fields, &msg))
    238     }
    239 
    240     {
    241         uint8_t buffer[10];
    242         pb_ostream_t s;
    243         CallbackArray msg;
    244 
    245         msg.data.funcs.encode = &fieldcallback;
    246 
    247         COMMENT("Test pb_encode with callback field.")
    248         TEST(WRITES(pb_encode(&s, CallbackArray_fields, &msg), "\x08\x55"))
    249     }
    250 
    251     {
    252         uint8_t buffer[10];
    253         pb_ostream_t s;
    254         IntegerContainer msg = {{5, {1,2,3,4,5}}};
    255 
    256         COMMENT("Test pb_encode with packed array in a submessage.")
    257         TEST(WRITES(pb_encode(&s, IntegerContainer_fields, &msg),
    258                     "\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"))
    259     }
    260 
    261     {
    262         uint8_t buffer[32];
    263         pb_ostream_t s;
    264         BytesMessage msg = {{3, "xyz"}};
    265 
    266         COMMENT("Test pb_encode with bytes message.")
    267         TEST(WRITES(pb_encode(&s, BytesMessage_fields, &msg),
    268                     "\x0A\x03xyz"))
    269 
    270         msg.data.size = 17; /* More than maximum */
    271         TEST(!pb_encode(&s, BytesMessage_fields, &msg))
    272     }
    273 
    274 
    275     {
    276         uint8_t buffer[20];
    277         pb_ostream_t s;
    278         IntegerContainer msg = {{5, {1,2,3,4,5}}};
    279 
    280         COMMENT("Test pb_encode_delimited.")
    281         TEST(WRITES(pb_encode_delimited(&s, IntegerContainer_fields, &msg),
    282                     "\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"))
    283     }
    284 
    285     {
    286         IntegerContainer msg = {{5, {1,2,3,4,5}}};
    287         size_t size;
    288 
    289         COMMENT("Test pb_get_encoded_size.")
    290         TEST(pb_get_encoded_size(&size, IntegerContainer_fields, &msg) &&
    291              size == 9);
    292     }
    293 
    294     {
    295         uint8_t buffer[10];
    296         pb_ostream_t s;
    297         CallbackContainer msg;
    298         CallbackContainerContainer msg2;
    299         uint32_t state = 1;
    300 
    301         msg.submsg.data.funcs.encode = &fieldcallback;
    302         msg2.submsg.submsg.data.funcs.encode = &fieldcallback;
    303 
    304         COMMENT("Test pb_encode with callback field in a submessage.")
    305         TEST(WRITES(pb_encode(&s, CallbackContainer_fields, &msg), "\x0A\x02\x08\x55"))
    306         TEST(WRITES(pb_encode(&s, CallbackContainerContainer_fields, &msg2),
    307                     "\x0A\x04\x0A\x02\x08\x55"))
    308 
    309         /* Misbehaving callback: varying output between calls */
    310         msg.submsg.data.funcs.encode = &crazyfieldcallback;
    311         msg.submsg.data.arg = &state;
    312         msg2.submsg.submsg.data.funcs.encode = &crazyfieldcallback;
    313         msg2.submsg.submsg.data.arg = &state;
    314 
    315         TEST(!pb_encode(&s, CallbackContainer_fields, &msg))
    316         state = 1;
    317         TEST(!pb_encode(&s, CallbackContainerContainer_fields, &msg2))
    318     }
    319 
    320     {
    321         uint8_t buffer[StringMessage_size];
    322         pb_ostream_t s;
    323         StringMessage msg = {"0123456789"};
    324 
    325         s = pb_ostream_from_buffer(buffer, sizeof(buffer));
    326 
    327         COMMENT("Test that StringMessage_size is correct")
    328 
    329         TEST(pb_encode(&s, StringMessage_fields, &msg));
    330         TEST(s.bytes_written == StringMessage_size);
    331     }
    332 
    333     if (status != 0)
    334         fprintf(stdout, "\n\nSome tests FAILED!\n");
    335 
    336     return status;
    337 }
    338