9 #define VIR_FROM_THIS VIR_FROM_NONE
20 testJSONFromFile(const void *data
)
22 const struct testInfo
*info
= data
;
23 g_autoptr(virJSONValue
) injson
= NULL
;
24 g_autofree
char *infile
= NULL
;
25 g_autofree
char *indata
= NULL
;
26 g_autofree
char *outfile
= NULL
;
27 g_autofree
char *actual
= NULL
;
29 infile
= g_strdup_printf("%s/virjsondata/parse-%s-in.json",
30 abs_srcdir
, info
->name
);
31 outfile
= g_strdup_printf("%s/virjsondata/parse-%s-out.json",
32 abs_srcdir
, info
->name
);
34 if (virTestLoadFile(infile
, &indata
) < 0)
37 injson
= virJSONValueFromString(indata
);
41 VIR_TEST_VERBOSE("Failed to parse %s", info
->doc
);
44 VIR_TEST_DEBUG("As expected, failed to parse %s", info
->doc
);
49 VIR_TEST_VERBOSE("Unexpected success while parsing %s", info
->doc
);
54 if (!(actual
= virJSONValueToString(injson
, false)))
57 if (virTestCompareToFile(actual
, outfile
) < 0)
65 testJSONFromString(const void *data
)
67 const struct testInfo
*info
= data
;
68 g_autoptr(virJSONValue
) json
= NULL
;
69 const char *expectstr
= info
->expect
? info
->expect
: info
->doc
;
70 g_autofree
char *formatted
= NULL
;
72 json
= virJSONValueFromString(info
->doc
);
76 VIR_TEST_VERBOSE("Failed to parse %s", info
->doc
);
79 VIR_TEST_DEBUG("As expected, failed to parse %s", info
->doc
);
84 VIR_TEST_VERBOSE("Unexpected success while parsing %s", info
->doc
);
89 VIR_TEST_DEBUG("Parsed %s", info
->doc
);
91 if (!(formatted
= virJSONValueToString(json
, false))) {
92 VIR_TEST_VERBOSE("Failed to format json data");
96 if (virTestCompareToString(expectstr
, formatted
) < 0) {
105 testJSONAddRemove(const void *data
)
107 const struct testInfo
*info
= data
;
108 g_autoptr(virJSONValue
) json
= NULL
;
109 g_autoptr(virJSONValue
) name
= NULL
;
110 g_autofree
char *infile
= NULL
;
111 g_autofree
char *indata
= NULL
;
112 g_autofree
char *outfile
= NULL
;
113 g_autofree
char *actual
= NULL
;
115 infile
= g_strdup_printf("%s/virjsondata/add-remove-%s-in.json",
116 abs_srcdir
, info
->name
);
117 outfile
= g_strdup_printf("%s/virjsondata/add-remove-%s-out.json",
118 abs_srcdir
, info
->name
);
120 if (virTestLoadFile(infile
, &indata
) < 0)
123 json
= virJSONValueFromString(indata
);
125 VIR_TEST_VERBOSE("Fail to parse %s", info
->name
);
129 switch (virJSONValueObjectRemoveKey(json
, "name", &name
)) {
132 VIR_TEST_VERBOSE("should not remove from non-object %s",
141 VIR_TEST_VERBOSE("Fail to recognize non-object %s", info
->name
);
144 VIR_TEST_VERBOSE("unexpected result when removing from %s",
148 if (STRNEQ_NULLABLE(virJSONValueGetString(name
), "sample")) {
149 VIR_TEST_VERBOSE("unexpected value after removing name: %s",
150 NULLSTR(virJSONValueGetString(name
)));
153 if (virJSONValueObjectRemoveKey(json
, "name", NULL
)) {
154 VIR_TEST_VERBOSE("%s",
155 "unexpected success when removing missing key");
158 if (virJSONValueObjectAppendString(json
, "newname", "foo") < 0) {
159 VIR_TEST_VERBOSE("%s", "unexpected failure adding new key");
162 if (!(actual
= virJSONValueToString(json
, false))) {
163 VIR_TEST_VERBOSE("%s", "failed to stringize result");
167 if (virTestCompareToFile(actual
, outfile
) < 0)
175 testJSONLookup(const void *data
)
177 const struct testInfo
*info
= data
;
178 g_autoptr(virJSONValue
) json
= NULL
;
179 virJSONValue
*value
= NULL
;
180 g_autofree
char *result
= NULL
;
185 json
= virJSONValueFromString(info
->doc
);
187 VIR_TEST_VERBOSE("Fail to parse %s", info
->doc
);
191 value
= virJSONValueObjectGetObject(json
, "a");
194 VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have failed",
198 result
= virJSONValueToString(value
, false);
199 if (STRNEQ_NULLABLE(result
, "{}")) {
200 VIR_TEST_VERBOSE("lookup for 'a' in '%s' found '%s' but "
201 "should have found '{}'",
202 info
->doc
, NULLSTR(result
));
207 } else if (info
->pass
) {
208 VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have succeeded",
214 rc
= virJSONValueObjectGetNumberInt(json
, "b", &number
);
217 VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have failed",
220 } else if (number
!= 1) {
221 VIR_TEST_VERBOSE("lookup for 'b' in '%s' found %d but "
222 "should have found 1",
226 } else if (info
->pass
) {
227 VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have succeeded",
232 str
= virJSONValueObjectGetString(json
, "c");
235 VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have failed",
238 } else if (STRNEQ(str
, "str")) {
239 VIR_TEST_VERBOSE("lookup for 'c' in '%s' found '%s' but "
240 "should have found 'str'", info
->doc
, str
);
243 } else if (info
->pass
) {
244 VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have succeeded",
249 value
= virJSONValueObjectGetArray(json
, "d");
252 VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have failed",
256 result
= virJSONValueToString(value
, false);
257 if (STRNEQ_NULLABLE(result
, "[]")) {
258 VIR_TEST_VERBOSE("lookup for 'd' in '%s' found '%s' but "
259 "should have found '[]'",
260 info
->doc
, NULLSTR(result
));
265 } else if (info
->pass
) {
266 VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have succeeded",
276 testJSONCopy(const void *data
)
278 const struct testInfo
*info
= data
;
279 g_autoptr(virJSONValue
) json
= NULL
;
280 g_autoptr(virJSONValue
) jsonCopy
= NULL
;
281 g_autofree
char *result
= NULL
;
282 g_autofree
char *resultCopy
= NULL
;
284 json
= virJSONValueFromString(info
->doc
);
286 VIR_TEST_VERBOSE("Failed to parse %s", info
->doc
);
290 jsonCopy
= virJSONValueCopy(json
);
292 VIR_TEST_VERBOSE("Failed to copy JSON data");
296 result
= virJSONValueToString(json
, false);
298 VIR_TEST_VERBOSE("Failed to format original JSON data");
302 resultCopy
= virJSONValueToString(json
, false);
304 VIR_TEST_VERBOSE("Failed to format copied JSON data");
308 if (STRNEQ(result
, resultCopy
)) {
309 if (virTestGetVerbose())
310 virTestDifference(stderr
, result
, resultCopy
);
315 VIR_FREE(resultCopy
);
317 result
= virJSONValueToString(json
, true);
319 VIR_TEST_VERBOSE("Failed to format original JSON data");
323 resultCopy
= virJSONValueToString(json
, true);
325 VIR_TEST_VERBOSE("Failed to format copied JSON data");
329 if (STRNEQ(result
, resultCopy
)) {
330 if (virTestGetVerbose())
331 virTestDifference(stderr
, result
, resultCopy
);
340 testJSONDeflatten(const void *data
)
342 const struct testInfo
*info
= data
;
343 g_autoptr(virJSONValue
) injson
= NULL
;
344 g_autoptr(virJSONValue
) deflattened
= NULL
;
345 g_autofree
char *infile
= NULL
;
346 g_autofree
char *indata
= NULL
;
347 g_autofree
char *outfile
= NULL
;
348 g_autofree
char *actual
= NULL
;
350 infile
= g_strdup_printf("%s/virjsondata/deflatten-%s-in.json",
351 abs_srcdir
, info
->name
);
352 outfile
= g_strdup_printf("%s/virjsondata/deflatten-%s-out.json",
353 abs_srcdir
, info
->name
);
355 if (virTestLoadFile(infile
, &indata
) < 0)
358 if (!(injson
= virJSONValueFromString(indata
)))
361 if ((deflattened
= virJSONValueObjectDeflatten(injson
))) {
363 VIR_TEST_VERBOSE("%s: deflattening should have failed", info
->name
);
373 if (!(actual
= virJSONValueToString(deflattened
, true)))
376 if (virTestCompareToFile(actual
, outfile
) < 0)
384 testJSONEscapeObj(const void *data G_GNUC_UNUSED
)
386 g_autoptr(virJSONValue
) json
= NULL
;
387 g_autoptr(virJSONValue
) nestjson
= NULL
;
388 g_autoptr(virJSONValue
) parsejson
= NULL
;
389 g_autofree
char *neststr
= NULL
;
390 g_autofree
char *result
= NULL
;
391 const char *parsednestedstr
;
393 if (virJSONValueObjectAdd(&nestjson
,
394 "s:stringkey", "stringvalue",
396 "b:booleankey", false, NULL
) < 0) {
397 VIR_TEST_VERBOSE("failed to create nested json object");
401 if (!(neststr
= virJSONValueToString(nestjson
, false))) {
402 VIR_TEST_VERBOSE("failed to format nested json object");
406 if (virJSONValueObjectAdd(&json
, "s:test", neststr
, NULL
) < 0) {
407 VIR_TEST_VERBOSE("Failed to create json object");
411 if (!(result
= virJSONValueToString(json
, false))) {
412 VIR_TEST_VERBOSE("Failed to format json object");
416 if (!(parsejson
= virJSONValueFromString(result
))) {
417 VIR_TEST_VERBOSE("Failed to parse JSON with nested JSON in string");
421 if (!(parsednestedstr
= virJSONValueObjectGetString(parsejson
, "test"))) {
422 VIR_TEST_VERBOSE("Failed to retrieve string containing nested json");
426 if (virTestCompareToString(neststr
, parsednestedstr
) < 0) {
435 testJSONObjectFormatSteal(const void *opaque G_GNUC_UNUSED
)
437 g_autoptr(virJSONValue
) a1
= NULL
;
438 g_autoptr(virJSONValue
) a2
= NULL
;
439 g_autoptr(virJSONValue
) t1
= NULL
;
440 g_autoptr(virJSONValue
) t2
= NULL
;
442 if (!(a1
= virJSONValueNewString(g_strdup("test"))) ||
443 !(a2
= virJSONValueNewString(g_strdup("test")))) {
444 VIR_TEST_VERBOSE("Failed to create json object");
447 if (virJSONValueObjectAdd(&t1
, "a:t", &a1
, "s:f", NULL
, NULL
) != -1) {
448 VIR_TEST_VERBOSE("virJSONValueObjectAdd(t1) should have failed");
453 VIR_TEST_VERBOSE("appended object a1 was not consumed");
457 if (virJSONValueObjectAdd(&t2
, "s:f", NULL
, "a:t", &a1
, NULL
) != -1) {
458 VIR_TEST_VERBOSE("virJSONValueObjectAdd(t2) should have failed");
463 VIR_TEST_VERBOSE("appended object a2 was consumed");
476 #define DO_TEST_FULL(name, cmd, doc, expect, pass) \
478 struct testInfo info = { name, doc, expect, pass }; \
479 if (virTestRun(name, testJSON ## cmd, &info) < 0) \
486 * @doc: source JSON string
487 * @expect: expected output JSON formatted from parsed @doc
489 * Parses @doc and formats it back. If @expect is NULL the result has to be
492 #define DO_TEST_PARSE(name, doc, expect) \
493 DO_TEST_FULL(name, FromString, doc, expect, true)
495 #define DO_TEST_PARSE_FAIL(name, doc) \
496 DO_TEST_FULL(name, FromString, doc, NULL, false)
498 #define DO_TEST_PARSE_FILE(name) \
499 DO_TEST_FULL(name, FromFile, NULL, NULL, true)
502 DO_TEST_PARSE_FILE("Simple");
503 DO_TEST_PARSE_FILE("NotSoSimple");
504 DO_TEST_PARSE_FILE("Harder");
505 DO_TEST_PARSE_FILE("VeryHard");
507 DO_TEST_FULL("success", AddRemove
, NULL
, NULL
, true);
508 DO_TEST_FULL("failure", AddRemove
, NULL
, NULL
, false);
510 DO_TEST_FULL("copy and free", Copy
,
511 "{\"return\": [{\"name\": \"quit\"}, {\"name\": \"eject\"},"
512 "{\"name\": \"change\"}, {\"name\": \"screendump\"},"
513 "{\"name\": \"stop\"}, {\"name\": \"cont\"}, {\"name\": "
514 "\"system_reset\"}, {\"name\": \"system_powerdown\"}, "
515 "{\"name\": \"device_add\"}, {\"name\": \"device_del\"}, "
516 "{\"name\": \"cpu\"}, {\"name\": \"memsave\"}, {\"name\": "
517 "\"pmemsave\"}, {\"name\": \"migrate\"}, {\"name\": "
518 "\"migrate_cancel\"}, {\"name\": \"migrate_set_speed\"},"
519 "{\"name\": \"client_migrate_info\"}, {\"name\": "
520 "\"migrate_set_downtime\"}, {\"name\": \"netdev_add\"}, "
521 "{\"name\": \"netdev_del\"}, {\"name\": \"block_resize\"},"
522 "{\"name\": \"balloon\"}, {\"name\": \"set_link\"}, {\"name\":"
523 "\"getfd\"}, {\"name\": \"closefd\"}, {\"name\": \"block_passwd\"},"
524 "{\"name\": \"set_password\"}, {\"name\": \"expire_password\"},"
525 "{\"name\": \"qmp_capabilities\"}, {\"name\": "
526 "\"human-monitor-command\"}, {\"name\": \"query-version\"},"
527 "{\"name\": \"query-commands\"}, {\"name\": \"query-chardev\"},"
528 "{\"name\": \"query-block\"}, {\"name\": \"query-blockstats\"}, "
529 "{\"name\": \"query-cpus\"}, {\"name\": \"query-pci\"}, {\"name\":"
530 "\"query-kvm\"}, {\"name\": \"query-status\"}, {\"name\": "
531 "\"query-mice\"}, {\"name\": \"query-vnc\"}, {\"name\": "
532 "\"query-spice\"}, {\"name\": \"query-name\"}, {\"name\": "
533 "\"query-uuid\"}, {\"name\": \"query-migrate\"}, {\"name\": "
534 "\"query-balloon\"}], \"id\": \"libvirt-2\"}", NULL
, true);
537 DO_TEST_PARSE("almost nothing", "[]", NULL
);
538 DO_TEST_PARSE_FAIL("nothing", "");
540 DO_TEST_PARSE("number without garbage", "[ 234545 ]", "[234545]");
541 DO_TEST_PARSE_FAIL("number with garbage", "[ 2345b45 ]");
543 DO_TEST_PARSE("float without garbage", "[ 1.024e19 ]", "[1.024e19]");
544 DO_TEST_PARSE_FAIL("float with garbage", "[ 0.0314159ee+100 ]");
546 DO_TEST_PARSE("unsigned minus one", "[ 18446744073709551615 ]", "[18446744073709551615]");
547 DO_TEST_PARSE("another big number", "[ 9223372036854775808 ]", "[9223372036854775808]");
549 DO_TEST_PARSE("string", "[ \"The meaning of life\" ]",
550 "[\"The meaning of life\"]");
551 DO_TEST_PARSE_FAIL("unterminated string", "[ \"The meaning of lif ]");
553 DO_TEST_PARSE("integer", "[1]", NULL
);
554 DO_TEST_PARSE("boolean", "[true]", NULL
);
555 DO_TEST_PARSE("null", "[null]", NULL
);
556 DO_TEST_PARSE("[]", "[]", NULL
);
558 DO_TEST_PARSE("escaping symbols", "[\"\\\"\\t\\n\\\\\"]", NULL
);
559 DO_TEST_PARSE("escaped strings", "[\"{\\\"blurb\\\":\\\"test\\\"}\"]", NULL
);
561 DO_TEST_PARSE_FAIL("incomplete keyword", "tr");
562 DO_TEST_PARSE_FAIL("overdone keyword", "[ truest ]");
563 DO_TEST_PARSE_FAIL("unknown keyword", "huh");
564 DO_TEST_PARSE_FAIL("comments", "[ /* nope */\n1 // not this either\n]");
565 DO_TEST_PARSE_FAIL("trailing garbage", "[] []");
566 DO_TEST_PARSE_FAIL("list without array", "1, 1");
567 DO_TEST_PARSE_FAIL("parser abuse", "1] [2");
568 DO_TEST_PARSE_FAIL("invalid UTF-8", "\"\x80\"");
570 DO_TEST_PARSE_FAIL("object with numeric keys", "{ 1:1, 2:1, 3:2 }");
571 DO_TEST_PARSE_FAIL("unterminated object", "{ \"1\":1, \"2\":1, \"3\":2");
572 DO_TEST_PARSE_FAIL("unterminated array of objects",
573 "[ {\"name\": \"John\"}, {\"name\": \"Paul\"}, ");
574 DO_TEST_PARSE_FAIL("array of an object with an array as a key",
575 "[ {[\"key1\", \"key2\"]: \"value\"} ]");
576 DO_TEST_PARSE_FAIL("object with unterminated key", "{ \"key:7 }");
578 DO_TEST_FULL("lookup on array", Lookup
,
579 "[ 1 ]", NULL
, false);
580 DO_TEST_FULL("lookup on string", Lookup
,
581 "\"str\"", NULL
, false);
582 DO_TEST_FULL("lookup with missing key", Lookup
,
584 DO_TEST_FULL("lookup with wrong type", Lookup
,
585 "{ \"a\": 1, \"b\": \"str\", \"c\": [], \"d\": {} }",
587 DO_TEST_FULL("lookup with correct type", Lookup
,
588 "{ \"a\": {}, \"b\": 1, \"c\": \"str\", \"d\": [] }",
590 DO_TEST_FULL("create object with nested json in attribute", EscapeObj
,
592 DO_TEST_FULL("stealing of attributes while creating objects",
593 ObjectFormatSteal
, NULL
, NULL
, true);
595 #define DO_TEST_DEFLATTEN(name, pass) \
596 DO_TEST_FULL(name, Deflatten, NULL, NULL, pass)
598 DO_TEST_DEFLATTEN("unflattened", true);
599 DO_TEST_DEFLATTEN("basic-file", true);
600 DO_TEST_DEFLATTEN("basic-generic", true);
601 DO_TEST_DEFLATTEN("deep-file", true);
602 DO_TEST_DEFLATTEN("deep-generic", true);
603 DO_TEST_DEFLATTEN("nested", true);
604 DO_TEST_DEFLATTEN("double-key", false);
605 DO_TEST_DEFLATTEN("concat", true);
606 DO_TEST_DEFLATTEN("concat-double-key", false);
607 DO_TEST_DEFLATTEN("qemu-sheepdog", true);
608 DO_TEST_DEFLATTEN("dotted-array", true);
610 return (ret
== 0) ? EXIT_SUCCESS
: EXIT_FAILURE
;
613 VIR_TEST_MAIN(mymain
)