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