|
|
1.1 root 1: /*
2: * Copyright IBM, Corp. 2009
3: *
4: * Authors:
5: * Anthony Liguori <[email protected]>
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 <glib.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:
23: static void escaped_string(void)
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: { "\"\\/\"", "/", .skip = 1 },
38: { "\"\\\\\"", "\\" },
39: { "\"\\\"\"", "\"" },
40: { "\"hello world \\\"embedded string\\\"\"",
41: "hello world \"embedded string\"" },
42: { "\"hello world\\nwith new line\"", "hello world\nwith new line" },
43: { "\"single byte utf-8 \\u0020\"", "single byte utf-8 ", .skip = 1 },
44: { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
45: { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
46: {}
47: };
48:
49: for (i = 0; test_cases[i].encoded; i++) {
50: QObject *obj;
51: QString *str;
52:
53: obj = qobject_from_json(test_cases[i].encoded);
54:
55: g_assert(obj != NULL);
56: g_assert(qobject_type(obj) == QTYPE_QSTRING);
57:
58: str = qobject_to_qstring(obj);
59: g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].decoded);
60:
61: if (test_cases[i].skip == 0) {
62: str = qobject_to_json(obj);
63: g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].encoded);
64: qobject_decref(obj);
65: }
66:
67: QDECREF(str);
68: }
69: }
70:
71: static void simple_string(void)
72: {
73: int i;
74: struct {
75: const char *encoded;
76: const char *decoded;
77: } test_cases[] = {
78: { "\"hello world\"", "hello world" },
79: { "\"the quick brown fox jumped over the fence\"",
80: "the quick brown fox jumped over the fence" },
81: {}
82: };
83:
84: for (i = 0; test_cases[i].encoded; i++) {
85: QObject *obj;
86: QString *str;
87:
88: obj = qobject_from_json(test_cases[i].encoded);
89:
90: g_assert(obj != NULL);
91: g_assert(qobject_type(obj) == QTYPE_QSTRING);
92:
93: str = qobject_to_qstring(obj);
94: g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
95:
96: str = qobject_to_json(obj);
97: g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
98:
99: qobject_decref(obj);
100:
101: QDECREF(str);
102: }
103: }
104:
105: static void single_quote_string(void)
106: {
107: int i;
108: struct {
109: const char *encoded;
110: const char *decoded;
111: } test_cases[] = {
112: { "'hello world'", "hello world" },
113: { "'the quick brown fox \\' jumped over the fence'",
114: "the quick brown fox ' jumped over the fence" },
115: {}
116: };
117:
118: for (i = 0; test_cases[i].encoded; i++) {
119: QObject *obj;
120: QString *str;
121:
122: obj = qobject_from_json(test_cases[i].encoded);
123:
124: g_assert(obj != NULL);
125: g_assert(qobject_type(obj) == QTYPE_QSTRING);
126:
127: str = qobject_to_qstring(obj);
128: g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
129:
130: QDECREF(str);
131: }
132: }
133:
134: static void vararg_string(void)
135: {
136: int i;
137: struct {
138: const char *decoded;
139: } test_cases[] = {
140: { "hello world" },
141: { "the quick brown fox jumped over the fence" },
142: {}
143: };
144:
145: for (i = 0; test_cases[i].decoded; i++) {
146: QObject *obj;
147: QString *str;
148:
149: obj = qobject_from_jsonf("%s", test_cases[i].decoded);
150:
151: g_assert(obj != NULL);
152: g_assert(qobject_type(obj) == QTYPE_QSTRING);
153:
154: str = qobject_to_qstring(obj);
155: g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
156:
157: QDECREF(str);
158: }
159: }
160:
161: static void simple_number(void)
162: {
163: int i;
164: struct {
165: const char *encoded;
166: int64_t decoded;
167: int skip;
168: } test_cases[] = {
169: { "0", 0 },
170: { "1234", 1234 },
171: { "1", 1 },
172: { "-32", -32 },
173: { "-0", 0, .skip = 1 },
174: { },
175: };
176:
177: for (i = 0; test_cases[i].encoded; i++) {
178: QObject *obj;
179: QInt *qint;
180:
181: obj = qobject_from_json(test_cases[i].encoded);
182: g_assert(obj != NULL);
183: g_assert(qobject_type(obj) == QTYPE_QINT);
184:
185: qint = qobject_to_qint(obj);
186: g_assert(qint_get_int(qint) == test_cases[i].decoded);
187: if (test_cases[i].skip == 0) {
188: QString *str;
189:
190: str = qobject_to_json(obj);
191: g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
192: QDECREF(str);
193: }
194:
195: QDECREF(qint);
196: }
197: }
198:
199: static void float_number(void)
200: {
201: int i;
202: struct {
203: const char *encoded;
204: double decoded;
205: int skip;
206: } test_cases[] = {
207: { "32.43", 32.43 },
208: { "0.222", 0.222 },
209: { "-32.12313", -32.12313 },
210: { "-32.20e-10", -32.20e-10, .skip = 1 },
211: { },
212: };
213:
214: for (i = 0; test_cases[i].encoded; i++) {
215: QObject *obj;
216: QFloat *qfloat;
217:
218: obj = qobject_from_json(test_cases[i].encoded);
219: g_assert(obj != NULL);
220: g_assert(qobject_type(obj) == QTYPE_QFLOAT);
221:
222: qfloat = qobject_to_qfloat(obj);
223: g_assert(qfloat_get_double(qfloat) == test_cases[i].decoded);
224:
225: if (test_cases[i].skip == 0) {
226: QString *str;
227:
228: str = qobject_to_json(obj);
229: g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
230: QDECREF(str);
231: }
232:
233: QDECREF(qfloat);
234: }
235: }
236:
237: static void vararg_number(void)
238: {
239: QObject *obj;
240: QInt *qint;
241: QFloat *qfloat;
242: int value = 0x2342;
243: int64_t value64 = 0x2342342343LL;
244: double valuef = 2.323423423;
245:
246: obj = qobject_from_jsonf("%d", value);
247: g_assert(obj != NULL);
248: g_assert(qobject_type(obj) == QTYPE_QINT);
249:
250: qint = qobject_to_qint(obj);
251: g_assert(qint_get_int(qint) == value);
252:
253: QDECREF(qint);
254:
255: obj = qobject_from_jsonf("%" PRId64, value64);
256: g_assert(obj != NULL);
257: g_assert(qobject_type(obj) == QTYPE_QINT);
258:
259: qint = qobject_to_qint(obj);
260: g_assert(qint_get_int(qint) == value64);
261:
262: QDECREF(qint);
263:
264: obj = qobject_from_jsonf("%f", valuef);
265: g_assert(obj != NULL);
266: g_assert(qobject_type(obj) == QTYPE_QFLOAT);
267:
268: qfloat = qobject_to_qfloat(obj);
269: g_assert(qfloat_get_double(qfloat) == valuef);
270:
271: QDECREF(qfloat);
272: }
273:
274: static void keyword_literal(void)
275: {
276: QObject *obj;
277: QBool *qbool;
278: QString *str;
279:
280: obj = qobject_from_json("true");
281: g_assert(obj != NULL);
282: g_assert(qobject_type(obj) == QTYPE_QBOOL);
283:
284: qbool = qobject_to_qbool(obj);
285: g_assert(qbool_get_int(qbool) != 0);
286:
287: str = qobject_to_json(obj);
288: g_assert(strcmp(qstring_get_str(str), "true") == 0);
289: QDECREF(str);
290:
291: QDECREF(qbool);
292:
293: obj = qobject_from_json("false");
294: g_assert(obj != NULL);
295: g_assert(qobject_type(obj) == QTYPE_QBOOL);
296:
297: qbool = qobject_to_qbool(obj);
298: g_assert(qbool_get_int(qbool) == 0);
299:
300: str = qobject_to_json(obj);
301: g_assert(strcmp(qstring_get_str(str), "false") == 0);
302: QDECREF(str);
303:
304: QDECREF(qbool);
305:
306: obj = qobject_from_jsonf("%i", false);
307: g_assert(obj != NULL);
308: g_assert(qobject_type(obj) == QTYPE_QBOOL);
309:
310: qbool = qobject_to_qbool(obj);
311: g_assert(qbool_get_int(qbool) == 0);
312:
313: QDECREF(qbool);
314:
315: obj = qobject_from_jsonf("%i", true);
316: g_assert(obj != NULL);
317: g_assert(qobject_type(obj) == QTYPE_QBOOL);
318:
319: qbool = qobject_to_qbool(obj);
320: g_assert(qbool_get_int(qbool) != 0);
321:
322: QDECREF(qbool);
323: }
324:
325: typedef struct LiteralQDictEntry LiteralQDictEntry;
326: typedef struct LiteralQObject LiteralQObject;
327:
328: struct LiteralQObject
329: {
330: int type;
331: union {
332: int64_t qint;
333: const char *qstr;
334: LiteralQDictEntry *qdict;
335: LiteralQObject *qlist;
336: } value;
337: };
338:
339: struct LiteralQDictEntry
340: {
341: const char *key;
342: LiteralQObject value;
343: };
344:
345: #define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
346: #define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
347: #define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
348: #define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
349:
350: typedef struct QListCompareHelper
351: {
352: int index;
353: LiteralQObject *objs;
354: int result;
355: } QListCompareHelper;
356:
357: static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
358:
359: static void compare_helper(QObject *obj, void *opaque)
360: {
361: QListCompareHelper *helper = opaque;
362:
363: if (helper->result == 0) {
364: return;
365: }
366:
367: if (helper->objs[helper->index].type == QTYPE_NONE) {
368: helper->result = 0;
369: return;
370: }
371:
372: helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
373: }
374:
375: static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
376: {
377: if (lhs->type != qobject_type(rhs)) {
378: return 0;
379: }
380:
381: switch (lhs->type) {
382: case QTYPE_QINT:
383: return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
384: case QTYPE_QSTRING:
385: return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
386: case QTYPE_QDICT: {
387: int i;
388:
389: for (i = 0; lhs->value.qdict[i].key; i++) {
390: QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
391:
392: if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
393: return 0;
394: }
395: }
396:
397: return 1;
398: }
399: case QTYPE_QLIST: {
400: QListCompareHelper helper;
401:
402: helper.index = 0;
403: helper.objs = lhs->value.qlist;
404: helper.result = 1;
405:
406: qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
407:
408: return helper.result;
409: }
410: default:
411: break;
412: }
413:
414: return 0;
415: }
416:
417: static void simple_dict(void)
418: {
419: int i;
420: struct {
421: const char *encoded;
422: LiteralQObject decoded;
423: } test_cases[] = {
424: {
425: .encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
426: .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
427: { "foo", QLIT_QINT(42) },
428: { "bar", QLIT_QSTR("hello world") },
429: { }
430: })),
431: }, {
432: .encoded = "{}",
433: .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
434: { }
435: })),
436: }, {
437: .encoded = "{\"foo\": 43}",
438: .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
439: { "foo", QLIT_QINT(43) },
440: { }
441: })),
442: },
443: { }
444: };
445:
446: for (i = 0; test_cases[i].encoded; i++) {
447: QObject *obj;
448: QString *str;
449:
450: obj = qobject_from_json(test_cases[i].encoded);
451: g_assert(obj != NULL);
452: g_assert(qobject_type(obj) == QTYPE_QDICT);
453:
454: g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
455:
456: str = qobject_to_json(obj);
457: qobject_decref(obj);
458:
459: obj = qobject_from_json(qstring_get_str(str));
460: g_assert(obj != NULL);
461: g_assert(qobject_type(obj) == QTYPE_QDICT);
462:
463: g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
464: qobject_decref(obj);
465: QDECREF(str);
466: }
467: }
468:
469: static void simple_list(void)
470: {
471: int i;
472: struct {
473: const char *encoded;
474: LiteralQObject decoded;
475: } test_cases[] = {
476: {
477: .encoded = "[43,42]",
478: .decoded = QLIT_QLIST(((LiteralQObject[]){
479: QLIT_QINT(43),
480: QLIT_QINT(42),
481: { }
482: })),
483: },
484: {
485: .encoded = "[43]",
486: .decoded = QLIT_QLIST(((LiteralQObject[]){
487: QLIT_QINT(43),
488: { }
489: })),
490: },
491: {
492: .encoded = "[]",
493: .decoded = QLIT_QLIST(((LiteralQObject[]){
494: { }
495: })),
496: },
497: {
498: .encoded = "[{}]",
499: .decoded = QLIT_QLIST(((LiteralQObject[]){
500: QLIT_QDICT(((LiteralQDictEntry[]){
501: {},
502: })),
503: {},
504: })),
505: },
506: { }
507: };
508:
509: for (i = 0; test_cases[i].encoded; i++) {
510: QObject *obj;
511: QString *str;
512:
513: obj = qobject_from_json(test_cases[i].encoded);
514: g_assert(obj != NULL);
515: g_assert(qobject_type(obj) == QTYPE_QLIST);
516:
517: g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
518:
519: str = qobject_to_json(obj);
520: qobject_decref(obj);
521:
522: obj = qobject_from_json(qstring_get_str(str));
523: g_assert(obj != NULL);
524: g_assert(qobject_type(obj) == QTYPE_QLIST);
525:
526: g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
527: qobject_decref(obj);
528: QDECREF(str);
529: }
530: }
531:
532: static void simple_whitespace(void)
533: {
534: int i;
535: struct {
536: const char *encoded;
537: LiteralQObject decoded;
538: } test_cases[] = {
539: {
540: .encoded = " [ 43 , 42 ]",
541: .decoded = QLIT_QLIST(((LiteralQObject[]){
542: QLIT_QINT(43),
543: QLIT_QINT(42),
544: { }
545: })),
546: },
547: {
548: .encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
549: .decoded = QLIT_QLIST(((LiteralQObject[]){
550: QLIT_QINT(43),
551: QLIT_QDICT(((LiteralQDictEntry[]){
552: { "h", QLIT_QSTR("b") },
553: { }})),
554: QLIT_QLIST(((LiteralQObject[]){
555: { }})),
556: QLIT_QINT(42),
557: { }
558: })),
559: },
560: {
561: .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
562: .decoded = QLIT_QLIST(((LiteralQObject[]){
563: QLIT_QINT(43),
564: QLIT_QDICT(((LiteralQDictEntry[]){
565: { "h", QLIT_QSTR("b") },
566: { "a", QLIT_QINT(32) },
567: { }})),
568: QLIT_QLIST(((LiteralQObject[]){
569: { }})),
570: QLIT_QINT(42),
571: { }
572: })),
573: },
574: { }
575: };
576:
577: for (i = 0; test_cases[i].encoded; i++) {
578: QObject *obj;
579: QString *str;
580:
581: obj = qobject_from_json(test_cases[i].encoded);
582: g_assert(obj != NULL);
583: g_assert(qobject_type(obj) == QTYPE_QLIST);
584:
585: g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
586:
587: str = qobject_to_json(obj);
588: qobject_decref(obj);
589:
590: obj = qobject_from_json(qstring_get_str(str));
591: g_assert(obj != NULL);
592: g_assert(qobject_type(obj) == QTYPE_QLIST);
593:
594: g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
595:
596: qobject_decref(obj);
597: QDECREF(str);
598: }
599: }
600:
601: static void simple_varargs(void)
602: {
603: QObject *embedded_obj;
604: QObject *obj;
605: LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
606: QLIT_QINT(1),
607: QLIT_QINT(2),
608: QLIT_QLIST(((LiteralQObject[]){
609: QLIT_QINT(32),
610: QLIT_QINT(42),
611: {}})),
612: {}}));
613:
614: embedded_obj = qobject_from_json("[32, 42]");
615: g_assert(embedded_obj != NULL);
616:
617: obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
618: g_assert(obj != NULL);
619:
620: g_assert(compare_litqobj_to_qobj(&decoded, obj) == 1);
621:
622: qobject_decref(obj);
623: }
624:
625: static void empty_input(void)
626: {
627: const char *empty = "";
628:
629: QObject *obj = qobject_from_json(empty);
630: g_assert(obj == NULL);
631: }
632:
633: static void unterminated_string(void)
634: {
635: QObject *obj = qobject_from_json("\"abc");
636: g_assert(obj == NULL);
637: }
638:
639: static void unterminated_sq_string(void)
640: {
641: QObject *obj = qobject_from_json("'abc");
642: g_assert(obj == NULL);
643: }
644:
645: static void unterminated_escape(void)
646: {
647: QObject *obj = qobject_from_json("\"abc\\\"");
648: g_assert(obj == NULL);
649: }
650:
651: static void unterminated_array(void)
652: {
653: QObject *obj = qobject_from_json("[32");
654: g_assert(obj == NULL);
655: }
656:
657: static void unterminated_array_comma(void)
658: {
659: QObject *obj = qobject_from_json("[32,");
660: g_assert(obj == NULL);
661: }
662:
663: static void invalid_array_comma(void)
664: {
665: QObject *obj = qobject_from_json("[32,}");
666: g_assert(obj == NULL);
667: }
668:
669: static void unterminated_dict(void)
670: {
671: QObject *obj = qobject_from_json("{'abc':32");
672: g_assert(obj == NULL);
673: }
674:
675: static void unterminated_dict_comma(void)
676: {
677: QObject *obj = qobject_from_json("{'abc':32,");
678: g_assert(obj == NULL);
679: }
680:
681: static void invalid_dict_comma(void)
682: {
683: QObject *obj = qobject_from_json("{'abc':32,}");
684: g_assert(obj == NULL);
685: }
686:
687: static void unterminated_literal(void)
688: {
689: QObject *obj = qobject_from_json("nul");
690: g_assert(obj == NULL);
691: }
692:
693: int main(int argc, char **argv)
694: {
695: g_test_init(&argc, &argv, NULL);
696:
697: g_test_add_func("/literals/string/simple", simple_string);
698: g_test_add_func("/literals/string/escaped", escaped_string);
699: g_test_add_func("/literals/string/single_quote", single_quote_string);
700: g_test_add_func("/literals/string/vararg", vararg_string);
701:
702: g_test_add_func("/literals/number/simple", simple_number);
703: g_test_add_func("/literals/number/float", float_number);
704: g_test_add_func("/literals/number/vararg", vararg_number);
705:
706: g_test_add_func("/literals/keyword", keyword_literal);
707:
708: g_test_add_func("/dicts/simple_dict", simple_dict);
709: g_test_add_func("/lists/simple_list", simple_list);
710:
711: g_test_add_func("/whitespace/simple_whitespace", simple_whitespace);
712:
713: g_test_add_func("/varargs/simple_varargs", simple_varargs);
714:
715: g_test_add_func("/errors/empty_input", empty_input);
716: g_test_add_func("/errors/unterminated/string", unterminated_string);
717: g_test_add_func("/errors/unterminated/escape", unterminated_escape);
718: g_test_add_func("/errors/unterminated/sq_string", unterminated_sq_string);
719: g_test_add_func("/errors/unterminated/array", unterminated_array);
720: g_test_add_func("/errors/unterminated/array_comma", unterminated_array_comma);
721: g_test_add_func("/errors/unterminated/dict", unterminated_dict);
722: g_test_add_func("/errors/unterminated/dict_comma", unterminated_dict_comma);
723: g_test_add_func("/errors/invalid_array_comma", invalid_array_comma);
724: g_test_add_func("/errors/invalid_dict_comma", invalid_dict_comma);
725: g_test_add_func("/errors/unterminated/literal", unterminated_literal);
726:
727: return g_test_run();
728: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.