]> git.proxmox.com Git - mirror_qemu.git/blame - check-qjson.c
Add a unit test for JSON support
[mirror_qemu.git] / check-qjson.c
CommitLineData
422c46a8
AL
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#include <stdbool.h>
13
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"
21
22#include "qemu-common.h"
23
24START_TEST(escaped_string)
25{
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" },
38 {}
39 };
40
41 for (i = 0; test_cases[i].encoded; i++) {
42 QObject *obj;
43 QString *str;
44
45 obj = qobject_from_json(test_cases[i].encoded);
46
47 fail_unless(obj != NULL);
48 fail_unless(qobject_type(obj) == QTYPE_QSTRING);
49
50 str = qobject_to_qstring(obj);
51 fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
52
53 QDECREF(str);
54 }
55}
56END_TEST
57
58START_TEST(simple_string)
59{
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" },
68 {}
69 };
70
71 for (i = 0; test_cases[i].encoded; i++) {
72 QObject *obj;
73 QString *str;
74
75 obj = qobject_from_json(test_cases[i].encoded);
76
77 fail_unless(obj != NULL);
78 fail_unless(qobject_type(obj) == QTYPE_QSTRING);
79
80 str = qobject_to_qstring(obj);
81 fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
82
83 QDECREF(str);
84 }
85}
86END_TEST
87
88START_TEST(single_quote_string)
89{
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" },
98 {}
99 };
100
101 for (i = 0; test_cases[i].encoded; i++) {
102 QObject *obj;
103 QString *str;
104
105 obj = qobject_from_json(test_cases[i].encoded);
106
107 fail_unless(obj != NULL);
108 fail_unless(qobject_type(obj) == QTYPE_QSTRING);
109
110 str = qobject_to_qstring(obj);
111 fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
112
113 QDECREF(str);
114 }
115}
116END_TEST
117
118START_TEST(vararg_string)
119{
120 int i;
121 struct {
122 const char *decoded;
123 } test_cases[] = {
124 { "hello world" },
125 { "the quick brown fox jumped over the fence" },
126 {}
127 };
128
129 for (i = 0; test_cases[i].decoded; i++) {
130 QObject *obj;
131 QString *str;
132
133 obj = qobject_from_jsonf("%s", test_cases[i].decoded);
134
135 fail_unless(obj != NULL);
136 fail_unless(qobject_type(obj) == QTYPE_QSTRING);
137
138 str = qobject_to_qstring(obj);
139 fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
140
141 QDECREF(str);
142 }
143}
144END_TEST
145
146START_TEST(simple_number)
147{
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 { },
159 };
160
161 for (i = 0; test_cases[i].encoded; i++) {
162 QObject *obj;
163 QInt *qint;
164
165 obj = qobject_from_json(test_cases[i].encoded);
166 fail_unless(obj != NULL);
167 fail_unless(qobject_type(obj) == QTYPE_QINT);
168
169 qint = qobject_to_qint(obj);
170 fail_unless(qint_get_int(qint) == test_cases[i].decoded);
171
172 QDECREF(qint);
173 }
174}
175END_TEST
176
177START_TEST(float_number)
178{
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 { },
189 };
190
191 for (i = 0; test_cases[i].encoded; i++) {
192 QObject *obj;
193 QFloat *qfloat;
194
195 obj = qobject_from_json(test_cases[i].encoded);
196 fail_unless(obj != NULL);
197 fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
198
199 qfloat = qobject_to_qfloat(obj);
200 fail_unless(qfloat_get_double(qfloat) == test_cases[i].decoded);
201
202 QDECREF(qfloat);
203 }
204}
205END_TEST
206
207START_TEST(vararg_number)
208{
209 QObject *obj;
210 QInt *qint;
211 QFloat *qfloat;
212 int value = 0x2342;
213 int64_t value64 = 0x2342342343LL;
214 double valuef = 2.323423423;
215
216 obj = qobject_from_jsonf("%d", value);
217 fail_unless(obj != NULL);
218 fail_unless(qobject_type(obj) == QTYPE_QINT);
219
220 qint = qobject_to_qint(obj);
221 fail_unless(qint_get_int(qint) == value);
222
223 QDECREF(qint);
224
225 obj = qobject_from_jsonf("%" PRId64, value64);
226 fail_unless(obj != NULL);
227 fail_unless(qobject_type(obj) == QTYPE_QINT);
228
229 qint = qobject_to_qint(obj);
230 fail_unless(qint_get_int(qint) == value64);
231
232 QDECREF(qint);
233
234 obj = qobject_from_jsonf("%f", valuef);
235 fail_unless(obj != NULL);
236 fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
237
238 qfloat = qobject_to_qfloat(obj);
239 fail_unless(qfloat_get_double(qfloat) == valuef);
240
241 QDECREF(qfloat);
242}
243END_TEST
244
245START_TEST(keyword_literal)
246{
247 QObject *obj;
248 QBool *qbool;
249
250 obj = qobject_from_json("true");
251 fail_unless(obj != NULL);
252 fail_unless(qobject_type(obj) == QTYPE_QBOOL);
253
254 qbool = qobject_to_qbool(obj);
255 fail_unless(qbool_get_int(qbool) != 0);
256
257 QDECREF(qbool);
258
259 obj = qobject_from_json("false");
260 fail_unless(obj != NULL);
261 fail_unless(qobject_type(obj) == QTYPE_QBOOL);
262
263 qbool = qobject_to_qbool(obj);
264 fail_unless(qbool_get_int(qbool) == 0);
265
266 QDECREF(qbool);
267
268 obj = qobject_from_jsonf("%i", false);
269 fail_unless(obj != NULL);
270 fail_unless(qobject_type(obj) == QTYPE_QBOOL);
271
272 qbool = qobject_to_qbool(obj);
273 fail_unless(qbool_get_int(qbool) == 0);
274
275 QDECREF(qbool);
276
277 obj = qobject_from_jsonf("%i", true);
278 fail_unless(obj != NULL);
279 fail_unless(qobject_type(obj) == QTYPE_QBOOL);
280
281 qbool = qobject_to_qbool(obj);
282 fail_unless(qbool_get_int(qbool) != 0);
283
284 QDECREF(qbool);
285}
286END_TEST
287
288typedef struct LiteralQDictEntry LiteralQDictEntry;
289typedef struct LiteralQObject LiteralQObject;
290
291struct LiteralQObject
292{
293 int type;
294 union {
295 int64_t qint;
296 const char *qstr;
297 LiteralQDictEntry *qdict;
298 LiteralQObject *qlist;
299 } value;
300};
301
302struct LiteralQDictEntry
303{
304 const char *key;
305 LiteralQObject value;
306};
307
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)}
312
313typedef struct QListCompareHelper
314{
315 int index;
316 LiteralQObject *objs;
317 int result;
318} QListCompareHelper;
319
320static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
321
322static void compare_helper(QObject *obj, void *opaque)
323{
324 QListCompareHelper *helper = opaque;
325
326 if (helper->result == 0) {
327 return;
328 }
329
330 if (helper->objs[helper->index].type == QTYPE_NONE) {
331 helper->result = 0;
332 return;
333 }
334
335 helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
336}
337
338static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
339{
340 if (lhs->type != qobject_type(rhs)) {
341 return 0;
342 }
343
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;
351
352 for (i = 0; lhs->value.qdict[i].key; i++) {
353 QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
354
355 if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
356 return 0;
357 }
358 }
359
360 return 1;
361 }
362 case QTYPE_QLIST: {
363 QListCompareHelper helper;
364
365 helper.index = 0;
366 helper.objs = lhs->value.qlist;
367 helper.result = 1;
368
369 qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
370
371 return helper.result;
372 }
373 default:
374 break;
375 }
376
377 return 0;
378}
379
380START_TEST(simple_dict)
381{
382 int i;
383 struct {
384 const char *encoded;
385 LiteralQObject decoded;
386 } test_cases[] = {
387 {
388 .encoded = "{\"foo\":42,\"bar\":\"hello world\"}",
389 .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
390 { "foo", QLIT_QINT(42) },
391 { "bar", QLIT_QSTR("hello world") },
392 { }
393 })),
394 }, {
395 .encoded = "{}",
396 .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
397 { }
398 })),
399 }, {
400 .encoded = "{\"foo\":43}",
401 .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
402 { "foo", QLIT_QINT(43) },
403 { }
404 })),
405 },
406 { }
407 };
408
409 for (i = 0; test_cases[i].encoded; i++) {
410 QObject *obj;
411
412 obj = qobject_from_json(test_cases[i].encoded);
413 fail_unless(obj != NULL);
414 fail_unless(qobject_type(obj) == QTYPE_QDICT);
415
416 fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
417
418 qobject_decref(obj);
419 }
420}
421END_TEST
422
423START_TEST(simple_list)
424{
425 int i;
426 struct {
427 const char *encoded;
428 LiteralQObject decoded;
429 } test_cases[] = {
430 {
431 .encoded = "[43,42]",
432 .decoded = QLIT_QLIST(((LiteralQObject[]){
433 QLIT_QINT(43),
434 QLIT_QINT(42),
435 { }
436 })),
437 },
438 {
439 .encoded = "[43]",
440 .decoded = QLIT_QLIST(((LiteralQObject[]){
441 QLIT_QINT(43),
442 { }
443 })),
444 },
445 {
446 .encoded = "[]",
447 .decoded = QLIT_QLIST(((LiteralQObject[]){
448 { }
449 })),
450 },
451 {
452 .encoded = "[{}]",
453 .decoded = QLIT_QLIST(((LiteralQObject[]){
454 QLIT_QDICT(((LiteralQDictEntry[]){
455 {},
456 })),
457 {},
458 })),
459 },
460 { }
461 };
462
463 for (i = 0; test_cases[i].encoded; i++) {
464 QObject *obj;
465
466 obj = qobject_from_json(test_cases[i].encoded);
467 fail_unless(obj != NULL);
468 fail_unless(qobject_type(obj) == QTYPE_QLIST);
469
470 fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
471
472 qobject_decref(obj);
473 }
474}
475END_TEST
476
477START_TEST(simple_whitespace)
478{
479 int i;
480 struct {
481 const char *encoded;
482 LiteralQObject decoded;
483 } test_cases[] = {
484 {
485 .encoded = " [ 43 , 42 ]",
486 .decoded = QLIT_QLIST(((LiteralQObject[]){
487 QLIT_QINT(43),
488 QLIT_QINT(42),
489 { }
490 })),
491 },
492 {
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),
502 { }
503 })),
504 },
505 {
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),
516 { }
517 })),
518 },
519 { }
520 };
521
522 for (i = 0; test_cases[i].encoded; i++) {
523 QObject *obj;
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 qobject_decref(obj);
532 }
533}
534END_TEST
535
536START_TEST(simple_varargs)
537{
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 {}}));
548
549 embedded_obj = qobject_from_json("[32, 42]");
550 fail_unless(embedded_obj != NULL);
551
552 obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
553 fail_unless(obj != NULL);
554
555 fail_unless(compare_litqobj_to_qobj(&decoded, obj) == 1);
556
557 qobject_decref(obj);
558}
559END_TEST
560
561static Suite *qjson_suite(void)
562{
563 Suite *suite;
564 TCase *string_literals, *number_literals, *keyword_literals;
565 TCase *dicts, *lists, *whitespace, *varargs;
566
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);
572
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);
577
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);
584
585 whitespace = tcase_create("Whitespace");
586 tcase_add_test(whitespace, simple_whitespace);
587
588 varargs = tcase_create("Varargs");
589 tcase_add_test(varargs, simple_varargs);
590
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);
599
600 return suite;
601}
602
603int main(void)
604{
605 int nf;
606 Suite *s;
607 SRunner *sr;
608
609 s = qjson_suite();
610 sr = srunner_create(s);
611
612 srunner_run_all(sr, CK_NORMAL);
613 nf = srunner_ntests_failed(sr);
614 srunner_free(sr);
615
616 return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
617}