docs: Reword virDomainGetEmulatorPinInfo description
[libvirt.git] / tests / virjsontest.c
blobefcbbbab9831bf6c9244c994ce43b971aab1dd16
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 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)
35 return -1;
37 injson = virJSONValueFromString(indata);
39 if (!injson) {
40 if (info->pass) {
41 VIR_TEST_VERBOSE("Failed to parse %s", info->doc);
42 return -1;
43 } else {
44 VIR_TEST_DEBUG("As expected, failed to parse %s", info->doc);
45 return 0;
47 } else {
48 if (!info->pass) {
49 VIR_TEST_VERBOSE("Unexpected success while parsing %s", info->doc);
50 return -1;
54 if (!(actual = virJSONValueToString(injson, false)))
55 return -1;
57 if (virTestCompareToFile(actual, outfile) < 0)
58 return -1;
60 return 0;
64 static int
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);
74 if (!json) {
75 if (info->pass) {
76 VIR_TEST_VERBOSE("Failed to parse %s", info->doc);
77 return -1;
78 } else {
79 VIR_TEST_DEBUG("As expected, failed to parse %s", info->doc);
80 return 0;
82 } else {
83 if (!info->pass) {
84 VIR_TEST_VERBOSE("Unexpected success while parsing %s", info->doc);
85 return -1;
89 VIR_TEST_DEBUG("Parsed %s", info->doc);
91 if (!(formatted = virJSONValueToString(json, false))) {
92 VIR_TEST_VERBOSE("Failed to format json data");
93 return -1;
96 if (virTestCompareToString(expectstr, formatted) < 0) {
97 return -1;
100 return 0;
104 static int
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)
121 return -1;
123 json = virJSONValueFromString(indata);
124 if (!json) {
125 VIR_TEST_VERBOSE("Fail to parse %s", info->name);
126 return -1;
129 switch (virJSONValueObjectRemoveKey(json, "name", &name)) {
130 case 1:
131 if (!info->pass) {
132 VIR_TEST_VERBOSE("should not remove from non-object %s",
133 info->name);
134 return -1;
136 break;
137 case -1:
138 if (!info->pass)
139 return 0;
140 else
141 VIR_TEST_VERBOSE("Fail to recognize non-object %s", info->name);
142 return -1;
143 default:
144 VIR_TEST_VERBOSE("unexpected result when removing from %s",
145 info->name);
146 return -1;
148 if (STRNEQ_NULLABLE(virJSONValueGetString(name), "sample")) {
149 VIR_TEST_VERBOSE("unexpected value after removing name: %s",
150 NULLSTR(virJSONValueGetString(name)));
151 return -1;
153 if (virJSONValueObjectRemoveKey(json, "name", NULL)) {
154 VIR_TEST_VERBOSE("%s",
155 "unexpected success when removing missing key");
156 return -1;
158 if (virJSONValueObjectAppendString(json, "newname", "foo") < 0) {
159 VIR_TEST_VERBOSE("%s", "unexpected failure adding new key");
160 return -1;
162 if (!(actual = virJSONValueToString(json, false))) {
163 VIR_TEST_VERBOSE("%s", "failed to stringize result");
164 return -1;
167 if (virTestCompareToFile(actual, outfile) < 0)
168 return -1;
170 return 0;
174 static int
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;
181 int rc;
182 int number;
183 const char *str;
185 json = virJSONValueFromString(info->doc);
186 if (!json) {
187 VIR_TEST_VERBOSE("Fail to parse %s", info->doc);
188 return -1;
191 value = virJSONValueObjectGetObject(json, "a");
192 if (value) {
193 if (!info->pass) {
194 VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have failed",
195 info->doc);
196 return -1;
197 } else {
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));
203 return -1;
205 VIR_FREE(result);
207 } else if (info->pass) {
208 VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have succeeded",
209 info->doc);
210 return -1;
213 number = 2;
214 rc = virJSONValueObjectGetNumberInt(json, "b", &number);
215 if (rc == 0) {
216 if (!info->pass) {
217 VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have failed",
218 info->doc);
219 return -1;
220 } else if (number != 1) {
221 VIR_TEST_VERBOSE("lookup for 'b' in '%s' found %d but "
222 "should have found 1",
223 info->doc, number);
224 return -1;
226 } else if (info->pass) {
227 VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have succeeded",
228 info->doc);
229 return -1;
232 str = virJSONValueObjectGetString(json, "c");
233 if (str) {
234 if (!info->pass) {
235 VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have failed",
236 info->doc);
237 return -1;
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);
241 return -1;
243 } else if (info->pass) {
244 VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have succeeded",
245 info->doc);
246 return -1;
249 value = virJSONValueObjectGetArray(json, "d");
250 if (value) {
251 if (!info->pass) {
252 VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have failed",
253 info->doc);
254 return -1;
255 } else {
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));
261 return -1;
263 VIR_FREE(result);
265 } else if (info->pass) {
266 VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have succeeded",
267 info->doc);
268 return -1;
271 return 0;
275 static int
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);
285 if (!json) {
286 VIR_TEST_VERBOSE("Failed to parse %s", info->doc);
287 return -1;
290 jsonCopy = virJSONValueCopy(json);
291 if (!jsonCopy) {
292 VIR_TEST_VERBOSE("Failed to copy JSON data");
293 return -1;
296 result = virJSONValueToString(json, false);
297 if (!result) {
298 VIR_TEST_VERBOSE("Failed to format original JSON data");
299 return -1;
302 resultCopy = virJSONValueToString(json, false);
303 if (!resultCopy) {
304 VIR_TEST_VERBOSE("Failed to format copied JSON data");
305 return -1;
308 if (STRNEQ(result, resultCopy)) {
309 if (virTestGetVerbose())
310 virTestDifference(stderr, result, resultCopy);
311 return -1;
314 VIR_FREE(result);
315 VIR_FREE(resultCopy);
317 result = virJSONValueToString(json, true);
318 if (!result) {
319 VIR_TEST_VERBOSE("Failed to format original JSON data");
320 return -1;
323 resultCopy = virJSONValueToString(json, true);
324 if (!resultCopy) {
325 VIR_TEST_VERBOSE("Failed to format copied JSON data");
326 return -1;
329 if (STRNEQ(result, resultCopy)) {
330 if (virTestGetVerbose())
331 virTestDifference(stderr, result, resultCopy);
332 return -1;
335 return 0;
339 static int
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)
356 return -1;
358 if (!(injson = virJSONValueFromString(indata)))
359 return -1;
361 if ((deflattened = virJSONValueObjectDeflatten(injson))) {
362 if (!info->pass) {
363 VIR_TEST_VERBOSE("%s: deflattening should have failed", info->name);
364 return -1;
366 } else {
367 if (!info->pass)
368 return 0;
370 return -1;
373 if (!(actual = virJSONValueToString(deflattened, true)))
374 return -1;
376 if (virTestCompareToFile(actual, outfile) < 0)
377 return -1;
379 return 0;
383 static int
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",
395 "i:numberkey", 1234,
396 "b:booleankey", false, NULL) < 0) {
397 VIR_TEST_VERBOSE("failed to create nested json object");
398 return -1;
401 if (!(neststr = virJSONValueToString(nestjson, false))) {
402 VIR_TEST_VERBOSE("failed to format nested json object");
403 return -1;
406 if (virJSONValueObjectAdd(&json, "s:test", neststr, NULL) < 0) {
407 VIR_TEST_VERBOSE("Failed to create json object");
408 return -1;
411 if (!(result = virJSONValueToString(json, false))) {
412 VIR_TEST_VERBOSE("Failed to format json object");
413 return -1;
416 if (!(parsejson = virJSONValueFromString(result))) {
417 VIR_TEST_VERBOSE("Failed to parse JSON with nested JSON in string");
418 return -1;
421 if (!(parsednestedstr = virJSONValueObjectGetString(parsejson, "test"))) {
422 VIR_TEST_VERBOSE("Failed to retrieve string containing nested json");
423 return -1;
426 if (virTestCompareToString(neststr, parsednestedstr) < 0) {
427 return -1;
430 return 0;
434 static int
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");
449 return -1;
452 if (a1) {
453 VIR_TEST_VERBOSE("appended object a1 was not consumed");
454 return -1;
457 if (virJSONValueObjectAdd(&t2, "s:f", NULL, "a:t", &a1, NULL) != -1) {
458 VIR_TEST_VERBOSE("virJSONValueObjectAdd(t2) should have failed");
459 return -1;
462 if (!a2) {
463 VIR_TEST_VERBOSE("appended object a2 was consumed");
464 return -1;
467 return 0;
471 static int
472 mymain(void)
474 int ret = 0;
476 #define DO_TEST_FULL(name, cmd, doc, expect, pass) \
477 do { \
478 struct testInfo info = { name, doc, expect, pass }; \
479 if (virTestRun(name, testJSON ## cmd, &info) < 0) \
480 ret = -1; \
481 } while (0)
484 * DO_TEST_PARSE:
485 * @name: test name
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
490 * identical to @doc.
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,
583 "{ }", NULL, false);
584 DO_TEST_FULL("lookup with wrong type", Lookup,
585 "{ \"a\": 1, \"b\": \"str\", \"c\": [], \"d\": {} }",
586 NULL, false);
587 DO_TEST_FULL("lookup with correct type", Lookup,
588 "{ \"a\": {}, \"b\": 1, \"c\": \"str\", \"d\": [] }",
589 NULL, true);
590 DO_TEST_FULL("create object with nested json in attribute", EscapeObj,
591 NULL, NULL, true);
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)