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 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 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 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 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[30]; 90 pb_ostream_t s; 91 92 COMMENT("Test pb_encode_tag") 93 TEST(WRITES(pb_encode_tag(&s, PB_WT_STRING, 5), "\x2A")); 94 TEST(WRITES(pb_encode_tag(&s, PB_WT_VARINT, 99), "\x98\x06")); 95 } 96 97 { 98 uint8_t buffer[30]; 99 pb_ostream_t s; 100 pb_field_t field = {10, PB_LTYPE_SVARINT}; 101 102 COMMENT("Test pb_encode_tag_for_field") 103 TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x50")); 104 105 field.type = PB_LTYPE_FIXED64; 106 TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x51")); 107 108 field.type = PB_LTYPE_STRING; 109 TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x52")); 110 111 field.type = PB_LTYPE_FIXED32; 112 TEST(WRITES(pb_encode_tag_for_field(&s, &field), "\x55")); 113 } 114 115 { 116 uint8_t buffer[30]; 117 pb_ostream_t s; 118 119 COMMENT("Test pb_encode_string") 120 TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"abcd", 4), "\x04""abcd")); 121 TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"abcd\x00", 5), "\x05""abcd\x00")); 122 TEST(WRITES(pb_encode_string(&s, (const uint8_t*)"", 0), "\x00")); 123 } 124 125 { 126 uint8_t buffer[30]; 127 pb_ostream_t s; 128 uint8_t value = 1; 129 int32_t max = INT32_MAX; 130 int32_t min = INT32_MIN; 131 int64_t lmax = INT64_MAX; 132 int64_t lmin = INT64_MIN; 133 pb_field_t field = {1, PB_LTYPE_VARINT, 0, 0, sizeof(value)}; 134 135 COMMENT("Test pb_enc_varint and pb_enc_svarint") 136 TEST(WRITES(pb_enc_varint(&s, &field, &value), "\x01")); 137 138 field.data_size = sizeof(max); 139 TEST(WRITES(pb_enc_svarint(&s, &field, &max), "\xfe\xff\xff\xff\x0f")); 140 TEST(WRITES(pb_enc_svarint(&s, &field, &min), "\xff\xff\xff\xff\x0f")); 141 142 field.data_size = sizeof(lmax); 143 TEST(WRITES(pb_enc_svarint(&s, &field, &lmax), "\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01")); 144 TEST(WRITES(pb_enc_svarint(&s, &field, &lmin), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01")); 145 } 146 147 { 148 uint8_t buffer[30]; 149 pb_ostream_t s; 150 float fvalue; 151 double dvalue; 152 153 COMMENT("Test pb_enc_fixed32 using float") 154 fvalue = 0.0f; 155 TEST(WRITES(pb_enc_fixed32(&s, NULL, &fvalue), "\x00\x00\x00\x00")) 156 fvalue = 99.0f; 157 TEST(WRITES(pb_enc_fixed32(&s, NULL, &fvalue), "\x00\x00\xc6\x42")) 158 fvalue = -12345678.0f; 159 TEST(WRITES(pb_enc_fixed32(&s, NULL, &fvalue), "\x4e\x61\x3c\xcb")) 160 161 COMMENT("Test pb_enc_fixed64 using double") 162 dvalue = 0.0; 163 TEST(WRITES(pb_enc_fixed64(&s, NULL, &dvalue), "\x00\x00\x00\x00\x00\x00\x00\x00")) 164 dvalue = 99.0; 165 TEST(WRITES(pb_enc_fixed64(&s, NULL, &dvalue), "\x00\x00\x00\x00\x00\xc0\x58\x40")) 166 dvalue = -12345678.0; 167 TEST(WRITES(pb_enc_fixed64(&s, NULL, &dvalue), "\x00\x00\x00\xc0\x29\x8c\x67\xc1")) 168 } 169 170 { 171 uint8_t buffer[30]; 172 pb_ostream_t s; 173 struct { pb_size_t size; uint8_t bytes[5]; } value = {5, {'x', 'y', 'z', 'z', 'y'}}; 174 175 COMMENT("Test pb_enc_bytes") 176 TEST(WRITES(pb_enc_bytes(&s, &BytesMessage_fields[0], &value), "\x05xyzzy")) 177 value.size = 0; 178 TEST(WRITES(pb_enc_bytes(&s, &BytesMessage_fields[0], &value), "\x00")) 179 } 180 181 { 182 uint8_t buffer[30]; 183 pb_ostream_t s; 184 char value[30] = "xyzzy"; 185 186 COMMENT("Test pb_enc_string") 187 TEST(WRITES(pb_enc_string(&s, &StringMessage_fields[0], &value), "\x05xyzzy")) 188 value[0] = '\0'; 189 TEST(WRITES(pb_enc_string(&s, &StringMessage_fields[0], &value), "\x00")) 190 memset(value, 'x', 30); 191 TEST(WRITES(pb_enc_string(&s, &StringMessage_fields[0], &value), "\x0Axxxxxxxxxx")) 192 } 193 194 { 195 uint8_t buffer[10]; 196 pb_ostream_t s; 197 IntegerArray msg = {5, {1, 2, 3, 4, 5}}; 198 199 COMMENT("Test pb_encode with int32 array") 200 201 TEST(WRITES(pb_encode(&s, IntegerArray_fields, &msg), "\x0A\x05\x01\x02\x03\x04\x05")) 202 203 msg.data_count = 0; 204 TEST(WRITES(pb_encode(&s, IntegerArray_fields, &msg), "")) 205 206 msg.data_count = 10; 207 TEST(!pb_encode(&s, IntegerArray_fields, &msg)) 208 } 209 210 { 211 uint8_t buffer[10]; 212 pb_ostream_t s; 213 FloatArray msg = {1, {99.0f}}; 214 215 COMMENT("Test pb_encode with float array") 216 217 TEST(WRITES(pb_encode(&s, FloatArray_fields, &msg), 218 "\x0A\x04\x00\x00\xc6\x42")) 219 220 msg.data_count = 0; 221 TEST(WRITES(pb_encode(&s, FloatArray_fields, &msg), "")) 222 223 msg.data_count = 3; 224 TEST(!pb_encode(&s, FloatArray_fields, &msg)) 225 } 226 227 { 228 uint8_t buffer[50]; 229 pb_ostream_t s; 230 FloatArray msg = {1, {99.0f}}; 231 232 COMMENT("Test array size limit in pb_encode") 233 234 s = pb_ostream_from_buffer(buffer, sizeof(buffer)); 235 TEST((msg.data_count = 10) && pb_encode(&s, FloatArray_fields, &msg)) 236 237 s = pb_ostream_from_buffer(buffer, sizeof(buffer)); 238 TEST((msg.data_count = 11) && !pb_encode(&s, FloatArray_fields, &msg)) 239 } 240 241 { 242 uint8_t buffer[10]; 243 pb_ostream_t s; 244 CallbackArray msg; 245 246 msg.data.funcs.encode = &fieldcallback; 247 248 COMMENT("Test pb_encode with callback field.") 249 TEST(WRITES(pb_encode(&s, CallbackArray_fields, &msg), "\x08\x55")) 250 } 251 252 { 253 uint8_t buffer[10]; 254 pb_ostream_t s; 255 IntegerContainer msg = {{5, {1,2,3,4,5}}}; 256 257 COMMENT("Test pb_encode with packed array in a submessage.") 258 TEST(WRITES(pb_encode(&s, IntegerContainer_fields, &msg), 259 "\x0A\x07\x0A\x05\x01\x02\x03\x04\x05")) 260 } 261 262 { 263 uint8_t buffer[32]; 264 pb_ostream_t s; 265 BytesMessage msg = {{3, "xyz"}}; 266 267 COMMENT("Test pb_encode with bytes message.") 268 TEST(WRITES(pb_encode(&s, BytesMessage_fields, &msg), 269 "\x0A\x03xyz")) 270 271 msg.data.size = 17; /* More than maximum */ 272 TEST(!pb_encode(&s, BytesMessage_fields, &msg)) 273 } 274 275 276 { 277 uint8_t buffer[20]; 278 pb_ostream_t s; 279 IntegerContainer msg = {{5, {1,2,3,4,5}}}; 280 281 COMMENT("Test pb_encode_delimited.") 282 TEST(WRITES(pb_encode_delimited(&s, IntegerContainer_fields, &msg), 283 "\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05")) 284 } 285 286 { 287 IntegerContainer msg = {{5, {1,2,3,4,5}}}; 288 size_t size; 289 290 COMMENT("Test pb_get_encoded_size.") 291 TEST(pb_get_encoded_size(&size, IntegerContainer_fields, &msg) && 292 size == 9); 293 } 294 295 { 296 uint8_t buffer[10]; 297 pb_ostream_t s; 298 CallbackContainer msg; 299 CallbackContainerContainer msg2; 300 uint32_t state = 1; 301 302 msg.submsg.data.funcs.encode = &fieldcallback; 303 msg2.submsg.submsg.data.funcs.encode = &fieldcallback; 304 305 COMMENT("Test pb_encode with callback field in a submessage.") 306 TEST(WRITES(pb_encode(&s, CallbackContainer_fields, &msg), "\x0A\x02\x08\x55")) 307 TEST(WRITES(pb_encode(&s, CallbackContainerContainer_fields, &msg2), 308 "\x0A\x04\x0A\x02\x08\x55")) 309 310 /* Misbehaving callback: varying output between calls */ 311 msg.submsg.data.funcs.encode = &crazyfieldcallback; 312 msg.submsg.data.arg = &state; 313 msg2.submsg.submsg.data.funcs.encode = &crazyfieldcallback; 314 msg2.submsg.submsg.data.arg = &state; 315 316 TEST(!pb_encode(&s, CallbackContainer_fields, &msg)) 317 state = 1; 318 TEST(!pb_encode(&s, CallbackContainerContainer_fields, &msg2)) 319 } 320 321 { 322 uint8_t buffer[StringMessage_size]; 323 pb_ostream_t s; 324 StringMessage msg = {"0123456789"}; 325 326 s = pb_ostream_from_buffer(buffer, sizeof(buffer)); 327 328 COMMENT("Test that StringMessage_size is correct") 329 330 TEST(pb_encode(&s, StringMessage_fields, &msg)); 331 TEST(s.bytes_written == StringMessage_size); 332 } 333 334 { 335 uint8_t buffer[128]; 336 pb_ostream_t s; 337 StringPointerContainer msg = StringPointerContainer_init_zero; 338 char *strs[1] = {NULL}; 339 char zstr[] = "Z"; 340 341 COMMENT("Test string pointer encoding."); 342 343 msg.rep_str = strs; 344 msg.rep_str_count = 1; 345 TEST(WRITES(pb_encode(&s, StringPointerContainer_fields, &msg), "\x0a\x00")) 346 347 strs[0] = zstr; 348 TEST(WRITES(pb_encode(&s, StringPointerContainer_fields, &msg), "\x0a\x01Z")) 349 } 350 351 if (status != 0) 352 fprintf(stdout, "\n\nSome tests FAILED!\n"); 353 354 return status; 355 } 356