1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "util_allocator.h"
30 #include "cx/test.h"
31
32 #include "cx/json.h"
33 #include "cx/compare.h"
34
35 #include <math.h>
36
37 CX_TEST(test_json_init_default) {
38 CxJson json;
39 CX_TEST_DO {
40 cxJsonInit(&json,
NULL);
41 CX_TEST_ASSERT(json.states.data == json.states_internal);
42 CX_TEST_ASSERT(json.states.size ==
1);
43 CX_TEST_ASSERT(json.states.capacity >=
8);
44 CX_TEST_ASSERT(json.vbuf.data == json.vbuf_internal);
45 CX_TEST_ASSERT(json.vbuf.size ==
0);
46 CX_TEST_ASSERT(json.vbuf.capacity >=
8);
47 cxJsonDestroy(&json);
48 }
49 }
50
51 CX_TEST(test_json_simple_object) {
52 cxstring text = cx_str(
53 "{\n"
54 "\t\"message\":\"success\",\n"
55 "\t\"position\":{\n"
56 "\t\t\"longitude\":-94.7099,\n"
57 "\t\t\"latitude\":51.5539\n"
58 "\t},\n"
59 "\t\"timestamp\":1729348561,\n"
60 "\t\"alive\":true\n"
61 "}"
62 );
63
64 CX_TEST_DO {
65 CxJsonStatus result;
66
67 CxJson json;
68 cxJsonInit(&json,
NULL);
69 cxJsonFill(&json, text);
70
71
72 CxJsonValue *obj;
73 result = cxJsonNext(&json, &obj);
74 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
75
76
77 CX_TEST_ASSERT(cxJsonIsObject(obj));
78
79 CxJsonValue *message = cxJsonObjGet(obj,
"message");
80 CX_TEST_ASSERT(cxJsonIsString(message));
81 CX_TEST_ASSERT(
0 == cx_strcmp(
82 cxJsonAsCxString(message),
83 "success")
84 );
85
86 CxJsonValue *position = cxJsonObjGet(obj,
"position");
87 CX_TEST_ASSERT(cxJsonIsObject(position));
88 CxJsonValue *longitude = cxJsonObjGet(position,
"longitude");
89 CX_TEST_ASSERT(cxJsonIsNumber(longitude));
90 CX_TEST_ASSERT(!cxJsonIsInteger(longitude));
91 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(longitude),
-94.7099));
92 CX_TEST_ASSERT(cxJsonAsInteger(longitude) ==
-94);
93 CxJsonValue *latitude = cxJsonObjGet(position,
"latitude");
94 CX_TEST_ASSERT(cxJsonIsNumber(latitude));
95 CX_TEST_ASSERT(!cxJsonIsInteger(latitude));
96 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(latitude),
51.5539));
97 CX_TEST_ASSERT(cxJsonAsInteger(latitude) ==
51);
98
99 CxJsonValue *timestamp = cxJsonObjGet(obj,
"timestamp");
100 CX_TEST_ASSERT(cxJsonIsInteger(timestamp));
101 CX_TEST_ASSERT(cxJsonIsNumber(timestamp));
102 CX_TEST_ASSERT(cxJsonAsInteger(timestamp) ==
1729348561);
103 CX_TEST_ASSERT(cxJsonAsDouble(timestamp) ==
1729348561.0);
104
105 CxJsonValue *alive = cxJsonObjGet(obj,
"alive");
106 CX_TEST_ASSERT(cxJsonIsBool(alive));
107 CX_TEST_ASSERT(cxJsonIsTrue(alive));
108 CX_TEST_ASSERT(!cxJsonIsFalse(alive));
109 CX_TEST_ASSERT(cxJsonAsBool(alive));
110
111
112 cxJsonValueFree(obj);
113
114
115 result = cxJsonNext(&json, &obj);
116 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
117
118 cxJsonDestroy(&json);
119 }
120 }
121
122 CX_TEST(test_json_large_object) {
123 CxJsonValue *obj = cxJsonCreateObj(
NULL);
124 CX_TEST_DO {
125 cxJsonObjPutString(obj,
"mystring",
"test");
126 char buf[
10];
127 for (
unsigned i =
0 ; i <
300 ; i++) {
128 snprintf(buf,
10,
"key %d", i);
129 cxJsonObjPutInteger(obj, buf, i);
130 }
131 CX_TEST_ASSERT(
301 == cxJsonObjSize(obj));
132
133 CxJsonValue *v;
134 v = cxJsonObjGet(obj,
"key 64");
135 CX_TEST_ASSERT(cxJsonIsInteger(v));
136 CX_TEST_ASSERT(cxJsonAsInteger(v) ==
64);
137 v = cxJsonObjGet(obj,
"key 228");
138 CX_TEST_ASSERT(cxJsonIsInteger(v));
139 CX_TEST_ASSERT(cxJsonAsInteger(v) ==
228);
140
141 v = cxJsonObjGet(obj,
"mystring");
142 CX_TEST_ASSERT(cxJsonIsString(v));
143 CX_TEST_ASSERT(
0 == cx_strcmp(cxJsonAsCxMutStr(v),
"test"));
144 }
145 cxJsonValueFree(obj);
146 }
147
148 CX_TEST(test_json_simple_array) {
149 cxstring empty_array = cx_str(
"[]");
150 cxstring int_array = cx_str(
"[ 0, 1, 2 ]");
151 cxstring str_array = cx_str(
"[ \"str1\", \"str2\" ]");
152 cxstring mixed_array = cx_str(
"[ true, false, 12, { \"a\": \"b\" }, [ 1,2,3,4] ]");
153
154 CxJsonValue *value;
155 CxJsonStatus result;
156 CxJson json0, json1, json2, json3;
157
158 CX_TEST_DO {
159
160 cxJsonInit(&json0,
NULL);
161 cxJsonFill(&json0, empty_array);
162 result = cxJsonNext(&json0, &value);
163 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
164 CX_TEST_ASSERT(value);
165 CX_TEST_ASSERT(cxJsonIsArray(value));
166
167 cxJsonValueFree(value);
168 cxJsonDestroy(&json0);
169
170
171 cxJsonInit(&json1,
NULL);
172 cxJsonFill(&json1, int_array);
173 result = cxJsonNext(&json1, &value);
174 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
175 CX_TEST_ASSERT(value);
176 CX_TEST_ASSERT(cxJsonIsArray(value));
177 CX_TEST_ASSERT(value->array.size ==
3);
178 for(
int i=
0;i<
3;i++) {
179 CxJsonValue *v = cxJsonArrGet(value, i);
180 CX_TEST_ASSERT(v);
181 CX_TEST_ASSERT(cxJsonIsInteger(v));
182 CX_TEST_ASSERT(v->integer == i);
183 }
184
185 cxJsonValueFree(value);
186 cxJsonDestroy(&json1);
187
188
189 cxJsonInit(&json2,
NULL);
190 cxJsonFill(&json2, str_array);
191 result = cxJsonNext(&json2, &value);
192 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
193 CX_TEST_ASSERT(value);
194 CX_TEST_ASSERT(cxJsonIsArray(value));
195 CX_TEST_ASSERT(value->array.size ==
2);
196 CxJsonValue *s0 = cxJsonArrGet(value,
0);
197 CxJsonValue *s1 = cxJsonArrGet(value,
1);
198 CX_TEST_ASSERT(s0 && s1);
199 CX_TEST_ASSERT(cxJsonIsString(s0) && cxJsonIsString(s1));
200 CX_TEST_ASSERT(cx_strcmp(s0->string,
"str1") ==
0);
201 CX_TEST_ASSERT(cx_strcmp(s1->string,
"str2") ==
0);
202
203 cxJsonValueFree(value);
204 cxJsonDestroy(&json2);
205
206
207 cxJsonInit(&json3,
NULL);
208 cxJsonFill(&json3, mixed_array);
209 result = cxJsonNext(&json3, &value);
210 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
211 CX_TEST_ASSERT(value);
212 CX_TEST_ASSERT(cxJsonIsArray(value));
213 CX_TEST_ASSERT(value->array.size ==
5);
214 CxJsonValue *m0 = cxJsonArrGet(value,
0);
215 CxJsonValue *m1 = cxJsonArrGet(value,
1);
216 CxJsonValue *m2 = cxJsonArrGet(value,
2);
217 CxJsonValue *m3 = cxJsonArrGet(value,
3);
218 CxJsonValue *m4 = cxJsonArrGet(value,
4);
219 CX_TEST_ASSERT(m0 && m1 && m2 && m3 && m4);
220 CX_TEST_ASSERT(cxJsonIsLiteral(m0));
221 CX_TEST_ASSERT(cxJsonIsLiteral(m1));
222 CX_TEST_ASSERT(cxJsonIsInteger(m2));
223 CX_TEST_ASSERT(cxJsonIsObject(m3));
224 CX_TEST_ASSERT(cxJsonIsArray(m4));
225
226 cxJsonValueFree(value);
227 cxJsonDestroy(&json3);
228 }
229 }
230
231 CX_TEST(test_json_from_string) {
232 cxstring text = cx_str(
233 "{\n"
234 "\t\"message\":\"success\",\n"
235 "\t\"position\":{\n"
236 "\t\t\"longitude\":-94.7099,\n"
237 "\t\t\"latitude\":51.5539\n"
238 "\t},\n"
239 "\t\"timestamp\":1729348561,\n"
240 "\t\"alive\":true\n"
241 "}"
242 );
243
244 CX_TEST_DO {
245 CxJsonValue *obj;
246 CX_TEST_ASSERT(cxJsonFromString(
NULL, text, &obj) ==
CX_JSON_NO_ERROR);
247
248
249 CX_TEST_ASSERT(cxJsonIsObject(obj));
250
251 CxJsonValue *message = cxJsonObjGet(obj,
"message");
252 CX_TEST_ASSERT(cxJsonIsString(message));
253 CX_TEST_ASSERT(
0 == cx_strcmp(
254 cxJsonAsCxString(message),
255 "success")
256 );
257
258 CxJsonValue *position = cxJsonObjGet(obj,
"position");
259 CX_TEST_ASSERT(cxJsonIsObject(position));
260 CxJsonValue *longitude = cxJsonObjGet(position,
"longitude");
261 CX_TEST_ASSERT(cxJsonIsNumber(longitude));
262 CX_TEST_ASSERT(!cxJsonIsInteger(longitude));
263 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(longitude),
-94.7099));
264 CX_TEST_ASSERT(cxJsonAsInteger(longitude) ==
-94);
265 CxJsonValue *latitude = cxJsonObjGet(position,
"latitude");
266 CX_TEST_ASSERT(cxJsonIsNumber(latitude));
267 CX_TEST_ASSERT(!cxJsonIsInteger(latitude));
268 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(latitude),
51.5539));
269 CX_TEST_ASSERT(cxJsonAsInteger(latitude) ==
51);
270
271 CxJsonValue *timestamp = cxJsonObjGet(obj,
"timestamp");
272 CX_TEST_ASSERT(cxJsonIsInteger(timestamp));
273 CX_TEST_ASSERT(cxJsonIsNumber(timestamp));
274 CX_TEST_ASSERT(cxJsonAsInteger(timestamp) ==
1729348561);
275 CX_TEST_ASSERT(cxJsonAsDouble(timestamp) ==
1729348561.0);
276
277 CxJsonValue *alive = cxJsonObjGet(obj,
"alive");
278 CX_TEST_ASSERT(cxJsonIsBool(alive));
279 CX_TEST_ASSERT(cxJsonIsTrue(alive));
280 CX_TEST_ASSERT(!cxJsonIsFalse(alive));
281 CX_TEST_ASSERT(cxJsonAsBool(alive));
282
283 cxJsonValueFree(obj);
284 }
285 }
286
287 CX_TEST(test_json_from_string_errors) {
288 CX_TEST_DO {
289 CxJsonValue *obj =
NULL;
290 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"", &obj) ==
CX_JSON_NO_DATA);
291 CX_TEST_ASSERT(cxJsonFromString(
NULL, cx_str(
NULL), &obj) ==
CX_JSON_NO_DATA);
292 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"\"incomplete", &obj) ==
CX_JSON_INCOMPLETE_DATA);
293 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"{ \"incomplete\": ", &obj) ==
CX_JSON_INCOMPLETE_DATA);
294 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"{\"number\": 47110815!}", &obj) ==
CX_JSON_FORMAT_ERROR_NUMBER);
295 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"[ \"unexpected token\" : true ]", &obj) ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
296 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"} [", &obj) ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
297 CX_TEST_ASSERT(obj && obj->type ==
CX_JSON_NOTHING);
298 }
299 }
300
301 CX_TEST(test_json_from_string_multiple_values) {
302 CxJsonStatus status;
303 CxJsonValue *obj;
304 CX_TEST_DO {
305 obj =
NULL;
306 status = cxJsonFromString(
NULL,
"{ \"obj1\": \"hello\" }\n\"value2\"\n", &obj);
307 CX_TEST_ASSERT(obj !=
NULL);
308 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
309 CX_TEST_ASSERT(status ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
310
311 obj =
NULL;
312 status = cxJsonFromString(
NULL,
"\"value\" \n ] syntax error [", &obj);
313 CX_TEST_ASSERT(obj !=
NULL);
314 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
315 CX_TEST_ASSERT(status ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
316 }
317 }
318
319 CX_TEST(test_json_from_string_untrimmed) {
320 CxJsonStatus status;
321 CxJsonValue *obj;
322 CX_TEST_DO {
323 obj =
NULL;
324 status = cxJsonFromString(
NULL,
"\n\t{ \"obj1\": \"hello\" } \n", &obj);
325 CX_TEST_ASSERT(status ==
CX_JSON_NO_ERROR);
326 CX_TEST_ASSERT(cxJsonIsObject(obj));
327 CxJsonValue *obj1 = cxJsonObjGet(obj,
"obj1");
328 CX_TEST_ASSERT(cxJsonIsString(obj1));
329 CX_TEST_ASSERT(cx_strcmp(cxJsonAsCxString(obj1),
"hello") ==
0);
330
331 cxJsonValueFree(obj);
332 }
333 }
334
335 CX_TEST(test_json_escaped_strings) {
336 cxstring text = cx_str(
337 "{\n"
338 "\t\"object\":\"{\\n\\t\\\"object\\\":null\\n}\",\n"
339 "\t\"ctrl-chars\":\"\\\\foo\\r\\nbar\\f*ring\\/ring*\\b\"\n"
340 "}"
341 );
342
343 CxJson json;
344 cxJsonInit(&json,
NULL);
345 CX_TEST_DO {
346 cxJsonFill(&json, text);
347 CxJsonValue *obj;
348 CxJsonStatus result = cxJsonNext(&json, &obj);
349 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
350 CX_TEST_ASSERT(cxJsonIsObject(obj));
351 CxJsonValue *object = cxJsonObjGet(obj,
"object");
352 CX_TEST_ASSERT(cxJsonIsString(object));
353 CX_TEST_ASSERT(
0 == cx_strcmp(
354 cxJsonAsCxString(object),
355 "{\n\t\"object\":null\n}")
356 );
357 CxJsonValue *ctrl = cxJsonObjGet(obj,
"ctrl-chars");
358 CX_TEST_ASSERT(cxJsonIsString(ctrl));
359 CX_TEST_ASSERT(
0 == cx_strcmp(
360 cxJsonAsCxString(ctrl),
361 "\\foo\r\nbar\f*ring/ring*\b")
362 );
363 cxJsonValueFree(obj);
364 }
365 cxJsonDestroy(&json);
366 }
367
368 CX_TEST(test_json_escaped_unicode_strings) {
369 cxstring text = cx_str(
370 "{\n"
371 "\"ascii\":\"\\u0041\\u0053\\u0043\\u0049\\u0049\",\n"
372 "\"unicode\":\"\\u00df\\u00DF\",\n"
373 "\"mixed\":\"mixed ä ö \\u00e4 \\u00f6\",\n"
374 "\"wide\":\"\\u03a3\\u29b0\",\n"
375 "\"surrogatepair1\":\"\\ud83e\\udff5\",\n"
376 "\"surrogatepair2\":\"test\\ud83e\\udff1AA\"\n,"
377 "\"mixed2\":\"123\\u03a3\\ud83e\\udfc5\\u00df\""
378 "}"
379 );
380
381 CxJson json;
382 cxJsonInit(&json,
NULL);
383 CX_TEST_DO {
384 cxJsonFill(&json, text);
385 CxJsonValue *obj;
386 CxJsonStatus result = cxJsonNext(&json, &obj);
387 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
388 CX_TEST_ASSERT(cxJsonIsObject(obj));
389
390 CxJsonValue *ascii = cxJsonObjGet(obj,
"ascii");
391 CX_TEST_ASSERT(cxJsonIsString(ascii));
392 CX_TEST_ASSERT(
0 == cx_strcmp(
393 cxJsonAsCxString(ascii),
394 "ASCII")
395 );
396
397 CxJsonValue *unicode = cxJsonObjGet(obj,
"unicode");
398 CX_TEST_ASSERT(cxJsonIsString(unicode));
399 CX_TEST_ASSERT(
0 == cx_strcmp(
400 cxJsonAsCxString(unicode),
401 "ßß")
402 );
403
404 CxJsonValue *mixed = cxJsonObjGet(obj,
"mixed");
405 CX_TEST_ASSERT(cxJsonIsString(mixed));
406 CX_TEST_ASSERT(
0 == cx_strcmp(
407 cxJsonAsCxString(mixed),
408 "mixed ä ö ä ö")
409 );
410
411 CxJsonValue *wide = cxJsonObjGet(obj,
"wide");
412 CX_TEST_ASSERT(cxJsonIsString(wide));
413 CX_TEST_ASSERT(
0 == cx_strcmp(cxJsonAsCxString(wide),
"Σ⦰"));
414
415 CxJsonValue *surrogatepair1 = cxJsonObjGet(obj,
"surrogatepair1");
416 CX_TEST_ASSERT(cxJsonIsString(surrogatepair1));
417 CX_TEST_ASSERT(
0 == cx_strcmp(
418 cxJsonAsCxString(surrogatepair1),
419 "\xf0\x9f\xaf\xb5")
420 );
421
422 CxJsonValue *surrogatepair2 = cxJsonObjGet(obj,
"surrogatepair2");
423 CX_TEST_ASSERT(cxJsonIsString(surrogatepair2));
424 CX_TEST_ASSERT(
0 == cx_strcmp(
425 cxJsonAsCxString(surrogatepair2),
426 "test\xf0\x9f\xaf\xb1" "AA")
427 );
428
429 CxJsonValue *mixed2 = cxJsonObjGet(obj,
"mixed2");
430 char test[
16];
431 strncpy(test, mixed2->string.ptr,
15);
432 CX_TEST_ASSERT(cxJsonIsString(mixed2));
433 CX_TEST_ASSERT(
0 == cx_strcmp(
434 cxJsonAsCxString(mixed2),
435 "123\xce\xa3\xf0\x9f\xaf\x85ß")
436 );
437
438 cxJsonValueFree(obj);
439 }
440 cxJsonDestroy(&json);
441 }
442
443 CX_TEST(test_json_escaped_unicode_malformed) {
444 CxJson json;
445 cxJsonInit(&json,
NULL);
446 CxJsonValue *obj;
447 CxJsonStatus result;
448 CX_TEST_DO {
449 cxJsonFill(&json,
"\"too few digits \\u123\"");
450 result = cxJsonNext(&json, &obj);
451 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
452 CX_TEST_ASSERT(cxJsonIsString(obj));
453 CX_TEST_ASSERT(
0 == cx_strcmp(
454 cxJsonAsCxString(obj),
455 "too few digits \\u123"
456 ));
457 cxJsonValueFree(obj);
458 cxJsonFill(&json,
"\"too many digits \\u00E456\"");
459 result = cxJsonNext(&json, &obj);
460 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
461 CX_TEST_ASSERT(cxJsonIsString(obj));
462 CX_TEST_ASSERT(
0 == cx_strcmp(
463 cxJsonAsCxString(obj),
464 "too many digits ä56"
465 ));
466 cxJsonValueFree(obj);
467 cxJsonFill(&json,
"\"only high \\uD800 surrogate\"");
468 result = cxJsonNext(&json, &obj);
469 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
470 CX_TEST_ASSERT(cxJsonIsString(obj));
471 CX_TEST_ASSERT(
0 == cx_strcmp(
472 cxJsonAsCxString(obj),
473 "only high \\uD800 surrogate"
474 ));
475 cxJsonValueFree(obj);
476 cxJsonFill(&json,
"\"only low \\uDC00 surrogate\"");
477 result = cxJsonNext(&json, &obj);
478 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
479 CX_TEST_ASSERT(cxJsonIsString(obj));
480 CX_TEST_ASSERT(
0 == cx_strcmp(
481 cxJsonAsCxString(obj),
482 "only low \\uDC00 surrogate"
483 ));
484 cxJsonValueFree(obj);
485 cxJsonFill(&json,
"\"two high \\uD800\\uD800 surrogates\"");
486 result = cxJsonNext(&json, &obj);
487 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
488 CX_TEST_ASSERT(cxJsonIsString(obj));
489 CX_TEST_ASSERT(
0 == cx_strcmp(
490 cxJsonAsCxString(obj),
491 "two high \\uD800\\uD800 surrogates"
492 ));
493 cxJsonValueFree(obj);
494 cxJsonFill(&json,
"\"high plus bullshit \\uD800\\u567 foo\"");
495 result = cxJsonNext(&json, &obj);
496 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
497 CX_TEST_ASSERT(cxJsonIsString(obj));
498 CX_TEST_ASSERT(
0 == cx_strcmp(
499 cxJsonAsCxString(obj),
500 "high plus bullshit \\uD800\\u567 foo"
501 ));
502 cxJsonValueFree(obj);
503 }
504 cxJsonDestroy(&json);
505 }
506
507 CX_TEST(test_json_escaped_end_of_string) {
508 CxJson json;
509 cxJsonInit(&json,
NULL);
510 CX_TEST_DO {
511
512 cxJsonFill(&json,
"\"a \\\"test\\\" string\"");
513 CxJsonValue *val;
514 CxJsonStatus result = cxJsonNext(&json, &val);
515 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
516 CX_TEST_ASSERT(cxJsonIsString(val));
517 CX_TEST_ASSERT(
0 == cx_strcmp(
518 cxJsonAsCxString(val),
519 "a \"test\" string")
520 );
521 cxJsonValueFree(val);
522
523
524 cxJsonFill(&json,
"\"a \\\"test\\");
525 result = cxJsonNext(&json, &val);
526 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
527 cxJsonFill(&json,
"\" string\"");
528 result = cxJsonNext(&json, &val);
529 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
530 CX_TEST_ASSERT(cxJsonIsString(val));
531 CX_TEST_ASSERT(
0 == cx_strcmp(
532 cxJsonAsCxString(val),
533 "a \"test\" string")
534 );
535 cxJsonValueFree(val);
536 }
537 cxJsonDestroy(&json);
538 }
539
540 CX_TEST(test_json_object_incomplete_token) {
541 cxstring text = cx_str(
542 "{\"message\":\"success\" , \"__timestamp\":1729348561}");
543 cxstring parts[
16];
544 size_t nparts =
0;
545 for(
size_t i=
0;i<text.length;i+=
4) {
546 parts[nparts++] = cx_strsubsl(text, i,
4);
547 }
548
549 CX_TEST_DO {
550 CxJsonStatus result;
551
552 CxJson json;
553 cxJsonInit(&json,
NULL);
554 CxJsonValue *obj;
555
556 size_t part =
0;
557 while(part < nparts -
1) {
558 cxJsonFill(&json, parts[part]);
559 part++;
560 result = cxJsonNext(&json, &obj);
561 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
562 }
563 cxJsonFill(&json, parts[nparts -
1]);
564 result = cxJsonNext(&json, &obj);
565 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
566 CX_TEST_ASSERT(cxJsonIsObject(obj));
567
568 CxJsonValue *message = cxJsonObjGet(obj,
"message");
569 CX_TEST_ASSERT(cxJsonIsString(message));
570 CX_TEST_ASSERT(
0 == cx_strcmp(
571 cxJsonAsCxString(message),
572 "success")
573 );
574 CxJsonValue *timestamp = cxJsonObjGet(obj,
"__timestamp");
575 CX_TEST_ASSERT(message->type ==
CX_JSON_STRING);
576 CX_TEST_ASSERT(cxJsonIsInteger(timestamp));
577 CX_TEST_ASSERT(cxJsonAsInteger(timestamp) ==
1729348561);
578
579
580 cxJsonValueFree(obj);
581
582
583 result = cxJsonNext(&json, &obj);
584 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
585
586
587 cxJsonReset(&json);
588
589 cxJsonFill(&json,
"\"incomplete token");
590 result = cxJsonNext(&json, &obj);
591 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
592
593 cxJsonDestroy(&json);
594 }
595 }
596
597 CX_TEST(test_json_token_wrongly_completed) {
598 CxTestingAllocator talloc;
599 cx_testing_allocator_init(&talloc);
600 const CxAllocator *alloc = &talloc.base;
601
602 cxstring text = cx_str(
"{\"number\": 47110815!}");
603 cxstring part1 = cx_strsubsl(text,
0,
16);
604 cxstring part2 = cx_strsubs(text,
16);
605
606 CX_TEST_DO {
607 CxJson json;
608 cxJsonInit(&json, alloc);
609
610 CxJsonStatus result;
611 CxJsonValue *obj;
612
613 cxJsonFill(&json, part1);
614 result = cxJsonNext(&json, &obj);
615 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
616 cxJsonFill(&json, part2);
617 result = cxJsonNext(&json, &obj);
618 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_NUMBER);
619 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
620
621 cxJsonDestroy(&json);
622 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
623 }
624 cx_testing_allocator_destroy(&talloc);
625 }
626
627 CX_TEST(test_json_parenthesis_mismatch) {
628 CxTestingAllocator talloc;
629 cx_testing_allocator_init(&talloc);
630 const CxAllocator *alloc = &talloc.base;
631
632 CX_TEST_DO {
633 CxJson json;
634 cxJsonInit(&json, alloc);
635
636 CxJsonStatus result;
637 CxJsonValue *obj;
638
639 cxJsonFill(&json,
"[0, 1, 2, 3}");
640 result = cxJsonNext(&json, &obj);
641 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
642
643 cxJsonReset(&json);
644 cxJsonFill(&json,
"{\"test\": 42]");
645 result = cxJsonNext(&json, &obj);
646 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
647
648 cxJsonDestroy(&json);
649 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
650 }
651 cx_testing_allocator_destroy(&talloc);
652 }
653
654 CX_TEST(test_json_object_name_is_no_string) {
655 CxTestingAllocator talloc;
656 cx_testing_allocator_init(&talloc);
657 const CxAllocator *alloc = &talloc.base;
658
659 CX_TEST_DO {
660 CxJson json;
661 cxJsonInit(&json, alloc);
662
663 CxJsonStatus result;
664 CxJsonValue *obj;
665
666 cxJsonFill(&json,
"{42: \"test\"}");
667 result = cxJsonNext(&json, &obj);
668 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
669
670 cxJsonDestroy(&json);
671 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
672 }
673 cx_testing_allocator_destroy(&talloc);
674 }
675
676 CX_TEST(test_json_subsequent_fill) {
677 cxstring text = cx_str(
678 "{\"message\":\"success\" , \"__timestamp\":1729348561}");
679
680 cxstring part1 = cx_strsubsl(text,
0,
25);
681 cxstring part2 = cx_strsubs(text,
25);
682
683 CX_TEST_DO {
684 CxJson json;
685 cxJsonInit(&json,
NULL);
686 CxJsonValue *obj;
687
688 cxJsonFill(&json, part1);
689 cxJsonFill(&json, part2);
690 CxJsonStatus result = cxJsonNext(&json, &obj);
691 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
692 CX_TEST_ASSERT(cxJsonIsObject(obj));
693
694 CxJsonValue *message = cxJsonObjGet(obj,
"message");
695 CX_TEST_ASSERT(cxJsonIsString(message));
696 CX_TEST_ASSERT(
0 == cx_strcmp(
697 cxJsonAsCxString(message),
698 "success")
699 );
700 CxJsonValue *timestamp = cxJsonObjGet(obj,
"__timestamp");
701 CX_TEST_ASSERT(message->type ==
CX_JSON_STRING);
702 CX_TEST_ASSERT(cxJsonIsInteger(timestamp));
703 CX_TEST_ASSERT(cxJsonAsInteger(timestamp) ==
1729348561);
704
705 cxJsonValueFree(obj);
706 result = cxJsonNext(&json, &obj);
707 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
708
709 cxJsonDestroy(&json);
710 }
711 }
712
713 CX_TEST(test_json_no_fill) {
714 CxJson json;
715 cxJsonInit(&json,
NULL);
716 CX_TEST_DO {
717 CxJsonValue *obj =
NULL;
718 CxJsonStatus result = cxJsonNext(&json, &obj);
719 CX_TEST_ASSERT(result ==
CX_JSON_NULL_DATA);
720 CX_TEST_ASSERT(obj !=
NULL);
721 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
722 }
723 cxJsonDestroy(&json);
724 }
725
726 CX_TEST(test_json_null_fill) {
727 CxJson json;
728 cxJsonInit(&json,
NULL);
729 CX_TEST_DO {
730 CxJsonStatus result;
731 CxJsonValue *obj =
NULL;
732 cxstring nullstr = cx_strn(
NULL,
0);
733 cxJsonFill(&json, nullstr);
734 result = cxJsonNext(&json, &obj);
735 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
736 CX_TEST_ASSERT(obj !=
NULL);
737 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
738 obj =
NULL;
739
740 cxJsonFill(&json,
"[0, 1");
741 result = cxJsonNext(&json, &obj);
742 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
743 CX_TEST_ASSERT(obj !=
NULL);
744 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
745 obj =
NULL;
746
747 cxJsonFill(&json, nullstr);
748 result = cxJsonNext(&json, &obj);
749 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
750 CX_TEST_ASSERT(obj !=
NULL);
751 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
752 obj =
NULL;
753
754 cxJsonFill(&json,
", 2]");
755 result = cxJsonNext(&json, &obj);
756 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
757 CX_TEST_ASSERT(obj !=
NULL);
758 CX_TEST_ASSERT(cxJsonIsArray(obj));
759 cxJsonValueFree(obj);
760
761 cxJsonFill(&json, nullstr);
762 result = cxJsonNext(&json, &obj);
763 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
764 CX_TEST_ASSERT(obj !=
NULL);
765 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
766 }
767 cxJsonDestroy(&json);
768 }
769
770 CX_TEST(test_json_object_error) {
771 cxstring text0 = cx_str(
772 "{\n"
773 "\t\"message\":\"success\",\n"
774 "\t\"data\":{\n"
775 "\t\t\"obj\":{\n"
776 "\t\t\t\"array\": [1, 2, 3, ?syntaxerror? ]\n"
777 "\t\t}\n"
778 "\t},\n"
779 "\t\"timestamp\":1729348561,\n"
780 "}"
781 );
782 cxstring text1 = cx_str(
"{ \"string\" }");
783 cxstring text2 = cx_str(
"{ \"a\" : }");
784 cxstring text3 = cx_str(
"{ \"a\" : \"b\" ]");
785 cxstring text4 = cx_str(
"{ \"name\": \"value\" ]");
786
787 cxstring tests[] = { text0, text1, text2, text3, text4 };
788 CxJsonStatus errors[] = {
789 CX_JSON_FORMAT_ERROR_NUMBER,
790 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN,
791 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN,
792 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN,
793 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN
794 };
795
796 CX_TEST_DO {
797 CxJsonStatus result;
798 CxJson json;
799 CxJsonValue *obj =
NULL;
800
801 for(
int i=
0;i<
5;i++) {
802 cxJsonInit(&json,
NULL);
803 cxJsonFill(&json, tests[i]);
804 result = cxJsonNext(&json, &obj);
805
806 CX_TEST_ASSERT(result == errors[i]);
807 CX_TEST_ASSERT(obj !=
NULL && obj->type ==
CX_JSON_NOTHING);
808 cxJsonDestroy(&json);
809 }
810 }
811 }
812
813 CX_TEST(test_json_object_remove_member) {
814 CxTestingAllocator talloc;
815 cx_testing_allocator_init(&talloc);
816 const CxAllocator *alloc = &talloc.base;
817 CX_TEST_DO {
818 CxJson json;
819 cxJsonInit(&json, alloc);
820 cxJsonFill(&json,
821 "{\n"
822 "\t\"message\":\"success\",\n"
823 "\t\"data\":{\n"
824 "\t\t\"obj\":{\n"
825 "\t\t\t\"array\": [1, 2, 3]\n"
826 "\t\t}\n"
827 "\t},\n"
828 "\t\"timestamp\":1729348561\n"
829 "}"
830 );
831 CxJsonValue *obj;
832 CX_TEST_ASSERT(
CX_JSON_NO_ERROR == cxJsonNext(&json, &obj));
833 cxJsonDestroy(&json);
834
835 CX_TEST_ASSERT(cxJsonIsObject(cxJsonObjGet(obj,
"data")));
836 CxJsonValue *data = cxJsonObjRemove(obj,
"data");
837 CX_TEST_ASSERT(cxJsonIsObject(data));
838 CX_TEST_ASSERT(!cxJsonIsObject(cxJsonObjGet(obj,
"data")));
839 CX_TEST_ASSERT(cxJsonIsObject(cxJsonObjGet(data,
"obj")));
840
841 CX_TEST_ASSERT(
NULL == cxJsonObjRemove(obj,
"data"));
842
843
844 cxJsonValueFree(obj);
845 CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
846
847 cxJsonValueFree(data);
848 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
849 }
850 cx_testing_allocator_destroy(&talloc);
851 }
852
853 CX_TEST(test_json_large_nesting_depth) {
854 CxJson json;
855 CxJsonValue *d1;
856 cxstring text = cx_str(
"{\"test\": [{},{\"foo\": [[{\"bar\":[4, 2, [null, {\"key\": 47}]]}]]}]}");
857 CX_TEST_DO {
858 cxJsonInit(&json,
NULL);
859 cxJsonFill(&json, text);
860 cxJsonNext(&json, &d1);
861
862 CX_TEST_ASSERT(d1 !=
NULL);
863 CX_TEST_ASSERT(cxJsonIsObject(d1));
864 CxJsonValue *d2 = cxJsonObjGet(d1,
"test");
865 CX_TEST_ASSERT(cxJsonIsArray(d2));
866 CX_TEST_ASSERT(cxJsonArrSize(d2) ==
2);
867 CxJsonValue *d3 = cxJsonArrGet(d2,
1);
868 CX_TEST_ASSERT(cxJsonIsObject(d3));
869 CxJsonValue *d4 = cxJsonObjGet(d3,
"foo");
870 CX_TEST_ASSERT(cxJsonIsArray(d4));
871 CX_TEST_ASSERT(cxJsonArrSize(d4) ==
1);
872 CxJsonValue *d5 = cxJsonArrGet(d4,
0);
873 CX_TEST_ASSERT(cxJsonIsArray(d5));
874 CX_TEST_ASSERT(cxJsonArrSize(d5) ==
1);
875 CxJsonValue *d6 = cxJsonArrGet(d5,
0);
876 CX_TEST_ASSERT(cxJsonIsObject(d6));
877 CxJsonValue *d7 = cxJsonObjGet(d6,
"bar");
878 CX_TEST_ASSERT(cxJsonIsArray(d7));
879 CX_TEST_ASSERT(cxJsonArrSize(d7) ==
3);
880 CxJsonValue *d8 = cxJsonArrGet(d7,
2);
881 CX_TEST_ASSERT(cxJsonIsArray(d8));
882 CX_TEST_ASSERT(cxJsonArrSize(d8) ==
2);
883 CxJsonValue *d9a = cxJsonArrGet(d8,
0);
884 CX_TEST_ASSERT(cxJsonIsNull(d9a));
885 CxJsonValue *d9b = cxJsonArrGet(d8,
1);
886 CX_TEST_ASSERT(cxJsonIsObject(d9b));
887 CxJsonValue *d10 = cxJsonObjGet(d9b,
"key");
888 CX_TEST_ASSERT(cxJsonIsInteger(d10));
889 CX_TEST_ASSERT(cxJsonAsInteger(d10) ==
47);
890
891 CX_TEST_ASSERT(json.states.data != json.states_internal);
892 CX_TEST_ASSERT(json.states.capacity > cx_nmemb(json.states_internal));
893
894 cxJsonValueFree(d1);
895 cxJsonDestroy(&json);
896 }
897 }
898
899 CX_TEST(test_json_number) {
900 CxJson json;
901 cxJsonInit(&json,
NULL);
902 CX_TEST_DO {
903 CxJsonValue *v;
904 CxJsonStatus result;
905
906 cxJsonFill(&json,
"3.1415 ");
907 result = cxJsonNext(&json, &v);
908 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
909 CX_TEST_ASSERT(cxJsonIsNumber(v));
910 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(v),
3.1415));
911 cxJsonValueFree(v);
912
913 cxJsonFill(&json,
"-47.11e2 ");
914 result = cxJsonNext(&json, &v);
915 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
916 CX_TEST_ASSERT(cxJsonIsNumber(v));
917 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(v),
-4711.0));
918 cxJsonValueFree(v);
919
920 cxJsonFill(&json,
"0.815e-3 ");
921 result = cxJsonNext(&json, &v);
922 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
923 CX_TEST_ASSERT(cxJsonIsNumber(v));
924 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(v),
0.000815));
925 cxJsonValueFree(v);
926
927 cxJsonFill(&json,
"1.23E4 ");
928 result = cxJsonNext(&json, &v);
929 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
930 CX_TEST_ASSERT(cxJsonIsNumber(v));
931 CX_TEST_ASSERT(cxJsonAsInteger(v) ==
12300);
932 CX_TEST_ASSERT(cxJsonAsDouble(v) ==
12300.0);
933 cxJsonValueFree(v);
934
935 cxJsonFill(&json,
"18446744073709551615.0123456789 ");
936 result = cxJsonNext(&json, &v);
937 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
938 CX_TEST_ASSERT(cxJsonIsNumber(v));
939
940
941 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(v),
1.8446744073709552e+19));
942 cxJsonValueFree(v);
943 }
944 cxJsonDestroy(&json);
945 }
946
947 CX_TEST(test_json_number_format_errors) {
948 CxJson json;
949 cxJsonInit(&json,
NULL);
950 CX_TEST_DO {
951 CxJsonValue *v;
952 CxJsonStatus result;
953
954 cxJsonFill(&json,
"+3.1415 ");
955 result = cxJsonNext(&json, &v);
956 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
957 "leading plus is not RFC-8259 compliant");
958 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
959 cxJsonReset(&json);
960
961 cxJsonFill(&json,
"0.815e-3.0 ");
962 result = cxJsonNext(&json, &v);
963 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
964 "exponent must be an integer");
965 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
966 cxJsonReset(&json);
967
968 cxJsonFill(&json,
"3.14e ");
969 result = cxJsonNext(&json, &v);
970 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
971 "exponent cannot be empty");
972 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
973 cxJsonReset(&json);
974
975 cxJsonFill(&json,
"3.14e~7 ");
976 result = cxJsonNext(&json, &v);
977 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
978 "exponent cannot start with bullshit");
979 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
980 cxJsonReset(&json);
981
982 cxJsonFill(&json,
"1.23e4f ");
983 result = cxJsonNext(&json, &v);
984 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
985 "non-digits in exponent");
986 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
987 cxJsonReset(&json);
988
989 cxJsonFill(&json,
"1.23f ");
990 result = cxJsonNext(&json, &v);
991 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
992 "non-digits in value");
993 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
994 cxJsonReset(&json);
995
996 cxJsonFill(&json,
"1.23.45 ");
997 result = cxJsonNext(&json, &v);
998 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
999 "multiple decimal separators");
1000 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
1001 cxJsonReset(&json);
1002
1003 cxJsonFill(&json,
"184467440737095516150123456789 ");
1004 result = cxJsonNext(&json, &v);
1005 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
1006 "30 digit int does not fit into 64-bit int");
1007 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
1008 cxJsonReset(&json);
1009 }
1010 cxJsonDestroy(&json);
1011 }
1012
1013 CX_TEST(test_json_multiple_values) {
1014 CxJson json;
1015 cxJsonInit(&json,
NULL);
1016 CX_TEST_DO {
1017 CxJsonValue *v;
1018 CxJsonStatus result;
1019
1020
1021 cxJsonFill(&json,
"10\n");
1022 result = cxJsonNext(&json, &v);
1023 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1024 CX_TEST_ASSERT(cxJsonIsNumber(v));
1025 CX_TEST_ASSERT(cxJsonAsInteger(v) ==
10);
1026 cxJsonValueFree(v);
1027
1028 result = cxJsonNext(&json, &v);
1029 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
1030
1031 cxJsonFill(&json,
"\"hello world\"\n");
1032 result = cxJsonNext(&json, &v);
1033 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1034 CX_TEST_ASSERT(cxJsonIsString(v));
1035 CX_TEST_ASSERT(!cx_strcmp(cxJsonAsCxString(v),
"hello world"));
1036 cxJsonValueFree(v);
1037
1038
1039 cxJsonFill(&json,
"{ \"value\": \"test\" }\n");
1040 result = cxJsonNext(&json, &v);
1041 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1042 CX_TEST_ASSERT(cxJsonIsObject(v));
1043 CxJsonValue *value = cxJsonObjGet(v,
"value");
1044 CX_TEST_ASSERT(cxJsonAsString(value));
1045 cxJsonValueFree(v);
1046
1047 cxJsonFill(&json,
"[ 0, 1, 2, 3, 4, 5 ]\n");
1048 result = cxJsonNext(&json, &v);
1049 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1050 CX_TEST_ASSERT(cxJsonIsArray(v));
1051 CxJsonValue *a0 = cxJsonArrGet(v,
0);
1052 CxJsonValue *a3 = cxJsonArrGet(v,
3);
1053 CX_TEST_ASSERT(cxJsonIsNumber(a0));
1054 CX_TEST_ASSERT(cxJsonAsInteger(a0) ==
0);
1055 CX_TEST_ASSERT(cxJsonIsNumber(a3));
1056 CX_TEST_ASSERT(cxJsonAsInteger(a3) ==
3);
1057 cxJsonValueFree(v);
1058
1059 cxJsonFill(&json,
"true\n");
1060 result = cxJsonNext(&json, &v);
1061 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1062 CX_TEST_ASSERT(cxJsonIsLiteral(v));
1063 CX_TEST_ASSERT(cxJsonIsBool(v));
1064 CX_TEST_ASSERT(cxJsonIsTrue(v));
1065 CX_TEST_ASSERT(cxJsonAsBool(v));
1066 cxJsonValueFree(v);
1067 cxJsonFill(&json,
"false\n");
1068 result = cxJsonNext(&json, &v);
1069 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1070 CX_TEST_ASSERT(cxJsonIsLiteral(v));
1071 CX_TEST_ASSERT(cxJsonIsBool(v));
1072 CX_TEST_ASSERT(cxJsonIsFalse(v));
1073 CX_TEST_ASSERT(!cxJsonAsBool(v));
1074 cxJsonValueFree(v);
1075 cxJsonFill(&json,
"null\n");
1076 result = cxJsonNext(&json, &v);
1077 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1078 CX_TEST_ASSERT(cxJsonIsLiteral(v));
1079 CX_TEST_ASSERT(!cxJsonIsBool(v));
1080 CX_TEST_ASSERT(cxJsonIsNull(v));
1081 cxJsonValueFree(v);
1082 }
1083 cxJsonDestroy(&json);
1084 }
1085
1086 CX_TEST(test_json_array) {
1087 CxTestingAllocator talloc;
1088 cx_testing_allocator_init(&talloc);
1089 const CxAllocator *allocator = &talloc.base;
1090 CX_TEST_DO {
1091 CxJsonValue *arr = cxJsonCreateArr(allocator,
0);
1092 cxJsonArrAddIntegers(arr, (
int64_t[]){
0,
3,
6,
9,
12,
15},
6);
1093 CX_TEST_ASSERT(cxJsonArrSize(arr) ==
6);
1094 CxJsonValue *e = cxJsonArrGet(arr,
3);
1095 CX_TEST_ASSERT(cxJsonIsNumber(e));
1096 CX_TEST_ASSERT(cxJsonAsInteger(e) ==
9);
1097 CX_TEST_ASSERT(cxJsonAsDouble(e) ==
9.0);
1098 CX_TEST_ASSERT(cxJsonArrSize(arr) ==
6);
1099 e = cxJsonArrGet(arr,
6);
1100 CX_TEST_ASSERT(!cxJsonIsNumber(e));
1101
1102 CX_TEST_ASSERT(!cxJsonIsNull(e));
1103 CX_TEST_ASSERT(e->type ==
CX_JSON_NOTHING);
1104 CxJsonValue *removed = cxJsonArrRemove(arr,
2);
1105 CX_TEST_ASSERT(cxJsonIsNumber(removed));
1106 CX_TEST_ASSERT(cxJsonAsInteger(removed) ==
6);
1107 CX_TEST_ASSERT(cxJsonArrSize(arr) ==
5);
1108 e = cxJsonArrGet(arr,
3);
1109 CX_TEST_ASSERT(cxJsonIsNumber(e));
1110 CX_TEST_ASSERT(cxJsonAsInteger(e) ==
12);
1111 e = cxJsonArrRemove(arr,
5);
1112 CX_TEST_ASSERT(e ==
NULL);
1113 cxJsonValueFree(arr);
1114
1115 CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
1116 cxJsonValueFree(removed);
1117 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1118 }
1119 cx_testing_allocator_destroy(&talloc);
1120 }
1121
1122 CX_TEST(test_json_array_iterator) {
1123 CxJson json;
1124 cxJsonInit(&json,
NULL);
1125 CX_TEST_DO {
1126 CxJsonValue *v;
1127 CxJsonStatus result;
1128 cxJsonFill(&json,
"[ 0, 3, 6, 9, 12, 15 ]\n");
1129 result = cxJsonNext(&json, &v);
1130 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1131 CX_TEST_ASSERT(cxJsonIsArray(v));
1132 CxIterator iter = cxJsonArrIter(v);
1133 unsigned i =
0;
1134 cx_foreach(CxJsonValue*, elem, iter) {
1135 CX_TEST_ASSERT(cxJsonIsNumber(elem));
1136 CX_TEST_ASSERT(i == cxJsonAsInteger(elem));
1137 i +=
3;
1138 }
1139 cxJsonValueFree(v);
1140 }
1141 cxJsonDestroy(&json);
1142 }
1143
1144 CX_TEST(test_json_allocator) {
1145 CxTestingAllocator talloc;
1146 cx_testing_allocator_init(&talloc);
1147 CxAllocator *allocator = &talloc.base;
1148
1149 cxstring text = cx_str(
1150 "{\n"
1151 "\t\"message\":\"success\",\n"
1152 "\t\"data\":[\"value1\",{\"x\":123, \"y\":523 }]\n"
1153 "}"
1154 );
1155
1156 CX_TEST_DO {
1157 CxJson json;
1158 cxJsonInit(&json, allocator);
1159 cxJsonFill(&json, text);
1160
1161 CxJsonValue *obj;
1162 CxJsonStatus result = cxJsonNext(&json, &obj);
1163 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1164 CX_TEST_ASSERT(obj->allocator == allocator);
1165
1166
1167 cxJsonValueFree(obj);
1168 cxJsonDestroy(&json);
1169
1170 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1171 }
1172 cx_testing_allocator_destroy(&talloc);
1173 }
1174
1175 CX_TEST(test_json_allocator_parse_error) {
1176 CxTestingAllocator talloc;
1177 cx_testing_allocator_init(&talloc);
1178 CxAllocator *allocator = &talloc.base;
1179
1180 cxstring text = cx_str(
1181 "{\n"
1182 "\t\"message\":\"success\"\n"
1183 "\t\"data\":[\"value1\",{\"x\":123, \"y\":523 }]\n"
1184 "}"
1185 );
1186
1187 CX_TEST_DO {
1188 CxJson json;
1189 cxJsonInit(&json, allocator);
1190 cxJsonFill(&json, text);
1191
1192 CxJsonValue *obj =
NULL;
1193 CxJsonStatus result = cxJsonNext(&json, &obj);
1194 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
1195 CX_TEST_ASSERT(obj !=
NULL && obj->type ==
CX_JSON_NOTHING);
1196
1197
1198 cxJsonDestroy(&json);
1199
1200 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1201 }
1202 cx_testing_allocator_destroy(&talloc);
1203 }
1204
1205 CX_TEST(test_json_create_value) {
1206 CxTestingAllocator talloc;
1207 cx_testing_allocator_init(&talloc);
1208 CxAllocator *allocator = &talloc.base;
1209 CX_TEST_DO {
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228 CxJsonValue *obj = cxJsonCreateObj(allocator);
1229 CX_TEST_ASSERT(obj !=
NULL);
1230 CX_TEST_ASSERT(cxJsonIsObject(obj));
1231 CX_TEST_ASSERT(obj->allocator == allocator);
1232
1233
1234 {
1235 cxJsonObjPutLiteral(obj,
"bool",
CX_JSON_FALSE);
1236 cxJsonObjPutInteger(obj,
"int",
47);
1237 CxJsonValue *strings = cxJsonObjPutArr(obj,
"strings",
0);
1238 CX_TEST_ASSERT(strings !=
NULL);
1239 CX_TEST_ASSERT(cxJsonIsArray(strings));
1240 const char* str[] = {
"hello",
"world"};
1241 CX_TEST_ASSERT(
0 == cxJsonArrAddStrings(strings, str,
2));
1242
1243 CxJsonValue *nested = cxJsonObjPutObj(obj,
"nested");
1244 CX_TEST_ASSERT(nested !=
NULL);
1245 CX_TEST_ASSERT(cxJsonIsObject(nested));
1246 cxJsonObjPutString(nested,
"string",
"test");
1247
1248 cxJsonArrAddNumbers(cxJsonObjPutArr(nested,
"floats",
0),
1249 (
double[]){
3.1415,
47.11,
8.15},
3);
1250 cxJsonArrAddIntegers(cxJsonObjPutArr(nested,
"ints",
0),
1251 (
int64_t[]){
4,
8,
15,
16,
23,
42},
6);
1252 cxJsonArrAddLiterals(cxJsonObjPutArr(nested,
"literals",
0),
1253 (CxJsonLiteral[]){
CX_JSON_TRUE,
CX_JSON_NULL,
CX_JSON_FALSE},
3);
1254 }
1255
1256
1257 {
1258 CX_TEST_ASSERT(cxJsonIsFalse(cxJsonObjGet(obj,
"bool")));
1259 CX_TEST_ASSERT(
47 == cxJsonAsInteger(cxJsonObjGet(obj,
"int")));
1260 CxJsonValue *strings = cxJsonObjGet(obj,
"strings");
1261 CX_TEST_ASSERT(cxJsonIsArray(strings));
1262 CX_TEST_ASSERT(
2 == cxJsonArrSize(strings));
1263 CX_TEST_ASSERT(
0 == cx_strcmp(
"hello", cxJsonAsString(cxJsonArrGet(strings,
0))));
1264 CX_TEST_ASSERT(
0 == cx_strcmp(
"world", cxJsonAsString(cxJsonArrGet(strings,
1))));
1265
1266 CxJsonValue *nested = cxJsonObjGet(obj,
"nested");
1267 CX_TEST_ASSERT(cxJsonIsObject(nested));
1268 CX_TEST_ASSERT(
0 == strcmp(
"test", cxJsonAsString(cxJsonObjGet(nested,
"string"))));
1269 CxJsonValue *floats = cxJsonObjGet(nested,
"floats");
1270 CX_TEST_ASSERT(cxJsonIsArray(floats));
1271 CX_TEST_ASSERT(
3 == cxJsonArrSize(floats));
1272 CX_TEST_ASSERT(
3.1415 == cxJsonAsDouble(cxJsonArrGet(floats,
0)));
1273 CX_TEST_ASSERT(
47.11 == cxJsonAsDouble(cxJsonArrGet(floats,
1)));
1274 CX_TEST_ASSERT(
8.15 == cxJsonAsDouble(cxJsonArrGet(floats,
2)));
1275 CxJsonValue *ints = cxJsonObjGet(nested,
"ints");
1276 CX_TEST_ASSERT(cxJsonIsArray(ints));
1277 CX_TEST_ASSERT(
6 == cxJsonArrSize(ints));
1278 CX_TEST_ASSERT(
4 == cxJsonAsInteger(cxJsonArrGet(ints,
0)));
1279 CX_TEST_ASSERT(
8 == cxJsonAsInteger(cxJsonArrGet(ints,
1)));
1280 CX_TEST_ASSERT(
15 == cxJsonAsInteger(cxJsonArrGet(ints,
2)));
1281 CX_TEST_ASSERT(
16 == cxJsonAsInteger(cxJsonArrGet(ints,
3)));
1282 CX_TEST_ASSERT(
23 == cxJsonAsInteger(cxJsonArrGet(ints,
4)));
1283 CX_TEST_ASSERT(
42 == cxJsonAsInteger(cxJsonArrGet(ints,
5)));
1284 CxJsonValue *literals = cxJsonObjGet(nested,
"literals");
1285 CX_TEST_ASSERT(cxJsonIsArray(literals));
1286 CX_TEST_ASSERT(
3 == cxJsonArrSize(literals));
1287 CX_TEST_ASSERT(cxJsonIsTrue(cxJsonArrGet(literals,
0)));
1288 CX_TEST_ASSERT(cxJsonIsNull(cxJsonArrGet(literals,
1)));
1289 CX_TEST_ASSERT(cxJsonIsFalse(cxJsonArrGet(literals,
2)));
1290 }
1291
1292
1293 cxJsonValueFree(obj);
1294 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1295 }
1296 cx_testing_allocator_destroy(&talloc);
1297 }
1298
1299 CX_TEST(test_json_overwrite_value) {
1300 CxTestingAllocator talloc;
1301 cx_testing_allocator_init(&talloc);
1302 CxAllocator *allocator = &talloc.base;
1303 CX_TEST_DO {
1304 CxJsonValue *obj = cxJsonCreateObj(allocator);
1305
1306
1307 cxJsonObjPutInteger(obj,
"test1",
1);
1308 cxJsonObjPutInteger(obj,
"test2",
2);
1309 cxJsonObjPutInteger(obj,
"test3",
3);
1310
1311
1312 cxJsonObjPutInteger(obj,
"test2",
0);
1313
1314
1315 CxMapIterator iter = cxJsonObjIter(obj);
1316 bool found[
5] = {
0};
1317 cx_foreach(CxMapEntry *, ov, iter) {
1318 CxJsonValue *v = ov->value;
1319 CX_TEST_ASSERT(cxJsonIsInteger(v));
1320 int64_t i = cxJsonAsInteger(v);
1321 CX_TEST_ASSERT(i >=
0 && i <=
4);
1322 found[i] = true;
1323 }
1324 CX_TEST_ASSERT(found[
0]);
1325 CX_TEST_ASSERT(found[
1]);
1326 CX_TEST_ASSERT(!found[
2]);
1327 CX_TEST_ASSERT(found[
3]);
1328 CX_TEST_ASSERT(!found[
4]);
1329
1330
1331 cxJsonValueFree(obj);
1332 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1333 }
1334 cx_testing_allocator_destroy(&talloc);
1335 }
1336
1337 CX_TEST(test_json_compare_primitives) {
1338 CxJsonValue *a[
14];
1339 a[
0] = cxJsonCreateLiteral(
NULL,
CX_JSON_NULL);
1340 a[
1] = cxJsonCreateLiteral(
NULL,
CX_JSON_TRUE);
1341 a[
2] = cxJsonCreateLiteral(
NULL,
CX_JSON_FALSE);
1342 a[
3] = cxJsonCreateInteger(
NULL,
1234);
1343 a[
4] = cxJsonCreateInteger(
NULL,
5432);
1344 a[
5] = cxJsonCreateInteger(
NULL,
-10);
1345 a[
6] = cxJsonCreateInteger(
NULL,
0);
1346 a[
7] = cxJsonCreateNumber(
NULL,
0.0f);
1347 a[
8] = cxJsonCreateNumber(
NULL,
13.37f);
1348 a[
9] = cxJsonCreateNumber(
NULL,
-123.456f);
1349 a[
10] = cxJsonCreateNumber(
NULL,
1234.0f);
1350 a[
11] = cxJsonCreateNumber(
NULL,
-10.3f);
1351 a[
12] = cxJsonCreateString(
NULL,
"hello");
1352 a[
13] = cxJsonCreateString(
NULL,
"world");
1353
1354 CxJsonValue *b[
14];
1355 b[
0] = cxJsonCreateLiteral(
NULL,
CX_JSON_NULL);
1356 b[
1] = cxJsonCreateLiteral(
NULL,
CX_JSON_TRUE);
1357 b[
2] = cxJsonCreateLiteral(
NULL,
CX_JSON_FALSE);
1358 b[
3] = cxJsonCreateInteger(
NULL,
1234);
1359 b[
4] = cxJsonCreateInteger(
NULL,
5432);
1360 b[
5] = cxJsonCreateInteger(
NULL,
-10);
1361 b[
6] = cxJsonCreateInteger(
NULL,
0);
1362 b[
7] = cxJsonCreateNumber(
NULL,
0.0f);
1363 b[
8] = cxJsonCreateNumber(
NULL,
13.37f);
1364 b[
9] = cxJsonCreateNumber(
NULL,
-123.456f);
1365 b[
10] = cxJsonCreateNumber(
NULL,
1234.0f);
1366 b[
11] = cxJsonCreateNumber(
NULL,
-10.3f);
1367 b[
12] = cxJsonCreateString(
NULL,
"hello");
1368 b[
13] = cxJsonCreateString(
NULL,
"world");
1369
1370 CX_TEST_DO {
1371 for(
int i=
0;i<
12;i++) {
1372 for(
int j=
0;j<
12;j++) {
1373 int ret = cxJsonCompare(a[i], b[j]);
1374 if(i == j) {
1375 CX_TEST_ASSERT(ret ==
0);
1376 }
else {
1377 if(cxJsonIsNumber(a[i]) && cxJsonIsNumber(b[j])) {
1378 double diff = fabs(cxJsonAsDouble(a[i]) - cxJsonAsDouble(b[j]));
1379 if(diff <
0.001) {
1380 CX_TEST_ASSERT(ret ==
0);
1381 }
else {
1382 CX_TEST_ASSERT(ret !=
0);
1383 }
1384 }
else {
1385 CX_TEST_ASSERT(ret !=
0);
1386 }
1387 }
1388 }
1389 }
1390
1391 }
1392 for(
int i=
0;i<
14;i++) {
1393 cxJsonValueFree(a[i]);
1394 cxJsonValueFree(b[i]);
1395 }
1396 }
1397
1398 CX_TEST(test_json_compare_objects) {
1399 CxJsonValue *json[
10];
1400 cxJsonFromString(
NULL,
"{ }", &json[
0]);
1401 cxJsonFromString(
NULL,
"{ }", &json[
1]);
1402 cxJsonFromString(
NULL,
"{ \"name\": \"value\" }", &json[
2]);
1403 cxJsonFromString(
NULL,
"{ \"name\": \"value\" }", &json[
7]);
1404 cxJsonFromString(
NULL,
"{ \"key0\": \"value0\", \"key1\": \"value1\", \"key2\":null }", &json[
3]);
1405 cxJsonFromString(
NULL,
"{ \"key1\": \"value1\", \"key2\":null, \"key0\": \"value0\" }", &json[
4]);
1406
1407 const char *json_complex_object =
1408 "{\n"
1409 " \"bool\": false,\n"
1410 " \"int\": 47,\n"
1411 " \"strings\": [ \"hello\", \"world\" ],\n"
1412 " \"nested\": {\n"
1413 " \"string\": \"test\",\n"
1414 " \"floats\": [ 3.1415, 47.11, 8.15 ],\n"
1415 " \"ints\": [ 4, 8, 15, 16, 23, 42 ],\n"
1416 " \"literals\": [ true, null, false ],\n"
1417 " \"objects\": [\n"
1418 " {},\n"
1419 " { \"unicode\": \"\\u03a3\\u29b0\" },\n"
1420 " { \"array\": [ 1,2,3] }\n"
1421 " ]\n"
1422 " }\n"
1423 "}\n";
1424 cxJsonFromString(
NULL, json_complex_object, &json[
5]);
1425 cxJsonFromString(
NULL, json_complex_object, &json[
6]);
1426 const char *json_complex_object_int_array_mismatch =
1427 "{\n"
1428 " \"bool\": false,\n"
1429 " \"int\": 47,\n"
1430 " \"strings\": [ \"hello\", \"world\" ],\n"
1431 " \"nested\": {\n"
1432 " \"string\": \"test\",\n"
1433 " \"floats\": [ 3.1415, 47.11, 8.15 ],\n"
1434 " \"ints\": [ 4, 8, 16, 15, 23, 42 ],\n"
1435 " \"literals\": [ true, null, false ],\n"
1436 " \"objects\": [\n"
1437 " {},\n"
1438 " { \"unicode\": \"\\u03a3\\u29b0\" },\n"
1439 " { \"array\": [ 1,2,3] }\n"
1440 " ]\n"
1441 " }\n"
1442 "}\n";
1443 cxJsonFromString(
NULL, json_complex_object_int_array_mismatch, &json[
8]);
1444 const char *json_complex_object_different_order =
1445 "{\n"
1446 " \"bool\": false,\n"
1447 " \"nested\": {\n"
1448 " \"string\": \"test\",\n"
1449 " \"ints\": [ 4, 8, 15, 16, 23, 42 ],\n"
1450 " \"floats\": [ 3.1415, 47.11, 8.15 ],\n"
1451 " \"objects\": [\n"
1452 " {},\n"
1453 " { \"unicode\": \"\\u03a3\\u29b0\" },\n"
1454 " { \"array\": [ 1,2,3] }\n"
1455 " ],\n"
1456 " \"literals\": [ true, null, false ]\n"
1457 " },\n"
1458 " \"int\": 47,\n"
1459 " \"strings\": [ \"hello\", \"world\" ]\n"
1460 "}\n";
1461 cxJsonFromString(
NULL, json_complex_object_different_order, &json[
9]);
1462
1463 CX_TEST_DO {
1464 for (
unsigned i =
0; i < cx_nmemb(json); i++) {
1465 CX_TEST_ASSERT(cxJsonIsObject(json[i]));
1466 }
1467
1468 CX_TEST_ASSERT(cxJsonCompare(json[
0], json[
0]) ==
0);
1469 CX_TEST_ASSERT(cxJsonCompare(json[
0], json[
1]) ==
0);
1470 CX_TEST_ASSERT(cxJsonCompare(json[
1], json[
0]) ==
0);
1471 CX_TEST_ASSERT(cxJsonCompare(json[
2], json[
7]) ==
0);
1472 CX_TEST_ASSERT(cxJsonCompare(json[
7], json[
2]) ==
0);
1473
1474
1475 CX_TEST_ASSERT(cxJsonCompare(json[
2], json[
3]) !=
0);
1476 CX_TEST_ASSERT(cxJsonCompare(json[
2], json[
5]) !=
0);
1477
1478
1479 CX_TEST_ASSERT(cxJsonCompare(json[
3], json[
4]) ==
0);
1480
1481
1482 CX_TEST_ASSERT(cxJsonCompare(json[
5], json[
6]) ==
0);
1483 CX_TEST_ASSERT(cxJsonCompare(json[
6], json[
5]) ==
0);
1484
1485
1486 CX_TEST_ASSERT(cxJsonCompare(json[
5], json[
8]) !=
0);
1487 CX_TEST_ASSERT(cxJsonCompare(json[
8], json[
5]) !=
0);
1488
1489
1490 CX_TEST_ASSERT(cxJsonCompare(json[
5], json[
9]) ==
0);
1491 CX_TEST_ASSERT(cxJsonCompare(json[
6], json[
9]) ==
0);
1492 CX_TEST_ASSERT(cxJsonCompare(json[
9], json[
5]) ==
0);
1493 CX_TEST_ASSERT(cxJsonCompare(json[
9], json[
6]) ==
0);
1494 }
1495
1496 for(
unsigned i=
0;i<cx_nmemb(json);i++) {
1497 cxJsonValueFree(json[i]);
1498 }
1499 }
1500
1501 CX_TEST(test_json_compare_arrays) {
1502 char *str[
6];
1503 str[
0] =
"[]";
1504 str[
1] =
"[[]]";
1505 str[
2] =
"[[ {} ], { \"a\": [[[[ {} ], null]]]} ]";
1506 str[
3] =
"[ true, false ]";
1507 str[
4] =
"[ 0, 1, \"hello\", true, false, null, {}, {\"a\":\"b\"}]";
1508 str[
5] =
"[ \"test\", [ 1, 2, [ \"sub\", \"sub1\", [{\"end\":null}]]]]";
1509
1510 CxJsonValue *a[
6];
1511 CxJsonValue *b[
6];
1512 for(
int i=
0;i<
6;i++) {
1513 cxJsonFromString(
NULL, str[i], &a[i]);
1514 cxJsonFromString(
NULL, str[i], &b[i]);
1515 }
1516
1517 CX_TEST_DO {
1518 for(
int i=
0;i<
6;i++) {
1519
1520 CX_TEST_ASSERT(cxJsonIsArray(a[i]));
1521
1522 for(
int j=
0;j<
6;j++) {
1523 int ret = cxJsonCompare(a[i], b[j]);
1524 CX_TEST_ASSERT(i == j ? ret ==
0 : ret !=
0);
1525 }
1526 }
1527
1528
1529 CxJsonValue *value;
1530 cxJsonFromString(
NULL,
1531 "{ \"array1\" : [ 1, 2, 10, 20, true, false, null, {} ],\n"
1532 " \"array2\" : [\n"
1533 " 1,\n"
1534 " 2,\n"
1535 " 10,\n"
1536 " 20,\n"
1537 " true,\n"
1538 " false,\n"
1539 " null,\n"
1540 " {},\n"
1541 " ]\n"
1542 "}\n",
1543 &value);
1544 CX_TEST_ASSERT(value);
1545 CX_TEST_ASSERT(cxJsonIsObject(value));
1546 CxJsonValue *arr1 = cxJsonObjGet(value,
"array1");
1547 CxJsonValue *arr2 = cxJsonObjGet(value,
"array2");
1548 CX_TEST_ASSERT(arr1 && arr2);
1549 CX_TEST_ASSERT(cxJsonIsArray(arr1) && cxJsonIsArray(arr2));
1550 CX_TEST_ASSERT(cxJsonCompare(arr1, arr2) ==
0);
1551 cxJsonValueFree(value);
1552
1553 cxJsonFromString(
NULL,
"[ 0, 1, 2, 3, 4, 5 ]", &value);
1554 CX_TEST_ASSERT(value);
1555 CX_TEST_ASSERT(cxJsonIsArray(value));
1556
1557 CxJsonValue *value2 = cxJsonCreateArr(
NULL,
16);
1558 int64_t ints[] = {
0,
1,
2,
3,
4,
5 };
1559 cxJsonArrAddIntegers(value2, ints,
6);
1560 CX_TEST_ASSERT(cxJsonCompare(value, value2) ==
0);
1561
1562 cxJsonValueFree(value);
1563 cxJsonValueFree(value2);
1564 }
1565
1566 for(
int i=
0;i<
6;i++) {
1567 cxJsonValueFree(a[i]);
1568 cxJsonValueFree(b[i]);
1569 }
1570 }
1571
1572 CX_TEST(test_json_clone_primitives) {
1573 CxJsonValue *a[
14];
1574 a[
0] = cxJsonCreateLiteral(
NULL,
CX_JSON_NULL);
1575 a[
1] = cxJsonCreateLiteral(
NULL,
CX_JSON_TRUE);
1576 a[
2] = cxJsonCreateLiteral(
NULL,
CX_JSON_FALSE);
1577 a[
3] = cxJsonCreateInteger(
NULL,
1234);
1578 a[
4] = cxJsonCreateInteger(
NULL,
5432);
1579 a[
5] = cxJsonCreateInteger(
NULL,
-10);
1580 a[
6] = cxJsonCreateInteger(
NULL,
0);
1581 a[
7] = cxJsonCreateNumber(
NULL,
0.0f);
1582 a[
8] = cxJsonCreateNumber(
NULL,
13.37f);
1583 a[
9] = cxJsonCreateNumber(
NULL,
-123.456f);
1584 a[
10] = cxJsonCreateNumber(
NULL,
1234.0f);
1585 a[
11] = cxJsonCreateNumber(
NULL,
-10.3f);
1586 a[
12] = cxJsonCreateString(
NULL,
"");
1587 a[
13] = cxJsonCreateString(
NULL,
"test");
1588
1589 CX_TEST_DO {
1590 CxJsonValue *n = cxJsonClone(
NULL,
NULL);
1591 CX_TEST_ASSERT(n !=
NULL);
1592 CX_TEST_ASSERT(n->type ==
CX_JSON_NOTHING);
1593
1594 for(
int i=
0;i<
14;i++) {
1595
1596 CX_TEST_ASSERT(a[i]->type !=
CX_JSON_NOTHING);
1597
1598 CxJsonValue *b = cxJsonClone(a[i],
NULL);
1599 CX_TEST_ASSERT(b !=
NULL);
1600 CX_TEST_ASSERT(a[i]->type == b->type);
1601 CX_TEST_ASSERT(cxJsonCompare(a[i], b) ==
0);
1602
1603
1604 cxmutstr aStr = cxJsonToString(
NULL, a[i]);
1605 cxmutstr bStr = cxJsonToString(
NULL, b);
1606 CX_TEST_ASSERT(cx_strcmp(aStr, bStr) ==
0);
1607 cxFree(cxDefaultAllocator, aStr.ptr);
1608 cxFree(cxDefaultAllocator, bStr.ptr);
1609
1610 cxJsonValueFree(b);
1611 }
1612
1613 CxJsonValue *nan1 = cxJsonCreateNumber(
NULL,
NAN);
1614 CxJsonValue *nan2 = cxJsonClone(nan1,
NULL);
1615 CX_TEST_ASSERT(nan2 !=
NULL);
1616 CX_TEST_ASSERT(nan2->type ==
CX_JSON_NUMBER);
1617 CX_TEST_ASSERT(isnan(nan2->number));
1618
1619 cxJsonValueFree(nan1);
1620 cxJsonValueFree(nan2);
1621 }
1622
1623 for(
int i=
0;i<
14;i++) {
1624 cxJsonValueFree(a[i]);
1625 }
1626 }
1627
1628 #ifndef TEST_CLONE_OBJECTS_LARGE_OBJ
1629 #define TEST_CLONE_OBJECTS_LARGE_OBJ 100
1630 #endif
1631 #ifndef TEST_CLONE_OBJECTS_LARGE_ARR
1632 #define TEST_CLONE_OBJECTS_LARGE_ARR 200
1633 #endif
1634 CX_TEST(test_json_clone_objects) {
1635 CxJsonValue *a[
10];
1636
1637 cxJsonFromString(
NULL,
"{}", &a[
0]);
1638 cxJsonFromString(
NULL,
"{ \"key\":\"value\" }", &a[
1]);
1639 cxJsonFromString(
NULL,
"{ \"abc\": {} }", &a[
2]);
1640 cxJsonFromString(
NULL,
"{ \"abc\": [ false ] }", &a[
3]);
1641 cxJsonFromString(
NULL,
"{ \"a4\": { \"x1\": 123, \"x2\": 456 } }", &a[
4]);
1642 cxJsonFromString(
NULL,
"{ \"a5\": [ true, false, null ] }", &a[
5]);
1643 cxJsonFromString(
NULL,
"{ \"a5\": [ true, false, null, {} ] }", &a[
6]);
1644 cxJsonFromString(
NULL,
"{ \"string\": \"hello\", \"int\": 12, \"literal\":true }", &a[
7]);
1645 cxJsonFromString(
NULL,
1646 "{ \"x0\": {\n"
1647 " \"x1\": {\n"
1648 " \"x2\": {\n"
1649 " \"x3\": {\n"
1650 " \"x4\": [\n"
1651 " 1, 2, [3, [4, [[[{\"x5\":6}]]]]]\n"
1652 " ]\n"
1653 " }\n"
1654 " }\n"
1655 " }\n"
1656 " }\n"
1657 "}",
1658 &a[
8]);
1659 a[
9] = cxJsonCreateObj(
NULL);
1660
1661
1662 for(
int i=
0;i<
TEST_CLONE_OBJECTS_LARGE_OBJ;i++) {
1663 char buf[
32];
1664 snprintf(buf,
32,
"int%d", i);
1665 cxJsonObjPutInteger(a[
9], buf, i);
1666
1667
1668 CxJsonValue *arr = cxJsonCreateArr(
NULL,
TEST_CLONE_OBJECTS_LARGE_ARR);
1669 int64_t *ints = calloc(
TEST_CLONE_OBJECTS_LARGE_ARR,
sizeof(
int64_t));
1670 for(
int n=
0;n<
TEST_CLONE_OBJECTS_LARGE_ARR;n++) {
1671 ints[i] = n;
1672 }
1673 cxJsonArrAddIntegers(arr, ints,
TEST_CLONE_OBJECTS_LARGE_ARR);
1674 free(ints);
1675 cxJsonObjPut(a[
9],
"array", arr);
1676 }
1677
1678 CX_TEST_DO {
1679 for(
unsigned i=
0;i<cx_nmemb(a);i++) {
1680 CX_TEST_ASSERT(cxJsonIsObject(a[i]));
1681
1682 CxJsonValue *b = cxJsonClone(a[i],
NULL);
1683
1684 CX_TEST_ASSERT(b !=
NULL);
1685 CX_TEST_ASSERT(b->type == a[i]->type);
1686 CX_TEST_ASSERT(cxJsonCompare(a[i], b) ==
0);
1687
1688 cxmutstr a_str = cxJsonToString(
NULL, a[i]);
1689 cxmutstr b_str = cxJsonToString(
NULL, b);
1690 CX_TEST_ASSERT(cx_strcmp(a_str, b_str) ==
0);
1691 cx_strfree(&a_str);
1692 cx_strfree(&b_str);
1693
1694 cxJsonValueFree(b);
1695 }
1696 }
1697
1698 for(
int i=
0;i<
10;i++) {
1699 cxJsonValueFree(a[i]);
1700 }
1701 }
1702
1703 CX_TEST(test_json_clone_arrays) {
1704 CxJsonValue *a[
6];
1705 cxJsonFromString(
NULL,
"[]", &a[
0]);
1706 cxJsonFromString(
NULL,
"[ 1, 2, 4, 8, 16, 32, 64 ]", &a[
1]);
1707 cxJsonFromString(
NULL,
"[ \"string\", 12, 3.14, true, null, false, [] ]", &a[
2]);
1708 cxJsonFromString(
NULL,
"[[1, [[2, [3, 4, 5]]], true], false]", &a[
3]);
1709 cxJsonFromString(
NULL,
"[ { \"abc\": 200, \"str\": \"hello\" }, { }, null ]", &a[
4]);
1710 cxJsonFromString(
NULL,
"[ { \"array\": [ 1,2,3 ]} ]", &a[
5]);
1711
1712 CX_TEST_DO {
1713 for(
unsigned i=
0;i<cx_nmemb(a);i++) {
1714 CX_TEST_ASSERT(cxJsonIsArray(a[i]));
1715
1716 CxJsonValue *b = cxJsonClone(a[i],
NULL);
1717 CX_TEST_ASSERT(b);
1718 CX_TEST_ASSERT(cxJsonIsArray(b));
1719 CX_TEST_ASSERT(cxJsonCompare(a[i], b) ==
0);
1720
1721 cxmutstr a_str = cxJsonToString(
NULL, a[i]);
1722 cxmutstr b_str = cxJsonToString(
NULL, b);
1723 CX_TEST_ASSERT(cx_strcmp(a_str, b_str) ==
0);
1724 cx_strfree(&a_str);
1725 cx_strfree(&b_str);
1726
1727 cxJsonValueFree(b);
1728 }
1729 }
1730
1731 for(
int i=
0;i<
6;i++) {
1732 cxJsonValueFree(a[i]);
1733 }
1734 }
1735
1736
1737
1738 static CxJsonValue *test_json_write_create_test_object(
const CxAllocator *allocator) {
1739 CxJsonValue *obj = cxJsonCreateObj(allocator);
1740 cxJsonObjPutLiteral(obj,
"bool",
CX_JSON_FALSE);
1741 cxJsonObjPutNumber(obj,
"int",
47);
1742 CxJsonValue *strings = cxJsonObjPutArr(obj,
"strings",
0);
1743 cxJsonArrAddCxStrings(strings, (cxstring[]) {cx_str(
"hello"), cx_str(
"world")},
2);
1744 CxJsonValue *nested = cxJsonObjPutObj(obj,
"nested");
1745 CxJsonValue *objects = cxJsonObjPutArr(nested,
"objects",
0);
1746 CxJsonValue *obj_in_arr[
2] = {cxJsonCreateObj(allocator), cxJsonCreateObj(allocator)};
1747 cxJsonObjPutInteger(obj_in_arr[
0],
"name1",
1);
1748 cxJsonObjPutInteger(obj_in_arr[
0],
"name2",
3);
1749 cxJsonObjPutInteger(obj_in_arr[
1],
"name2",
7);
1750 cxJsonObjPutInteger(obj_in_arr[
1],
"name1",
3);
1751 cxJsonArrAddValues(objects, obj_in_arr,
2);
1752 cxJsonArrAddNumbers(cxJsonObjPutArr(nested,
"floats",
0),
1753 (
double[]){
3.1415,
47.11,
8.15},
3);
1754 cxJsonArrAddLiterals(cxJsonObjPutArr(nested,
"literals",
2),
1755 (CxJsonLiteral[]){
CX_JSON_TRUE,
CX_JSON_NULL,
CX_JSON_FALSE},
3);
1756 CxJsonValue *ints = cxJsonObjPutArr(nested,
"ints",
3);
1757 cxJsonArrAddIntegers(ints, (
int64_t[]){
4,
8,
15},
3);
1758 CxJsonValue *nested_array = cxJsonCreateArr(allocator,
0);
1759 cxJsonArrAddValues(ints, &nested_array,
1);
1760 cxJsonArrAddIntegers(nested_array, (
int64_t[]){
16,
23},
2);
1761 cxJsonArrAddIntegers(ints, (
int64_t[]){
42},
1);
1762 return obj;
1763 }
1764
1765 CX_TEST_SUBROUTINE(test_json_write_sub,
1766 const CxAllocator *allocator,
1767 cxstring expected,
1768 const CxJsonWriter *writer
1769 ) {
1770
1771 CxJsonValue *obj = test_json_write_create_test_object(allocator);
1772
1773
1774 CxBuffer buf;
1775 cxBufferInit(&buf,
NULL,
NULL,
512,
CX_BUFFER_DEFAULT);
1776 int result = cxJsonWrite(&buf, obj, cxBufferWriteFunc, writer);
1777 cxBufferTerminate(&buf);
1778 CX_TEST_ASSERT(result ==
0);
1779
1780
1781 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size), expected));
1782
1783
1784 cxBufferDestroy(&buf);
1785 cxJsonValueFree(obj);
1786 }
1787
1788 CX_TEST(test_json_write_default_format) {
1789 CxTestingAllocator talloc;
1790 cx_testing_allocator_init(&talloc);
1791 CxAllocator *allocator = &talloc.base;
1792 CX_TEST_DO {
1793
1794 cxstring expected = cx_str(
1795 "{\"bool\":false,"
1796 "\"int\":47,"
1797 "\"strings\":[\"hello\",\"world\"],"
1798 "\"nested\":{"
1799 "\"objects\":[{"
1800 "\"name1\":1,"
1801 "\"name2\":3"
1802 "},{"
1803 "\"name2\":7,"
1804 "\"name1\":3"
1805 "}],"
1806 "\"floats\":[3.1415,47.11,8.15],"
1807 "\"literals\":[true,null,false],"
1808 "\"ints\":[4,8,15,[16,23],42]"
1809 "}"
1810 "}"
1811 );
1812
1813 CxJsonWriter writer = cxJsonWriterCompact();
1814 CX_TEST_CALL_SUBROUTINE(test_json_write_sub, allocator, expected, &writer);
1815
1816 CX_TEST_CALL_SUBROUTINE(test_json_write_sub, allocator, expected,
NULL);
1817 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1818 }
1819 cx_testing_allocator_destroy(&talloc);
1820 }
1821
1822 CX_TEST(test_json_write_pretty_default_spaces) {
1823 CxTestingAllocator talloc;
1824 cx_testing_allocator_init(&talloc);
1825 CxAllocator *allocator = &talloc.base;
1826 CX_TEST_DO {
1827 cxstring expected = cx_str(
1828 "{\n"
1829 " \"bool\": false,\n"
1830 " \"int\": 47,\n"
1831 " \"strings\": [\"hello\", \"world\"],\n"
1832 " \"nested\": {\n"
1833 " \"objects\": [{\n"
1834 " \"name1\": 1,\n"
1835 " \"name2\": 3\n"
1836 " }, {\n"
1837 " \"name2\": 7,\n"
1838 " \"name1\": 3\n"
1839 " }],\n"
1840 " \"floats\": [3.1415, 47.11, 8.15],\n"
1841 " \"literals\": [true, null, false],\n"
1842 " \"ints\": [4, 8, 15, [16, 23], 42]\n"
1843 " }\n"
1844 "}"
1845 );
1846
1847 CxJsonWriter writer = cxJsonWriterPretty(true);
1848 CX_TEST_CALL_SUBROUTINE(test_json_write_sub, allocator, expected, &writer);
1849 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1850 }
1851 cx_testing_allocator_destroy(&talloc);
1852 }
1853
1854 CX_TEST(test_json_write_pretty_default_tabs) {
1855 CxTestingAllocator talloc;
1856 cx_testing_allocator_init(&talloc);
1857 CxAllocator *allocator = &talloc.base;
1858 CX_TEST_DO {
1859 cxstring expected = cx_str(
1860 "{\n"
1861 "\t\"bool\": false,\n"
1862 "\t\"int\": 47,\n"
1863 "\t\"strings\": [\"hello\", \"world\"],\n"
1864 "\t\"nested\": {\n"
1865 "\t\t\"objects\": [{\n"
1866 "\t\t\t\"name1\": 1,\n"
1867 "\t\t\t\"name2\": 3\n"
1868 "\t\t}, {\n"
1869 "\t\t\t\"name2\": 7,\n"
1870 "\t\t\t\"name1\": 3\n"
1871 "\t\t}],\n"
1872 "\t\t\"floats\": [3.1415, 47.11, 8.15],\n"
1873 "\t\t\"literals\": [true, null, false],\n"
1874 "\t\t\"ints\": [4, 8, 15, [16, 23], 42]\n"
1875 "\t}\n"
1876 "}"
1877 );
1878 CxJsonWriter writer = cxJsonWriterPretty(false);
1879 CX_TEST_CALL_SUBROUTINE(test_json_write_sub, allocator, expected, &writer);
1880 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1881 }
1882 cx_testing_allocator_destroy(&talloc);
1883 }
1884
1885 CX_TEST(test_json_write_pretty_deep_nesting) {
1886 CxTestingAllocator talloc;
1887 cx_testing_allocator_init(&talloc);
1888 CxAllocator *allocator = &talloc.base;
1889 CX_TEST_DO {
1890 cxstring expected = cx_str(
1891 "{\n"
1892 " \"test\": {\n"
1893 " \"test\": {\n"
1894 " \"test\": {\n"
1895 " \"test\": {\n"
1896 " \"test\": {\n"
1897 " \"test\": 47\n"
1898 " }\n"
1899 " }\n"
1900 " }\n"
1901 " }\n"
1902 " }\n"
1903 "}"
1904 );
1905
1906 CxJsonValue *obj = cxJsonCreateObj(allocator);
1907 CxJsonValue *test = obj;
1908 for (
unsigned i =
0 ; i <
5 ; i++) {
1909 test = cxJsonObjPutObj(test,
"test");
1910 }
1911 cxJsonObjPutInteger(test,
"test",
47);
1912
1913 CxJsonWriter writer = cxJsonWriterPretty(true);
1914 writer.indent =
8;
1915 CxBuffer buf;
1916 cxBufferInit(&buf,
NULL,
NULL,
512,
CX_BUFFER_DEFAULT);
1917 int result = cxJsonWrite(&buf, obj, cxBufferWriteFunc, &writer);
1918 cxBufferTerminate(&buf);
1919 CX_TEST_ASSERT(result ==
0);
1920
1921
1922 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size), expected));
1923
1924
1925 cxBufferDestroy(&buf);
1926 cxJsonValueFree(obj);
1927
1928 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1929 }
1930 cx_testing_allocator_destroy(&talloc);
1931 }
1932
1933 CX_TEST(test_json_write_frac_max_digits) {
1934 CxJsonValue* num = cxJsonCreateNumber(
NULL,
3.141592653589793);
1935 CxJsonWriter writer = cxJsonWriterCompact();
1936 CxBuffer buf;
1937 cxBufferInit(&buf,
NULL,
NULL,
32,
0);
1938 CX_TEST_DO {
1939
1940 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1941 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3.141592"));
1942
1943
1944 cxBufferReset(&buf);
1945 writer.frac_max_digits =
200;
1946 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1947 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3.141592653589793"));
1948
1949
1950 cxBufferReset(&buf);
1951 writer.frac_max_digits =
0;
1952 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1953 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3"));
1954
1955
1956 cxBufferReset(&buf);
1957 writer.frac_max_digits =
2;
1958 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1959 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3.14"));
1960
1961
1962 cxBufferReset(&buf);
1963 writer.frac_max_digits =
3;
1964 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1965 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3.141"));
1966
1967
1968 num->number =
47.110815;
1969 cxBufferReset(&buf);
1970 writer.frac_max_digits =
6;
1971 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1972 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"47.110815"));
1973
1974
1975 num->number =
5.11223344e23;
1976 cxBufferReset(&buf);
1977 writer.frac_max_digits =
4;
1978 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1979 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"5.1122e+23"));
1980 }
1981 cxBufferDestroy(&buf);
1982 cxJsonValueFree(num);
1983 }
1984
1985 CX_TEST(test_json_write_string_escape) {
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999 CxJsonValue* str = cxJsonCreateString(
NULL,
2000 "hello\twörld\r\nthis is\\a \"string\"\b in \a string\f");
2001 CxJsonWriter writer = cxJsonWriterCompact();
2002 CxBuffer buf;
2003 cxBufferInit(&buf,
NULL,
NULL,
128,
0);
2004 CX_TEST_DO {
2005 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, str, cxBufferWriteFunc, &writer));
2006 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
2007 "\"hello\\twörld\\r\\nthis is\\\\a \\\"string\\\"\\b in \\u0007 string\\f\""));
2008 }
2009 cxBufferDestroy(&buf);
2010 cxJsonValueFree(str);
2011 }
2012
2013 CX_TEST(test_json_write_name_escape) {
2014 CxJsonValue* obj = cxJsonCreateObj(
NULL);
2015 cxJsonObjPutLiteral(obj,
2016 "hello\twörld\r\nthis is\\a \"string\"\b in \a string\f",
CX_JSON_TRUE);
2017 CxJsonWriter writer = cxJsonWriterCompact();
2018 CxBuffer buf;
2019 cxBufferInit(&buf,
NULL,
NULL,
128,
0);
2020 CX_TEST_DO {
2021 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, obj, cxBufferWriteFunc, &writer));
2022 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
2023 "{\"hello\\twörld\\r\\nthis is\\\\a \\\"string\\\"\\b in \\u0007 string\\f\":true}"));
2024 }
2025 cxBufferDestroy(&buf);
2026 cxJsonValueFree(obj);
2027 }
2028
2029 CX_TEST(test_json_write_solidus) {
2030 CxJsonValue* str = cxJsonCreateString(
NULL,
"test/solidus");
2031 CxJsonWriter writer = cxJsonWriterCompact();
2032 CxBuffer buf;
2033 cxBufferInit(&buf,
NULL,
NULL,
16,
0);
2034 CX_TEST_DO {
2035
2036 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, str, cxBufferWriteFunc, &writer));
2037 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"\"test/solidus\""));
2038
2039
2040 writer.escape_slash = true;
2041 cxBufferReset(&buf);
2042 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, str, cxBufferWriteFunc, &writer));
2043 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"\"test\\/solidus\""));
2044 }
2045 cxBufferDestroy(&buf);
2046 cxJsonValueFree(str);
2047 }
2048
2049 CX_TEST(test_json_write_nothing) {
2050 CxBuffer buf;
2051 cxBufferInit(&buf,
NULL,
NULL,
16,
0);
2052 CX_TEST_DO {
2053 CxJsonValue nothing;
2054 nothing.type =
CX_JSON_NOTHING;
2055 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, ¬hing, cxBufferWriteFunc,
NULL));
2056 CX_TEST_ASSERT(buf.size ==
0);
2057 }
2058 cxBufferDestroy(&buf);
2059 }
2060
2061 CX_TEST(test_json_to_string) {
2062 CxTestingAllocator talloc;
2063 cx_testing_allocator_init(&talloc);
2064 CxAllocator *allocator = &talloc.base;
2065 CX_TEST_DO {
2066
2067 cxstring expected = cx_str(
2068 "{\"bool\":false,"
2069 "\"int\":47,"
2070 "\"strings\":[\"hello\",\"world\"],"
2071 "\"nested\":{"
2072 "\"objects\":[{"
2073 "\"name1\":1,"
2074 "\"name2\":3"
2075 "},{"
2076 "\"name2\":7,"
2077 "\"name1\":3"
2078 "}],"
2079 "\"floats\":[3.1415,47.11,8.15],"
2080 "\"literals\":[true,null,false],"
2081 "\"ints\":[4,8,15,[16,23],42]"
2082 "}"
2083 "}"
2084 );
2085
2086 CxJsonValue *obj = test_json_write_create_test_object(allocator);
2087 cxmutstr result = cxJsonToString(allocator, obj);
2088 CX_TEST_ASSERT(
0 == cx_strcmp(result, expected));
2089 CX_TEST_ASSERT(result.ptr[result.length] ==
'\0');
2090
2091 cx_strfree_a(allocator, &result);
2092 cxJsonValueFree(obj);
2093
2094 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
2095 }
2096 cx_testing_allocator_destroy(&talloc);
2097 }
2098
2099 CX_TEST(test_json_to_pretty_string) {
2100 CxTestingAllocator talloc;
2101 cx_testing_allocator_init(&talloc);
2102 CxAllocator *allocator = &talloc.base;
2103 CX_TEST_DO {
2104 cxstring expected = cx_str(
2105 "{\n"
2106 " \"bool\": false,\n"
2107 " \"int\": 47,\n"
2108 " \"strings\": [\"hello\", \"world\"],\n"
2109 " \"nested\": {\n"
2110 " \"objects\": [{\n"
2111 " \"name1\": 1,\n"
2112 " \"name2\": 3\n"
2113 " }, {\n"
2114 " \"name2\": 7,\n"
2115 " \"name1\": 3\n"
2116 " }],\n"
2117 " \"floats\": [3.1415, 47.11, 8.15],\n"
2118 " \"literals\": [true, null, false],\n"
2119 " \"ints\": [4, 8, 15, [16, 23], 42]\n"
2120 " }\n"
2121 "}"
2122 );
2123
2124 CxJsonValue *obj = test_json_write_create_test_object(allocator);
2125 cxmutstr result = cxJsonToPrettyString(allocator, obj);
2126 CX_TEST_ASSERT(
0 == cx_strcmp(result, expected));
2127 CX_TEST_ASSERT(result.ptr[result.length] ==
'\0');
2128
2129 cx_strfree_a(allocator, &result);
2130 cxJsonValueFree(obj);
2131
2132 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
2133 }
2134 cx_testing_allocator_destroy(&talloc);
2135 }
2136
2137 CxTestSuite *cx_test_suite_json(
void) {
2138 CxTestSuite *suite = cx_test_suite_new(
"json");
2139
2140 cx_test_register(suite, test_json_init_default);
2141 cx_test_register(suite, test_json_simple_object);
2142 cx_test_register(suite, test_json_large_object);
2143 cx_test_register(suite, test_json_simple_array);
2144 cx_test_register(suite, test_json_from_string);
2145 cx_test_register(suite, test_json_from_string_errors);
2146 cx_test_register(suite, test_json_from_string_multiple_values);
2147 cx_test_register(suite, test_json_from_string_untrimmed);
2148 cx_test_register(suite, test_json_escaped_strings);
2149 cx_test_register(suite, test_json_escaped_unicode_strings);
2150 cx_test_register(suite, test_json_escaped_unicode_malformed);
2151 cx_test_register(suite, test_json_escaped_end_of_string);
2152 cx_test_register(suite, test_json_object_incomplete_token);
2153 cx_test_register(suite, test_json_parenthesis_mismatch);
2154 cx_test_register(suite, test_json_object_name_is_no_string);
2155 cx_test_register(suite, test_json_token_wrongly_completed);
2156 cx_test_register(suite, test_json_object_error);
2157 cx_test_register(suite, test_json_object_remove_member);
2158 cx_test_register(suite, test_json_subsequent_fill);
2159 cx_test_register(suite, test_json_no_fill);
2160 cx_test_register(suite, test_json_null_fill);
2161 cx_test_register(suite, test_json_large_nesting_depth);
2162 cx_test_register(suite, test_json_number);
2163 cx_test_register(suite, test_json_number_format_errors);
2164 cx_test_register(suite, test_json_multiple_values);
2165 cx_test_register(suite, test_json_array);
2166 cx_test_register(suite, test_json_array_iterator);
2167 cx_test_register(suite, test_json_allocator);
2168 cx_test_register(suite, test_json_allocator_parse_error);
2169 cx_test_register(suite, test_json_create_value);
2170 cx_test_register(suite, test_json_overwrite_value);
2171 cx_test_register(suite, test_json_compare_primitives);
2172 cx_test_register(suite, test_json_compare_objects);
2173 cx_test_register(suite, test_json_compare_arrays);
2174 cx_test_register(suite, test_json_clone_primitives);
2175 cx_test_register(suite, test_json_clone_objects);
2176 cx_test_register(suite, test_json_clone_arrays);
2177 cx_test_register(suite, test_json_write_default_format);
2178 cx_test_register(suite, test_json_write_pretty_default_spaces);
2179 cx_test_register(suite, test_json_write_pretty_default_tabs);
2180 cx_test_register(suite, test_json_write_pretty_deep_nesting);
2181 cx_test_register(suite, test_json_write_frac_max_digits);
2182 cx_test_register(suite, test_json_write_string_escape);
2183 cx_test_register(suite, test_json_write_name_escape);
2184 cx_test_register(suite, test_json_write_solidus);
2185 cx_test_register(suite, test_json_write_nothing);
2186 cx_test_register(suite, test_json_to_string);
2187 cx_test_register(suite, test_json_to_pretty_string);
2188
2189 return suite;
2190 }
2191
2192