json.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. /*
  2. * Copyright (c) 2018-2023 SignalWire, Inc
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in all
  12. * copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. #include "KSTest.hpp"
  23. #include "cJSON/cJSON.h"
  24. #include "catch/catch.hpp"
  25. using namespace signalwire::pal;
  26. using namespace signalwire::pal::async;
  27. // Coverage for:
  28. // KS_JSON_TYPE_INVALID
  29. // KS_JSON_TYPE_FALSE
  30. // KS_JSON_TYPE_TRUE
  31. // KS_JSON_TYPE_NULL
  32. // KS_JSON_TYPE_NUMBER
  33. // KS_JSON_TYPE_STRING
  34. // KS_JSON_TYPE_ARRAY
  35. // KS_JSON_TYPE_OBJECT
  36. // KS_JSON_TYPE_RAW
  37. TEST_CASE("json_types")
  38. {
  39. REQUIRE(KS_JSON_TYPE_INVALID == static_cast<KS_JSON_TYPES>(cJSON_Invalid));
  40. REQUIRE(KS_JSON_TYPE_FALSE == static_cast<KS_JSON_TYPES>(cJSON_False));
  41. REQUIRE(KS_JSON_TYPE_TRUE == static_cast<KS_JSON_TYPES>(cJSON_True));
  42. REQUIRE(KS_JSON_TYPE_NULL == static_cast<KS_JSON_TYPES>(cJSON_NULL));
  43. REQUIRE(KS_JSON_TYPE_NUMBER == static_cast<KS_JSON_TYPES>(cJSON_Number));
  44. REQUIRE(KS_JSON_TYPE_STRING == static_cast<KS_JSON_TYPES>(cJSON_String));
  45. REQUIRE(KS_JSON_TYPE_ARRAY == static_cast<KS_JSON_TYPES>(cJSON_Array));
  46. REQUIRE(KS_JSON_TYPE_OBJECT == static_cast<KS_JSON_TYPES>(cJSON_Object));
  47. REQUIRE(KS_JSON_TYPE_RAW == static_cast<KS_JSON_TYPES>(cJSON_Raw));
  48. }
  49. // Coverage for:
  50. // ks_json_init
  51. // ks_json_deinit
  52. TEST_CASE("json_init")
  53. {
  54. // Always leave this scope initialized...
  55. auto cleanup = util::Scope(ks_json_init);
  56. // By default ks binds the pool to all json allocations
  57. // this can be disabled by calling ks_json_deinit, lets
  58. // test that assumption
  59. auto str1 = ks_json_create_string("bobo");
  60. // This will crash if so...
  61. ks_free(str1);
  62. // Ok now lets deinit and re-allocate one, should be free-able
  63. // by glibc free
  64. ks_json_deinit();
  65. str1 = ks_json_create_string("bobo");
  66. // This will crash if so...
  67. free(str1);
  68. // Now re-init to verify that works
  69. ks_json_init();
  70. str1 = ks_json_create_string("bobo");
  71. // This will crash if it didn't work...
  72. ks_free(str1);
  73. }
  74. // Coverage for:
  75. // ks_json_create_string
  76. // ks_json_create_string_fmt
  77. // ks_json_create_number
  78. // ks_json_create_array
  79. // ks_json_create_object
  80. // ks_json_create_false
  81. // ks_json_create_true
  82. // ks_json_create_bool
  83. // ks_json_create_null
  84. TEST_CASE("json_create")
  85. {
  86. // ks_json_create_string
  87. auto j = ks_json_create_string("bobo");
  88. REQUIRE(j->type == cJSON_String);
  89. ks_json_delete(&j);
  90. // ks_json_create_fmt
  91. j = ks_json_create_string_fmt("A Format %s Of Stuff", "(say wut)");
  92. REQUIRE(j->type == cJSON_String);
  93. REQUIRE(ks_json_type_is_string(j));
  94. REQUIRE("A Format (say wut) Of Stuff"s == j->valuestring);
  95. ks_json_delete(&j);
  96. // ks_json_create_number
  97. j = ks_json_create_number(42);
  98. REQUIRE(j->type == cJSON_Number);
  99. REQUIRE(ks_json_type_is_number(j));
  100. REQUIRE(42 == j->valueint);
  101. ks_json_delete(&j);
  102. // ks_json_create_array
  103. j = ks_json_create_array();
  104. REQUIRE(j->type == cJSON_Array);
  105. REQUIRE(ks_json_type_is_array(j));
  106. ks_json_delete(&j);
  107. // ks_json_create_object
  108. j = ks_json_create_object();
  109. REQUIRE(j->type == cJSON_Object);
  110. REQUIRE(ks_json_type_is_object(j));
  111. ks_json_delete(&j);
  112. // ks_json_create_true
  113. j = ks_json_create_true();
  114. REQUIRE(j->type == cJSON_True);
  115. ks_json_delete(&j);
  116. // ks_json_create_false
  117. j = ks_json_create_false();
  118. REQUIRE(j->type == cJSON_False);
  119. ks_json_delete(&j);
  120. // ks_json_create_bool
  121. j = ks_json_create_bool(KS_TRUE);
  122. REQUIRE(j->type == cJSON_True);
  123. ks_json_delete(&j);
  124. j = ks_json_create_bool(KS_FALSE);
  125. REQUIRE(j->type == cJSON_False);
  126. ks_json_delete(&j);
  127. // ks_json_create_null
  128. j = ks_json_create_null();
  129. REQUIRE(j->type == cJSON_NULL);
  130. ks_json_delete(&j);
  131. }
  132. // Coverage for:
  133. // ks_json_parse
  134. TEST_CASE("json_parse")
  135. {
  136. // ks_json_parse
  137. auto j = ks_json_parse(R"({
  138. "glossary": {
  139. "title": "example glossary",
  140. "GlossDiv": {
  141. "title": "S",
  142. "GlossList": {
  143. "GlossEntry": {
  144. "ID": "SGML",
  145. "SortAs": "SGML",
  146. "GlossTerm": "Standard Generalized Markup Language",
  147. "Acronym": "SGML",
  148. "Abbrev": "ISO 8879:1986",
  149. "GlossDef": {
  150. "para": "A meta-markup language, used to create markup languages such as DocBook.",
  151. "GlossSeeAlso": ["GML", "XML"]
  152. },
  153. "GlossSee": "markup"
  154. }
  155. }
  156. }
  157. }
  158. })"
  159. );
  160. // @@ TODO validate
  161. ks_json_delete(&j);
  162. }
  163. // Coverage for:
  164. // ks_json_add_item_to_array
  165. // ks_json_add_number_to_array
  166. // ks_json_add_string_to_array
  167. // ks_json_add_true_to_array
  168. // ks_json_add_false_to_array
  169. // ks_json_add_item_to_object
  170. // ks_json_add_number_to_object
  171. // ks_json_add_string_to_object
  172. // ks_json_add_true_to_object
  173. // ks_json_add_false_to_object
  174. // ks_json_add_uuid_to_array
  175. // ks_json_add_uuid_to_object
  176. // ks_json_get_object_uuid
  177. // ks_json_get_array_uuid
  178. TEST_CASE("json_add")
  179. {
  180. // ks_json_add_item_to_array
  181. auto j = ks_json_create_array();
  182. REQUIRE(ks_json_get_array_size(j) == 0);
  183. ks_json_add_item_to_array(j, ks_json_create_string("bobo"));
  184. REQUIRE(ks_json_get_array_size(j) == 1);
  185. ks_json_add_item_to_array(j, ks_json_create_string("frodo"));
  186. REQUIRE(ks_json_get_array_size(j) == 2);
  187. REQUIRE("bobo"s == ks_json_get_array_item(j, 0)->valuestring);
  188. REQUIRE("frodo"s == ks_json_get_array_item(j, 1)->valuestring);
  189. #if !defined(KS_BUILD_DEBUG)
  190. REQUIRE(nullptr == ks_json_get_array_item(j, 2));
  191. #endif
  192. ks_json_delete(&j);
  193. // ks_json_add_number_to_array
  194. j = ks_json_create_array();
  195. ks_json_add_number_to_array(j, 42);
  196. REQUIRE(ks_json_type_is_number(ks_json_get_array_item(j, 0)));
  197. REQUIRE(ks_json_get_array_number_int(j, 0) == 42);
  198. ks_json_add_number_to_array(j, 42.5);
  199. REQUIRE(ks_json_get_array_number_double(j, 1) == 42.5);
  200. ks_json_delete(&j);
  201. // ks_json_add_string_to_array
  202. j = ks_json_create_array();
  203. ks_json_add_string_to_array(j, "42");
  204. REQUIRE(ks_json_type_is_string(ks_json_get_array_item(j, 0)));
  205. REQUIRE("42"s == ks_json_get_array_cstr(j, 0));
  206. ks_json_delete(&j);
  207. // ks_json_add_true_to_array
  208. j = ks_json_create_array();
  209. ks_json_add_true_to_array(j);
  210. REQUIRE(ks_json_type_is_true(ks_json_get_array_item(j, 0)));
  211. REQUIRE(KS_TRUE == ks_json_get_array_bool(j, 0));
  212. ks_json_delete(&j);
  213. // ks_json_add_false_to_array
  214. j = ks_json_create_array();
  215. ks_json_add_false_to_array(j);
  216. REQUIRE(ks_json_type_is_false(ks_json_get_array_item(j, 0)));
  217. REQUIRE(KS_FALSE == ks_json_get_array_bool(j, 0));
  218. ks_json_delete(&j);
  219. // ks_json_add_item_to_object
  220. j = ks_json_create_object();
  221. ks_json_add_item_to_object(j, "key", ks_json_create_string("value"));
  222. REQUIRE("value"s == ks_json_get_object_cstr(j, "key"));
  223. ks_json_add_item_to_object(j, "key2", ks_json_create_string("value2"));
  224. REQUIRE("value2"s == ks_json_get_object_cstr(j, "key2"));
  225. ks_json_add_item_to_object(j, "key", ks_json_create_string("value"));
  226. REQUIRE("value"s == ks_json_get_object_cstr(j, "key"));
  227. ks_json_delete(&j);
  228. // ks_json_add_number_to_object
  229. j = ks_json_create_object();
  230. ks_json_add_number_to_object(j, "answer_to_life", 42);
  231. REQUIRE(ks_json_type_is_number(ks_json_get_object_item(j, "answer_to_life")));
  232. REQUIRE(ks_json_get_object_number_int(j, "answer_to_life") == 42);
  233. ks_json_add_number_to_object(j, "answer_to_life_2", 42.5);
  234. REQUIRE(ks_json_get_object_number_double(j, "answer_to_life_2") == 42.5);
  235. ks_json_delete(&j);
  236. // ks_json_add_string_to_object
  237. j = ks_json_create_object();
  238. ks_json_add_string_to_object(j, "answer_to_life", "42");
  239. REQUIRE(ks_json_type_is_string(ks_json_get_object_item(j, "answer_to_life")));
  240. REQUIRE("42"s == ks_json_get_object_cstr(j, "answer_to_life"));
  241. ks_json_delete(&j);
  242. // ks_json_add_true_to_object
  243. j = ks_json_create_object();
  244. ks_json_add_true_to_object(j, "answer_to_life");
  245. REQUIRE(ks_json_type_is_true(ks_json_get_object_item(j, "answer_to_life")));
  246. REQUIRE(KS_TRUE == ks_json_get_object_bool(j, "answer_to_life"));
  247. ks_json_delete(&j);
  248. // ks_json_add_false_to_object
  249. j = ks_json_create_object();
  250. ks_json_add_false_to_object(j, "answer_to_life");
  251. REQUIRE(ks_json_type_is_false(ks_json_get_object_item(j, "answer_to_life")));
  252. REQUIRE(KS_FALSE == ks_json_get_object_bool(j, "answer_to_life"));
  253. ks_json_delete(&j);
  254. // ks_json_add_uuid_to_array
  255. // ks_json_get_array_uuid
  256. j = ks_json_create_array();
  257. uuid_t uuid;
  258. REQUIRE(ks_json_add_uuid_to_array(j, *ks_uuid(&uuid)));
  259. auto new_uuid = ks_json_get_array_uuid(j, 0);
  260. REQUIRE(uuid == new_uuid);
  261. ks_json_delete(&j);
  262. // ks_json_add_uuid_to_object
  263. // ks_json_get_object_uuid
  264. j = ks_json_create_object();
  265. REQUIRE(ks_json_add_uuid_to_object(j, "bobo", *ks_uuid(&uuid)));
  266. new_uuid = ks_json_get_object_uuid(j, "bobo");
  267. REQUIRE(uuid == new_uuid);
  268. ks_json_delete(&j);
  269. }
  270. // Coverage for:
  271. // ks_json_duplicate
  272. TEST_CASE("json_dupe")
  273. {
  274. // ks_json_duplicate
  275. auto j1 = ks_json_create_object();
  276. ks_json_add_string_to_object(j1, "another_day", "another_dollar");
  277. auto j2 = ks_json_duplicate(j1, KS_TRUE);
  278. REQUIRE("another_dollar"s == ks_json_get_object_cstr(j1, "another_day"));
  279. REQUIRE("another_dollar"s == ks_json_get_object_cstr(j2, "another_day"));
  280. ks_json_delete(&j1);
  281. REQUIRE("another_dollar"s == ks_json_get_object_cstr(j2, "another_day"));
  282. ks_json_delete(&j2);
  283. }
  284. // Coverage for:
  285. // ks_json_delete
  286. // ks_json_delete_item_from_array
  287. // ks_json_delete_item_from_object
  288. TEST_CASE("json_delete")
  289. {
  290. // ks_json_delete
  291. auto j = ks_json_create_object();
  292. // Modify the hook to ensure delete is called
  293. cJSON_Hooks hooks = {
  294. [](size_t size)->auto {
  295. return ks_malloc(size);
  296. },
  297. [](void *data)->auto {
  298. ks_free(data);
  299. throw true;
  300. }
  301. };
  302. cJSON_InitHooks(&hooks);
  303. // Now try to delete we should catch true
  304. try {
  305. ks_json_delete(&j);
  306. REQUIRE(!"Should've thrown");
  307. } catch (bool) {
  308. // Success
  309. REQUIRE(true);
  310. }
  311. // Restore the hooks
  312. ks_json_init();
  313. // ks_json_delete_item_from_array
  314. j = ks_json_create_array();
  315. ks_json_add_item_to_array(j, ks_json_create_string("hello"));
  316. ks_json_add_item_to_array(j, ks_json_create_string("there"));
  317. REQUIRE("hello"s == ks_json_get_array_cstr(j, 0));
  318. REQUIRE("there"s == ks_json_get_array_cstr(j, 1));
  319. ks_json_delete_item_from_array(j, 0);
  320. REQUIRE("there"s == ks_json_get_array_cstr(j, 0));
  321. ks_json_delete_item_from_array(j, 0);
  322. ks_json_delete(&j);
  323. // ks_json_delete_item_from_object
  324. j = ks_json_create_object();
  325. ks_json_add_item_to_object(j, "yup", ks_json_create_string("hello"));
  326. REQUIRE("hello"s == ks_json_get_object_cstr(j, "yup"));
  327. ks_json_delete_item_from_object(j, "yup");
  328. #if !defined(KS_BUILD_DEBUG)
  329. REQUIRE(nullptr == ks_json_get_object_item(j, "yup"));
  330. #endif
  331. }
  332. // Coverage for:
  333. // ks_json_get_object_item
  334. // ks_json_get_object_cstr
  335. // ks_json_get_object_number_int
  336. // ks_json_get_object_number_double
  337. // ks_json_get_object_bool
  338. TEST_CASE("json_get_object")
  339. {
  340. // ks_json_get_object_item
  341. auto j = ks_json_create_object();
  342. #if !defined(KS_BUILD_DEBUG)
  343. REQUIRE(nullptr == ks_json_get_object_item(j, "does_not_exist"));
  344. #endif
  345. ks_json_add_item_to_object(j, "does_exist", ks_json_create_string("Yup"));
  346. REQUIRE("Yup"s == ks_json_get_object_cstr(j, "does_exist"));
  347. ks_json_delete(&j);
  348. // ks_json_get_object_cstr
  349. j = ks_json_create_object();
  350. ks_json_add_item_to_object(j, "key", ks_json_create_string("A Test String"));
  351. REQUIRE("A Test String"s == ks_json_get_object_cstr(j, "key"));
  352. ks_json_delete(&j);
  353. // ks_json_get_object_number_int
  354. j = ks_json_create_object();
  355. ks_json_add_item_to_object(j, "key", ks_json_create_number(42));
  356. REQUIRE(42 == ks_json_get_object_number_int(j, "key"));
  357. ks_json_delete(&j);
  358. // ks_json_get_object_number_double
  359. j = ks_json_create_object();
  360. ks_json_add_item_to_object(j, "key", ks_json_create_number(42.5));
  361. REQUIRE(42.5 == ks_json_get_object_number_double(j, "key"));
  362. ks_json_delete(&j);
  363. // ks_json_get_object_bool
  364. j = ks_json_create_object();
  365. ks_json_add_false_to_object(j, "bobo");
  366. ks_json_add_true_to_object(j, "bobo2");
  367. REQUIRE(KS_FALSE == ks_json_get_object_bool(j, "bobo"));
  368. REQUIRE(KS_TRUE == ks_json_get_object_bool(j, "bobo2"));
  369. ks_json_delete(&j);
  370. }
  371. // Coverage for:
  372. // ks_json_get_array_item
  373. // ks_json_get_array_size
  374. // ks_json_get_array_cstr
  375. // ks_json_get_array_number_int
  376. // ks_json_get_array_number_double
  377. // ks_json_get_array_bool
  378. TEST_CASE("json_get_array")
  379. {
  380. // ks_json_get_array_item
  381. // ks_json_get_array_size
  382. auto j = ks_json_create_array();
  383. REQUIRE(ks_json_get_array_size(j) == 0);
  384. ks_json_add_item_to_array(j, ks_json_create_string("bobo"));
  385. REQUIRE(ks_json_get_array_size(j) == 1);
  386. ks_json_add_item_to_array(j, ks_json_create_string("frodo"));
  387. REQUIRE(ks_json_get_array_size(j) == 2);
  388. REQUIRE("bobo"s == ks_json_get_array_item(j, 0)->valuestring);
  389. REQUIRE("frodo"s == ks_json_get_array_item(j, 1)->valuestring);
  390. #if !defined(KS_BUILD_DEBUG)
  391. REQUIRE(nullptr == ks_json_get_array_item(j, 2));
  392. #endif
  393. ks_json_delete(&j);
  394. // ks_json_get_array_cstr
  395. j = ks_json_create_array();
  396. #if !defined(KS_BUILD_DEBUG)
  397. REQUIRE(nullptr == ks_json_get_array_item(j, 0));
  398. #endif
  399. ks_json_add_item_to_array(j, ks_json_create_string("Yup"));
  400. REQUIRE("Yup"s == ks_json_get_array_cstr(j, 0));
  401. ks_json_add_item_to_array(j, ks_json_create_string("Yup2"));
  402. REQUIRE("Yup2"s == ks_json_get_array_cstr(j, 1));
  403. ks_json_delete(&j);
  404. // ks_json_get_array_number_double
  405. j = ks_json_create_array();
  406. #if !defined(KS_BUILD_DEBUG)
  407. REQUIRE(nullptr == ks_json_get_array_item(j, 0));
  408. #endif
  409. ks_json_add_item_to_array(j, ks_json_create_number(51.21));
  410. REQUIRE(51.21 == ks_json_get_array_number_double(j, 0));
  411. ks_json_delete(&j);
  412. // ks_json_get_array_number_int
  413. j = ks_json_create_array();
  414. #if !defined(KS_BUILD_DEBUG)
  415. REQUIRE(nullptr == ks_json_get_array_item(j, 0));
  416. #endif
  417. ks_json_add_item_to_array(j, ks_json_create_number(616));
  418. REQUIRE(616 == ks_json_get_array_number_int(j, 0));
  419. ks_json_delete(&j);
  420. // ks_json_get_array_bool
  421. j = ks_json_create_array();
  422. #if !defined(KS_BUILD_DEBUG)
  423. REQUIRE(nullptr == ks_json_get_array_item(j, 0));
  424. #endif
  425. ks_json_add_item_to_array(j, ks_json_create_bool(KS_TRUE));
  426. REQUIRE(KS_TRUE == ks_json_get_array_bool(j, 0));
  427. ks_json_add_item_to_array(j, ks_json_create_bool(KS_FALSE));
  428. REQUIRE(KS_FALSE == ks_json_get_array_bool(j, 1));
  429. ks_json_delete(&j);
  430. // ks_json_get_array_uuid
  431. }
  432. // Coverage for:
  433. // ks_json_print
  434. // ks_json_print_unformatted
  435. TEST_CASE("json_print")
  436. {
  437. // ks_json_print
  438. auto j = ks_json_parse(R"({"menu": {"id": "file", "value": "File" } })");
  439. REQUIRE(ks_json_get_object_item(j, "menu")->type == cJSON_Object);
  440. auto result = ks_json_print(j);
  441. auto j2 = ks_json_parse(result);
  442. REQUIRE(ks_json_get_object_item(j2, "menu")->type == cJSON_Object);
  443. auto result2 = ks_json_print(j2);
  444. REQUIRE(std::string_view(result) == std::string_view(result2));
  445. ks_json_free(&result);
  446. ks_json_free(&result2);
  447. ks_json_delete(&j2);
  448. ks_json_delete(&j);
  449. // ks_json_print
  450. j = ks_json_parse(R"({"menu": {"id": "file", "value": "File" } })");
  451. REQUIRE(ks_json_get_object_item(j, "menu")->type == cJSON_Object);
  452. result = ks_json_print_unformatted(j);
  453. j2 = ks_json_parse(result);
  454. REQUIRE(ks_json_get_object_item(j2, "menu")->type == cJSON_Object);
  455. result2 = ks_json_print_unformatted(j2);
  456. REQUIRE(std::string_view(result) == std::string_view(result2));
  457. ks_json_free(&result);
  458. ks_json_free(&result2);
  459. ks_json_delete(&j2);
  460. ks_json_delete(&j);
  461. }
  462. // Coverage for:
  463. // ks_json_type_get
  464. // ks_json_type_is
  465. // ks_json_type_is_array
  466. // ks_json_type_is_string
  467. // ks_json_type_is_number
  468. // ks_json_type_is_null
  469. // ks_json_type_is_object
  470. // ks_json_type_is_false
  471. // ks_json_type_is_true
  472. TEST_CASE("json_type")
  473. {
  474. auto j = ks_json_create_object();
  475. REQUIRE(ks_json_type_get(j) == KS_JSON_TYPE_OBJECT);
  476. REQUIRE(ks_json_type_is_object(j));
  477. ks_json_delete(&j);
  478. j = ks_json_create_array();
  479. REQUIRE(ks_json_type_get(j) == KS_JSON_TYPE_ARRAY);
  480. REQUIRE(ks_json_type_is_array(j));
  481. ks_json_delete(&j);
  482. j = ks_json_create_false();
  483. REQUIRE(ks_json_type_get(j) == KS_JSON_TYPE_FALSE);
  484. REQUIRE(ks_json_type_is_false(j));
  485. ks_json_delete(&j);
  486. j = ks_json_create_true();
  487. REQUIRE(ks_json_type_get(j) == KS_JSON_TYPE_TRUE);
  488. REQUIRE(ks_json_type_is_true(j));
  489. ks_json_delete(&j);
  490. j = ks_json_create_string("hallo");
  491. REQUIRE(ks_json_type_get(j) == KS_JSON_TYPE_STRING);
  492. REQUIRE(ks_json_type_is_string(j));
  493. ks_json_delete(&j);
  494. j = ks_json_create_number(42);
  495. REQUIRE(ks_json_type_get(j) == KS_JSON_TYPE_NUMBER);
  496. REQUIRE(ks_json_type_is_number(j));
  497. ks_json_delete(&j);
  498. j = ks_json_create_null();
  499. REQUIRE(ks_json_type_get(j) == KS_JSON_TYPE_NULL);
  500. REQUIRE(ks_json_type_is_null(j));
  501. ks_json_delete(&j);
  502. }
  503. // Coverage for:
  504. // ks_json_value_string
  505. // ks_json_value_number_int
  506. // ks_json_value_number_intptr
  507. // ks_json_value_number_double
  508. // ks_json_value_number_doubleptr
  509. // ks_json_value_number_bool
  510. // ks_json_value_uuid
  511. // ks_json_create_uuid
  512. TEST_CASE("json_value")
  513. {
  514. // ks_json_value_string
  515. auto j = ks_json_create_string("Hallo");
  516. REQUIRE("Hallo"s == ks_json_value_string(j));
  517. ks_json_delete(&j);
  518. // ks_json_value_number_int
  519. j = ks_json_create_number(42);
  520. REQUIRE(42 == ks_json_value_number_int(j));
  521. ks_json_delete(&j);
  522. // ks_json_value_number_intptr
  523. j = ks_json_create_number(42);
  524. REQUIRE(42 == *ks_json_value_number_intptr(j));
  525. ks_json_delete(&j);
  526. // ks_json_value_number_double
  527. j = ks_json_create_number(42.5);
  528. REQUIRE(42.5 == ks_json_value_number_double(j));
  529. ks_json_delete(&j);
  530. // ks_json_value_number_doubleptr
  531. j = ks_json_create_number(42.5);
  532. REQUIRE(42.5 == *ks_json_value_number_doubleptr(j));
  533. ks_json_delete(&j);
  534. // ks_json_value_bool
  535. j = ks_json_create_bool(KS_TRUE);
  536. REQUIRE(KS_TRUE == ks_json_value_bool(j));
  537. ks_json_delete(&j);
  538. j = ks_json_create_bool(KS_FALSE);
  539. REQUIRE(KS_FALSE == ks_json_value_bool(j));
  540. ks_json_delete(&j);
  541. // ks_json_value_uuid
  542. // ks_json_create_uuid
  543. uuid_t uuid;
  544. j = ks_json_create_uuid(*ks_uuid(&uuid));
  545. REQUIRE(j);
  546. std::string uuid_str = ks_uuid_str(nullptr, &uuid);
  547. REQUIRE(uuid_str == j->valuestring);
  548. REQUIRE(ks_json_value_uuid(j) == uuid);
  549. }
  550. // Coverage for:
  551. // KS_JSON_ARRAY_FOREACH
  552. // ks_json_enum_next
  553. // ks_json_enum_child
  554. TEST_CASE("json_enum")
  555. {
  556. // ks_json_enum_next
  557. // ks_json_enum_child
  558. // KS_JSON_ARRAY_FOREACH
  559. auto j = ks_json_create_array();
  560. ks_json_add_string_to_array(j, "hallo");
  561. ks_json_add_string_to_array(j, "hallo?");
  562. ks_json_add_string_to_array(j, "hallo!?!?");
  563. auto object = ks_json_add_item_to_array(j, ks_json_create_object());
  564. ks_json_add_item_to_object(object, "key", ks_json_create_string("value"));
  565. uint32_t index = 0;
  566. ks_json_t *element;
  567. KS_JSON_ARRAY_FOREACH(element, j) {
  568. switch(index++) {
  569. case 0:
  570. REQUIRE("hallo"s == ks_json_value_string(element));
  571. break;
  572. case 1:
  573. REQUIRE("hallo?"s == ks_json_value_string(element));
  574. break;
  575. case 2:
  576. REQUIRE("hallo!?!?"s == ks_json_value_string(element));
  577. break;
  578. case 3:
  579. REQUIRE(ks_json_type_is_object(element));
  580. break;
  581. case 4:
  582. REQUIRE("value"s == ks_json_value_string(element));
  583. break;
  584. default:
  585. REQUIRE(!"Unexpected element");
  586. }
  587. }
  588. }
  589. // Coverage for:
  590. // ks_json_lookup
  591. // ks_json_valookup
  592. // ks_json_lookup_cstr
  593. // ks_json_lookup_number_doubleptr
  594. // ks_json_lookup_number_intptr
  595. // ks_json_lookup_array_item
  596. // ks_json_lookup_uuid
  597. TEST_CASE("json_lookup")
  598. {
  599. // ks_json_address_item
  600. auto top_obj = ks_json_create_object();
  601. REQUIRE(top_obj);
  602. auto sub_obj = ks_json_create_object();
  603. REQUIRE(sub_obj);
  604. auto sub_array = ks_json_create_array();
  605. ks_json_add_number_to_array(sub_array, 42.5); // 0
  606. ks_json_add_number_to_array(sub_array, 42); // 1
  607. ks_json_add_string_to_array(sub_array, "I live in an array"); // 2
  608. auto string_item = ks_json_add_string_to_object(sub_obj, "string_is_here", "You found me!");
  609. REQUIRE(ks_json_add_item_to_object(sub_obj, "array_is_here", sub_array));
  610. REQUIRE(string_item);
  611. REQUIRE(ks_json_add_number_to_object(sub_obj, "double_is_here", 42.5));
  612. uuid_t uuid;
  613. ks_uuid(&uuid);
  614. REQUIRE(ks_json_add_uuid_to_object(sub_obj, "uuid_is_here", uuid));
  615. REQUIRE(ks_json_add_number_to_object(sub_obj, "int_is_here", 42));
  616. REQUIRE(ks_json_add_item_to_object(top_obj, "top_level_key", sub_obj));
  617. // Now try to address it!
  618. REQUIRE(ks_json_lookup(top_obj, 0) == top_obj);
  619. REQUIRE(ks_json_lookup(top_obj, 1, "top_level_key") == sub_obj);
  620. REQUIRE("You found me!"s == ks_json_lookup(top_obj, 2, "top_level_key", "string_is_here")->valuestring);
  621. REQUIRE(ks_json_lookup(top_obj, 1, "blahasr") == NULL);
  622. REQUIRE(ks_json_lookup(top_obj, 3, "bhasd", "asdhsad", "asdsah") == NULL);
  623. auto lookup = [&](ks_json_t *obj, int components, ...)->ks_json_t * {
  624. va_list argptr;
  625. va_start(argptr, components);
  626. auto item = ks_json_valookup(obj, components, argptr);
  627. va_end(argptr);
  628. return item;
  629. };
  630. REQUIRE(lookup(top_obj, 0) == top_obj);
  631. REQUIRE(lookup(top_obj, 1, "top_level_key") == sub_obj);
  632. REQUIRE("You found me!"s == lookup(top_obj, 2, "top_level_key", "string_is_here")->valuestring);
  633. REQUIRE(lookup(top_obj, 1, "blahasr") == NULL);
  634. REQUIRE(lookup(top_obj, 3, "bhasd", "asdhsad", "asdsah") == NULL);
  635. REQUIRE("You found me!"s == ks_json_lookup_cstr(top_obj, 2, "top_level_key", "string_is_here"));
  636. REQUIRE(*ks_json_lookup_number_doubleptr(top_obj, 2, "top_level_key", "double_is_here") == 42.5);
  637. REQUIRE(*ks_json_lookup_number_intptr(top_obj, 2, "top_level_key", "int_is_here") == 42);
  638. REQUIRE(ks_json_lookup_array_item(top_obj, 0, 2, "top_level_key", "array_is_here")->valuedouble == 42.5);
  639. REQUIRE(ks_json_lookup_array_item(top_obj, 1, 2, "top_level_key", "array_is_here")->valueint == 42);
  640. REQUIRE("I live in an array"s == ks_json_lookup_array_item(top_obj, 2, 2, "top_level_key", "array_is_here")->valuestring);
  641. auto print = ks_json_lookup_print(top_obj, 2, "top_level_key", "array_is_here");
  642. REQUIRE(print);
  643. REQUIRE("[42.5, 42, \"I live in an array\"]"s == print);
  644. ks_json_free(&print);
  645. print = ks_json_lookup_print_unformatted(top_obj, 2, "top_level_key", "array_is_here");
  646. REQUIRE(print);
  647. REQUIRE("[42.5,42,\"I live in an array\"]"s == print);
  648. ks_json_free(&print);
  649. // ks_json_lookup_uuid
  650. REQUIRE(ks_json_lookup_uuid(top_obj, 2, "top_level_key", "uuid_is_here") == uuid);
  651. }