test_dump.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
  3. *
  4. * Jansson is free software; you can redistribute it and/or modify
  5. * it under the terms of the MIT license. See LICENSE for details.
  6. */
  7. #include "jansson_private_config.h"
  8. #include <jansson.h>
  9. #include <string.h>
  10. #ifdef HAVE_UNISTD_H
  11. #include <unistd.h>
  12. #endif
  13. #include "util.h"
  14. #ifdef __MINGW32__
  15. #include <fcntl.h>
  16. #define pipe(fds) _pipe(fds, 1024, _O_BINARY)
  17. #endif
  18. static int encode_null_callback(const char *buffer, size_t size, void *data) {
  19. (void)buffer;
  20. (void)size;
  21. (void)data;
  22. return 0;
  23. }
  24. static void encode_null() {
  25. if (json_dumps(NULL, JSON_ENCODE_ANY) != NULL)
  26. fail("json_dumps didn't fail for NULL");
  27. if (json_dumpb(NULL, NULL, 0, JSON_ENCODE_ANY) != 0)
  28. fail("json_dumpb didn't fail for NULL");
  29. if (json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1)
  30. fail("json_dumpf didn't fail for NULL");
  31. #ifdef HAVE_UNISTD_H
  32. if (json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1)
  33. fail("json_dumpfd didn't fail for NULL");
  34. #endif
  35. /* Don't test json_dump_file to avoid creating a file */
  36. if (json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1)
  37. fail("json_dump_callback didn't fail for NULL");
  38. }
  39. static void encode_twice() {
  40. /* Encode an empty object/array, add an item, encode again */
  41. json_t *json;
  42. char *result;
  43. json = json_object();
  44. result = json_dumps(json, 0);
  45. if (!result || strcmp(result, "{}"))
  46. fail("json_dumps failed");
  47. free(result);
  48. json_object_set_new(json, "foo", json_integer(5));
  49. result = json_dumps(json, 0);
  50. if (!result || strcmp(result, "{\"foo\": 5}"))
  51. fail("json_dumps failed");
  52. free(result);
  53. json_decref(json);
  54. json = json_array();
  55. result = json_dumps(json, 0);
  56. if (!result || strcmp(result, "[]"))
  57. fail("json_dumps failed");
  58. free(result);
  59. json_array_append_new(json, json_integer(5));
  60. result = json_dumps(json, 0);
  61. if (!result || strcmp(result, "[5]"))
  62. fail("json_dumps failed");
  63. free(result);
  64. json_decref(json);
  65. }
  66. static void circular_references() {
  67. /* Construct a JSON object/array with a circular reference:
  68. object: {"a": {"b": {"c": <circular reference to $.a>}}}
  69. array: [[[<circular reference to the $[0] array>]]]
  70. Encode it, remove the circular reference and encode again.
  71. */
  72. json_t *json;
  73. char *result;
  74. json = json_object();
  75. json_object_set_new(json, "a", json_object());
  76. json_object_set_new(json_object_get(json, "a"), "b", json_object());
  77. json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
  78. json_object_get(json, "a"));
  79. if (json_dumps(json, 0))
  80. fail("json_dumps encoded a circular reference!");
  81. json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
  82. result = json_dumps(json, 0);
  83. if (!result || strcmp(result, "{\"a\": {\"b\": {}}}"))
  84. fail("json_dumps failed!");
  85. free(result);
  86. json_decref(json);
  87. json = json_array();
  88. json_array_append_new(json, json_array());
  89. json_array_append_new(json_array_get(json, 0), json_array());
  90. json_array_append(json_array_get(json_array_get(json, 0), 0),
  91. json_array_get(json, 0));
  92. if (json_dumps(json, 0))
  93. fail("json_dumps encoded a circular reference!");
  94. json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
  95. result = json_dumps(json, 0);
  96. if (!result || strcmp(result, "[[[]]]"))
  97. fail("json_dumps failed!");
  98. free(result);
  99. json_decref(json);
  100. }
  101. static void encode_other_than_array_or_object() {
  102. /* Encoding anything other than array or object should only
  103. * succeed if the JSON_ENCODE_ANY flag is used */
  104. json_t *json;
  105. char *result;
  106. json = json_string("foo");
  107. if (json_dumps(json, 0) != NULL)
  108. fail("json_dumps encoded a string!");
  109. if (json_dumpf(json, NULL, 0) == 0)
  110. fail("json_dumpf encoded a string!");
  111. if (json_dumpfd(json, -1, 0) == 0)
  112. fail("json_dumpfd encoded a string!");
  113. result = json_dumps(json, JSON_ENCODE_ANY);
  114. if (!result || strcmp(result, "\"foo\"") != 0)
  115. fail("json_dumps failed to encode a string with JSON_ENCODE_ANY");
  116. free(result);
  117. json_decref(json);
  118. json = json_integer(42);
  119. if (json_dumps(json, 0) != NULL)
  120. fail("json_dumps encoded an integer!");
  121. if (json_dumpf(json, NULL, 0) == 0)
  122. fail("json_dumpf encoded an integer!");
  123. if (json_dumpfd(json, -1, 0) == 0)
  124. fail("json_dumpfd encoded an integer!");
  125. result = json_dumps(json, JSON_ENCODE_ANY);
  126. if (!result || strcmp(result, "42") != 0)
  127. fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY");
  128. free(result);
  129. json_decref(json);
  130. }
  131. static void escape_slashes() {
  132. /* Test dump escaping slashes */
  133. json_t *json;
  134. char *result;
  135. json = json_object();
  136. json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson"));
  137. result = json_dumps(json, 0);
  138. if (!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}"))
  139. fail("json_dumps failed to not escape slashes");
  140. free(result);
  141. result = json_dumps(json, JSON_ESCAPE_SLASH);
  142. if (!result ||
  143. strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}"))
  144. fail("json_dumps failed to escape slashes");
  145. free(result);
  146. json_decref(json);
  147. }
  148. static void encode_nul_byte() {
  149. json_t *json;
  150. char *result;
  151. json = json_stringn("nul byte \0 in string", 20);
  152. result = json_dumps(json, JSON_ENCODE_ANY);
  153. if (!result || memcmp(result, "\"nul byte \\u0000 in string\"", 27))
  154. fail("json_dumps failed to dump an embedded NUL byte");
  155. free(result);
  156. json_decref(json);
  157. }
  158. static void dump_file() {
  159. json_t *json;
  160. int result;
  161. result = json_dump_file(NULL, "", 0);
  162. if (result != -1)
  163. fail("json_dump_file succeeded with invalid args");
  164. json = json_object();
  165. result = json_dump_file(json, "json_dump_file.json", 0);
  166. if (result != 0)
  167. fail("json_dump_file failed");
  168. json_decref(json);
  169. remove("json_dump_file.json");
  170. }
  171. static void dumpb() {
  172. char buf[2];
  173. json_t *obj;
  174. size_t size;
  175. obj = json_object();
  176. size = json_dumpb(obj, buf, sizeof(buf), 0);
  177. if (size != 2 || strncmp(buf, "{}", 2))
  178. fail("json_dumpb failed");
  179. json_decref(obj);
  180. obj = json_pack("{s:s}", "foo", "bar");
  181. size = json_dumpb(obj, buf, sizeof(buf), JSON_COMPACT);
  182. if (size != 13)
  183. fail("json_dumpb size check failed");
  184. json_decref(obj);
  185. }
  186. static void dumpfd() {
  187. #ifdef HAVE_UNISTD_H
  188. int fds[2] = {-1, -1};
  189. json_t *a, *b;
  190. if (pipe(fds))
  191. fail("pipe() failed");
  192. a = json_pack("{s:s}", "foo", "bar");
  193. if (json_dumpfd(a, fds[1], 0))
  194. fail("json_dumpfd() failed");
  195. close(fds[1]);
  196. b = json_loadfd(fds[0], 0, NULL);
  197. if (!b)
  198. fail("json_loadfd() failed");
  199. close(fds[0]);
  200. if (!json_equal(a, b))
  201. fail("json_equal() failed for fd test");
  202. json_decref(a);
  203. json_decref(b);
  204. #endif
  205. }
  206. static void embed() {
  207. static const char *plains[] = {"{\"bar\":[],\"foo\":{}}", "[[],{}]", "{}", "[]",
  208. NULL};
  209. size_t i;
  210. for (i = 0; plains[i]; i++) {
  211. const char *plain = plains[i];
  212. json_t *parse = NULL;
  213. char *embed = NULL;
  214. size_t psize = 0;
  215. size_t esize = 0;
  216. psize = strlen(plain) - 2;
  217. embed = calloc(1, psize);
  218. parse = json_loads(plain, 0, NULL);
  219. esize =
  220. json_dumpb(parse, embed, psize, JSON_COMPACT | JSON_SORT_KEYS | JSON_EMBED);
  221. json_decref(parse);
  222. if (esize != psize)
  223. fail("json_dumpb(JSON_EMBED) returned an invalid size");
  224. if (strncmp(plain + 1, embed, esize) != 0)
  225. fail("json_dumps(JSON_EMBED) returned an invalid value");
  226. free(embed);
  227. }
  228. }
  229. static void run_tests() {
  230. encode_null();
  231. encode_twice();
  232. circular_references();
  233. encode_other_than_array_or_object();
  234. escape_slashes();
  235. encode_nul_byte();
  236. dump_file();
  237. dumpb();
  238. dumpfd();
  239. embed();
  240. }