Add a unit test for JSON support
[qemu/aliguori-queue.git] / check-qjson.c
blob17533897837682866e36686cb3a831fbf683167e
1 /*
2 * Copyright IBM, Corp. 2009
4 * Authors:
5 * Anthony Liguori <aliguori@us.ibm.com>
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.
11 #include <check.h>
12 #include <stdbool.h>
14 #include "qstring.h"
15 #include "qint.h"
16 #include "qdict.h"
17 #include "qlist.h"
18 #include "qfloat.h"
19 #include "qbool.h"
20 #include "qjson.h"
22 #include "qemu-common.h"
24 START_TEST(escaped_string)
26 int i;
27 struct {
28 const char *encoded;
29 const char *decoded;
30 } test_cases[] = {
31 { "\"\\\"\"", "\"" },
32 { "\"hello world \\\"embedded string\\\"\"",
33 "hello world \"embedded string\"" },
34 { "\"hello world\\nwith new line\"", "hello world\nwith new line" },
35 { "\"single byte utf-8 \\u0020\"", "single byte utf-8 " },
36 { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
37 { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
41 for (i = 0; test_cases[i].encoded; i++) {
42 QObject *obj;
43 QString *str;
45 obj = qobject_from_json(test_cases[i].encoded);
47 fail_unless(obj != NULL);
48 fail_unless(qobject_type(obj) == QTYPE_QSTRING);
50 str = qobject_to_qstring(obj);
51 fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
53 QDECREF(str);
56 END_TEST
58 START_TEST(simple_string)
60 int i;
61 struct {
62 const char *encoded;
63 const char *decoded;
64 } test_cases[] = {
65 { "\"hello world\"", "hello world" },
66 { "\"the quick brown fox jumped over the fence\"",
67 "the quick brown fox jumped over the fence" },
71 for (i = 0; test_cases[i].encoded; i++) {
72 QObject *obj;
73 QString *str;
75 obj = qobject_from_json(test_cases[i].encoded);
77 fail_unless(obj != NULL);
78 fail_unless(qobject_type(obj) == QTYPE_QSTRING);
80 str = qobject_to_qstring(obj);
81 fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
83 QDECREF(str);
86 END_TEST
88 START_TEST(single_quote_string)
90 int i;
91 struct {
92 const char *encoded;
93 const char *decoded;
94 } test_cases[] = {
95 { "'hello world'", "hello world" },
96 { "'the quick brown fox \\' jumped over the fence'",
97 "the quick brown fox ' jumped over the fence" },
101 for (i = 0; test_cases[i].encoded; i++) {
102 QObject *obj;
103 QString *str;
105 obj = qobject_from_json(test_cases[i].encoded);
107 fail_unless(obj != NULL);
108 fail_unless(qobject_type(obj) == QTYPE_QSTRING);
110 str = qobject_to_qstring(obj);
111 fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
113 QDECREF(str);
116 END_TEST
118 START_TEST(vararg_string)
120 int i;
121 struct {
122 const char *decoded;
123 } test_cases[] = {
124 { "hello world" },
125 { "the quick brown fox jumped over the fence" },
129 for (i = 0; test_cases[i].decoded; i++) {
130 QObject *obj;
131 QString *str;
133 obj = qobject_from_jsonf("%s", test_cases[i].decoded);
135 fail_unless(obj != NULL);
136 fail_unless(qobject_type(obj) == QTYPE_QSTRING);
138 str = qobject_to_qstring(obj);
139 fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
141 QDECREF(str);
144 END_TEST
146 START_TEST(simple_number)
148 int i;
149 struct {
150 const char *encoded;
151 int64_t decoded;
152 } test_cases[] = {
153 { "0", 0 },
154 { "1234", 1234 },
155 { "1", 1 },
156 { "-32", -32 },
157 { "-0", 0 },
158 { },
161 for (i = 0; test_cases[i].encoded; i++) {
162 QObject *obj;
163 QInt *qint;
165 obj = qobject_from_json(test_cases[i].encoded);
166 fail_unless(obj != NULL);
167 fail_unless(qobject_type(obj) == QTYPE_QINT);
169 qint = qobject_to_qint(obj);
170 fail_unless(qint_get_int(qint) == test_cases[i].decoded);
172 QDECREF(qint);
175 END_TEST
177 START_TEST(float_number)
179 int i;
180 struct {
181 const char *encoded;
182 double decoded;
183 } test_cases[] = {
184 { "32.43", 32.43 },
185 { "0.222", 0.222 },
186 { "-32.12313", -32.12313 },
187 { "-32.20e-10", -32.20e-10 },
188 { },
191 for (i = 0; test_cases[i].encoded; i++) {
192 QObject *obj;
193 QFloat *qfloat;
195 obj = qobject_from_json(test_cases[i].encoded);
196 fail_unless(obj != NULL);
197 fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
199 qfloat = qobject_to_qfloat(obj);
200 fail_unless(qfloat_get_double(qfloat) == test_cases[i].decoded);
202 QDECREF(qfloat);
205 END_TEST
207 START_TEST(vararg_number)
209 QObject *obj;
210 QInt *qint;
211 QFloat *qfloat;
212 int value = 0x2342;
213 int64_t value64 = 0x2342342343LL;
214 double valuef = 2.323423423;
216 obj = qobject_from_jsonf("%d", value);
217 fail_unless(obj != NULL);
218 fail_unless(qobject_type(obj) == QTYPE_QINT);
220 qint = qobject_to_qint(obj);
221 fail_unless(qint_get_int(qint) == value);
223 QDECREF(qint);
225 obj = qobject_from_jsonf("%" PRId64, value64);
226 fail_unless(obj != NULL);
227 fail_unless(qobject_type(obj) == QTYPE_QINT);
229 qint = qobject_to_qint(obj);
230 fail_unless(qint_get_int(qint) == value64);
232 QDECREF(qint);
234 obj = qobject_from_jsonf("%f", valuef);
235 fail_unless(obj != NULL);
236 fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
238 qfloat = qobject_to_qfloat(obj);
239 fail_unless(qfloat_get_double(qfloat) == valuef);
241 QDECREF(qfloat);
243 END_TEST
245 START_TEST(keyword_literal)
247 QObject *obj;
248 QBool *qbool;
250 obj = qobject_from_json("true");
251 fail_unless(obj != NULL);
252 fail_unless(qobject_type(obj) == QTYPE_QBOOL);
254 qbool = qobject_to_qbool(obj);
255 fail_unless(qbool_get_int(qbool) != 0);
257 QDECREF(qbool);
259 obj = qobject_from_json("false");
260 fail_unless(obj != NULL);
261 fail_unless(qobject_type(obj) == QTYPE_QBOOL);
263 qbool = qobject_to_qbool(obj);
264 fail_unless(qbool_get_int(qbool) == 0);
266 QDECREF(qbool);
268 obj = qobject_from_jsonf("%i", false);
269 fail_unless(obj != NULL);
270 fail_unless(qobject_type(obj) == QTYPE_QBOOL);
272 qbool = qobject_to_qbool(obj);
273 fail_unless(qbool_get_int(qbool) == 0);
275 QDECREF(qbool);
277 obj = qobject_from_jsonf("%i", true);
278 fail_unless(obj != NULL);
279 fail_unless(qobject_type(obj) == QTYPE_QBOOL);
281 qbool = qobject_to_qbool(obj);
282 fail_unless(qbool_get_int(qbool) != 0);
284 QDECREF(qbool);
286 END_TEST
288 typedef struct LiteralQDictEntry LiteralQDictEntry;
289 typedef struct LiteralQObject LiteralQObject;
291 struct LiteralQObject
293 int type;
294 union {
295 int64_t qint;
296 const char *qstr;
297 LiteralQDictEntry *qdict;
298 LiteralQObject *qlist;
299 } value;
302 struct LiteralQDictEntry
304 const char *key;
305 LiteralQObject value;
308 #define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
309 #define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
310 #define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
311 #define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
313 typedef struct QListCompareHelper
315 int index;
316 LiteralQObject *objs;
317 int result;
318 } QListCompareHelper;
320 static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
322 static void compare_helper(QObject *obj, void *opaque)
324 QListCompareHelper *helper = opaque;
326 if (helper->result == 0) {
327 return;
330 if (helper->objs[helper->index].type == QTYPE_NONE) {
331 helper->result = 0;
332 return;
335 helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
338 static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
340 if (lhs->type != qobject_type(rhs)) {
341 return 0;
344 switch (lhs->type) {
345 case QTYPE_QINT:
346 return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
347 case QTYPE_QSTRING:
348 return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
349 case QTYPE_QDICT: {
350 int i;
352 for (i = 0; lhs->value.qdict[i].key; i++) {
353 QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
355 if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
356 return 0;
360 return 1;
362 case QTYPE_QLIST: {
363 QListCompareHelper helper;
365 helper.index = 0;
366 helper.objs = lhs->value.qlist;
367 helper.result = 1;
369 qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
371 return helper.result;
373 default:
374 break;
377 return 0;
380 START_TEST(simple_dict)
382 int i;
383 struct {
384 const char *encoded;
385 LiteralQObject decoded;
386 } test_cases[] = {
388 .encoded = "{\"foo\":42,\"bar\":\"hello world\"}",
389 .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
390 { "foo", QLIT_QINT(42) },
391 { "bar", QLIT_QSTR("hello world") },
393 })),
394 }, {
395 .encoded = "{}",
396 .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
398 })),
399 }, {
400 .encoded = "{\"foo\":43}",
401 .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
402 { "foo", QLIT_QINT(43) },
404 })),
409 for (i = 0; test_cases[i].encoded; i++) {
410 QObject *obj;
412 obj = qobject_from_json(test_cases[i].encoded);
413 fail_unless(obj != NULL);
414 fail_unless(qobject_type(obj) == QTYPE_QDICT);
416 fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
418 qobject_decref(obj);
421 END_TEST
423 START_TEST(simple_list)
425 int i;
426 struct {
427 const char *encoded;
428 LiteralQObject decoded;
429 } test_cases[] = {
431 .encoded = "[43,42]",
432 .decoded = QLIT_QLIST(((LiteralQObject[]){
433 QLIT_QINT(43),
434 QLIT_QINT(42),
436 })),
439 .encoded = "[43]",
440 .decoded = QLIT_QLIST(((LiteralQObject[]){
441 QLIT_QINT(43),
443 })),
446 .encoded = "[]",
447 .decoded = QLIT_QLIST(((LiteralQObject[]){
449 })),
452 .encoded = "[{}]",
453 .decoded = QLIT_QLIST(((LiteralQObject[]){
454 QLIT_QDICT(((LiteralQDictEntry[]){
456 })),
458 })),
463 for (i = 0; test_cases[i].encoded; i++) {
464 QObject *obj;
466 obj = qobject_from_json(test_cases[i].encoded);
467 fail_unless(obj != NULL);
468 fail_unless(qobject_type(obj) == QTYPE_QLIST);
470 fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
472 qobject_decref(obj);
475 END_TEST
477 START_TEST(simple_whitespace)
479 int i;
480 struct {
481 const char *encoded;
482 LiteralQObject decoded;
483 } test_cases[] = {
485 .encoded = " [ 43 , 42 ]",
486 .decoded = QLIT_QLIST(((LiteralQObject[]){
487 QLIT_QINT(43),
488 QLIT_QINT(42),
490 })),
493 .encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
494 .decoded = QLIT_QLIST(((LiteralQObject[]){
495 QLIT_QINT(43),
496 QLIT_QDICT(((LiteralQDictEntry[]){
497 { "h", QLIT_QSTR("b") },
498 { }})),
499 QLIT_QLIST(((LiteralQObject[]){
500 { }})),
501 QLIT_QINT(42),
503 })),
506 .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
507 .decoded = QLIT_QLIST(((LiteralQObject[]){
508 QLIT_QINT(43),
509 QLIT_QDICT(((LiteralQDictEntry[]){
510 { "h", QLIT_QSTR("b") },
511 { "a", QLIT_QINT(32) },
512 { }})),
513 QLIT_QLIST(((LiteralQObject[]){
514 { }})),
515 QLIT_QINT(42),
517 })),
522 for (i = 0; test_cases[i].encoded; i++) {
523 QObject *obj;
525 obj = qobject_from_json(test_cases[i].encoded);
526 fail_unless(obj != NULL);
527 fail_unless(qobject_type(obj) == QTYPE_QLIST);
529 fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
531 qobject_decref(obj);
534 END_TEST
536 START_TEST(simple_varargs)
538 QObject *embedded_obj;
539 QObject *obj;
540 LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
541 QLIT_QINT(1),
542 QLIT_QINT(2),
543 QLIT_QLIST(((LiteralQObject[]){
544 QLIT_QINT(32),
545 QLIT_QINT(42),
546 {}})),
547 {}}));
549 embedded_obj = qobject_from_json("[32, 42]");
550 fail_unless(embedded_obj != NULL);
552 obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
553 fail_unless(obj != NULL);
555 fail_unless(compare_litqobj_to_qobj(&decoded, obj) == 1);
557 qobject_decref(obj);
559 END_TEST
561 static Suite *qjson_suite(void)
563 Suite *suite;
564 TCase *string_literals, *number_literals, *keyword_literals;
565 TCase *dicts, *lists, *whitespace, *varargs;
567 string_literals = tcase_create("String Literals");
568 tcase_add_test(string_literals, simple_string);
569 tcase_add_test(string_literals, escaped_string);
570 tcase_add_test(string_literals, single_quote_string);
571 tcase_add_test(string_literals, vararg_string);
573 number_literals = tcase_create("Number Literals");
574 tcase_add_test(number_literals, simple_number);
575 tcase_add_test(number_literals, float_number);
576 tcase_add_test(number_literals, vararg_number);
578 keyword_literals = tcase_create("Keywords");
579 tcase_add_test(keyword_literals, keyword_literal);
580 dicts = tcase_create("Objects");
581 tcase_add_test(dicts, simple_dict);
582 lists = tcase_create("Lists");
583 tcase_add_test(lists, simple_list);
585 whitespace = tcase_create("Whitespace");
586 tcase_add_test(whitespace, simple_whitespace);
588 varargs = tcase_create("Varargs");
589 tcase_add_test(varargs, simple_varargs);
591 suite = suite_create("QJSON test-suite");
592 suite_add_tcase(suite, string_literals);
593 suite_add_tcase(suite, number_literals);
594 suite_add_tcase(suite, keyword_literals);
595 suite_add_tcase(suite, dicts);
596 suite_add_tcase(suite, lists);
597 suite_add_tcase(suite, whitespace);
598 suite_add_tcase(suite, varargs);
600 return suite;
603 int main(void)
605 int nf;
606 Suite *s;
607 SRunner *sr;
609 s = qjson_suite();
610 sr = srunner_create(s);
612 srunner_run_all(sr, CK_NORMAL);
613 nf = srunner_ntests_failed(sr);
614 srunner_free(sr);
616 return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;