xref: /illumos-kvm-cmd/check-qjson.c (revision 68396ea9)
1 /*
2  * Copyright IBM, Corp. 2009
3  *
4  * Authors:
5  *  Anthony Liguori   <aliguori@us.ibm.com>
6  *
7  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
8  * See the COPYING.LIB file in the top-level directory.
9  *
10  */
11 #include <check.h>
12 
13 #include "qstring.h"
14 #include "qint.h"
15 #include "qdict.h"
16 #include "qlist.h"
17 #include "qfloat.h"
18 #include "qbool.h"
19 #include "qjson.h"
20 
21 #include "qemu-common.h"
22 
START_TEST(escaped_string)23 START_TEST(escaped_string)
24 {
25     int i;
26     struct {
27         const char *encoded;
28         const char *decoded;
29         int skip;
30     } test_cases[] = {
31         { "\"\\b\"", "\b" },
32         { "\"\\f\"", "\f" },
33         { "\"\\n\"", "\n" },
34         { "\"\\r\"", "\r" },
35         { "\"\\t\"", "\t" },
36         { "\"\\/\"", "\\/" },
37         { "\"\\\\\"", "\\" },
38         { "\"\\\"\"", "\"" },
39         { "\"hello world \\\"embedded string\\\"\"",
40           "hello world \"embedded string\"" },
41         { "\"hello world\\nwith new line\"", "hello world\nwith new line" },
42         { "\"single byte utf-8 \\u0020\"", "single byte utf-8  ", .skip = 1 },
43         { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
44         { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
45         {}
46     };
47 
48     for (i = 0; test_cases[i].encoded; i++) {
49         QObject *obj;
50         QString *str;
51 
52         obj = qobject_from_json(test_cases[i].encoded);
53 
54         fail_unless(obj != NULL);
55         fail_unless(qobject_type(obj) == QTYPE_QSTRING);
56 
57         str = qobject_to_qstring(obj);
58         fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0,
59                     "%s != %s\n", qstring_get_str(str), test_cases[i].decoded);
60 
61         if (test_cases[i].skip == 0) {
62             str = qobject_to_json(obj);
63             fail_unless(strcmp(qstring_get_str(str),test_cases[i].encoded) == 0,
64                         "%s != %s\n", qstring_get_str(str),
65                                       test_cases[i].encoded);
66 
67             qobject_decref(obj);
68         }
69 
70         QDECREF(str);
71     }
72 }
73 END_TEST
74 
START_TEST(simple_string)75 START_TEST(simple_string)
76 {
77     int i;
78     struct {
79         const char *encoded;
80         const char *decoded;
81     } test_cases[] = {
82         { "\"hello world\"", "hello world" },
83         { "\"the quick brown fox jumped over the fence\"",
84           "the quick brown fox jumped over the fence" },
85         {}
86     };
87 
88     for (i = 0; test_cases[i].encoded; i++) {
89         QObject *obj;
90         QString *str;
91 
92         obj = qobject_from_json(test_cases[i].encoded);
93 
94         fail_unless(obj != NULL);
95         fail_unless(qobject_type(obj) == QTYPE_QSTRING);
96 
97         str = qobject_to_qstring(obj);
98         fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
99 
100         str = qobject_to_json(obj);
101         fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
102 
103         qobject_decref(obj);
104 
105         QDECREF(str);
106     }
107 }
108 END_TEST
109 
START_TEST(single_quote_string)110 START_TEST(single_quote_string)
111 {
112     int i;
113     struct {
114         const char *encoded;
115         const char *decoded;
116     } test_cases[] = {
117         { "'hello world'", "hello world" },
118         { "'the quick brown fox \\' jumped over the fence'",
119           "the quick brown fox ' jumped over the fence" },
120         {}
121     };
122 
123     for (i = 0; test_cases[i].encoded; i++) {
124         QObject *obj;
125         QString *str;
126 
127         obj = qobject_from_json(test_cases[i].encoded);
128 
129         fail_unless(obj != NULL);
130         fail_unless(qobject_type(obj) == QTYPE_QSTRING);
131 
132         str = qobject_to_qstring(obj);
133         fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
134 
135         QDECREF(str);
136     }
137 }
138 END_TEST
139 
START_TEST(vararg_string)140 START_TEST(vararg_string)
141 {
142     int i;
143     struct {
144         const char *decoded;
145     } test_cases[] = {
146         { "hello world" },
147         { "the quick brown fox jumped over the fence" },
148         {}
149     };
150 
151     for (i = 0; test_cases[i].decoded; i++) {
152         QObject *obj;
153         QString *str;
154 
155         obj = qobject_from_jsonf("%s", test_cases[i].decoded);
156 
157         fail_unless(obj != NULL);
158         fail_unless(qobject_type(obj) == QTYPE_QSTRING);
159 
160         str = qobject_to_qstring(obj);
161         fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
162 
163         QDECREF(str);
164     }
165 }
166 END_TEST
167 
START_TEST(simple_number)168 START_TEST(simple_number)
169 {
170     int i;
171     struct {
172         const char *encoded;
173         int64_t decoded;
174         int skip;
175     } test_cases[] = {
176         { "0", 0 },
177         { "1234", 1234 },
178         { "1", 1 },
179         { "-32", -32 },
180         { "-0", 0, .skip = 1 },
181         { },
182     };
183 
184     for (i = 0; test_cases[i].encoded; i++) {
185         QObject *obj;
186         QInt *qint;
187 
188         obj = qobject_from_json(test_cases[i].encoded);
189         fail_unless(obj != NULL);
190         fail_unless(qobject_type(obj) == QTYPE_QINT);
191 
192         qint = qobject_to_qint(obj);
193         fail_unless(qint_get_int(qint) == test_cases[i].decoded);
194         if (test_cases[i].skip == 0) {
195             QString *str;
196 
197             str = qobject_to_json(obj);
198             fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
199             QDECREF(str);
200         }
201 
202         QDECREF(qint);
203     }
204 }
205 END_TEST
206 
START_TEST(float_number)207 START_TEST(float_number)
208 {
209     int i;
210     struct {
211         const char *encoded;
212         double decoded;
213         int skip;
214     } test_cases[] = {
215         { "32.43", 32.43 },
216         { "0.222", 0.222 },
217         { "-32.12313", -32.12313 },
218         { "-32.20e-10", -32.20e-10, .skip = 1 },
219         { },
220     };
221 
222     for (i = 0; test_cases[i].encoded; i++) {
223         QObject *obj;
224         QFloat *qfloat;
225 
226         obj = qobject_from_json(test_cases[i].encoded);
227         fail_unless(obj != NULL);
228         fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
229 
230         qfloat = qobject_to_qfloat(obj);
231         fail_unless(qfloat_get_double(qfloat) == test_cases[i].decoded);
232 
233         if (test_cases[i].skip == 0) {
234             QString *str;
235 
236             str = qobject_to_json(obj);
237             fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
238             QDECREF(str);
239         }
240 
241         QDECREF(qfloat);
242     }
243 }
244 END_TEST
245 
START_TEST(vararg_number)246 START_TEST(vararg_number)
247 {
248     QObject *obj;
249     QInt *qint;
250     QFloat *qfloat;
251     int value = 0x2342;
252     int64_t value64 = 0x2342342343LL;
253     double valuef = 2.323423423;
254 
255     obj = qobject_from_jsonf("%d", value);
256     fail_unless(obj != NULL);
257     fail_unless(qobject_type(obj) == QTYPE_QINT);
258 
259     qint = qobject_to_qint(obj);
260     fail_unless(qint_get_int(qint) == value);
261 
262     QDECREF(qint);
263 
264     obj = qobject_from_jsonf("%" PRId64, value64);
265     fail_unless(obj != NULL);
266     fail_unless(qobject_type(obj) == QTYPE_QINT);
267 
268     qint = qobject_to_qint(obj);
269     fail_unless(qint_get_int(qint) == value64);
270 
271     QDECREF(qint);
272 
273     obj = qobject_from_jsonf("%f", valuef);
274     fail_unless(obj != NULL);
275     fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
276 
277     qfloat = qobject_to_qfloat(obj);
278     fail_unless(qfloat_get_double(qfloat) == valuef);
279 
280     QDECREF(qfloat);
281 }
282 END_TEST
283 
START_TEST(keyword_literal)284 START_TEST(keyword_literal)
285 {
286     QObject *obj;
287     QBool *qbool;
288     QString *str;
289 
290     obj = qobject_from_json("true");
291     fail_unless(obj != NULL);
292     fail_unless(qobject_type(obj) == QTYPE_QBOOL);
293 
294     qbool = qobject_to_qbool(obj);
295     fail_unless(qbool_get_int(qbool) != 0);
296 
297     str = qobject_to_json(obj);
298     fail_unless(strcmp(qstring_get_str(str), "true") == 0);
299     QDECREF(str);
300 
301     QDECREF(qbool);
302 
303     obj = qobject_from_json("false");
304     fail_unless(obj != NULL);
305     fail_unless(qobject_type(obj) == QTYPE_QBOOL);
306 
307     qbool = qobject_to_qbool(obj);
308     fail_unless(qbool_get_int(qbool) == 0);
309 
310     str = qobject_to_json(obj);
311     fail_unless(strcmp(qstring_get_str(str), "false") == 0);
312     QDECREF(str);
313 
314     QDECREF(qbool);
315 
316     obj = qobject_from_jsonf("%i", false);
317     fail_unless(obj != NULL);
318     fail_unless(qobject_type(obj) == QTYPE_QBOOL);
319 
320     qbool = qobject_to_qbool(obj);
321     fail_unless(qbool_get_int(qbool) == 0);
322 
323     QDECREF(qbool);
324 
325     obj = qobject_from_jsonf("%i", true);
326     fail_unless(obj != NULL);
327     fail_unless(qobject_type(obj) == QTYPE_QBOOL);
328 
329     qbool = qobject_to_qbool(obj);
330     fail_unless(qbool_get_int(qbool) != 0);
331 
332     QDECREF(qbool);
333 }
334 END_TEST
335 
336 typedef struct LiteralQDictEntry LiteralQDictEntry;
337 typedef struct LiteralQObject LiteralQObject;
338 
339 struct LiteralQObject
340 {
341     int type;
342     union {
343         int64_t qint;
344         const char *qstr;
345         LiteralQDictEntry *qdict;
346         LiteralQObject *qlist;
347     } value;
348 };
349 
350 struct LiteralQDictEntry
351 {
352     const char *key;
353     LiteralQObject value;
354 };
355 
356 #define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
357 #define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
358 #define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
359 #define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
360 
361 typedef struct QListCompareHelper
362 {
363     int index;
364     LiteralQObject *objs;
365     int result;
366 } QListCompareHelper;
367 
368 static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
369 
compare_helper(QObject * obj,void * opaque)370 static void compare_helper(QObject *obj, void *opaque)
371 {
372     QListCompareHelper *helper = opaque;
373 
374     if (helper->result == 0) {
375         return;
376     }
377 
378     if (helper->objs[helper->index].type == QTYPE_NONE) {
379         helper->result = 0;
380         return;
381     }
382 
383     helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
384 }
385 
compare_litqobj_to_qobj(LiteralQObject * lhs,QObject * rhs)386 static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
387 {
388     if (lhs->type != qobject_type(rhs)) {
389         return 0;
390     }
391 
392     switch (lhs->type) {
393     case QTYPE_QINT:
394         return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
395     case QTYPE_QSTRING:
396         return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
397     case QTYPE_QDICT: {
398         int i;
399 
400         for (i = 0; lhs->value.qdict[i].key; i++) {
401             QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
402 
403             if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
404                 return 0;
405             }
406         }
407 
408         return 1;
409     }
410     case QTYPE_QLIST: {
411         QListCompareHelper helper;
412 
413         helper.index = 0;
414         helper.objs = lhs->value.qlist;
415         helper.result = 1;
416 
417         qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
418 
419         return helper.result;
420     }
421     default:
422         break;
423     }
424 
425     return 0;
426 }
427 
START_TEST(simple_dict)428 START_TEST(simple_dict)
429 {
430     int i;
431     struct {
432         const char *encoded;
433         LiteralQObject decoded;
434     } test_cases[] = {
435         {
436             .encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
437             .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
438                         { "foo", QLIT_QINT(42) },
439                         { "bar", QLIT_QSTR("hello world") },
440                         { }
441                     })),
442         }, {
443             .encoded = "{}",
444             .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
445                         { }
446                     })),
447         }, {
448             .encoded = "{\"foo\": 43}",
449             .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
450                         { "foo", QLIT_QINT(43) },
451                         { }
452                     })),
453         },
454         { }
455     };
456 
457     for (i = 0; test_cases[i].encoded; i++) {
458         QObject *obj;
459         QString *str;
460 
461         obj = qobject_from_json(test_cases[i].encoded);
462         fail_unless(obj != NULL);
463         fail_unless(qobject_type(obj) == QTYPE_QDICT);
464 
465         fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
466 
467         str = qobject_to_json(obj);
468         qobject_decref(obj);
469 
470         obj = qobject_from_json(qstring_get_str(str));
471         fail_unless(obj != NULL);
472         fail_unless(qobject_type(obj) == QTYPE_QDICT);
473 
474         fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
475         qobject_decref(obj);
476         QDECREF(str);
477     }
478 }
479 END_TEST
480 
START_TEST(simple_list)481 START_TEST(simple_list)
482 {
483     int i;
484     struct {
485         const char *encoded;
486         LiteralQObject decoded;
487     } test_cases[] = {
488         {
489             .encoded = "[43,42]",
490             .decoded = QLIT_QLIST(((LiteralQObject[]){
491                         QLIT_QINT(43),
492                         QLIT_QINT(42),
493                         { }
494                     })),
495         },
496         {
497             .encoded = "[43]",
498             .decoded = QLIT_QLIST(((LiteralQObject[]){
499                         QLIT_QINT(43),
500                         { }
501                     })),
502         },
503         {
504             .encoded = "[]",
505             .decoded = QLIT_QLIST(((LiteralQObject[]){
506                         { }
507                     })),
508         },
509         {
510             .encoded = "[{}]",
511             .decoded = QLIT_QLIST(((LiteralQObject[]){
512                         QLIT_QDICT(((LiteralQDictEntry[]){
513                                     {},
514                                         })),
515                         {},
516                             })),
517         },
518         { }
519     };
520 
521     for (i = 0; test_cases[i].encoded; i++) {
522         QObject *obj;
523         QString *str;
524 
525         obj = qobject_from_json(test_cases[i].encoded);
526         fail_unless(obj != NULL);
527         fail_unless(qobject_type(obj) == QTYPE_QLIST);
528 
529         fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
530 
531         str = qobject_to_json(obj);
532         qobject_decref(obj);
533 
534         obj = qobject_from_json(qstring_get_str(str));
535         fail_unless(obj != NULL);
536         fail_unless(qobject_type(obj) == QTYPE_QLIST);
537 
538         fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
539         qobject_decref(obj);
540         QDECREF(str);
541     }
542 }
543 END_TEST
544 
START_TEST(simple_whitespace)545 START_TEST(simple_whitespace)
546 {
547     int i;
548     struct {
549         const char *encoded;
550         LiteralQObject decoded;
551     } test_cases[] = {
552         {
553             .encoded = " [ 43 , 42 ]",
554             .decoded = QLIT_QLIST(((LiteralQObject[]){
555                         QLIT_QINT(43),
556                         QLIT_QINT(42),
557                         { }
558                     })),
559         },
560         {
561             .encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
562             .decoded = QLIT_QLIST(((LiteralQObject[]){
563                         QLIT_QINT(43),
564                         QLIT_QDICT(((LiteralQDictEntry[]){
565                                     { "h", QLIT_QSTR("b") },
566                                     { }})),
567                         QLIT_QLIST(((LiteralQObject[]){
568                                     { }})),
569                         QLIT_QINT(42),
570                         { }
571                     })),
572         },
573         {
574             .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
575             .decoded = QLIT_QLIST(((LiteralQObject[]){
576                         QLIT_QINT(43),
577                         QLIT_QDICT(((LiteralQDictEntry[]){
578                                     { "h", QLIT_QSTR("b") },
579                                     { "a", QLIT_QINT(32) },
580                                     { }})),
581                         QLIT_QLIST(((LiteralQObject[]){
582                                     { }})),
583                         QLIT_QINT(42),
584                         { }
585                     })),
586         },
587         { }
588     };
589 
590     for (i = 0; test_cases[i].encoded; i++) {
591         QObject *obj;
592         QString *str;
593 
594         obj = qobject_from_json(test_cases[i].encoded);
595         fail_unless(obj != NULL);
596         fail_unless(qobject_type(obj) == QTYPE_QLIST);
597 
598         fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
599 
600         str = qobject_to_json(obj);
601         qobject_decref(obj);
602 
603         obj = qobject_from_json(qstring_get_str(str));
604         fail_unless(obj != NULL);
605         fail_unless(qobject_type(obj) == QTYPE_QLIST);
606 
607         fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
608 
609         qobject_decref(obj);
610         QDECREF(str);
611     }
612 }
613 END_TEST
614 
START_TEST(simple_varargs)615 START_TEST(simple_varargs)
616 {
617     QObject *embedded_obj;
618     QObject *obj;
619     LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
620             QLIT_QINT(1),
621             QLIT_QINT(2),
622             QLIT_QLIST(((LiteralQObject[]){
623                         QLIT_QINT(32),
624                         QLIT_QINT(42),
625                         {}})),
626             {}}));
627 
628     embedded_obj = qobject_from_json("[32, 42]");
629     fail_unless(embedded_obj != NULL);
630 
631     obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
632     fail_unless(obj != NULL);
633 
634     fail_unless(compare_litqobj_to_qobj(&decoded, obj) == 1);
635 
636     qobject_decref(obj);
637 }
638 END_TEST
639 
START_TEST(empty_input)640 START_TEST(empty_input)
641 {
642     const char *empty = "";
643 
644     QObject *obj = qobject_from_json(empty);
645     fail_unless(obj == NULL);
646 }
647 END_TEST
648 
START_TEST(unterminated_string)649 START_TEST(unterminated_string)
650 {
651     QObject *obj = qobject_from_json("\"abc");
652     fail_unless(obj == NULL);
653 }
654 END_TEST
655 
START_TEST(unterminated_sq_string)656 START_TEST(unterminated_sq_string)
657 {
658     QObject *obj = qobject_from_json("'abc");
659     fail_unless(obj == NULL);
660 }
661 END_TEST
662 
START_TEST(unterminated_escape)663 START_TEST(unterminated_escape)
664 {
665     QObject *obj = qobject_from_json("\"abc\\\"");
666     fail_unless(obj == NULL);
667 }
668 END_TEST
669 
START_TEST(unterminated_array)670 START_TEST(unterminated_array)
671 {
672     QObject *obj = qobject_from_json("[32");
673     fail_unless(obj == NULL);
674 }
675 END_TEST
676 
START_TEST(unterminated_array_comma)677 START_TEST(unterminated_array_comma)
678 {
679     QObject *obj = qobject_from_json("[32,");
680     fail_unless(obj == NULL);
681 }
682 END_TEST
683 
START_TEST(invalid_array_comma)684 START_TEST(invalid_array_comma)
685 {
686     QObject *obj = qobject_from_json("[32,}");
687     fail_unless(obj == NULL);
688 }
689 END_TEST
690 
START_TEST(unterminated_dict)691 START_TEST(unterminated_dict)
692 {
693     QObject *obj = qobject_from_json("{'abc':32");
694     fail_unless(obj == NULL);
695 }
696 END_TEST
697 
START_TEST(unterminated_dict_comma)698 START_TEST(unterminated_dict_comma)
699 {
700     QObject *obj = qobject_from_json("{'abc':32,");
701     fail_unless(obj == NULL);
702 }
703 END_TEST
704 
705 #if 0
706 START_TEST(invalid_dict_comma)
707 {
708     QObject *obj = qobject_from_json("{'abc':32,}");
709     fail_unless(obj == NULL);
710 }
711 END_TEST
712 
713 START_TEST(unterminated_literal)
714 {
715     QObject *obj = qobject_from_json("nul");
716     fail_unless(obj == NULL);
717 }
718 END_TEST
719 #endif
720 
qjson_suite(void)721 static Suite *qjson_suite(void)
722 {
723     Suite *suite;
724     TCase *string_literals, *number_literals, *keyword_literals;
725     TCase *dicts, *lists, *whitespace, *varargs, *errors;
726 
727     string_literals = tcase_create("String Literals");
728     tcase_add_test(string_literals, simple_string);
729     tcase_add_test(string_literals, escaped_string);
730     tcase_add_test(string_literals, single_quote_string);
731     tcase_add_test(string_literals, vararg_string);
732 
733     number_literals = tcase_create("Number Literals");
734     tcase_add_test(number_literals, simple_number);
735     tcase_add_test(number_literals, float_number);
736     tcase_add_test(number_literals, vararg_number);
737 
738     keyword_literals = tcase_create("Keywords");
739     tcase_add_test(keyword_literals, keyword_literal);
740     dicts = tcase_create("Objects");
741     tcase_add_test(dicts, simple_dict);
742     lists = tcase_create("Lists");
743     tcase_add_test(lists, simple_list);
744 
745     whitespace = tcase_create("Whitespace");
746     tcase_add_test(whitespace, simple_whitespace);
747 
748     varargs = tcase_create("Varargs");
749     tcase_add_test(varargs, simple_varargs);
750 
751     errors = tcase_create("Invalid JSON");
752     tcase_add_test(errors, empty_input);
753     tcase_add_test(errors, unterminated_string);
754     tcase_add_test(errors, unterminated_escape);
755     tcase_add_test(errors, unterminated_sq_string);
756     tcase_add_test(errors, unterminated_array);
757     tcase_add_test(errors, unterminated_array_comma);
758     tcase_add_test(errors, invalid_array_comma);
759     tcase_add_test(errors, unterminated_dict);
760     tcase_add_test(errors, unterminated_dict_comma);
761 #if 0
762     /* FIXME: this print parse error messages on stderr.  */
763     tcase_add_test(errors, invalid_dict_comma);
764     tcase_add_test(errors, unterminated_literal);
765 #endif
766 
767     suite = suite_create("QJSON test-suite");
768     suite_add_tcase(suite, string_literals);
769     suite_add_tcase(suite, number_literals);
770     suite_add_tcase(suite, keyword_literals);
771     suite_add_tcase(suite, dicts);
772     suite_add_tcase(suite, lists);
773     suite_add_tcase(suite, whitespace);
774     suite_add_tcase(suite, varargs);
775     suite_add_tcase(suite, errors);
776 
777     return suite;
778 }
779 
main(void)780 int main(void)
781 {
782     int nf;
783     Suite *s;
784     SRunner *sr;
785 
786     s = qjson_suite();
787     sr = srunner_create(s);
788 
789     srunner_run_all(sr, CK_NORMAL);
790     nf = srunner_ntests_failed(sr);
791     srunner_free(sr);
792 
793     return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
794 }
795