unit_test.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * Copyright (c) 2004-2013 Sergey Lyubka <[email protected]>
  3. * Copyright (c) 2013 Cesanta Software Limited
  4. * All rights reserved
  5. *
  6. * This library is dual-licensed: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation. For the terms of this
  9. * license, see <http: *www.gnu.org/licenses/>.
  10. *
  11. * You are free to use this library under the terms of the GNU General
  12. * Public License, but WITHOUT ANY WARRANTY; without even the implied
  13. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. * See the GNU General Public License for more details.
  15. *
  16. * Alternatively, you can license this library under a commercial
  17. * license, as set out in <http://cesanta.com/products.html>.
  18. */
  19. /*
  20. * To unit test on Mac system, do
  21. *
  22. * g++ unit_test.c -o unit_test -W -Wall -g -O0 -fprofile-arcs -ftest-coverage
  23. * clang unit_test.c -o unit_test -W -Wall -g -O0 -fprofile-arcs -ftest-coverage
  24. * ./unit_test
  25. * gcov -a unit_test.c
  26. */
  27. #include "frozen.c"
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #define FAIL(str, line) do { \
  32. printf("Fail on line %d: [%s]\n", line, str); \
  33. return str; \
  34. } while (0)
  35. #define ASSERT(expr) do { \
  36. static_num_tests++; \
  37. if (!(expr)) FAIL(#expr, __LINE__); \
  38. } while (0)
  39. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  40. #define RUN_TEST(test) do { const char *msg = test(); \
  41. if (msg) return msg; } while (0)
  42. static int static_num_tests = 0;
  43. static int cmp_token(const struct json_token *tok, const char *str, int type) {
  44. #if 0
  45. printf("[%.*s] [%s]\n", tok->len, tok->ptr, str);
  46. #endif
  47. return tok->type == type && (int) strlen(str) == tok->len &&
  48. memcmp(tok->ptr, str, tok->len) == 0;
  49. }
  50. static const char *test_errors(void) {
  51. struct json_token ar[100];
  52. int size = ARRAY_SIZE(ar);
  53. static const char *invalid_tests[] = {
  54. "1", "a:3", "\x01", "{:", " { 1", "{a:\"\n\"}", "{a:1x}", "{a:1e}",
  55. "{a:.1}", "{a:0.}", "{a:0.e}", "{a:0.e1}", "{a:0.1e}", "{a:\"\\u\" } ",
  56. "{a:\"\\yx\"}", "{a:\"\\u111r\"}",
  57. NULL
  58. };
  59. static const char *incomplete_tests[] = {
  60. "", " \r\n\t", "{", " { a", "{a:", "{a:\"", " { a : \"xx", "{a:12",
  61. "{a:\"\\uf", "{a:\"\\uff", "{a:\"\\ufff", "{a:\"\\uffff",
  62. "{a:\"\\uffff\"", "{a:\"\\uffff\" ,", "{a:n", "{a:nu", "{a:nul", "{a:null",
  63. NULL
  64. };
  65. static const struct { const char *str; int expected_len; } success_tests[] = {
  66. { "{}", 2 },
  67. /* 2, 3, 4 byte utf-8 chars */
  68. { "{a:\"\xd0\xb1\xe3\x81\xaf\xf0\xa2\xb3\x82\"}", 15 },
  69. { "{a:\"\\u0006\"}", 12 },
  70. { " { } ", 4 },
  71. { "{a:1}", 5 },
  72. { "{a:1.23}", 8 },
  73. { "{a:1e23}", 8 },
  74. { "{a:1.23e2}", 10 },
  75. { "{a:-123}", 8 },
  76. { "{a:-1.3}", 8 },
  77. { "{a:-1.3e-2}", 11},
  78. { "{a:\"\"}", 6 },
  79. { "{a:\" \\n\\t\\r\"}", 13 },
  80. { " {a:[1]} 123456", 8 },
  81. { " {a:[]} 123456", 7 },
  82. { " {a:[1,2]} 123456", 10 },
  83. { "{a:1,b:2} xxxx", 9 },
  84. { "{a:1,b:{},c:[{}]} xxxx", 17 },
  85. { "{a:true,b:[false,null]} xxxx", 23 },
  86. { NULL, 0 }
  87. };
  88. const char *s1 = " { a: 1, b: \"hi there\", c: true, d: false, "
  89. " e : null, f: [ 1, -2, 3], g: { \"1\": [], h: [ 7 ] } } ";
  90. const char *s2 = "{ a: 1, b: \"hi there\", c: true, d: false, "
  91. " e : null, f: [ 1, -2, 3], g: { \"1\": [], h: [ 7 ] } }";
  92. const char *s3 = "{ \"1\": [], h: [ 7 ] }";
  93. int i;
  94. ASSERT(parse_json(NULL, 0, NULL, 0) == JSON_STRING_INVALID);
  95. for (i = 0; invalid_tests[i] != NULL; i++) {
  96. ASSERT(parse_json(invalid_tests[i], strlen(invalid_tests[i]),
  97. ar, size) == JSON_STRING_INVALID);
  98. }
  99. for (i = 0; incomplete_tests[i] != NULL; i++) {
  100. ASSERT(parse_json(incomplete_tests[i], strlen(incomplete_tests[i]),
  101. ar, size) == JSON_STRING_INCOMPLETE);
  102. }
  103. for (i = 0; success_tests[i].str != NULL; i++) {
  104. ASSERT(parse_json(success_tests[i].str, strlen(success_tests[i].str),
  105. ar, size) == success_tests[i].expected_len);
  106. }
  107. ASSERT(parse_json("{}", 2, ar, 1) == JSON_TOKEN_ARRAY_TOO_SMALL);
  108. ASSERT(parse_json("{}", 2, ar, 2) == 2);
  109. ASSERT(cmp_token(&ar[0], "{}", JSON_TYPE_OBJECT));
  110. ASSERT(ar[1].type == JSON_TYPE_EOF);
  111. ASSERT(parse_json(s1, strlen(s1), NULL, 0) > 0);
  112. ASSERT(parse_json(s1, strlen(s1), ar, 10) == JSON_TOKEN_ARRAY_TOO_SMALL);
  113. ASSERT(parse_json(s1, strlen(s1), ar, size) > 0);
  114. ASSERT(cmp_token(&ar[0], s2, JSON_TYPE_OBJECT));
  115. ASSERT(cmp_token(&ar[1], "a", JSON_TYPE_STRING));
  116. ASSERT(cmp_token(&ar[2], "1", JSON_TYPE_NUMBER));
  117. ASSERT(cmp_token(&ar[3], "b", JSON_TYPE_STRING));
  118. ASSERT(cmp_token(&ar[4], "hi there", JSON_TYPE_STRING));
  119. ASSERT(cmp_token(&ar[5], "c", JSON_TYPE_STRING));
  120. ASSERT(cmp_token(&ar[6], "true", JSON_TYPE_TRUE));
  121. ASSERT(cmp_token(&ar[7], "d", JSON_TYPE_STRING));
  122. ASSERT(cmp_token(&ar[8], "false", JSON_TYPE_FALSE));
  123. ASSERT(cmp_token(&ar[9], "e", JSON_TYPE_STRING));
  124. ASSERT(cmp_token(&ar[10], "null", JSON_TYPE_NULL));
  125. ASSERT(cmp_token(&ar[11], "f", JSON_TYPE_STRING));
  126. ASSERT(cmp_token(&ar[12], "[ 1, -2, 3]", JSON_TYPE_ARRAY));
  127. ASSERT(cmp_token(&ar[13], "1", JSON_TYPE_NUMBER));
  128. ASSERT(cmp_token(&ar[14], "-2", JSON_TYPE_NUMBER));
  129. ASSERT(cmp_token(&ar[15], "3", JSON_TYPE_NUMBER));
  130. ASSERT(cmp_token(&ar[16], "g", JSON_TYPE_STRING));
  131. ASSERT(cmp_token(&ar[17], s3, JSON_TYPE_OBJECT));
  132. ASSERT(cmp_token(&ar[18], "1", JSON_TYPE_STRING));
  133. ASSERT(cmp_token(&ar[19], "[]", JSON_TYPE_ARRAY));
  134. ASSERT(cmp_token(&ar[20], "h", JSON_TYPE_STRING));
  135. ASSERT(cmp_token(&ar[21], "[ 7 ]", JSON_TYPE_ARRAY));
  136. ASSERT(cmp_token(&ar[22], "7", JSON_TYPE_NUMBER));
  137. ASSERT(ar[23].type == JSON_TYPE_EOF);
  138. ASSERT(find_json_token(ar, "a") == &ar[2]);
  139. ASSERT(find_json_token(ar, "f") == &ar[12]);
  140. ASSERT(find_json_token(ar, "g.h") == &ar[21]);
  141. ASSERT(find_json_token(ar, "g.h[0]") == &ar[22]);
  142. ASSERT(find_json_token(ar, "g.h[1]") == NULL);
  143. ASSERT(find_json_token(ar, "g.h1") == NULL);
  144. ASSERT(find_json_token(ar, "") == NULL);
  145. ASSERT(find_json_token(ar, NULL) == NULL);
  146. return NULL;
  147. }
  148. static const char *test_config(void) {
  149. static const char *config_str = "{ ports: [ 80, 443 ] } ";
  150. struct json_token tokens[100];
  151. int tokens_size = sizeof(tokens) / sizeof(tokens[0]);
  152. ASSERT(parse_json(config_str, strlen(config_str), tokens, tokens_size) > 0);
  153. ASSERT(tokens[0].type == JSON_TYPE_OBJECT);
  154. ASSERT(tokens[1].type == JSON_TYPE_STRING);
  155. ASSERT(tokens[2].type == JSON_TYPE_ARRAY);
  156. ASSERT(tokens[3].type == JSON_TYPE_NUMBER);
  157. ASSERT(tokens[4].type == JSON_TYPE_NUMBER);
  158. ASSERT(tokens[5].type == JSON_TYPE_EOF);
  159. ASSERT(find_json_token(tokens, "ports") == &tokens[2]);
  160. ASSERT(find_json_token(tokens, "ports[0]") == &tokens[3]);
  161. ASSERT(find_json_token(tokens, "ports[1]") == &tokens[4]);
  162. ASSERT(find_json_token(tokens, "ports[3]") == NULL);
  163. ASSERT(find_json_token(tokens, "foo.bar") == NULL);
  164. return NULL;
  165. }
  166. static const char *test_emit_overflow(void) {
  167. char buf[1000];
  168. memset(buf, 0, sizeof(buf));
  169. ASSERT(json_emit_unquoted_str(buf, 0, "hi", 2) == 2);
  170. ASSERT(json_emit_quoted_str(buf, 0, "hi", 2) == 4);
  171. ASSERT(buf[0] == '\0');
  172. return NULL;
  173. }
  174. static const char *test_emit_escapes(void) {
  175. const char *s4 = "\"\\\"\\\\\\b\\f\\n\\r\\t\"";
  176. char buf[1000];
  177. ASSERT(json_emit_quoted_str(buf, sizeof(buf), "\"\\\b\f\n\r\t", 7) > 0);
  178. ASSERT(strcmp(buf, s4) == 0);
  179. return NULL;
  180. }
  181. static const char *test_emit(void) {
  182. char buf[1000], *p = buf;
  183. const char *s5 = "{\"foo\":[-123,1.23,true]}";
  184. const char *s6 = "{\"foo\":[-7,true, false,null]}";
  185. p += json_emit_unquoted_str(p, &buf[sizeof(buf)] - p, "{", 1);
  186. p += json_emit_quoted_str(p, &buf[sizeof(buf)] - p, "foo", 3);
  187. p += json_emit_unquoted_str(p, &buf[sizeof(buf)] - p, ":[", 2);
  188. p += json_emit_long(p, &buf[sizeof(buf)] - p, -123);
  189. p += json_emit_unquoted_str(p, &buf[sizeof(buf)] - p, ",", 1);
  190. p += json_emit_double(p, &buf[sizeof(buf)] - p, 1.23);
  191. p += json_emit_unquoted_str(p, &buf[sizeof(buf)] - p, ",", 1);
  192. p += json_emit_unquoted_str(p, &buf[sizeof(buf)] - p, "true", 4);
  193. p += json_emit_unquoted_str(p, &buf[sizeof(buf)] - p, "]}", 2);
  194. ASSERT(strcmp(buf, s5) == 0);
  195. ASSERT(p < &buf[sizeof(buf)]);
  196. ASSERT(json_emit(buf, sizeof(buf), "{v:[i,f,V]}",
  197. "foo", 3, (long) -123, 1.23, "true", 4) > 0);
  198. ASSERT(strcmp(buf, s5) == 0);
  199. ASSERT(json_emit(buf, 4, "{S:i}", "a", 12345) > 4);
  200. ASSERT(json_emit(buf, sizeof(buf), "{S:d}", "a", 12345) == 0);
  201. ASSERT(json_emit(buf, sizeof(buf), "{s:[i,T, F,N]}", "foo", (long) -7) > 0);
  202. ASSERT(strcmp(buf, s6) == 0);
  203. return NULL;
  204. }
  205. static const char *test_nested(void) {
  206. struct json_token ar[100];
  207. const char *s = "{ a : [ [1, 2, { b : 2 } ] ] }";
  208. enum json_type types[] = {
  209. JSON_TYPE_OBJECT, JSON_TYPE_STRING, JSON_TYPE_ARRAY, JSON_TYPE_ARRAY,
  210. JSON_TYPE_NUMBER, JSON_TYPE_NUMBER, JSON_TYPE_OBJECT, JSON_TYPE_STRING,
  211. JSON_TYPE_NUMBER, JSON_TYPE_EOF
  212. };
  213. int i, ar_size = ARRAY_SIZE(ar), types_size = ARRAY_SIZE(types);
  214. ASSERT(parse_json(s, strlen(s), ar, ar_size) == (int) strlen(s));
  215. for (i = 0; i < types_size; i++) {
  216. ASSERT(ar[i].type == types[i]);
  217. }
  218. ASSERT(find_json_token(ar, "a[0]") == &ar[3]);
  219. ASSERT(find_json_token(ar, "a[0][0]") == &ar[4]);
  220. ASSERT(find_json_token(ar, "a[0][1]") == &ar[5]);
  221. ASSERT(find_json_token(ar, "a[0][2]") == &ar[6]);
  222. ASSERT(find_json_token(ar, "a[0][2].b") == &ar[8]);
  223. return NULL;
  224. }
  225. static const char *test_realloc(void) {
  226. struct json_token *p;
  227. ASSERT(parse_json2("{ foo: 2 }", 2) == NULL);
  228. ASSERT((p = parse_json2("{ foo: 2 }", 10)) != NULL);
  229. free(p);
  230. return NULL;
  231. }
  232. static const char *run_all_tests(void) {
  233. RUN_TEST(test_errors);
  234. RUN_TEST(test_config);
  235. RUN_TEST(test_emit);
  236. RUN_TEST(test_emit_escapes);
  237. RUN_TEST(test_emit_overflow);
  238. RUN_TEST(test_nested);
  239. RUN_TEST(test_realloc);
  240. return NULL;
  241. }
  242. int main(void) {
  243. const char *fail_msg = run_all_tests();
  244. printf("%s, tests run: %d\n", fail_msg ? "FAIL" : "PASS", static_num_tests);
  245. return fail_msg == NULL ? EXIT_SUCCESS : EXIT_FAILURE;
  246. }