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