unit_test.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright (c) 2004-2013 Sergey Lyubka <[email protected]>
  2. // Copyright (c) 2013 Cesanta Software Limited
  3. // All rights reserved
  4. //
  5. // This library is dual-licensed: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License version 2 as
  7. // published by the Free Software Foundation. For the terms of this
  8. // license, see <http://www.gnu.org/licenses/>.
  9. //
  10. // You are free to use this library under the terms of the GNU General
  11. // Public License, but WITHOUT ANY WARRANTY; without even the implied
  12. // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. // See the GNU General Public License for more details.
  14. //
  15. // Alternatively, you can license this library under a commercial
  16. // license, as set out in <http://cesanta.com/products.html>.
  17. #include "frozen.c"
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #define FAIL(str, line) do { \
  22. printf("Fail on line %d: [%s]\n", line, str); \
  23. return str; \
  24. } while (0)
  25. #define ASSERT(expr) do { \
  26. static_num_tests++; \
  27. if (!(expr)) FAIL(#expr, __LINE__); \
  28. } while (0)
  29. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  30. #define RUN_TEST(test) do { const char *msg = test(); \
  31. if (msg) return msg; } while (0)
  32. static int static_num_tests = 0;
  33. static int cmp_token(const struct json_token *tok, const char *str, int type) {
  34. #if 0
  35. printf("[%.*s] [%s]\n", tok->len, tok->ptr, str);
  36. #endif
  37. return tok->type == type && (int) strlen(str) == tok->len &&
  38. memcmp(tok->ptr, str, tok->len) == 0;
  39. }
  40. static const char *test_errors(void) {
  41. struct json_token ar[100];
  42. int size = ARRAY_SIZE(ar);
  43. static const char *invalid_tests[] = {
  44. "1", "a:3", "\x01", "{:", " { 1", "{a:\"\n\"}",
  45. NULL
  46. };
  47. static const char *incomplete_tests[] = {
  48. "", " \r\n\t", "{", " { a", "{a:", "{a:\"", " { a : \"xx", "{a:12",
  49. NULL
  50. };
  51. static const struct { const char *str; int expected_len; } success_tests[] = {
  52. { "{}", 2 },
  53. { " { } ", 4 },
  54. { "{a:1}", 5 },
  55. { "{a:1}", 5 },
  56. { "{a:\"\"}", 6 },
  57. { "{a:\" \\n\\t\\r\"}", 13 },
  58. { " {a:[1]} 123456", 8 },
  59. { " {a:[]} 123456", 7 },
  60. { " {a:[1,2]} 123456", 10 },
  61. { "{a:1,b:2} xxxx", 9 },
  62. { "{a:1,b:{},c:[{}]} xxxx", 17 },
  63. { "{a:true,b:[false,null]} xxxx", 23 },
  64. { NULL, 0 }
  65. };
  66. const char *s1 = " { a: 1, b: \"hi there\", c: true, d: false, "
  67. " e : null, f: [ 1, -2, 3], g: { \"1\": [], h: [ 7 ] } } ";
  68. int i;
  69. ASSERT(parse_json(NULL, 0, NULL, 0) == JSON_STRING_INVALID);
  70. for (i = 0; invalid_tests[i] != NULL; i++) {
  71. ASSERT(parse_json(invalid_tests[i], strlen(invalid_tests[i]),
  72. ar, size) == JSON_STRING_INVALID);
  73. }
  74. for (i = 0; incomplete_tests[i] != NULL; i++) {
  75. ASSERT(parse_json(incomplete_tests[i], strlen(incomplete_tests[i]),
  76. ar, size) == JSON_STRING_INCOMPLETE);
  77. }
  78. for (i = 0; success_tests[i].str != NULL; i++) {
  79. ASSERT(parse_json(success_tests[i].str, strlen(success_tests[i].str),
  80. ar, size) == success_tests[i].expected_len);
  81. }
  82. ASSERT(parse_json("{}", 2, ar, 1) == JSON_TOKEN_ARRAY_TOO_SMALL);
  83. ASSERT(parse_json("{}", 2, ar, 2) == 2);
  84. ASSERT(cmp_token(&ar[0], "{}", JSON_TYPE_OBJECT));
  85. ASSERT(ar[1].type == JSON_TYPE_EOF);
  86. ASSERT(parse_json(s1, strlen(s1), NULL, 0) > 0);
  87. ASSERT(parse_json(s1, strlen(s1), ar, 10) == JSON_TOKEN_ARRAY_TOO_SMALL);
  88. ASSERT(parse_json(s1, strlen(s1), ar, size) > 0);
  89. ASSERT(cmp_token(&ar[0], "{ a: 1, b: \"hi there\", c: true, d: false, "
  90. " e : null, f: [ 1, -2, 3], g: { \"1\": [], h: [ 7 ] } }",
  91. JSON_TYPE_OBJECT));
  92. ASSERT(cmp_token(&ar[1], "a", JSON_TYPE_STRING));
  93. ASSERT(cmp_token(&ar[2], "1", JSON_TYPE_NUMBER));
  94. ASSERT(cmp_token(&ar[3], "b", JSON_TYPE_STRING));
  95. ASSERT(cmp_token(&ar[4], "hi there", JSON_TYPE_STRING));
  96. ASSERT(cmp_token(&ar[5], "c", JSON_TYPE_STRING));
  97. ASSERT(cmp_token(&ar[6], "true", JSON_TYPE_TRUE));
  98. ASSERT(cmp_token(&ar[7], "d", JSON_TYPE_STRING));
  99. ASSERT(cmp_token(&ar[8], "false", JSON_TYPE_FALSE));
  100. ASSERT(cmp_token(&ar[9], "e", JSON_TYPE_STRING));
  101. ASSERT(cmp_token(&ar[10], "null", JSON_TYPE_NULL));
  102. ASSERT(cmp_token(&ar[11], "f", JSON_TYPE_STRING));
  103. ASSERT(cmp_token(&ar[12], "[ 1, -2, 3]", JSON_TYPE_ARRAY));
  104. ASSERT(cmp_token(&ar[13], "1", JSON_TYPE_NUMBER));
  105. ASSERT(cmp_token(&ar[14], "-2", JSON_TYPE_NUMBER));
  106. ASSERT(cmp_token(&ar[15], "3", JSON_TYPE_NUMBER));
  107. ASSERT(cmp_token(&ar[16], "g", JSON_TYPE_STRING));
  108. ASSERT(cmp_token(&ar[17], "{ \"1\": [], h: [ 7 ] }" , JSON_TYPE_OBJECT));
  109. ASSERT(cmp_token(&ar[18], "1", JSON_TYPE_STRING));
  110. ASSERT(cmp_token(&ar[19], "[]", JSON_TYPE_ARRAY));
  111. ASSERT(cmp_token(&ar[20], "h", JSON_TYPE_STRING));
  112. ASSERT(cmp_token(&ar[21], "[ 7 ]", JSON_TYPE_ARRAY));
  113. ASSERT(cmp_token(&ar[22], "7", JSON_TYPE_NUMBER));
  114. ASSERT(ar[23].type == JSON_TYPE_EOF);
  115. ASSERT(find_json_token(ar, "a") == &ar[2]);
  116. ASSERT(find_json_token(ar, "f") == &ar[12]);
  117. ASSERT(find_json_token(ar, "g.h") == &ar[21]);
  118. ASSERT(find_json_token(ar, "g.h[0]") == &ar[22]);
  119. ASSERT(find_json_token(ar, "g.h[1]") == NULL);
  120. ASSERT(find_json_token(ar, "g.h1") == NULL);
  121. return NULL;
  122. }
  123. static const char *test_config(void) {
  124. static const char *config_str = "{ ports: [ 80, 443 ] } ";
  125. struct json_token tokens[100];
  126. int tokens_size = sizeof(tokens) / sizeof(tokens[0]);
  127. ASSERT(parse_json(config_str, strlen(config_str), tokens, tokens_size) > 0);
  128. ASSERT(tokens[0].type == JSON_TYPE_OBJECT);
  129. ASSERT(tokens[1].type == JSON_TYPE_STRING);
  130. ASSERT(tokens[2].type == JSON_TYPE_ARRAY);
  131. ASSERT(tokens[3].type == JSON_TYPE_NUMBER);
  132. ASSERT(tokens[4].type == JSON_TYPE_NUMBER);
  133. ASSERT(tokens[5].type == JSON_TYPE_EOF);
  134. ASSERT(find_json_token(tokens, "ports") == &tokens[2]);
  135. ASSERT(find_json_token(tokens, "ports[0]") == &tokens[3]);
  136. ASSERT(find_json_token(tokens, "ports[1]") == &tokens[4]);
  137. ASSERT(find_json_token(tokens, "ports[3]") == NULL);
  138. ASSERT(find_json_token(tokens, "foo.bar") == NULL);
  139. return NULL;
  140. }
  141. static const char *run_all_tests(void) {
  142. RUN_TEST(test_errors);
  143. RUN_TEST(test_config);
  144. return NULL;
  145. }
  146. int main(void) {
  147. const char *fail_msg = run_all_tests();
  148. printf("%s, tests run: %d\n", fail_msg ? "FAIL" : "PASS", static_num_tests);
  149. return fail_msg == NULL ? EXIT_SUCCESS : EXIT_FAILURE;
  150. }