encode_unittests.c 15 KB

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