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 CX_TEST(test_json_init_default) {
36 CxJson json;
37 CX_TEST_DO {
38 cxJsonInit(&json,
NULL);
39 CX_TEST_ASSERT(json.states == json.states_internal);
40 CX_TEST_ASSERT(json.states_size ==
1);
41 CX_TEST_ASSERT(json.states_capacity >=
8);
42 CX_TEST_ASSERT(json.vbuf == json.vbuf_internal);
43 CX_TEST_ASSERT(json.vbuf_size ==
0);
44 CX_TEST_ASSERT(json.vbuf_capacity >=
8);
45 cxJsonDestroy(&json);
46 }
47 }
48
49 CX_TEST(test_json_simple_object) {
50 cxstring text = cx_str(
51 "{\n"
52 "\t\"message\":\"success\",\n"
53 "\t\"position\":{\n"
54 "\t\t\"longitude\":-94.7099,\n"
55 "\t\t\"latitude\":51.5539\n"
56 "\t},\n"
57 "\t\"timestamp\":1729348561,\n"
58 "\t\"alive\":true\n"
59 "}"
60 );
61
62 CX_TEST_DO {
63 CxJsonStatus result;
64
65 CxJson json;
66 cxJsonInit(&json,
NULL);
67 cxJsonFill(&json, text);
68
69
70 CxJsonValue *obj;
71 result = cxJsonNext(&json, &obj);
72 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
73
74
75 CX_TEST_ASSERT(cxJsonIsObject(obj));
76
77 CxJsonValue *message = cxJsonObjGet(obj,
"message");
78 CX_TEST_ASSERT(cxJsonIsString(message));
79 CX_TEST_ASSERT(
0 == cx_strcmp(
80 cxJsonAsCxString(message),
81 "success")
82 );
83
84 CxJsonValue *position = cxJsonObjGet(obj,
"position");
85 CX_TEST_ASSERT(cxJsonIsObject(position));
86 CxJsonValue *longitude = cxJsonObjGet(position,
"longitude");
87 CX_TEST_ASSERT(cxJsonIsNumber(longitude));
88 CX_TEST_ASSERT(!cxJsonIsInteger(longitude));
89 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(longitude),
-94.7099));
90 CX_TEST_ASSERT(cxJsonAsInteger(longitude) ==
-94);
91 CxJsonValue *latitude = cxJsonObjGet(position,
"latitude");
92 CX_TEST_ASSERT(cxJsonIsNumber(latitude));
93 CX_TEST_ASSERT(!cxJsonIsInteger(latitude));
94 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(latitude),
51.5539));
95 CX_TEST_ASSERT(cxJsonAsInteger(latitude) ==
51);
96
97 CxJsonValue *timestamp = cxJsonObjGet(obj,
"timestamp");
98 CX_TEST_ASSERT(cxJsonIsInteger(timestamp));
99 CX_TEST_ASSERT(cxJsonIsNumber(timestamp));
100 CX_TEST_ASSERT(cxJsonAsInteger(timestamp) ==
1729348561);
101 CX_TEST_ASSERT(cxJsonAsDouble(timestamp) ==
1729348561.0);
102
103 CxJsonValue *alive = cxJsonObjGet(obj,
"alive");
104 CX_TEST_ASSERT(cxJsonIsBool(alive));
105 CX_TEST_ASSERT(cxJsonIsTrue(alive));
106 CX_TEST_ASSERT(!cxJsonIsFalse(alive));
107 CX_TEST_ASSERT(cxJsonAsBool(alive));
108
109
110 cxJsonValueFree(obj);
111
112
113 result = cxJsonNext(&json, &obj);
114 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
115
116 cxJsonDestroy(&json);
117 }
118 }
119
120 CX_TEST(test_json_large_object) {
121 CxJsonValue *obj = cxJsonCreateObj(
NULL);
122 CX_TEST_DO {
123 cxJsonObjPutString(obj,
"mystring",
"test");
124 char buf[
10];
125 for (
unsigned i =
0 ; i <
300 ; i++) {
126 sprintf(buf,
"key %d", i);
127 cxJsonObjPutInteger(obj, buf, i);
128 }
129 CX_TEST_ASSERT(
301 == cxJsonObjSize(obj));
130
131 CxJsonValue *v;
132 v = cxJsonObjGet(obj,
"key 64");
133 CX_TEST_ASSERT(cxJsonIsInteger(v));
134 CX_TEST_ASSERT(cxJsonAsInteger(v) ==
64);
135 v = cxJsonObjGet(obj,
"key 228");
136 CX_TEST_ASSERT(cxJsonIsInteger(v));
137 CX_TEST_ASSERT(cxJsonAsInteger(v) ==
228);
138
139 v = cxJsonObjGet(obj,
"mystring");
140 CX_TEST_ASSERT(cxJsonIsString(v));
141 CX_TEST_ASSERT(
0 == cx_strcmp(cxJsonAsCxMutStr(v),
"test"));
142 }
143 cxJsonValueFree(obj);
144 }
145
146 CX_TEST(test_json_from_string) {
147 cxstring text = cx_str(
148 "{\n"
149 "\t\"message\":\"success\",\n"
150 "\t\"position\":{\n"
151 "\t\t\"longitude\":-94.7099,\n"
152 "\t\t\"latitude\":51.5539\n"
153 "\t},\n"
154 "\t\"timestamp\":1729348561,\n"
155 "\t\"alive\":true\n"
156 "}"
157 );
158
159 CX_TEST_DO {
160 CxJsonValue *obj;
161 CX_TEST_ASSERT(cxJsonFromString(
NULL, text, &obj) ==
CX_JSON_NO_ERROR);
162
163
164 CX_TEST_ASSERT(cxJsonIsObject(obj));
165
166 CxJsonValue *message = cxJsonObjGet(obj,
"message");
167 CX_TEST_ASSERT(cxJsonIsString(message));
168 CX_TEST_ASSERT(
0 == cx_strcmp(
169 cxJsonAsCxString(message),
170 "success")
171 );
172
173 CxJsonValue *position = cxJsonObjGet(obj,
"position");
174 CX_TEST_ASSERT(cxJsonIsObject(position));
175 CxJsonValue *longitude = cxJsonObjGet(position,
"longitude");
176 CX_TEST_ASSERT(cxJsonIsNumber(longitude));
177 CX_TEST_ASSERT(!cxJsonIsInteger(longitude));
178 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(longitude),
-94.7099));
179 CX_TEST_ASSERT(cxJsonAsInteger(longitude) ==
-94);
180 CxJsonValue *latitude = cxJsonObjGet(position,
"latitude");
181 CX_TEST_ASSERT(cxJsonIsNumber(latitude));
182 CX_TEST_ASSERT(!cxJsonIsInteger(latitude));
183 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(latitude),
51.5539));
184 CX_TEST_ASSERT(cxJsonAsInteger(latitude) ==
51);
185
186 CxJsonValue *timestamp = cxJsonObjGet(obj,
"timestamp");
187 CX_TEST_ASSERT(cxJsonIsInteger(timestamp));
188 CX_TEST_ASSERT(cxJsonIsNumber(timestamp));
189 CX_TEST_ASSERT(cxJsonAsInteger(timestamp) ==
1729348561);
190 CX_TEST_ASSERT(cxJsonAsDouble(timestamp) ==
1729348561.0);
191
192 CxJsonValue *alive = cxJsonObjGet(obj,
"alive");
193 CX_TEST_ASSERT(cxJsonIsBool(alive));
194 CX_TEST_ASSERT(cxJsonIsTrue(alive));
195 CX_TEST_ASSERT(!cxJsonIsFalse(alive));
196 CX_TEST_ASSERT(cxJsonAsBool(alive));
197
198 cxJsonValueFree(obj);
199 }
200 }
201
202 CX_TEST(test_json_from_string_errors) {
203 CX_TEST_DO {
204 CxJsonValue *obj =
NULL;
205 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"", &obj) ==
CX_JSON_NO_DATA);
206 CX_TEST_ASSERT(cxJsonFromString(
NULL, cx_str(
NULL), &obj) ==
CX_JSON_NO_DATA);
207 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"\"incomplete", &obj) ==
CX_JSON_INCOMPLETE_DATA);
208 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"{ \"incomplete\": ", &obj) ==
CX_JSON_INCOMPLETE_DATA);
209 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"{\"number\": 47110815!}", &obj) ==
CX_JSON_FORMAT_ERROR_NUMBER);
210 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"[ \"unexpected token\" : true ]", &obj) ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
211 CX_TEST_ASSERT(cxJsonFromString(
NULL,
"} [", &obj) ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
212 CX_TEST_ASSERT(obj && obj->type ==
CX_JSON_NOTHING);
213 }
214 }
215
216 CX_TEST(test_json_from_string_multiple_values) {
217 CxJsonStatus status;
218 CxJsonValue *obj;
219 CX_TEST_DO {
220 obj =
NULL;
221 status = cxJsonFromString(
NULL,
"{ \"obj1\": \"hello\" }\n\"value2\"\n", &obj);
222 CX_TEST_ASSERT(obj !=
NULL);
223 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
224 CX_TEST_ASSERT(status ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
225
226 obj =
NULL;
227 status = cxJsonFromString(
NULL,
"\"value\" \n ] syntax error [", &obj);
228 CX_TEST_ASSERT(obj !=
NULL);
229 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
230 CX_TEST_ASSERT(status ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
231 }
232 }
233
234 CX_TEST(test_json_from_string_untrimmed) {
235 CxJsonStatus status;
236 CxJsonValue *obj;
237 CX_TEST_DO {
238 obj =
NULL;
239 status = cxJsonFromString(
NULL,
"\n\t{ \"obj1\": \"hello\" } \n", &obj);
240 CX_TEST_ASSERT(status ==
CX_JSON_NO_ERROR);
241 CX_TEST_ASSERT(cxJsonIsObject(obj));
242 CxJsonValue *obj1 = cxJsonObjGet(obj,
"obj1");
243 CX_TEST_ASSERT(cxJsonIsString(obj1));
244 CX_TEST_ASSERT(cx_strcmp(cxJsonAsCxString(obj1),
"hello") ==
0);
245
246 cxJsonValueFree(obj);
247 }
248 }
249
250 CX_TEST(test_json_escaped_strings) {
251 cxstring text = cx_str(
252 "{\n"
253 "\t\"object\":\"{\\n\\t\\\"object\\\":null\\n}\",\n"
254 "\t\"ctrl-chars\":\"\\\\foo\\r\\nbar\\f*ring\\/ring*\\b\"\n"
255 "}"
256 );
257
258 CxJson json;
259 cxJsonInit(&json,
NULL);
260 CX_TEST_DO {
261 cxJsonFill(&json, text);
262 CxJsonValue *obj;
263 CxJsonStatus result = cxJsonNext(&json, &obj);
264 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
265 CX_TEST_ASSERT(cxJsonIsObject(obj));
266 CxJsonValue *object = cxJsonObjGet(obj,
"object");
267 CX_TEST_ASSERT(cxJsonIsString(object));
268 CX_TEST_ASSERT(
0 == cx_strcmp(
269 cxJsonAsCxString(object),
270 "{\n\t\"object\":null\n}")
271 );
272 CxJsonValue *ctrl = cxJsonObjGet(obj,
"ctrl-chars");
273 CX_TEST_ASSERT(cxJsonIsString(ctrl));
274 CX_TEST_ASSERT(
0 == cx_strcmp(
275 cxJsonAsCxString(ctrl),
276 "\\foo\r\nbar\f*ring/ring*\b")
277 );
278 cxJsonValueFree(obj);
279 }
280 cxJsonDestroy(&json);
281 }
282
283 CX_TEST(test_json_escaped_unicode_strings) {
284 cxstring text = cx_str(
285 "{\n"
286 "\"ascii\":\"\\u0041\\u0053\\u0043\\u0049\\u0049\",\n"
287 "\"unicode\":\"\\u00df\\u00DF\",\n"
288 "\"mixed\":\"mixed ä ö \\u00e4 \\u00f6\",\n"
289 "\"wide\":\"\\u03a3\\u29b0\",\n"
290 "\"surrogatepair1\":\"\\ud83e\\udff5\",\n"
291 "\"surrogatepair2\":\"test\\ud83e\\udff1AA\"\n,"
292 "\"mixed2\":\"123\\u03a3\\ud83e\\udfc5\\u00df\""
293 "}"
294 );
295
296 CxJson json;
297 cxJsonInit(&json,
NULL);
298 CX_TEST_DO {
299 cxJsonFill(&json, text);
300 CxJsonValue *obj;
301 CxJsonStatus result = cxJsonNext(&json, &obj);
302 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
303 CX_TEST_ASSERT(cxJsonIsObject(obj));
304
305 CxJsonValue *ascii = cxJsonObjGet(obj,
"ascii");
306 CX_TEST_ASSERT(cxJsonIsString(ascii));
307 CX_TEST_ASSERT(
0 == cx_strcmp(
308 cxJsonAsCxString(ascii),
309 "ASCII")
310 );
311
312 CxJsonValue *unicode = cxJsonObjGet(obj,
"unicode");
313 CX_TEST_ASSERT(cxJsonIsString(unicode));
314 CX_TEST_ASSERT(
0 == cx_strcmp(
315 cxJsonAsCxString(unicode),
316 "ßß")
317 );
318
319 CxJsonValue *mixed = cxJsonObjGet(obj,
"mixed");
320 CX_TEST_ASSERT(cxJsonIsString(mixed));
321 CX_TEST_ASSERT(
0 == cx_strcmp(
322 cxJsonAsCxString(mixed),
323 "mixed ä ö ä ö")
324 );
325
326 CxJsonValue *wide = cxJsonObjGet(obj,
"wide");
327 CX_TEST_ASSERT(cxJsonIsString(wide));
328 CX_TEST_ASSERT(
0 == cx_strcmp(cxJsonAsCxString(wide),
"Σ⦰"));
329
330 CxJsonValue *surrogatepair1 = cxJsonObjGet(obj,
"surrogatepair1");
331 CX_TEST_ASSERT(cxJsonIsString(surrogatepair1));
332 CX_TEST_ASSERT(
0 == cx_strcmp(
333 cxJsonAsCxString(surrogatepair1),
334 "\xf0\x9f\xaf\xb5")
335 );
336
337 CxJsonValue *surrogatepair2 = cxJsonObjGet(obj,
"surrogatepair2");
338 CX_TEST_ASSERT(cxJsonIsString(surrogatepair2));
339 CX_TEST_ASSERT(
0 == cx_strcmp(
340 cxJsonAsCxString(surrogatepair2),
341 "test\xf0\x9f\xaf\xb1" "AA")
342 );
343
344 CxJsonValue *mixed2 = cxJsonObjGet(obj,
"mixed2");
345 char test[
16];
346 strncpy(test, mixed2->string.ptr,
15);
347 CX_TEST_ASSERT(cxJsonIsString(mixed2));
348 CX_TEST_ASSERT(
0 == cx_strcmp(
349 cxJsonAsCxString(mixed2),
350 "123\xce\xa3\xf0\x9f\xaf\x85ß")
351 );
352
353 cxJsonValueFree(obj);
354 }
355 cxJsonDestroy(&json);
356 }
357
358 CX_TEST(test_json_escaped_unicode_malformed) {
359 CxJson json;
360 cxJsonInit(&json,
NULL);
361 CxJsonValue *obj;
362 CxJsonStatus result;
363 CX_TEST_DO {
364 cxJsonFill(&json,
"\"too few digits \\u123\"");
365 result = cxJsonNext(&json, &obj);
366 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
367 CX_TEST_ASSERT(cxJsonIsString(obj));
368 CX_TEST_ASSERT(
0 == cx_strcmp(
369 cxJsonAsCxString(obj),
370 "too few digits \\u123"
371 ));
372 cxJsonValueFree(obj);
373 cxJsonFill(&json,
"\"too many digits \\u00E456\"");
374 result = cxJsonNext(&json, &obj);
375 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
376 CX_TEST_ASSERT(cxJsonIsString(obj));
377 CX_TEST_ASSERT(
0 == cx_strcmp(
378 cxJsonAsCxString(obj),
379 "too many digits ä56"
380 ));
381 cxJsonValueFree(obj);
382 cxJsonFill(&json,
"\"only high \\uD800 surrogate\"");
383 result = cxJsonNext(&json, &obj);
384 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
385 CX_TEST_ASSERT(cxJsonIsString(obj));
386 CX_TEST_ASSERT(
0 == cx_strcmp(
387 cxJsonAsCxString(obj),
388 "only high \\uD800 surrogate"
389 ));
390 cxJsonValueFree(obj);
391 cxJsonFill(&json,
"\"only low \\uDC00 surrogate\"");
392 result = cxJsonNext(&json, &obj);
393 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
394 CX_TEST_ASSERT(cxJsonIsString(obj));
395 CX_TEST_ASSERT(
0 == cx_strcmp(
396 cxJsonAsCxString(obj),
397 "only low \\uDC00 surrogate"
398 ));
399 cxJsonValueFree(obj);
400 cxJsonFill(&json,
"\"two high \\uD800\\uD800 surrogates\"");
401 result = cxJsonNext(&json, &obj);
402 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
403 CX_TEST_ASSERT(cxJsonIsString(obj));
404 CX_TEST_ASSERT(
0 == cx_strcmp(
405 cxJsonAsCxString(obj),
406 "two high \\uD800\\uD800 surrogates"
407 ));
408 cxJsonValueFree(obj);
409 cxJsonFill(&json,
"\"high plus bullshit \\uD800\\u567 foo\"");
410 result = cxJsonNext(&json, &obj);
411 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
412 CX_TEST_ASSERT(cxJsonIsString(obj));
413 CX_TEST_ASSERT(
0 == cx_strcmp(
414 cxJsonAsCxString(obj),
415 "high plus bullshit \\uD800\\u567 foo"
416 ));
417 cxJsonValueFree(obj);
418 }
419 cxJsonDestroy(&json);
420 }
421
422 CX_TEST(test_json_escaped_end_of_string) {
423 CxJson json;
424 cxJsonInit(&json,
NULL);
425 CX_TEST_DO {
426
427 cxJsonFill(&json,
"\"a \\\"test\\\" string\"");
428 CxJsonValue *val;
429 CxJsonStatus result = cxJsonNext(&json, &val);
430 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
431 CX_TEST_ASSERT(cxJsonIsString(val));
432 CX_TEST_ASSERT(
0 == cx_strcmp(
433 cxJsonAsCxString(val),
434 "a \"test\" string")
435 );
436 cxJsonValueFree(val);
437
438
439 cxJsonFill(&json,
"\"a \\\"test\\");
440 result = cxJsonNext(&json, &val);
441 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
442 cxJsonFill(&json,
"\" string\"");
443 result = cxJsonNext(&json, &val);
444 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
445 CX_TEST_ASSERT(cxJsonIsString(val));
446 CX_TEST_ASSERT(
0 == cx_strcmp(
447 cxJsonAsCxString(val),
448 "a \"test\" string")
449 );
450 cxJsonValueFree(val);
451 }
452 cxJsonDestroy(&json);
453 }
454
455 CX_TEST(test_json_object_incomplete_token) {
456 cxstring text = cx_str(
457 "{\"message\":\"success\" , \"__timestamp\":1729348561}");
458 cxstring parts[
16];
459 size_t nparts =
0;
460 for(
size_t i=
0;i<text.length;i+=
4) {
461 parts[nparts++] = cx_strsubsl(text, i,
4);
462 }
463
464 CX_TEST_DO {
465 CxJsonStatus result;
466
467 CxJson json;
468 cxJsonInit(&json,
NULL);
469 CxJsonValue *obj;
470
471 size_t part =
0;
472 while(part < nparts -
1) {
473 cxJsonFill(&json, parts[part]);
474 part++;
475 result = cxJsonNext(&json, &obj);
476 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
477 }
478 cxJsonFill(&json, parts[nparts -
1]);
479 result = cxJsonNext(&json, &obj);
480 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
481 CX_TEST_ASSERT(cxJsonIsObject(obj));
482
483 CxJsonValue *message = cxJsonObjGet(obj,
"message");
484 CX_TEST_ASSERT(cxJsonIsString(message));
485 CX_TEST_ASSERT(
0 == cx_strcmp(
486 cxJsonAsCxString(message),
487 "success")
488 );
489 CxJsonValue *timestamp = cxJsonObjGet(obj,
"__timestamp");
490 CX_TEST_ASSERT(message->type ==
CX_JSON_STRING);
491 CX_TEST_ASSERT(cxJsonIsInteger(timestamp));
492 CX_TEST_ASSERT(cxJsonAsInteger(timestamp) ==
1729348561);
493
494
495 cxJsonValueFree(obj);
496
497
498 result = cxJsonNext(&json, &obj);
499 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
500
501
502 cxJsonReset(&json);
503
504 cxJsonFill(&json,
"\"incomplete token");
505 result = cxJsonNext(&json, &obj);
506 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
507
508 cxJsonDestroy(&json);
509 }
510 }
511
512 CX_TEST(test_json_token_wrongly_completed) {
513 CxTestingAllocator talloc;
514 cx_testing_allocator_init(&talloc);
515 const CxAllocator *alloc = &talloc.base;
516
517 cxstring text = cx_str(
"{\"number\": 47110815!}");
518 cxstring part1 = cx_strsubsl(text,
0,
16);
519 cxstring part2 = cx_strsubs(text,
16);
520
521 CX_TEST_DO {
522 CxJson json;
523 cxJsonInit(&json, alloc);
524
525 CxJsonStatus result;
526 CxJsonValue *obj;
527
528 cxJsonFill(&json, part1);
529 result = cxJsonNext(&json, &obj);
530 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
531 cxJsonFill(&json, part2);
532 result = cxJsonNext(&json, &obj);
533 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_NUMBER);
534 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
535
536 cxJsonDestroy(&json);
537 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
538 }
539 cx_testing_allocator_destroy(&talloc);
540 }
541
542 CX_TEST(test_json_parenthesis_mismatch) {
543 CxTestingAllocator talloc;
544 cx_testing_allocator_init(&talloc);
545 const CxAllocator *alloc = &talloc.base;
546
547 CX_TEST_DO {
548 CxJson json;
549 cxJsonInit(&json, alloc);
550
551 CxJsonStatus result;
552 CxJsonValue *obj;
553
554 cxJsonFill(&json,
"[0, 1, 2, 3}");
555 result = cxJsonNext(&json, &obj);
556 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
557
558 cxJsonReset(&json);
559 cxJsonFill(&json,
"{\"test\": 42]");
560 result = cxJsonNext(&json, &obj);
561 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
562
563 cxJsonDestroy(&json);
564 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
565 }
566 cx_testing_allocator_destroy(&talloc);
567 }
568
569 CX_TEST(test_json_object_name_is_no_string) {
570 CxTestingAllocator talloc;
571 cx_testing_allocator_init(&talloc);
572 const CxAllocator *alloc = &talloc.base;
573
574 CX_TEST_DO {
575 CxJson json;
576 cxJsonInit(&json, alloc);
577
578 CxJsonStatus result;
579 CxJsonValue *obj;
580
581 cxJsonFill(&json,
"{42: \"test\"}");
582 result = cxJsonNext(&json, &obj);
583 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
584
585 cxJsonDestroy(&json);
586 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
587 }
588 cx_testing_allocator_destroy(&talloc);
589 }
590
591 CX_TEST(test_json_subsequent_fill) {
592 cxstring text = cx_str(
593 "{\"message\":\"success\" , \"__timestamp\":1729348561}");
594
595 cxstring part1 = cx_strsubsl(text,
0,
25);
596 cxstring part2 = cx_strsubs(text,
25);
597
598 CX_TEST_DO {
599 CxJson json;
600 cxJsonInit(&json,
NULL);
601 CxJsonValue *obj;
602
603 cxJsonFill(&json, part1);
604 cxJsonFill(&json, part2);
605 CxJsonStatus result = cxJsonNext(&json, &obj);
606 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
607 CX_TEST_ASSERT(cxJsonIsObject(obj));
608
609 CxJsonValue *message = cxJsonObjGet(obj,
"message");
610 CX_TEST_ASSERT(cxJsonIsString(message));
611 CX_TEST_ASSERT(
0 == cx_strcmp(
612 cxJsonAsCxString(message),
613 "success")
614 );
615 CxJsonValue *timestamp = cxJsonObjGet(obj,
"__timestamp");
616 CX_TEST_ASSERT(message->type ==
CX_JSON_STRING);
617 CX_TEST_ASSERT(cxJsonIsInteger(timestamp));
618 CX_TEST_ASSERT(cxJsonAsInteger(timestamp) ==
1729348561);
619
620 cxJsonValueFree(obj);
621 result = cxJsonNext(&json, &obj);
622 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
623
624 cxJsonDestroy(&json);
625 }
626 }
627
628 CX_TEST(test_json_no_fill) {
629 CxJson json;
630 cxJsonInit(&json,
NULL);
631 CX_TEST_DO {
632 CxJsonValue *obj =
NULL;
633 CxJsonStatus result = cxJsonNext(&json, &obj);
634 CX_TEST_ASSERT(result ==
CX_JSON_NULL_DATA);
635 CX_TEST_ASSERT(obj !=
NULL);
636 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
637 }
638 cxJsonDestroy(&json);
639 }
640
641 CX_TEST(test_json_null_fill) {
642 CxJson json;
643 cxJsonInit(&json,
NULL);
644 CX_TEST_DO {
645 CxJsonStatus result;
646 CxJsonValue *obj =
NULL;
647 cxstring nullstr = cx_strn(
NULL,
0);
648 cxJsonFill(&json, nullstr);
649 result = cxJsonNext(&json, &obj);
650 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
651 CX_TEST_ASSERT(obj !=
NULL);
652 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
653 obj =
NULL;
654
655 cxJsonFill(&json,
"[0, 1");
656 result = cxJsonNext(&json, &obj);
657 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
658 CX_TEST_ASSERT(obj !=
NULL);
659 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
660 obj =
NULL;
661
662 cxJsonFill(&json, nullstr);
663 result = cxJsonNext(&json, &obj);
664 CX_TEST_ASSERT(result ==
CX_JSON_INCOMPLETE_DATA);
665 CX_TEST_ASSERT(obj !=
NULL);
666 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
667 obj =
NULL;
668
669 cxJsonFill(&json,
", 2]");
670 result = cxJsonNext(&json, &obj);
671 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
672 CX_TEST_ASSERT(obj !=
NULL);
673 CX_TEST_ASSERT(cxJsonIsArray(obj));
674 cxJsonValueFree(obj);
675
676 cxJsonFill(&json, nullstr);
677 result = cxJsonNext(&json, &obj);
678 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
679 CX_TEST_ASSERT(obj !=
NULL);
680 CX_TEST_ASSERT(obj->type ==
CX_JSON_NOTHING);
681 }
682 cxJsonDestroy(&json);
683 }
684
685 CX_TEST(test_json_object_error) {
686 cxstring text0 = cx_str(
687 "{\n"
688 "\t\"message\":\"success\",\n"
689 "\t\"data\":{\n"
690 "\t\t\"obj\":{\n"
691 "\t\t\t\"array\": [1, 2, 3, ?syntaxerror? ]\n"
692 "\t\t}\n"
693 "\t},\n"
694 "\t\"timestamp\":1729348561,\n"
695 "}"
696 );
697 cxstring text1 = cx_str(
"{ \"string\" }");
698 cxstring text2 = cx_str(
"{ \"a\" : }");
699 cxstring text3 = cx_str(
"{ \"a\" : \"b\" ]");
700 cxstring text4 = cx_str(
"{ \"name\": \"value\" ]");
701
702 cxstring tests[] = { text0, text1, text2, text3, text4 };
703 CxJsonStatus errors[] = {
704 CX_JSON_FORMAT_ERROR_NUMBER,
705 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN,
706 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN,
707 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN,
708 CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN
709 };
710
711 CX_TEST_DO {
712 CxJsonStatus result;
713 CxJson json;
714 CxJsonValue *obj =
NULL;
715
716 for(
int i=
0;i<
5;i++) {
717 cxJsonInit(&json,
NULL);
718 cxJsonFill(&json, tests[i]);
719 result = cxJsonNext(&json, &obj);
720
721 CX_TEST_ASSERT(result == errors[i]);
722 CX_TEST_ASSERT(obj !=
NULL && obj->type ==
CX_JSON_NOTHING);
723 cxJsonDestroy(&json);
724 }
725 }
726 }
727
728 CX_TEST(test_json_object_remove_member) {
729 CxTestingAllocator talloc;
730 cx_testing_allocator_init(&talloc);
731 const CxAllocator *alloc = &talloc.base;
732 CX_TEST_DO {
733 CxJson json;
734 cxJsonInit(&json, alloc);
735 cxJsonFill(&json,
736 "{\n"
737 "\t\"message\":\"success\",\n"
738 "\t\"data\":{\n"
739 "\t\t\"obj\":{\n"
740 "\t\t\t\"array\": [1, 2, 3]\n"
741 "\t\t}\n"
742 "\t},\n"
743 "\t\"timestamp\":1729348561\n"
744 "}"
745 );
746 CxJsonValue *obj;
747 CX_TEST_ASSERT(
CX_JSON_NO_ERROR == cxJsonNext(&json, &obj));
748 cxJsonDestroy(&json);
749
750 CX_TEST_ASSERT(cxJsonIsObject(cxJsonObjGet(obj,
"data")));
751 CxJsonValue *data = cxJsonObjRemove(obj,
"data");
752 CX_TEST_ASSERT(cxJsonIsObject(data));
753 CX_TEST_ASSERT(!cxJsonIsObject(cxJsonObjGet(obj,
"data")));
754 CX_TEST_ASSERT(cxJsonIsObject(cxJsonObjGet(data,
"obj")));
755
756 CX_TEST_ASSERT(
NULL == cxJsonObjRemove(obj,
"data"));
757
758
759 cxJsonValueFree(obj);
760 CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
761
762 cxJsonValueFree(data);
763 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
764 }
765 cx_testing_allocator_destroy(&talloc);
766 }
767
768 CX_TEST(test_json_large_nesting_depth) {
769 CxJson json;
770 CxJsonValue *d1;
771 cxstring text = cx_str(
"{\"test\": [{},{\"foo\": [[{\"bar\":[4, 2, [null, {\"key\": 47}]]}]]}]}");
772 CX_TEST_DO {
773 cxJsonInit(&json,
NULL);
774 cxJsonFill(&json, text);
775 cxJsonNext(&json, &d1);
776
777 CX_TEST_ASSERT(d1 !=
NULL);
778 CX_TEST_ASSERT(cxJsonIsObject(d1));
779 CxJsonValue *d2 = cxJsonObjGet(d1,
"test");
780 CX_TEST_ASSERT(cxJsonIsArray(d2));
781 CX_TEST_ASSERT(cxJsonArrSize(d2) ==
2);
782 CxJsonValue *d3 = cxJsonArrGet(d2,
1);
783 CX_TEST_ASSERT(cxJsonIsObject(d3));
784 CxJsonValue *d4 = cxJsonObjGet(d3,
"foo");
785 CX_TEST_ASSERT(cxJsonIsArray(d4));
786 CX_TEST_ASSERT(cxJsonArrSize(d4) ==
1);
787 CxJsonValue *d5 = cxJsonArrGet(d4,
0);
788 CX_TEST_ASSERT(cxJsonIsArray(d5));
789 CX_TEST_ASSERT(cxJsonArrSize(d5) ==
1);
790 CxJsonValue *d6 = cxJsonArrGet(d5,
0);
791 CX_TEST_ASSERT(cxJsonIsObject(d6));
792 CxJsonValue *d7 = cxJsonObjGet(d6,
"bar");
793 CX_TEST_ASSERT(cxJsonIsArray(d7));
794 CX_TEST_ASSERT(cxJsonArrSize(d7) ==
3);
795 CxJsonValue *d8 = cxJsonArrGet(d7,
2);
796 CX_TEST_ASSERT(cxJsonIsArray(d8));
797 CX_TEST_ASSERT(cxJsonArrSize(d8) ==
2);
798 CxJsonValue *d9a = cxJsonArrGet(d8,
0);
799 CX_TEST_ASSERT(cxJsonIsNull(d9a));
800 CxJsonValue *d9b = cxJsonArrGet(d8,
1);
801 CX_TEST_ASSERT(cxJsonIsObject(d9b));
802 CxJsonValue *d10 = cxJsonObjGet(d9b,
"key");
803 CX_TEST_ASSERT(cxJsonIsInteger(d10));
804 CX_TEST_ASSERT(cxJsonAsInteger(d10) ==
47);
805
806 CX_TEST_ASSERT(json.states != json.states_internal);
807 CX_TEST_ASSERT(json.states_capacity > cx_nmemb(json.states_internal));
808
809 cxJsonValueFree(d1);
810 cxJsonDestroy(&json);
811 }
812 }
813
814 CX_TEST(test_json_number) {
815 CxJson json;
816 cxJsonInit(&json,
NULL);
817 CX_TEST_DO {
818 CxJsonValue *v;
819 CxJsonStatus result;
820
821 cxJsonFill(&json,
"3.1415 ");
822 result = cxJsonNext(&json, &v);
823 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
824 CX_TEST_ASSERT(cxJsonIsNumber(v));
825 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(v),
3.1415));
826 cxJsonValueFree(v);
827
828 cxJsonFill(&json,
"-47.11e2 ");
829 result = cxJsonNext(&json, &v);
830 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
831 CX_TEST_ASSERT(cxJsonIsNumber(v));
832 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(v),
-4711.0));
833 cxJsonValueFree(v);
834
835 cxJsonFill(&json,
"0.815e-3 ");
836 result = cxJsonNext(&json, &v);
837 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
838 CX_TEST_ASSERT(cxJsonIsNumber(v));
839 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(v),
0.000815));
840 cxJsonValueFree(v);
841
842 cxJsonFill(&json,
"1.23E4 ");
843 result = cxJsonNext(&json, &v);
844 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
845 CX_TEST_ASSERT(cxJsonIsNumber(v));
846 CX_TEST_ASSERT(cxJsonAsInteger(v) ==
12300);
847 CX_TEST_ASSERT(cxJsonAsDouble(v) ==
12300.0);
848 cxJsonValueFree(v);
849
850 cxJsonFill(&json,
"18446744073709551615.0123456789 ");
851 result = cxJsonNext(&json, &v);
852 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
853 CX_TEST_ASSERT(cxJsonIsNumber(v));
854
855
856 CX_TEST_ASSERT(
0 == cx_vcmp_double(cxJsonAsDouble(v),
1.8446744073709552e+19));
857 cxJsonValueFree(v);
858 }
859 cxJsonDestroy(&json);
860 }
861
862 CX_TEST(test_json_number_format_errors) {
863 CxJson json;
864 cxJsonInit(&json,
NULL);
865 CX_TEST_DO {
866 CxJsonValue *v;
867 CxJsonStatus result;
868
869 cxJsonFill(&json,
"+3.1415 ");
870 result = cxJsonNext(&json, &v);
871 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
872 "leading plus is not RFC-8259 compliant");
873 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
874 cxJsonReset(&json);
875
876 cxJsonFill(&json,
"0.815e-3.0 ");
877 result = cxJsonNext(&json, &v);
878 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
879 "exponent must be an integer");
880 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
881 cxJsonReset(&json);
882
883 cxJsonFill(&json,
"3.14e ");
884 result = cxJsonNext(&json, &v);
885 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
886 "exponent cannot be empty");
887 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
888 cxJsonReset(&json);
889
890 cxJsonFill(&json,
"3.14e~7 ");
891 result = cxJsonNext(&json, &v);
892 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
893 "exponent cannot start with bullshit");
894 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
895 cxJsonReset(&json);
896
897 cxJsonFill(&json,
"1.23e4f ");
898 result = cxJsonNext(&json, &v);
899 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
900 "non-digits in exponent");
901 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
902 cxJsonReset(&json);
903
904 cxJsonFill(&json,
"1.23f ");
905 result = cxJsonNext(&json, &v);
906 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
907 "non-digits in value");
908 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
909 cxJsonReset(&json);
910
911 cxJsonFill(&json,
"1.23.45 ");
912 result = cxJsonNext(&json, &v);
913 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
914 "multiple decimal separators");
915 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
916 cxJsonReset(&json);
917
918 cxJsonFill(&json,
"184467440737095516150123456789 ");
919 result = cxJsonNext(&json, &v);
920 CX_TEST_ASSERTM(result ==
CX_JSON_FORMAT_ERROR_NUMBER,
921 "30 digit int does not fit into 64-bit int");
922 CX_TEST_ASSERT(v->type ==
CX_JSON_NOTHING);
923 cxJsonReset(&json);
924 }
925 cxJsonDestroy(&json);
926 }
927
928 CX_TEST(test_json_multiple_values) {
929 CxJson json;
930 cxJsonInit(&json,
NULL);
931 CX_TEST_DO {
932 CxJsonValue *v;
933 CxJsonStatus result;
934
935
936 cxJsonFill(&json,
"10\n");
937 result = cxJsonNext(&json, &v);
938 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
939 CX_TEST_ASSERT(cxJsonIsNumber(v));
940 CX_TEST_ASSERT(cxJsonAsInteger(v) ==
10);
941 cxJsonValueFree(v);
942
943 result = cxJsonNext(&json, &v);
944 CX_TEST_ASSERT(result ==
CX_JSON_NO_DATA);
945
946 cxJsonFill(&json,
"\"hello world\"\n");
947 result = cxJsonNext(&json, &v);
948 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
949 CX_TEST_ASSERT(cxJsonIsString(v));
950 CX_TEST_ASSERT(!cx_strcmp(cxJsonAsCxString(v),
"hello world"));
951 cxJsonValueFree(v);
952
953
954 cxJsonFill(&json,
"{ \"value\": \"test\" }\n");
955 result = cxJsonNext(&json, &v);
956 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
957 CX_TEST_ASSERT(cxJsonIsObject(v));
958 CxJsonValue *value = cxJsonObjGet(v,
"value");
959 CX_TEST_ASSERT(cxJsonAsString(value));
960 cxJsonValueFree(v);
961
962 cxJsonFill(&json,
"[ 0, 1, 2, 3, 4, 5 ]\n");
963 result = cxJsonNext(&json, &v);
964 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
965 CX_TEST_ASSERT(cxJsonIsArray(v));
966 CxJsonValue *a0 = cxJsonArrGet(v,
0);
967 CxJsonValue *a3 = cxJsonArrGet(v,
3);
968 CX_TEST_ASSERT(cxJsonIsNumber(a0));
969 CX_TEST_ASSERT(cxJsonAsInteger(a0) ==
0);
970 CX_TEST_ASSERT(cxJsonIsNumber(a3));
971 CX_TEST_ASSERT(cxJsonAsInteger(a3) ==
3);
972 cxJsonValueFree(v);
973
974 cxJsonFill(&json,
"true\n");
975 result = cxJsonNext(&json, &v);
976 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
977 CX_TEST_ASSERT(cxJsonIsLiteral(v));
978 CX_TEST_ASSERT(cxJsonIsBool(v));
979 CX_TEST_ASSERT(cxJsonIsTrue(v));
980 CX_TEST_ASSERT(cxJsonAsBool(v));
981 cxJsonValueFree(v);
982 cxJsonFill(&json,
"false\n");
983 result = cxJsonNext(&json, &v);
984 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
985 CX_TEST_ASSERT(cxJsonIsLiteral(v));
986 CX_TEST_ASSERT(cxJsonIsBool(v));
987 CX_TEST_ASSERT(cxJsonIsFalse(v));
988 CX_TEST_ASSERT(!cxJsonAsBool(v));
989 cxJsonValueFree(v);
990 cxJsonFill(&json,
"null\n");
991 result = cxJsonNext(&json, &v);
992 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
993 CX_TEST_ASSERT(cxJsonIsLiteral(v));
994 CX_TEST_ASSERT(!cxJsonIsBool(v));
995 CX_TEST_ASSERT(cxJsonIsNull(v));
996 cxJsonValueFree(v);
997 }
998 cxJsonDestroy(&json);
999 }
1000
1001 CX_TEST(test_json_array) {
1002 CxTestingAllocator talloc;
1003 cx_testing_allocator_init(&talloc);
1004 const CxAllocator *allocator = &talloc.base;
1005 CX_TEST_DO {
1006 CxJsonValue *arr = cxJsonCreateArr(allocator);
1007 cxJsonArrAddIntegers(arr, (
int64_t[]){
0,
3,
6,
9,
12,
15},
6);
1008 CX_TEST_ASSERT(cxJsonArrSize(arr) ==
6);
1009 CxJsonValue *e = cxJsonArrGet(arr,
3);
1010 CX_TEST_ASSERT(cxJsonIsNumber(e));
1011 CX_TEST_ASSERT(cxJsonAsInteger(e) ==
9);
1012 CX_TEST_ASSERT(cxJsonAsDouble(e) ==
9.0);
1013 CX_TEST_ASSERT(cxJsonArrSize(arr) ==
6);
1014 e = cxJsonArrGet(arr,
6);
1015 CX_TEST_ASSERT(!cxJsonIsNumber(e));
1016
1017 CX_TEST_ASSERT(!cxJsonIsNull(e));
1018 CX_TEST_ASSERT(e->type ==
CX_JSON_NOTHING);
1019 CxJsonValue *removed = cxJsonArrRemove(arr,
2);
1020 CX_TEST_ASSERT(cxJsonIsNumber(removed));
1021 CX_TEST_ASSERT(cxJsonAsInteger(removed) ==
6);
1022 CX_TEST_ASSERT(cxJsonArrSize(arr) ==
5);
1023 e = cxJsonArrGet(arr,
3);
1024 CX_TEST_ASSERT(cxJsonIsNumber(e));
1025 CX_TEST_ASSERT(cxJsonAsInteger(e) ==
12);
1026 e = cxJsonArrRemove(arr,
5);
1027 CX_TEST_ASSERT(e ==
NULL);
1028 cxJsonValueFree(arr);
1029
1030 CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
1031 cxJsonValueFree(removed);
1032 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1033 }
1034 cx_testing_allocator_destroy(&talloc);
1035 }
1036
1037 CX_TEST(test_json_array_iterator) {
1038 CxJson json;
1039 cxJsonInit(&json,
NULL);
1040 CX_TEST_DO {
1041 CxJsonValue *v;
1042 CxJsonStatus result;
1043 cxJsonFill(&json,
"[ 0, 3, 6, 9, 12, 15 ]\n");
1044 result = cxJsonNext(&json, &v);
1045 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1046 CX_TEST_ASSERT(cxJsonIsArray(v));
1047 CxIterator iter = cxJsonArrIter(v);
1048 unsigned i =
0;
1049 cx_foreach(CxJsonValue*, elem, iter) {
1050 CX_TEST_ASSERT(cxJsonIsNumber(elem));
1051 CX_TEST_ASSERT(i == cxJsonAsInteger(elem));
1052 i +=
3;
1053 }
1054 cxJsonValueFree(v);
1055 }
1056 cxJsonDestroy(&json);
1057 }
1058
1059 CX_TEST(test_json_allocator) {
1060 CxTestingAllocator talloc;
1061 cx_testing_allocator_init(&talloc);
1062 CxAllocator *allocator = &talloc.base;
1063
1064 cxstring text = cx_str(
1065 "{\n"
1066 "\t\"message\":\"success\",\n"
1067 "\t\"data\":[\"value1\",{\"x\":123, \"y\":523 }]\n"
1068 "}"
1069 );
1070
1071 CX_TEST_DO {
1072 CxJson json;
1073 cxJsonInit(&json, allocator);
1074 cxJsonFill(&json, text);
1075
1076 CxJsonValue *obj;
1077 CxJsonStatus result = cxJsonNext(&json, &obj);
1078 CX_TEST_ASSERT(result ==
CX_JSON_NO_ERROR);
1079 CX_TEST_ASSERT(obj->allocator == allocator);
1080
1081
1082 cxJsonValueFree(obj);
1083 cxJsonDestroy(&json);
1084
1085 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1086 }
1087 cx_testing_allocator_destroy(&talloc);
1088 }
1089
1090 CX_TEST(test_json_allocator_parse_error) {
1091 CxTestingAllocator talloc;
1092 cx_testing_allocator_init(&talloc);
1093 CxAllocator *allocator = &talloc.base;
1094
1095 cxstring text = cx_str(
1096 "{\n"
1097 "\t\"message\":\"success\"\n"
1098 "\t\"data\":[\"value1\",{\"x\":123, \"y\":523 }]\n"
1099 "}"
1100 );
1101
1102 CX_TEST_DO {
1103 CxJson json;
1104 cxJsonInit(&json, allocator);
1105 cxJsonFill(&json, text);
1106
1107 CxJsonValue *obj =
NULL;
1108 CxJsonStatus result = cxJsonNext(&json, &obj);
1109 CX_TEST_ASSERT(result ==
CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
1110 CX_TEST_ASSERT(obj !=
NULL && obj->type ==
CX_JSON_NOTHING);
1111
1112
1113 cxJsonDestroy(&json);
1114
1115 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1116 }
1117 cx_testing_allocator_destroy(&talloc);
1118 }
1119
1120 CX_TEST(test_json_create_value) {
1121 CxTestingAllocator talloc;
1122 cx_testing_allocator_init(&talloc);
1123 CxAllocator *allocator = &talloc.base;
1124 CX_TEST_DO {
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143 CxJsonValue *obj = cxJsonCreateObj(allocator);
1144 CX_TEST_ASSERT(obj !=
NULL);
1145 CX_TEST_ASSERT(cxJsonIsObject(obj));
1146 CX_TEST_ASSERT(obj->allocator == allocator);
1147
1148
1149 {
1150 cxJsonObjPutLiteral(obj,
"bool",
CX_JSON_FALSE);
1151 cxJsonObjPutInteger(obj,
"int",
47);
1152 CxJsonValue *strings = cxJsonObjPutArr(obj,
"strings");
1153 CX_TEST_ASSERT(strings !=
NULL);
1154 CX_TEST_ASSERT(cxJsonIsArray(strings));
1155 const char* str[] = {
"hello",
"world"};
1156 CX_TEST_ASSERT(
0 == cxJsonArrAddStrings(strings, str,
2));
1157
1158 CxJsonValue *nested = cxJsonObjPutObj(obj,
"nested");
1159 CX_TEST_ASSERT(nested !=
NULL);
1160 CX_TEST_ASSERT(cxJsonIsObject(nested));
1161 cxJsonObjPutString(nested,
"string",
"test");
1162
1163 cxJsonArrAddNumbers(cxJsonObjPutArr(nested,
"floats"),
1164 (
double[]){
3.1415,
47.11,
8.15},
3);
1165 cxJsonArrAddIntegers(cxJsonObjPutArr(nested,
"ints"),
1166 (
int64_t[]){
4,
8,
15,
16,
23,
42},
6);
1167 cxJsonArrAddLiterals(cxJsonObjPutArr(nested,
"literals"),
1168 (CxJsonLiteral[]){
CX_JSON_TRUE,
CX_JSON_NULL,
CX_JSON_FALSE},
3);
1169 }
1170
1171
1172 {
1173 CX_TEST_ASSERT(cxJsonIsFalse(cxJsonObjGet(obj,
"bool")));
1174 CX_TEST_ASSERT(
47 == cxJsonAsInteger(cxJsonObjGet(obj,
"int")));
1175 CxJsonValue *strings = cxJsonObjGet(obj,
"strings");
1176 CX_TEST_ASSERT(cxJsonIsArray(strings));
1177 CX_TEST_ASSERT(
2 == cxJsonArrSize(strings));
1178 CX_TEST_ASSERT(
0 == cx_strcmp(
"hello", cxJsonAsString(cxJsonArrGet(strings,
0))));
1179 CX_TEST_ASSERT(
0 == cx_strcmp(
"world", cxJsonAsString(cxJsonArrGet(strings,
1))));
1180
1181 CxJsonValue *nested = cxJsonObjGet(obj,
"nested");
1182 CX_TEST_ASSERT(cxJsonIsObject(nested));
1183 CX_TEST_ASSERT(
0 == strcmp(
"test", cxJsonAsString(cxJsonObjGet(nested,
"string"))));
1184 CxJsonValue *floats = cxJsonObjGet(nested,
"floats");
1185 CX_TEST_ASSERT(cxJsonIsArray(floats));
1186 CX_TEST_ASSERT(
3 == cxJsonArrSize(floats));
1187 CX_TEST_ASSERT(
3.1415 == cxJsonAsDouble(cxJsonArrGet(floats,
0)));
1188 CX_TEST_ASSERT(
47.11 == cxJsonAsDouble(cxJsonArrGet(floats,
1)));
1189 CX_TEST_ASSERT(
8.15 == cxJsonAsDouble(cxJsonArrGet(floats,
2)));
1190 CxJsonValue *ints = cxJsonObjGet(nested,
"ints");
1191 CX_TEST_ASSERT(cxJsonIsArray(ints));
1192 CX_TEST_ASSERT(
6 == cxJsonArrSize(ints));
1193 CX_TEST_ASSERT(
4 == cxJsonAsInteger(cxJsonArrGet(ints,
0)));
1194 CX_TEST_ASSERT(
8 == cxJsonAsInteger(cxJsonArrGet(ints,
1)));
1195 CX_TEST_ASSERT(
15 == cxJsonAsInteger(cxJsonArrGet(ints,
2)));
1196 CX_TEST_ASSERT(
16 == cxJsonAsInteger(cxJsonArrGet(ints,
3)));
1197 CX_TEST_ASSERT(
23 == cxJsonAsInteger(cxJsonArrGet(ints,
4)));
1198 CX_TEST_ASSERT(
42 == cxJsonAsInteger(cxJsonArrGet(ints,
5)));
1199 CxJsonValue *literals = cxJsonObjGet(nested,
"literals");
1200 CX_TEST_ASSERT(cxJsonIsArray(literals));
1201 CX_TEST_ASSERT(
3 == cxJsonArrSize(literals));
1202 CX_TEST_ASSERT(cxJsonIsTrue(cxJsonArrGet(literals,
0)));
1203 CX_TEST_ASSERT(cxJsonIsNull(cxJsonArrGet(literals,
1)));
1204 CX_TEST_ASSERT(cxJsonIsFalse(cxJsonArrGet(literals,
2)));
1205 }
1206
1207
1208 cxJsonValueFree(obj);
1209 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1210 }
1211 cx_testing_allocator_destroy(&talloc);
1212 }
1213
1214 CX_TEST(test_json_overwrite_value) {
1215 CxTestingAllocator talloc;
1216 cx_testing_allocator_init(&talloc);
1217 CxAllocator *allocator = &talloc.base;
1218 CX_TEST_DO {
1219 CxJsonValue *obj = cxJsonCreateObj(allocator);
1220
1221
1222 cxJsonObjPutInteger(obj,
"test1",
1);
1223 cxJsonObjPutInteger(obj,
"test2",
2);
1224 cxJsonObjPutInteger(obj,
"test3",
3);
1225
1226
1227 cxJsonObjPutInteger(obj,
"test2",
0);
1228
1229
1230 CxMapIterator iter = cxJsonObjIter(obj);
1231 bool found[
5] = {
0};
1232 cx_foreach(CxMapEntry *, ov, iter) {
1233 CxJsonValue *v = ov->value;
1234 CX_TEST_ASSERT(cxJsonIsInteger(v));
1235 int64_t i = cxJsonAsInteger(v);
1236 CX_TEST_ASSERT(i >=
0 && i <=
4);
1237 found[i] = true;
1238 }
1239 CX_TEST_ASSERT(found[
0]);
1240 CX_TEST_ASSERT(found[
1]);
1241 CX_TEST_ASSERT(!found[
2]);
1242 CX_TEST_ASSERT(found[
3]);
1243 CX_TEST_ASSERT(!found[
4]);
1244
1245
1246 cxJsonValueFree(obj);
1247 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1248 }
1249 cx_testing_allocator_destroy(&talloc);
1250 }
1251
1252 CX_TEST_SUBROUTINE(test_json_write_sub,
1253 const CxAllocator *allocator,
1254 cxstring expected,
1255 const CxJsonWriter *writer
1256 ) {
1257
1258 CxJsonValue *obj = cxJsonCreateObj(allocator);
1259 cxJsonObjPutLiteral(obj,
"bool",
CX_JSON_FALSE);
1260 cxJsonObjPutNumber(obj,
"int",
47);
1261 CxJsonValue *strings = cxJsonObjPutArr(obj,
"strings");
1262 cxJsonArrAddCxStrings(strings, (cxstring[]) {
CX_STR(
"hello"),
CX_STR(
"world")},
2);
1263 CxJsonValue *nested = cxJsonObjPutObj(obj,
"nested");
1264 CxJsonValue *objects = cxJsonObjPutArr(nested,
"objects");
1265 CxJsonValue *obj_in_arr[
2] = {cxJsonCreateObj(allocator), cxJsonCreateObj(allocator)};
1266 cxJsonObjPutInteger(obj_in_arr[
0],
"name1",
1);
1267 cxJsonObjPutInteger(obj_in_arr[
0],
"name2",
3);
1268 cxJsonObjPutInteger(obj_in_arr[
1],
"name2",
7);
1269 cxJsonObjPutInteger(obj_in_arr[
1],
"name1",
3);
1270 cxJsonArrAddValues(objects, obj_in_arr,
2);
1271 cxJsonArrAddNumbers(cxJsonObjPutArr(nested,
"floats"),
1272 (
double[]){
3.1415,
47.11,
8.15},
3);
1273 cxJsonArrAddLiterals(cxJsonObjPutArr(nested,
"literals"),
1274 (CxJsonLiteral[]){
CX_JSON_TRUE,
CX_JSON_NULL,
CX_JSON_FALSE},
3);
1275 CxJsonValue *ints = cxJsonObjPutArr(nested,
"ints");
1276 cxJsonArrAddIntegers(ints, (
int64_t[]){
4,
8,
15},
3);
1277 CxJsonValue *nested_array = cxJsonCreateArr(allocator);
1278 cxJsonArrAddValues(ints, &nested_array,
1);
1279 cxJsonArrAddIntegers(nested_array, (
int64_t[]){
16,
23},
2);
1280 cxJsonArrAddIntegers(ints, (
int64_t[]){
42},
1);
1281
1282
1283 CxBuffer buf;
1284 cxBufferInit(&buf,
NULL,
512,
NULL,
CX_BUFFER_DEFAULT);
1285 int result = cxJsonWrite(&buf, obj, cxBufferWriteFunc, writer);
1286 cxBufferTerminate(&buf);
1287 CX_TEST_ASSERT(result ==
0);
1288
1289
1290 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size), expected));
1291
1292
1293 cxBufferDestroy(&buf);
1294 cxJsonValueFree(obj);
1295 }
1296
1297 CX_TEST(test_json_write_default_format) {
1298 CxTestingAllocator talloc;
1299 cx_testing_allocator_init(&talloc);
1300 CxAllocator *allocator = &talloc.base;
1301 CX_TEST_DO {
1302
1303 cxstring expected = cx_str(
1304 "{\"bool\":false,"
1305 "\"int\":47,"
1306 "\"strings\":[\"hello\",\"world\"],"
1307 "\"nested\":{"
1308 "\"objects\":[{"
1309 "\"name1\":1,"
1310 "\"name2\":3"
1311 "},{"
1312 "\"name2\":7,"
1313 "\"name1\":3"
1314 "}],"
1315 "\"floats\":[3.1415,47.11,8.15],"
1316 "\"literals\":[true,null,false],"
1317 "\"ints\":[4,8,15,[16,23],42]"
1318 "}"
1319 "}"
1320 );
1321
1322 CxJsonWriter writer = cxJsonWriterCompact();
1323 CX_TEST_CALL_SUBROUTINE(test_json_write_sub, allocator, expected, &writer);
1324
1325 CX_TEST_CALL_SUBROUTINE(test_json_write_sub, allocator, expected,
NULL);
1326 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1327 }
1328 cx_testing_allocator_destroy(&talloc);
1329 }
1330
1331 CX_TEST(test_json_write_pretty_default_spaces) {
1332 CxTestingAllocator talloc;
1333 cx_testing_allocator_init(&talloc);
1334 CxAllocator *allocator = &talloc.base;
1335 CX_TEST_DO {
1336 cxstring expected = cx_str(
1337 "{\n"
1338 " \"bool\": false,\n"
1339 " \"int\": 47,\n"
1340 " \"strings\": [\"hello\", \"world\"],\n"
1341 " \"nested\": {\n"
1342 " \"objects\": [{\n"
1343 " \"name1\": 1,\n"
1344 " \"name2\": 3\n"
1345 " }, {\n"
1346 " \"name2\": 7,\n"
1347 " \"name1\": 3\n"
1348 " }],\n"
1349 " \"floats\": [3.1415, 47.11, 8.15],\n"
1350 " \"literals\": [true, null, false],\n"
1351 " \"ints\": [4, 8, 15, [16, 23], 42]\n"
1352 " }\n"
1353 "}"
1354 );
1355
1356 CxJsonWriter writer = cxJsonWriterPretty(true);
1357 CX_TEST_CALL_SUBROUTINE(test_json_write_sub, allocator, expected, &writer);
1358 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1359 }
1360 cx_testing_allocator_destroy(&talloc);
1361 }
1362
1363 CX_TEST(test_json_write_pretty_default_tabs) {
1364 CxTestingAllocator talloc;
1365 cx_testing_allocator_init(&talloc);
1366 CxAllocator *allocator = &talloc.base;
1367 CX_TEST_DO {
1368 cxstring expected = cx_str(
1369 "{\n"
1370 "\t\"bool\": false,\n"
1371 "\t\"int\": 47,\n"
1372 "\t\"strings\": [\"hello\", \"world\"],\n"
1373 "\t\"nested\": {\n"
1374 "\t\t\"objects\": [{\n"
1375 "\t\t\t\"name1\": 1,\n"
1376 "\t\t\t\"name2\": 3\n"
1377 "\t\t}, {\n"
1378 "\t\t\t\"name2\": 7,\n"
1379 "\t\t\t\"name1\": 3\n"
1380 "\t\t}],\n"
1381 "\t\t\"floats\": [3.1415, 47.11, 8.15],\n"
1382 "\t\t\"literals\": [true, null, false],\n"
1383 "\t\t\"ints\": [4, 8, 15, [16, 23], 42]\n"
1384 "\t}\n"
1385 "}"
1386 );
1387 CxJsonWriter writer = cxJsonWriterPretty(false);
1388 CX_TEST_CALL_SUBROUTINE(test_json_write_sub, allocator, expected, &writer);
1389 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1390 }
1391 cx_testing_allocator_destroy(&talloc);
1392 }
1393
1394 CX_TEST(test_json_write_pretty_deep_nesting) {
1395 CxTestingAllocator talloc;
1396 cx_testing_allocator_init(&talloc);
1397 CxAllocator *allocator = &talloc.base;
1398 CX_TEST_DO {
1399 cxstring expected = cx_str(
1400 "{\n"
1401 " \"test\": {\n"
1402 " \"test\": {\n"
1403 " \"test\": {\n"
1404 " \"test\": {\n"
1405 " \"test\": {\n"
1406 " \"test\": 47\n"
1407 " }\n"
1408 " }\n"
1409 " }\n"
1410 " }\n"
1411 " }\n"
1412 "}"
1413 );
1414
1415 CxJsonValue *obj = cxJsonCreateObj(allocator);
1416 CxJsonValue *test = obj;
1417 for (
unsigned i =
0 ; i <
5 ; i++) {
1418 test = cxJsonObjPutObj(test,
"test");
1419 }
1420 cxJsonObjPutInteger(test,
"test",
47);
1421
1422 CxJsonWriter writer = cxJsonWriterPretty(true);
1423 writer.indent =
8;
1424 CxBuffer buf;
1425 cxBufferInit(&buf,
NULL,
512,
NULL,
CX_BUFFER_DEFAULT);
1426 int result = cxJsonWrite(&buf, obj, cxBufferWriteFunc, &writer);
1427 cxBufferTerminate(&buf);
1428 CX_TEST_ASSERT(result ==
0);
1429
1430
1431 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size), expected));
1432
1433
1434 cxBufferDestroy(&buf);
1435 cxJsonValueFree(obj);
1436
1437 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
1438 }
1439 cx_testing_allocator_destroy(&talloc);
1440 }
1441
1442 CX_TEST(test_json_write_frac_max_digits) {
1443 CxJsonValue* num = cxJsonCreateNumber(
NULL,
3.141592653589793);
1444 CxJsonWriter writer = cxJsonWriterCompact();
1445 CxBuffer buf;
1446 cxBufferInit(&buf,
NULL,
32,
NULL,
0);
1447 CX_TEST_DO {
1448
1449 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1450 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3.141592"));
1451
1452
1453 cxBufferReset(&buf);
1454 writer.frac_max_digits =
200;
1455 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1456 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3.141592653589793"));
1457
1458
1459 cxBufferReset(&buf);
1460 writer.frac_max_digits =
0;
1461 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1462 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3"));
1463
1464
1465 cxBufferReset(&buf);
1466 writer.frac_max_digits =
2;
1467 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1468 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3.14"));
1469
1470
1471 cxBufferReset(&buf);
1472 writer.frac_max_digits =
3;
1473 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1474 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"3.141"));
1475
1476
1477 num->number =
47.110815;
1478 cxBufferReset(&buf);
1479 writer.frac_max_digits =
6;
1480 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1481 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"47.110815"));
1482
1483
1484 num->number =
5.11223344e23;
1485 cxBufferReset(&buf);
1486 writer.frac_max_digits =
4;
1487 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, num, cxBufferWriteFunc, &writer));
1488 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"5.1122e+23"));
1489 }
1490 cxBufferDestroy(&buf);
1491 cxJsonValueFree(num);
1492 }
1493
1494 CX_TEST(test_json_write_string_escape) {
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508 CxJsonValue* str = cxJsonCreateString(
NULL,
1509 "hello\twörld\r\nthis is\\a \"string\"\b in \a string\f");
1510 CxJsonWriter writer = cxJsonWriterCompact();
1511 CxBuffer buf;
1512 cxBufferInit(&buf,
NULL,
128,
NULL,
0);
1513 CX_TEST_DO {
1514 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, str, cxBufferWriteFunc, &writer));
1515 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
1516 "\"hello\\twörld\\r\\nthis is\\\\a \\\"string\\\"\\b in \\u0007 string\\f\""));
1517 }
1518 cxBufferDestroy(&buf);
1519 cxJsonValueFree(str);
1520 }
1521
1522 CX_TEST(test_json_write_name_escape) {
1523 CxJsonValue* obj = cxJsonCreateObj(
NULL);
1524 cxJsonObjPutLiteral(obj,
1525 "hello\twörld\r\nthis is\\a \"string\"\b in \a string\f",
CX_JSON_TRUE);
1526 CxJsonWriter writer = cxJsonWriterCompact();
1527 CxBuffer buf;
1528 cxBufferInit(&buf,
NULL,
128,
NULL,
0);
1529 CX_TEST_DO {
1530 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, obj, cxBufferWriteFunc, &writer));
1531 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
1532 "{\"hello\\twörld\\r\\nthis is\\\\a \\\"string\\\"\\b in \\u0007 string\\f\":true}"));
1533 }
1534 cxBufferDestroy(&buf);
1535 cxJsonValueFree(obj);
1536 }
1537
1538 CX_TEST(test_json_write_solidus) {
1539 CxJsonValue* str = cxJsonCreateString(
NULL,
"test/solidus");
1540 CxJsonWriter writer = cxJsonWriterCompact();
1541 CxBuffer buf;
1542 cxBufferInit(&buf,
NULL,
16,
NULL,
0);
1543 CX_TEST_DO {
1544
1545 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, str, cxBufferWriteFunc, &writer));
1546 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"\"test/solidus\""));
1547
1548
1549 writer.escape_slash = true;
1550 cxBufferReset(&buf);
1551 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, str, cxBufferWriteFunc, &writer));
1552 CX_TEST_ASSERT(
0 == cx_strcmp(cx_strn(buf.space, buf.size),
"\"test\\/solidus\""));
1553 }
1554 cxBufferDestroy(&buf);
1555 cxJsonValueFree(str);
1556 }
1557
1558 CX_TEST(test_json_write_nothing) {
1559 CxBuffer buf;
1560 cxBufferInit(&buf,
NULL,
16,
NULL,
0);
1561 CX_TEST_DO {
1562 CxJsonValue nothing;
1563 nothing.type =
CX_JSON_NOTHING;
1564 CX_TEST_ASSERT(
0 == cxJsonWrite(&buf, ¬hing, cxBufferWriteFunc,
NULL));
1565 CX_TEST_ASSERT(buf.size ==
0);
1566 }
1567 cxBufferDestroy(&buf);
1568 }
1569
1570 CxTestSuite *cx_test_suite_json(
void) {
1571 CxTestSuite *suite = cx_test_suite_new(
"json");
1572
1573 cx_test_register(suite, test_json_init_default);
1574 cx_test_register(suite, test_json_simple_object);
1575 cx_test_register(suite, test_json_large_object);
1576 cx_test_register(suite, test_json_from_string);
1577 cx_test_register(suite, test_json_from_string_errors);
1578 cx_test_register(suite, test_json_from_string_multiple_values);
1579 cx_test_register(suite, test_json_from_string_untrimmed);
1580 cx_test_register(suite, test_json_escaped_strings);
1581 cx_test_register(suite, test_json_escaped_unicode_strings);
1582 cx_test_register(suite, test_json_escaped_unicode_malformed);
1583 cx_test_register(suite, test_json_escaped_end_of_string);
1584 cx_test_register(suite, test_json_object_incomplete_token);
1585 cx_test_register(suite, test_json_parenthesis_mismatch);
1586 cx_test_register(suite, test_json_object_name_is_no_string);
1587 cx_test_register(suite, test_json_token_wrongly_completed);
1588 cx_test_register(suite, test_json_object_error);
1589 cx_test_register(suite, test_json_object_remove_member);
1590 cx_test_register(suite, test_json_subsequent_fill);
1591 cx_test_register(suite, test_json_no_fill);
1592 cx_test_register(suite, test_json_null_fill);
1593 cx_test_register(suite, test_json_large_nesting_depth);
1594 cx_test_register(suite, test_json_number);
1595 cx_test_register(suite, test_json_number_format_errors);
1596 cx_test_register(suite, test_json_multiple_values);
1597 cx_test_register(suite, test_json_array);
1598 cx_test_register(suite, test_json_array_iterator);
1599 cx_test_register(suite, test_json_allocator);
1600 cx_test_register(suite, test_json_allocator_parse_error);
1601 cx_test_register(suite, test_json_create_value);
1602 cx_test_register(suite, test_json_overwrite_value);
1603 cx_test_register(suite, test_json_write_default_format);
1604 cx_test_register(suite, test_json_write_pretty_default_spaces);
1605 cx_test_register(suite, test_json_write_pretty_default_tabs);
1606 cx_test_register(suite, test_json_write_pretty_deep_nesting);
1607 cx_test_register(suite, test_json_write_frac_max_digits);
1608 cx_test_register(suite, test_json_write_string_escape);
1609 cx_test_register(suite, test_json_write_name_escape);
1610 cx_test_register(suite, test_json_write_solidus);
1611 cx_test_register(suite, test_json_write_nothing);
1612
1613 return suite;
1614 }
1615
1616