backup: Wire up qemu full pull backup commands over QMP
[libvirt/ericb.git] / tests / virjsontest.c
blob4241acd9113de52747a59d57368afeb8abf99ed2
1 #include <config.h>
3 #include <time.h>
5 #include "internal.h"
6 #include "virjson.h"
7 #include "testutils.h"
9 #define VIR_FROM_THIS VIR_FROM_NONE
11 struct testInfo {
12 const char *name;
13 const char *doc;
14 const char *expect;
15 bool pass;
19 static int
20 testJSONFromFile(const void *data)
22 const struct testInfo *info = data;
23 VIR_AUTOPTR(virJSONValue) injson = NULL;
24 VIR_AUTOFREE(char *) infile = NULL;
25 VIR_AUTOFREE(char *) indata = NULL;
26 VIR_AUTOFREE(char *) outfile = NULL;
27 VIR_AUTOFREE(char *) actual = NULL;
29 if (virAsprintf(&infile, "%s/virjsondata/parse-%s-in.json",
30 abs_srcdir, info->name) < 0 ||
31 virAsprintf(&outfile, "%s/virjsondata/parse-%s-out.json",
32 abs_srcdir, info->name) < 0)
33 return -1;
35 if (virTestLoadFile(infile, &indata) < 0)
36 return -1;
38 injson = virJSONValueFromString(indata);
40 if (!injson) {
41 if (info->pass) {
42 VIR_TEST_VERBOSE("Failed to parse %s\n", info->doc);
43 return -1;
44 } else {
45 VIR_TEST_DEBUG("As expected, failed to parse %s\n", info->doc);
46 return 0;
48 } else {
49 if (!info->pass) {
50 VIR_TEST_VERBOSE("Unexpected success while parsing %s\n", info->doc);
51 return -1;
55 if (!(actual = virJSONValueToString(injson, false)))
56 return -1;
58 if (virTestCompareToFile(actual, outfile) < 0)
59 return -1;
61 return 0;
65 static int
66 testJSONFromString(const void *data)
68 const struct testInfo *info = data;
69 VIR_AUTOPTR(virJSONValue) json = NULL;
70 const char *expectstr = info->expect ? info->expect : info->doc;
71 VIR_AUTOFREE(char *) formatted = NULL;
73 json = virJSONValueFromString(info->doc);
75 if (!json) {
76 if (info->pass) {
77 VIR_TEST_VERBOSE("Failed to parse %s\n", info->doc);
78 return -1;
79 } else {
80 VIR_TEST_DEBUG("As expected, failed to parse %s\n", info->doc);
81 return 0;
83 } else {
84 if (!info->pass) {
85 VIR_TEST_VERBOSE("Unexpected success while parsing %s\n", info->doc);
86 return -1;
90 VIR_TEST_DEBUG("Parsed %s\n", info->doc);
92 if (!(formatted = virJSONValueToString(json, false))) {
93 VIR_TEST_VERBOSE("Failed to format json data\n");
94 return -1;
97 if (STRNEQ(expectstr, formatted)) {
98 virTestDifference(stderr, expectstr, formatted);
99 return -1;
102 return 0;
106 static int
107 testJSONAddRemove(const void *data)
109 const struct testInfo *info = data;
110 VIR_AUTOPTR(virJSONValue) json = NULL;
111 VIR_AUTOPTR(virJSONValue) name = NULL;
112 VIR_AUTOFREE(char *) infile = NULL;
113 VIR_AUTOFREE(char *) indata = NULL;
114 VIR_AUTOFREE(char *) outfile = NULL;
115 VIR_AUTOFREE(char *) actual = NULL;
117 if (virAsprintf(&infile, "%s/virjsondata/add-remove-%s-in.json",
118 abs_srcdir, info->name) < 0 ||
119 virAsprintf(&outfile, "%s/virjsondata/add-remove-%s-out.json",
120 abs_srcdir, info->name) < 0)
121 return -1;
123 if (virTestLoadFile(infile, &indata) < 0)
124 return -1;
126 json = virJSONValueFromString(indata);
127 if (!json) {
128 VIR_TEST_VERBOSE("Fail to parse %s\n", info->name);
129 return -1;
132 switch (virJSONValueObjectRemoveKey(json, "name", &name)) {
133 case 1:
134 if (!info->pass) {
135 VIR_TEST_VERBOSE("should not remove from non-object %s\n",
136 info->name);
137 return -1;
139 break;
140 case -1:
141 if (!info->pass)
142 return 0;
143 else
144 VIR_TEST_VERBOSE("Fail to recognize non-object %s\n", info->name);
145 return -1;
146 default:
147 VIR_TEST_VERBOSE("unexpected result when removing from %s\n",
148 info->name);
149 return -1;
151 if (STRNEQ_NULLABLE(virJSONValueGetString(name), "sample")) {
152 VIR_TEST_VERBOSE("unexpected value after removing name: %s\n",
153 NULLSTR(virJSONValueGetString(name)));
154 return -1;
156 if (virJSONValueObjectRemoveKey(json, "name", NULL)) {
157 VIR_TEST_VERBOSE("%s",
158 "unexpected success when removing missing key\n");
159 return -1;
161 if (virJSONValueObjectAppendString(json, "newname", "foo") < 0) {
162 VIR_TEST_VERBOSE("%s", "unexpected failure adding new key\n");
163 return -1;
165 if (!(actual = virJSONValueToString(json, false))) {
166 VIR_TEST_VERBOSE("%s", "failed to stringize result\n");
167 return -1;
170 if (virTestCompareToFile(actual, outfile) < 0)
171 return -1;
173 return 0;
177 static int
178 testJSONLookup(const void *data)
180 const struct testInfo *info = data;
181 VIR_AUTOPTR(virJSONValue) json = NULL;
182 virJSONValuePtr value = NULL;
183 VIR_AUTOFREE(char *) result = NULL;
184 int rc;
185 int number;
186 const char *str;
188 json = virJSONValueFromString(info->doc);
189 if (!json) {
190 VIR_TEST_VERBOSE("Fail to parse %s\n", info->doc);
191 return -1;
194 value = virJSONValueObjectGetObject(json, "a");
195 if (value) {
196 if (!info->pass) {
197 VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have failed\n",
198 info->doc);
199 return -1;
200 } else {
201 result = virJSONValueToString(value, false);
202 if (STRNEQ_NULLABLE(result, "{}")) {
203 VIR_TEST_VERBOSE("lookup for 'a' in '%s' found '%s' but "
204 "should have found '{}'\n",
205 info->doc, NULLSTR(result));
206 return -1;
208 VIR_FREE(result);
210 } else if (info->pass) {
211 VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have succeeded\n",
212 info->doc);
213 return -1;
216 number = 2;
217 rc = virJSONValueObjectGetNumberInt(json, "b", &number);
218 if (rc == 0) {
219 if (!info->pass) {
220 VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have failed\n",
221 info->doc);
222 return -1;
223 } else if (number != 1) {
224 VIR_TEST_VERBOSE("lookup for 'b' in '%s' found %d but "
225 "should have found 1\n",
226 info->doc, number);
227 return -1;
229 } else if (info->pass) {
230 VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have succeeded\n",
231 info->doc);
232 return -1;
235 str = virJSONValueObjectGetString(json, "c");
236 if (str) {
237 if (!info->pass) {
238 VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have failed\n",
239 info->doc);
240 return -1;
241 } else if (STRNEQ(str, "str")) {
242 VIR_TEST_VERBOSE("lookup for 'c' in '%s' found '%s' but "
243 "should have found 'str'\n", info->doc, str);
244 return -1;
246 } else if (info->pass) {
247 VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have succeeded\n",
248 info->doc);
249 return -1;
252 value = virJSONValueObjectGetArray(json, "d");
253 if (value) {
254 if (!info->pass) {
255 VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have failed\n",
256 info->doc);
257 return -1;
258 } else {
259 result = virJSONValueToString(value, false);
260 if (STRNEQ_NULLABLE(result, "[]")) {
261 VIR_TEST_VERBOSE("lookup for 'd' in '%s' found '%s' but "
262 "should have found '[]'\n",
263 info->doc, NULLSTR(result));
264 return -1;
266 VIR_FREE(result);
268 } else if (info->pass) {
269 VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have succeeded\n",
270 info->doc);
271 return -1;
274 return 0;
278 static int
279 testJSONCopy(const void *data)
281 const struct testInfo *info = data;
282 VIR_AUTOPTR(virJSONValue) json = NULL;
283 VIR_AUTOPTR(virJSONValue) jsonCopy = NULL;
284 VIR_AUTOFREE(char *) result = NULL;
285 VIR_AUTOFREE(char *) resultCopy = NULL;
287 json = virJSONValueFromString(info->doc);
288 if (!json) {
289 VIR_TEST_VERBOSE("Failed to parse %s\n", info->doc);
290 return -1;
293 jsonCopy = virJSONValueCopy(json);
294 if (!jsonCopy) {
295 VIR_TEST_VERBOSE("Failed to copy JSON data\n");
296 return -1;
299 result = virJSONValueToString(json, false);
300 if (!result) {
301 VIR_TEST_VERBOSE("Failed to format original JSON data\n");
302 return -1;
305 resultCopy = virJSONValueToString(json, false);
306 if (!resultCopy) {
307 VIR_TEST_VERBOSE("Failed to format copied JSON data\n");
308 return -1;
311 if (STRNEQ(result, resultCopy)) {
312 if (virTestGetVerbose())
313 virTestDifference(stderr, result, resultCopy);
314 return -1;
317 VIR_FREE(result);
318 VIR_FREE(resultCopy);
320 result = virJSONValueToString(json, true);
321 if (!result) {
322 VIR_TEST_VERBOSE("Failed to format original JSON data\n");
323 return -1;
326 resultCopy = virJSONValueToString(json, true);
327 if (!resultCopy) {
328 VIR_TEST_VERBOSE("Failed to format copied JSON data\n");
329 return -1;
332 if (STRNEQ(result, resultCopy)) {
333 if (virTestGetVerbose())
334 virTestDifference(stderr, result, resultCopy);
335 return -1;
338 return 0;
342 static int
343 testJSONDeflatten(const void *data)
345 const struct testInfo *info = data;
346 VIR_AUTOPTR(virJSONValue) injson = NULL;
347 VIR_AUTOPTR(virJSONValue) deflattened = NULL;
348 VIR_AUTOFREE(char *) infile = NULL;
349 VIR_AUTOFREE(char *) indata = NULL;
350 VIR_AUTOFREE(char *) outfile = NULL;
351 VIR_AUTOFREE(char *) actual = NULL;
353 if (virAsprintf(&infile, "%s/virjsondata/deflatten-%s-in.json",
354 abs_srcdir, info->name) < 0 ||
355 virAsprintf(&outfile, "%s/virjsondata/deflatten-%s-out.json",
356 abs_srcdir, info->name) < 0)
357 return -1;
359 if (virTestLoadFile(infile, &indata) < 0)
360 return -1;
362 if (!(injson = virJSONValueFromString(indata)))
363 return -1;
365 if ((deflattened = virJSONValueObjectDeflatten(injson))) {
366 if (!info->pass) {
367 VIR_TEST_VERBOSE("%s: deflattening should have failed\n", info->name);
368 return -1;
370 } else {
371 if (!info->pass)
372 return 0;
374 return -1;
377 if (!(actual = virJSONValueToString(deflattened, true)))
378 return -1;
380 if (virTestCompareToFile(actual, outfile) < 0)
381 return -1;
383 return 0;
387 static int
388 testJSONEscapeObj(const void *data ATTRIBUTE_UNUSED)
390 VIR_AUTOPTR(virJSONValue) json = NULL;
391 VIR_AUTOPTR(virJSONValue) nestjson = NULL;
392 VIR_AUTOPTR(virJSONValue) parsejson = NULL;
393 VIR_AUTOFREE(char *) neststr = NULL;
394 VIR_AUTOFREE(char *) result = NULL;
395 const char *parsednestedstr;
397 if (virJSONValueObjectCreate(&nestjson,
398 "s:stringkey", "stringvalue",
399 "i:numberkey", 1234,
400 "b:booleankey", false, NULL) < 0) {
401 VIR_TEST_VERBOSE("failed to create nested json object");
402 return -1;
405 if (!(neststr = virJSONValueToString(nestjson, false))) {
406 VIR_TEST_VERBOSE("failed to format nested json object");
407 return -1;
410 if (virJSONValueObjectCreate(&json, "s:test", neststr, NULL) < 0) {
411 VIR_TEST_VERBOSE("Failed to create json object");
412 return -1;
415 if (!(result = virJSONValueToString(json, false))) {
416 VIR_TEST_VERBOSE("Failed to format json object");
417 return -1;
420 if (!(parsejson = virJSONValueFromString(result))) {
421 VIR_TEST_VERBOSE("Failed to parse JSON with nested JSON in string");
422 return -1;
425 if (!(parsednestedstr = virJSONValueObjectGetString(parsejson, "test"))) {
426 VIR_TEST_VERBOSE("Failed to retrieve string containing nested json");
427 return -1;
430 if (STRNEQ(parsednestedstr, neststr)) {
431 virTestDifference(stderr, neststr, parsednestedstr);
432 return -1;
435 return 0;
439 static int
440 testJSONObjectFormatSteal(const void *opaque ATTRIBUTE_UNUSED)
442 VIR_AUTOPTR(virJSONValue) a1 = NULL;
443 VIR_AUTOPTR(virJSONValue) a2 = NULL;
444 VIR_AUTOPTR(virJSONValue) t1 = NULL;
445 VIR_AUTOPTR(virJSONValue) t2 = NULL;
447 if (!(a1 = virJSONValueNewString("test")) ||
448 !(a2 = virJSONValueNewString("test"))) {
449 VIR_TEST_VERBOSE("Failed to create json object");
452 if (virJSONValueObjectCreate(&t1, "a:t", &a1, "s:f", NULL, NULL) != -1) {
453 VIR_TEST_VERBOSE("virJSONValueObjectCreate(t1) should have failed\n");
454 return -1;
457 if (a1) {
458 VIR_TEST_VERBOSE("appended object a1 was not consumed\n");
459 return -1;
462 if (virJSONValueObjectCreate(&t2, "s:f", NULL, "a:t", &a1, NULL) != -1) {
463 VIR_TEST_VERBOSE("virJSONValueObjectCreate(t2) should have failed\n");
464 return -1;
467 if (!a2) {
468 VIR_TEST_VERBOSE("appended object a2 was consumed\n");
469 return -1;
472 return 0;
476 static int
477 mymain(void)
479 int ret = 0;
481 #define DO_TEST_FULL(name, cmd, doc, expect, pass) \
482 do { \
483 struct testInfo info = { name, doc, expect, pass }; \
484 if (virTestRun(name, testJSON ## cmd, &info) < 0) \
485 ret = -1; \
486 } while (0)
489 * DO_TEST_PARSE:
490 * @name: test name
491 * @doc: source JSON string
492 * @expect: expected output JSON formatted from parsed @doc
494 * Parses @doc and formats it back. If @expect is NULL the result has to be
495 * identical to @doc.
497 #define DO_TEST_PARSE(name, doc, expect) \
498 DO_TEST_FULL(name, FromString, doc, expect, true)
500 #define DO_TEST_PARSE_FAIL(name, doc) \
501 DO_TEST_FULL(name, FromString, doc, NULL, false)
503 #define DO_TEST_PARSE_FILE(name) \
504 DO_TEST_FULL(name, FromFile, NULL, NULL, true)
507 DO_TEST_PARSE_FILE("Simple");
508 DO_TEST_PARSE_FILE("NotSoSimple");
509 DO_TEST_PARSE_FILE("Harder");
510 DO_TEST_PARSE_FILE("VeryHard");
512 DO_TEST_FULL("success", AddRemove, NULL, NULL, true);
513 DO_TEST_FULL("failure", AddRemove, NULL, NULL, false);
515 DO_TEST_FULL("copy and free", Copy,
516 "{\"return\": [{\"name\": \"quit\"}, {\"name\": \"eject\"},"
517 "{\"name\": \"change\"}, {\"name\": \"screendump\"},"
518 "{\"name\": \"stop\"}, {\"name\": \"cont\"}, {\"name\": "
519 "\"system_reset\"}, {\"name\": \"system_powerdown\"}, "
520 "{\"name\": \"device_add\"}, {\"name\": \"device_del\"}, "
521 "{\"name\": \"cpu\"}, {\"name\": \"memsave\"}, {\"name\": "
522 "\"pmemsave\"}, {\"name\": \"migrate\"}, {\"name\": "
523 "\"migrate_cancel\"}, {\"name\": \"migrate_set_speed\"},"
524 "{\"name\": \"client_migrate_info\"}, {\"name\": "
525 "\"migrate_set_downtime\"}, {\"name\": \"netdev_add\"}, "
526 "{\"name\": \"netdev_del\"}, {\"name\": \"block_resize\"},"
527 "{\"name\": \"balloon\"}, {\"name\": \"set_link\"}, {\"name\":"
528 "\"getfd\"}, {\"name\": \"closefd\"}, {\"name\": \"block_passwd\"},"
529 "{\"name\": \"set_password\"}, {\"name\": \"expire_password\"},"
530 "{\"name\": \"qmp_capabilities\"}, {\"name\": "
531 "\"human-monitor-command\"}, {\"name\": \"query-version\"},"
532 "{\"name\": \"query-commands\"}, {\"name\": \"query-chardev\"},"
533 "{\"name\": \"query-block\"}, {\"name\": \"query-blockstats\"}, "
534 "{\"name\": \"query-cpus\"}, {\"name\": \"query-pci\"}, {\"name\":"
535 "\"query-kvm\"}, {\"name\": \"query-status\"}, {\"name\": "
536 "\"query-mice\"}, {\"name\": \"query-vnc\"}, {\"name\": "
537 "\"query-spice\"}, {\"name\": \"query-name\"}, {\"name\": "
538 "\"query-uuid\"}, {\"name\": \"query-migrate\"}, {\"name\": "
539 "\"query-balloon\"}], \"id\": \"libvirt-2\"}", NULL, true);
542 DO_TEST_PARSE("almost nothing", "[]", NULL);
543 DO_TEST_PARSE_FAIL("nothing", "");
545 DO_TEST_PARSE("number without garbage", "[ 234545 ]", "[234545]");
546 DO_TEST_PARSE_FAIL("number with garbage", "[ 2345b45 ]");
548 DO_TEST_PARSE("float without garbage", "[ 1.024e19 ]", "[1.024e19]");
549 DO_TEST_PARSE_FAIL("float with garbage", "[ 0.0314159ee+100 ]");
551 DO_TEST_PARSE("unsigned minus one", "[ 18446744073709551615 ]", "[18446744073709551615]");
552 DO_TEST_PARSE("another big number", "[ 9223372036854775808 ]", "[9223372036854775808]");
554 DO_TEST_PARSE("string", "[ \"The meaning of life\" ]",
555 "[\"The meaning of life\"]");
556 DO_TEST_PARSE_FAIL("unterminated string", "[ \"The meaning of lif ]");
558 DO_TEST_PARSE("integer", "1", NULL);
559 DO_TEST_PARSE("boolean", "true", NULL);
560 DO_TEST_PARSE("null", "null", NULL);
562 DO_TEST_PARSE("escaping symbols", "[\"\\\"\\t\\n\\\\\"]", NULL);
563 DO_TEST_PARSE("escaped strings", "[\"{\\\"blurb\\\":\\\"test\\\"}\"]", NULL);
565 DO_TEST_PARSE_FAIL("incomplete keyword", "tr");
566 DO_TEST_PARSE_FAIL("overdone keyword", "[ truest ]");
567 DO_TEST_PARSE_FAIL("unknown keyword", "huh");
568 DO_TEST_PARSE_FAIL("comments", "[ /* nope */\n1 // not this either\n]");
569 DO_TEST_PARSE_FAIL("trailing garbage", "[] []");
570 DO_TEST_PARSE_FAIL("list without array", "1, 1");
571 DO_TEST_PARSE_FAIL("parser abuse", "1] [2");
572 DO_TEST_PARSE_FAIL("invalid UTF-8", "\"\x80\"");
574 DO_TEST_PARSE_FAIL("object with numeric keys", "{ 1:1, 2:1, 3:2 }");
575 DO_TEST_PARSE_FAIL("unterminated object", "{ \"1\":1, \"2\":1, \"3\":2");
576 DO_TEST_PARSE_FAIL("unterminated array of objects",
577 "[ {\"name\": \"John\"}, {\"name\": \"Paul\"}, ");
578 DO_TEST_PARSE_FAIL("array of an object with an array as a key",
579 "[ {[\"key1\", \"key2\"]: \"value\"} ]");
580 DO_TEST_PARSE_FAIL("object with unterminated key", "{ \"key:7 }");
581 DO_TEST_PARSE_FAIL("duplicate key", "{ \"a\": 1, \"a\": 1 }");
583 DO_TEST_FULL("lookup on array", Lookup,
584 "[ 1 ]", NULL, false);
585 DO_TEST_FULL("lookup on string", Lookup,
586 "\"str\"", NULL, false);
587 DO_TEST_FULL("lookup on integer", Lookup,
588 "1", NULL, false);
589 DO_TEST_FULL("lookup with missing key", Lookup,
590 "{ }", NULL, false);
591 DO_TEST_FULL("lookup with wrong type", Lookup,
592 "{ \"a\": 1, \"b\": \"str\", \"c\": [], \"d\": {} }",
593 NULL, false);
594 DO_TEST_FULL("lookup with correct type", Lookup,
595 "{ \"a\": {}, \"b\": 1, \"c\": \"str\", \"d\": [] }",
596 NULL, true);
597 DO_TEST_FULL("create object with nested json in attribute", EscapeObj,
598 NULL, NULL, true);
599 DO_TEST_FULL("stealing of attributes while creating objects",
600 ObjectFormatSteal, NULL, NULL, true);
602 #define DO_TEST_DEFLATTEN(name, pass) \
603 DO_TEST_FULL(name, Deflatten, NULL, NULL, pass)
605 DO_TEST_DEFLATTEN("unflattened", true);
606 DO_TEST_DEFLATTEN("basic-file", true);
607 DO_TEST_DEFLATTEN("basic-generic", true);
608 DO_TEST_DEFLATTEN("deep-file", true);
609 DO_TEST_DEFLATTEN("deep-generic", true);
610 DO_TEST_DEFLATTEN("nested", true);
611 DO_TEST_DEFLATTEN("double-key", false);
612 DO_TEST_DEFLATTEN("concat", true);
613 DO_TEST_DEFLATTEN("concat-double-key", false);
614 DO_TEST_DEFLATTEN("qemu-sheepdog", true);
616 return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
619 VIR_TEST_MAIN(mymain)