]> git.proxmox.com Git - mirror_qemu.git/blob - tests/unit/test-qobject-input-visitor.c
Merge tag 'linux-user-for-7.0-pull-request' of https://gitlab.com/laurent_vivier...
[mirror_qemu.git] / tests / unit / test-qobject-input-visitor.c
1 /*
2 * QObject Input Visitor unit-tests.
3 *
4 * Copyright (C) 2011-2016 Red Hat Inc.
5 *
6 * Authors:
7 * Luiz Capitulino <lcapitulino@redhat.com>
8 * Paolo Bonzini <pbonzini@redhat.com>
9 *
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
12 */
13
14 #include "qemu/osdep.h"
15
16 #include "qemu-common.h"
17 #include "qapi/error.h"
18 #include "qapi/qapi-visit-introspect.h"
19 #include "qapi/qobject-input-visitor.h"
20 #include "test-qapi-visit.h"
21 #include "qapi/qmp/qbool.h"
22 #include "qapi/qmp/qdict.h"
23 #include "qapi/qmp/qnull.h"
24 #include "qapi/qmp/qnum.h"
25 #include "qapi/qmp/qstring.h"
26 #include "qapi/qmp/qjson.h"
27 #include "test-qapi-introspect.h"
28 #include "qapi/qapi-introspect.h"
29
30 typedef struct TestInputVisitorData {
31 QObject *obj;
32 Visitor *qiv;
33 } TestInputVisitorData;
34
35 static void visitor_input_teardown(TestInputVisitorData *data,
36 const void *unused)
37 {
38 qobject_unref(data->obj);
39 data->obj = NULL;
40
41 if (data->qiv) {
42 visit_free(data->qiv);
43 data->qiv = NULL;
44 }
45 }
46
47 /* The various test_init functions are provided instead of a test setup
48 function so that the JSON string used by the tests are kept in the test
49 functions (and not in main()). */
50
51 static Visitor *test_init_internal(TestInputVisitorData *data, bool keyval,
52 QObject *obj)
53 {
54 visitor_input_teardown(data, NULL);
55
56 data->obj = obj;
57
58 if (keyval) {
59 data->qiv = qobject_input_visitor_new_keyval(data->obj);
60 } else {
61 data->qiv = qobject_input_visitor_new(data->obj);
62 }
63 g_assert(data->qiv);
64 return data->qiv;
65 }
66
67 static G_GNUC_PRINTF(3, 4)
68 Visitor *visitor_input_test_init_full(TestInputVisitorData *data,
69 bool keyval,
70 const char *json_string, ...)
71 {
72 Visitor *v;
73 va_list ap;
74
75 va_start(ap, json_string);
76 v = test_init_internal(data, keyval,
77 qobject_from_vjsonf_nofail(json_string, ap));
78 va_end(ap);
79 return v;
80 }
81
82 static G_GNUC_PRINTF(2, 3)
83 Visitor *visitor_input_test_init(TestInputVisitorData *data,
84 const char *json_string, ...)
85 {
86 Visitor *v;
87 va_list ap;
88
89 va_start(ap, json_string);
90 v = test_init_internal(data, false,
91 qobject_from_vjsonf_nofail(json_string, ap));
92 va_end(ap);
93 return v;
94 }
95
96 /* similar to visitor_input_test_init(), but does not expect a string
97 * literal/format json_string argument and so can be used for
98 * programatically generated strings (and we can't pass in programatically
99 * generated strings via %s format parameters since qobject_from_jsonv()
100 * will wrap those in double-quotes and treat the entire object as a
101 * string)
102 */
103 static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data,
104 const char *json_string)
105 {
106 return test_init_internal(data, false,
107 qobject_from_json(json_string, &error_abort));
108 }
109
110 static void test_visitor_in_int(TestInputVisitorData *data,
111 const void *unused)
112 {
113 int64_t res = 0;
114 double dbl;
115 int value = -42;
116 Visitor *v;
117
118 v = visitor_input_test_init(data, "%d", value);
119
120 visit_type_int(v, NULL, &res, &error_abort);
121 g_assert_cmpint(res, ==, value);
122
123 visit_type_number(v, NULL, &dbl, &error_abort);
124 g_assert_cmpfloat(dbl, ==, -42.0);
125 }
126
127 static void test_visitor_in_uint(TestInputVisitorData *data,
128 const void *unused)
129 {
130 uint64_t res = 0;
131 int64_t i64;
132 double dbl;
133 int value = 42;
134 Visitor *v;
135
136 v = visitor_input_test_init(data, "%d", value);
137
138 visit_type_uint64(v, NULL, &res, &error_abort);
139 g_assert_cmpuint(res, ==, (uint64_t)value);
140
141 visit_type_int(v, NULL, &i64, &error_abort);
142 g_assert_cmpint(i64, ==, value);
143
144 visit_type_number(v, NULL, &dbl, &error_abort);
145 g_assert_cmpfloat(dbl, ==, value);
146
147 /* BUG: value between INT64_MIN and -1 accepted modulo 2^64 */
148 v = visitor_input_test_init(data, "%d", -value);
149
150 visit_type_uint64(v, NULL, &res, &error_abort);
151 g_assert_cmpuint(res, ==, (uint64_t)-value);
152
153 v = visitor_input_test_init(data, "18446744073709551574");
154
155 visit_type_uint64(v, NULL, &res, &error_abort);
156 g_assert_cmpuint(res, ==, 18446744073709551574U);
157
158 visit_type_number(v, NULL, &dbl, &error_abort);
159 g_assert_cmpfloat(dbl, ==, 18446744073709552000.0);
160 }
161
162 static void test_visitor_in_int_overflow(TestInputVisitorData *data,
163 const void *unused)
164 {
165 int64_t res = 0;
166 Error *err = NULL;
167 Visitor *v;
168
169 /*
170 * This will overflow a QNUM_I64, so should be deserialized into a
171 * QNUM_DOUBLE field instead, leading to an error if we pass it to
172 * visit_type_int(). Confirm this.
173 */
174 v = visitor_input_test_init(data, "%f", DBL_MAX);
175
176 visit_type_int(v, NULL, &res, &err);
177 error_free_or_abort(&err);
178 }
179
180 static void test_visitor_in_int_keyval(TestInputVisitorData *data,
181 const void *unused)
182 {
183 int64_t res = 0, value = -42;
184 Error *err = NULL;
185 Visitor *v;
186
187 v = visitor_input_test_init_full(data, true, "%" PRId64, value);
188 visit_type_int(v, NULL, &res, &err);
189 error_free_or_abort(&err);
190 }
191
192 static void test_visitor_in_int_str_keyval(TestInputVisitorData *data,
193 const void *unused)
194 {
195 int64_t res = 0, value = -42;
196 Visitor *v;
197
198 v = visitor_input_test_init_full(data, true, "\"-42\"");
199
200 visit_type_int(v, NULL, &res, &error_abort);
201 g_assert_cmpint(res, ==, value);
202 }
203
204 static void test_visitor_in_int_str_fail(TestInputVisitorData *data,
205 const void *unused)
206 {
207 int64_t res = 0;
208 Visitor *v;
209 Error *err = NULL;
210
211 v = visitor_input_test_init(data, "\"-42\"");
212
213 visit_type_int(v, NULL, &res, &err);
214 error_free_or_abort(&err);
215 }
216
217 static void test_visitor_in_bool(TestInputVisitorData *data,
218 const void *unused)
219 {
220 bool res = false;
221 Visitor *v;
222
223 v = visitor_input_test_init(data, "true");
224
225 visit_type_bool(v, NULL, &res, &error_abort);
226 g_assert_cmpint(res, ==, true);
227 }
228
229 static void test_visitor_in_bool_keyval(TestInputVisitorData *data,
230 const void *unused)
231 {
232 bool res = false;
233 Error *err = NULL;
234 Visitor *v;
235
236 v = visitor_input_test_init_full(data, true, "true");
237
238 visit_type_bool(v, NULL, &res, &err);
239 error_free_or_abort(&err);
240 }
241
242 static void test_visitor_in_bool_str_keyval(TestInputVisitorData *data,
243 const void *unused)
244 {
245 bool res = false;
246 Visitor *v;
247
248 v = visitor_input_test_init_full(data, true, "\"on\"");
249
250 visit_type_bool(v, NULL, &res, &error_abort);
251 g_assert_cmpint(res, ==, true);
252 }
253
254 static void test_visitor_in_bool_str_fail(TestInputVisitorData *data,
255 const void *unused)
256 {
257 bool res = false;
258 Visitor *v;
259 Error *err = NULL;
260
261 v = visitor_input_test_init(data, "\"true\"");
262
263 visit_type_bool(v, NULL, &res, &err);
264 error_free_or_abort(&err);
265 }
266
267 static void test_visitor_in_number(TestInputVisitorData *data,
268 const void *unused)
269 {
270 double res = 0, value = 3.14;
271 Visitor *v;
272
273 v = visitor_input_test_init(data, "%f", value);
274
275 visit_type_number(v, NULL, &res, &error_abort);
276 g_assert_cmpfloat(res, ==, value);
277 }
278
279 static void test_visitor_in_large_number(TestInputVisitorData *data,
280 const void *unused)
281 {
282 Error *err = NULL;
283 double res = 0;
284 int64_t i64;
285 uint64_t u64;
286 Visitor *v;
287
288 v = visitor_input_test_init(data, "-18446744073709551616"); /* -2^64 */
289
290 visit_type_number(v, NULL, &res, &error_abort);
291 g_assert_cmpfloat(res, ==, -18446744073709552e3);
292
293 visit_type_int(v, NULL, &i64, &err);
294 error_free_or_abort(&err);
295
296 visit_type_uint64(v, NULL, &u64, &err);
297 error_free_or_abort(&err);
298 }
299
300 static void test_visitor_in_number_keyval(TestInputVisitorData *data,
301 const void *unused)
302 {
303 double res = 0, value = 3.14;
304 Error *err = NULL;
305 Visitor *v;
306
307 v = visitor_input_test_init_full(data, true, "%f", value);
308
309 visit_type_number(v, NULL, &res, &err);
310 error_free_or_abort(&err);
311 }
312
313 static void test_visitor_in_number_str_keyval(TestInputVisitorData *data,
314 const void *unused)
315 {
316 double res = 0, value = 3.14;
317 Visitor *v;
318 Error *err = NULL;
319
320 v = visitor_input_test_init_full(data, true, "\"3.14\"");
321
322 visit_type_number(v, NULL, &res, &error_abort);
323 g_assert_cmpfloat(res, ==, value);
324
325 v = visitor_input_test_init_full(data, true, "\"inf\"");
326
327 visit_type_number(v, NULL, &res, &err);
328 error_free_or_abort(&err);
329 }
330
331 static void test_visitor_in_number_str_fail(TestInputVisitorData *data,
332 const void *unused)
333 {
334 double res = 0;
335 Visitor *v;
336 Error *err = NULL;
337
338 v = visitor_input_test_init(data, "\"3.14\"");
339
340 visit_type_number(v, NULL, &res, &err);
341 error_free_or_abort(&err);
342 }
343
344 static void test_visitor_in_size_str_keyval(TestInputVisitorData *data,
345 const void *unused)
346 {
347 uint64_t res, value = 500 * 1024 * 1024;
348 Visitor *v;
349
350 v = visitor_input_test_init_full(data, true, "\"500M\"");
351
352 visit_type_size(v, NULL, &res, &error_abort);
353 g_assert_cmpfloat(res, ==, value);
354 }
355
356 static void test_visitor_in_size_str_fail(TestInputVisitorData *data,
357 const void *unused)
358 {
359 uint64_t res = 0;
360 Visitor *v;
361 Error *err = NULL;
362
363 v = visitor_input_test_init(data, "\"500M\"");
364
365 visit_type_size(v, NULL, &res, &err);
366 error_free_or_abort(&err);
367 }
368
369 static void test_visitor_in_string(TestInputVisitorData *data,
370 const void *unused)
371 {
372 char *res = NULL, *value = (char *) "Q E M U";
373 Visitor *v;
374
375 v = visitor_input_test_init(data, "%s", value);
376
377 visit_type_str(v, NULL, &res, &error_abort);
378 g_assert_cmpstr(res, ==, value);
379
380 g_free(res);
381 }
382
383 static void test_visitor_in_enum(TestInputVisitorData *data,
384 const void *unused)
385 {
386 Visitor *v;
387 EnumOne i;
388
389 for (i = 0; i < ENUM_ONE__MAX; i++) {
390 EnumOne res = -1;
391
392 v = visitor_input_test_init(data, "%s", EnumOne_str(i));
393
394 visit_type_EnumOne(v, NULL, &res, &error_abort);
395 g_assert_cmpint(i, ==, res);
396 }
397 }
398
399
400 static void test_visitor_in_struct(TestInputVisitorData *data,
401 const void *unused)
402 {
403 TestStruct *p = NULL;
404 Visitor *v;
405
406 v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
407
408 visit_type_TestStruct(v, NULL, &p, &error_abort);
409 g_assert_cmpint(p->integer, ==, -42);
410 g_assert(p->boolean == true);
411 g_assert_cmpstr(p->string, ==, "foo");
412
413 g_free(p->string);
414 g_free(p);
415 }
416
417 static void test_visitor_in_struct_nested(TestInputVisitorData *data,
418 const void *unused)
419 {
420 g_autoptr(UserDefTwo) udp = NULL;
421 Visitor *v;
422
423 v = visitor_input_test_init(data, "{ 'string0': 'string0', "
424 "'dict1': { 'string1': 'string1', "
425 "'dict2': { 'userdef': { 'integer': 42, "
426 "'string': 'string' }, 'string': 'string2'}}}");
427
428 visit_type_UserDefTwo(v, NULL, &udp, &error_abort);
429
430 g_assert_cmpstr(udp->string0, ==, "string0");
431 g_assert_cmpstr(udp->dict1->string1, ==, "string1");
432 g_assert_cmpint(udp->dict1->dict2->userdef->integer, ==, 42);
433 g_assert_cmpstr(udp->dict1->dict2->userdef->string, ==, "string");
434 g_assert_cmpstr(udp->dict1->dict2->string, ==, "string2");
435 g_assert(udp->dict1->has_dict3 == false);
436 }
437
438 static void test_visitor_in_list(TestInputVisitorData *data,
439 const void *unused)
440 {
441 UserDefOneList *item, *head = NULL;
442 Visitor *v;
443 int i;
444
445 v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
446
447 visit_type_UserDefOneList(v, NULL, &head, &error_abort);
448 g_assert(head != NULL);
449
450 for (i = 0, item = head; item; item = item->next, i++) {
451 char string[12];
452
453 snprintf(string, sizeof(string), "string%d", i);
454 g_assert_cmpstr(item->value->string, ==, string);
455 g_assert_cmpint(item->value->integer, ==, 42 + i);
456 }
457
458 qapi_free_UserDefOneList(head);
459 head = NULL;
460
461 /* An empty list is valid */
462 v = visitor_input_test_init(data, "[]");
463 visit_type_UserDefOneList(v, NULL, &head, &error_abort);
464 g_assert(!head);
465 }
466
467 static void test_visitor_in_list_struct(TestInputVisitorData *data,
468 const void *unused)
469 {
470 const char *int_member[] = {
471 "integer", "s8", "s16", "s32", "s64", "u8", "u16", "u32", "u64" };
472 g_autoptr(GString) json = g_string_new("");
473 int i, j;
474 const char *sep;
475 g_autoptr(ArrayStruct) arrs = NULL;
476 Visitor *v;
477 intList *int_list;
478 int8List *s8_list;
479 int16List *s16_list;
480 int32List *s32_list;
481 int64List *s64_list;
482 uint8List *u8_list;
483 uint16List *u16_list;
484 uint32List *u32_list;
485 uint64List *u64_list;
486 numberList *num_list;
487 boolList *bool_list;
488 strList *str_list;
489
490 g_string_append_printf(json, "{");
491
492 for (i = 0; i < G_N_ELEMENTS(int_member); i++) {
493 g_string_append_printf(json, "'%s': [", int_member[i]);
494 sep = "";
495 for (j = 0; j < 32; j++) {
496 g_string_append_printf(json, "%s%d", sep, j);
497 sep = ", ";
498 }
499 g_string_append_printf(json, "], ");
500 }
501
502 g_string_append_printf(json, "'number': [");
503 sep = "";
504 for (i = 0; i < 32; i++) {
505 g_string_append_printf(json, "%s%f", sep, (double)i / 3);
506 sep = ", ";
507 }
508 g_string_append_printf(json, "], ");
509
510 g_string_append_printf(json, "'boolean': [");
511 sep = "";
512 for (i = 0; i < 32; i++) {
513 g_string_append_printf(json, "%s%s",
514 sep, i % 3 == 0 ? "true" : "false");
515 sep = ", ";
516 }
517 g_string_append_printf(json, "], ");
518
519 g_string_append_printf(json, "'string': [");
520 sep = "";
521 for (i = 0; i < 32; i++) {
522 g_string_append_printf(json, "%s'%d'", sep, i);
523 sep = ", ";
524 }
525 g_string_append_printf(json, "]");
526
527 g_string_append_printf(json, "}");
528
529 v = visitor_input_test_init_raw(data, json->str);
530 visit_type_ArrayStruct(v, NULL, &arrs, &error_abort);
531
532 i = 0;
533 for (int_list = arrs->integer; int_list; int_list = int_list->next) {
534 g_assert_cmpint(int_list->value, ==, i);
535 i++;
536 }
537
538 i = 0;
539 for (s8_list = arrs->s8; s8_list; s8_list = s8_list->next) {
540 g_assert_cmpint(s8_list->value, ==, i);
541 i++;
542 }
543
544 i = 0;
545 for (s16_list = arrs->s16; s16_list; s16_list = s16_list->next) {
546 g_assert_cmpint(s16_list->value, ==, i);
547 i++;
548 }
549
550 i = 0;
551 for (s32_list = arrs->s32; s32_list; s32_list = s32_list->next) {
552 g_assert_cmpint(s32_list->value, ==, i);
553 i++;
554 }
555
556 i = 0;
557 for (s64_list = arrs->s64; s64_list; s64_list = s64_list->next) {
558 g_assert_cmpint(s64_list->value, ==, i);
559 i++;
560 }
561
562 i = 0;
563 for (u8_list = arrs->u8; u8_list; u8_list = u8_list->next) {
564 g_assert_cmpint(u8_list->value, ==, i);
565 i++;
566 }
567
568 i = 0;
569 for (u16_list = arrs->u16; u16_list; u16_list = u16_list->next) {
570 g_assert_cmpint(u16_list->value, ==, i);
571 i++;
572 }
573
574 i = 0;
575 for (u32_list = arrs->u32; u32_list; u32_list = u32_list->next) {
576 g_assert_cmpint(u32_list->value, ==, i);
577 i++;
578 }
579
580 i = 0;
581 for (u64_list = arrs->u64; u64_list; u64_list = u64_list->next) {
582 g_assert_cmpint(u64_list->value, ==, i);
583 i++;
584 }
585
586 i = 0;
587 for (num_list = arrs->number; num_list; num_list = num_list->next) {
588 char expected[32], actual[32];
589
590 sprintf(expected, "%.6f", (double)i / 3);
591 sprintf(actual, "%.6f", num_list->value);
592 g_assert_cmpstr(expected, ==, actual);
593 i++;
594 }
595
596 i = 0;
597 for (bool_list = arrs->boolean; bool_list; bool_list = bool_list->next) {
598 g_assert_cmpint(bool_list->value, ==, i % 3 == 0);
599 i++;
600 }
601
602 i = 0;
603 for (str_list = arrs->string; str_list; str_list = str_list->next) {
604 char expected[32];
605
606 sprintf(expected, "%d", i);
607 g_assert_cmpstr(str_list->value, ==, expected);
608 i++;
609 }
610 }
611
612 static void test_visitor_in_any(TestInputVisitorData *data,
613 const void *unused)
614 {
615 QObject *res = NULL;
616 Visitor *v;
617 QNum *qnum;
618 QBool *qbool;
619 QString *qstring;
620 QDict *qdict;
621 QObject *qobj;
622 int64_t val;
623
624 v = visitor_input_test_init(data, "-42");
625 visit_type_any(v, NULL, &res, &error_abort);
626 qnum = qobject_to(QNum, res);
627 g_assert(qnum);
628 g_assert(qnum_get_try_int(qnum, &val));
629 g_assert_cmpint(val, ==, -42);
630 qobject_unref(res);
631
632 v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
633 visit_type_any(v, NULL, &res, &error_abort);
634 qdict = qobject_to(QDict, res);
635 g_assert(qdict && qdict_size(qdict) == 3);
636 qobj = qdict_get(qdict, "integer");
637 g_assert(qobj);
638 qnum = qobject_to(QNum, qobj);
639 g_assert(qnum);
640 g_assert(qnum_get_try_int(qnum, &val));
641 g_assert_cmpint(val, ==, -42);
642 qobj = qdict_get(qdict, "boolean");
643 g_assert(qobj);
644 qbool = qobject_to(QBool, qobj);
645 g_assert(qbool);
646 g_assert(qbool_get_bool(qbool) == true);
647 qobj = qdict_get(qdict, "string");
648 g_assert(qobj);
649 qstring = qobject_to(QString, qobj);
650 g_assert(qstring);
651 g_assert_cmpstr(qstring_get_str(qstring), ==, "foo");
652 qobject_unref(res);
653 }
654
655 static void test_visitor_in_null(TestInputVisitorData *data,
656 const void *unused)
657 {
658 Visitor *v;
659 Error *err = NULL;
660 QNull *null;
661 char *tmp;
662
663 /*
664 * FIXME: Since QAPI doesn't know the 'null' type yet, we can't
665 * test visit_type_null() by reading into a QAPI struct then
666 * checking that it was populated correctly. The best we can do
667 * for now is ensure that we consumed null from the input, proven
668 * by the fact that we can't re-read the key; and that we detect
669 * when input is not null.
670 */
671
672 v = visitor_input_test_init_full(data, false,
673 "{ 'a': null, 'b': '' }");
674 visit_start_struct(v, NULL, NULL, 0, &error_abort);
675 visit_type_null(v, "a", &null, &error_abort);
676 g_assert(qobject_type(QOBJECT(null)) == QTYPE_QNULL);
677 qobject_unref(null);
678 visit_type_null(v, "b", &null, &err);
679 error_free_or_abort(&err);
680 g_assert(!null);
681 visit_type_str(v, "c", &tmp, &err);
682 error_free_or_abort(&err);
683 g_assert(!tmp);
684 visit_check_struct(v, &error_abort);
685 visit_end_struct(v, NULL);
686 }
687
688 static void test_visitor_in_union_flat(TestInputVisitorData *data,
689 const void *unused)
690 {
691 Visitor *v;
692 g_autoptr(UserDefFlatUnion) tmp = NULL;
693 UserDefUnionBase *base;
694
695 v = visitor_input_test_init(data,
696 "{ 'enum1': 'value1', "
697 "'integer': 41, "
698 "'string': 'str', "
699 "'boolean': true }");
700
701 visit_type_UserDefFlatUnion(v, NULL, &tmp, &error_abort);
702 g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
703 g_assert_cmpstr(tmp->string, ==, "str");
704 g_assert_cmpint(tmp->integer, ==, 41);
705 g_assert_cmpint(tmp->u.value1.boolean, ==, true);
706
707 base = qapi_UserDefFlatUnion_base(tmp);
708 g_assert(&base->enum1 == &tmp->enum1);
709 }
710
711 static void test_visitor_in_alternate(TestInputVisitorData *data,
712 const void *unused)
713 {
714 Visitor *v;
715 UserDefAlternate *tmp;
716 WrapAlternate *wrap;
717
718 v = visitor_input_test_init(data, "42");
719 visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
720 g_assert_cmpint(tmp->type, ==, QTYPE_QNUM);
721 g_assert_cmpint(tmp->u.i, ==, 42);
722 qapi_free_UserDefAlternate(tmp);
723
724 v = visitor_input_test_init(data, "'value1'");
725 visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
726 g_assert_cmpint(tmp->type, ==, QTYPE_QSTRING);
727 g_assert_cmpint(tmp->u.e, ==, ENUM_ONE_VALUE1);
728 qapi_free_UserDefAlternate(tmp);
729
730 v = visitor_input_test_init(data, "null");
731 visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
732 g_assert_cmpint(tmp->type, ==, QTYPE_QNULL);
733 qapi_free_UserDefAlternate(tmp);
734
735 v = visitor_input_test_init(data, "{'integer':1, 'string':'str', "
736 "'enum1':'value1', 'boolean':true}");
737 visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
738 g_assert_cmpint(tmp->type, ==, QTYPE_QDICT);
739 g_assert_cmpint(tmp->u.udfu.integer, ==, 1);
740 g_assert_cmpstr(tmp->u.udfu.string, ==, "str");
741 g_assert_cmpint(tmp->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
742 g_assert_cmpint(tmp->u.udfu.u.value1.boolean, ==, true);
743 g_assert_cmpint(tmp->u.udfu.u.value1.has_a_b, ==, false);
744 qapi_free_UserDefAlternate(tmp);
745
746 v = visitor_input_test_init(data, "{ 'alt': 42 }");
747 visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
748 g_assert_cmpint(wrap->alt->type, ==, QTYPE_QNUM);
749 g_assert_cmpint(wrap->alt->u.i, ==, 42);
750 qapi_free_WrapAlternate(wrap);
751
752 v = visitor_input_test_init(data, "{ 'alt': 'value1' }");
753 visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
754 g_assert_cmpint(wrap->alt->type, ==, QTYPE_QSTRING);
755 g_assert_cmpint(wrap->alt->u.e, ==, ENUM_ONE_VALUE1);
756 qapi_free_WrapAlternate(wrap);
757
758 v = visitor_input_test_init(data, "{ 'alt': {'integer':1, 'string':'str', "
759 "'enum1':'value1', 'boolean':true} }");
760 visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
761 g_assert_cmpint(wrap->alt->type, ==, QTYPE_QDICT);
762 g_assert_cmpint(wrap->alt->u.udfu.integer, ==, 1);
763 g_assert_cmpstr(wrap->alt->u.udfu.string, ==, "str");
764 g_assert_cmpint(wrap->alt->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
765 g_assert_cmpint(wrap->alt->u.udfu.u.value1.boolean, ==, true);
766 g_assert_cmpint(wrap->alt->u.udfu.u.value1.has_a_b, ==, false);
767 qapi_free_WrapAlternate(wrap);
768 }
769
770 static void test_visitor_in_alternate_number(TestInputVisitorData *data,
771 const void *unused)
772 {
773 Visitor *v;
774 Error *err = NULL;
775 AltEnumBool *aeb;
776 AltEnumNum *aen;
777 AltNumEnum *ans;
778 AltEnumInt *asi;
779
780 /* Parsing an int */
781
782 v = visitor_input_test_init(data, "42");
783 visit_type_AltEnumBool(v, NULL, &aeb, &err);
784 error_free_or_abort(&err);
785 qapi_free_AltEnumBool(aeb);
786
787 v = visitor_input_test_init(data, "42");
788 visit_type_AltEnumNum(v, NULL, &aen, &error_abort);
789 g_assert_cmpint(aen->type, ==, QTYPE_QNUM);
790 g_assert_cmpfloat(aen->u.n, ==, 42);
791 qapi_free_AltEnumNum(aen);
792
793 v = visitor_input_test_init(data, "42");
794 visit_type_AltNumEnum(v, NULL, &ans, &error_abort);
795 g_assert_cmpint(ans->type, ==, QTYPE_QNUM);
796 g_assert_cmpfloat(ans->u.n, ==, 42);
797 qapi_free_AltNumEnum(ans);
798
799 v = visitor_input_test_init(data, "42");
800 visit_type_AltEnumInt(v, NULL, &asi, &error_abort);
801 g_assert_cmpint(asi->type, ==, QTYPE_QNUM);
802 g_assert_cmpint(asi->u.i, ==, 42);
803 qapi_free_AltEnumInt(asi);
804
805 /* Parsing a double */
806
807 v = visitor_input_test_init(data, "42.5");
808 visit_type_AltEnumBool(v, NULL, &aeb, &err);
809 error_free_or_abort(&err);
810 qapi_free_AltEnumBool(aeb);
811
812 v = visitor_input_test_init(data, "42.5");
813 visit_type_AltEnumNum(v, NULL, &aen, &error_abort);
814 g_assert_cmpint(aen->type, ==, QTYPE_QNUM);
815 g_assert_cmpfloat(aen->u.n, ==, 42.5);
816 qapi_free_AltEnumNum(aen);
817
818 v = visitor_input_test_init(data, "42.5");
819 visit_type_AltNumEnum(v, NULL, &ans, &error_abort);
820 g_assert_cmpint(ans->type, ==, QTYPE_QNUM);
821 g_assert_cmpfloat(ans->u.n, ==, 42.5);
822 qapi_free_AltNumEnum(ans);
823
824 v = visitor_input_test_init(data, "42.5");
825 visit_type_AltEnumInt(v, NULL, &asi, &err);
826 error_free_or_abort(&err);
827 qapi_free_AltEnumInt(asi);
828 }
829
830 static void input_visitor_test_add(const char *testpath,
831 const void *user_data,
832 void (*test_func)(TestInputVisitorData *data,
833 const void *user_data))
834 {
835 g_test_add(testpath, TestInputVisitorData, user_data, NULL, test_func,
836 visitor_input_teardown);
837 }
838
839 static void test_visitor_in_errors(TestInputVisitorData *data,
840 const void *unused)
841 {
842 TestStruct *p = NULL;
843 Error *err = NULL;
844 Visitor *v;
845 strList *q = NULL;
846 UserDefTwo *r = NULL;
847 WrapAlternate *s = NULL;
848
849 v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', "
850 "'string': -42 }");
851
852 visit_type_TestStruct(v, NULL, &p, &err);
853 error_free_or_abort(&err);
854 g_assert(!p);
855
856 v = visitor_input_test_init(data, "[ '1', '2', false, '3' ]");
857 visit_type_strList(v, NULL, &q, &err);
858 error_free_or_abort(&err);
859 assert(!q);
860
861 v = visitor_input_test_init(data, "{ 'str':'hi' }");
862 visit_type_UserDefTwo(v, NULL, &r, &err);
863 error_free_or_abort(&err);
864 assert(!r);
865
866 v = visitor_input_test_init(data, "{ }");
867 visit_type_WrapAlternate(v, NULL, &s, &err);
868 error_free_or_abort(&err);
869 assert(!s);
870 }
871
872 static void test_visitor_in_wrong_type(TestInputVisitorData *data,
873 const void *unused)
874 {
875 TestStruct *p = NULL;
876 Visitor *v;
877 strList *q = NULL;
878 int64_t i;
879 Error *err = NULL;
880
881 /* Make sure arrays and structs cannot be confused */
882
883 v = visitor_input_test_init(data, "[]");
884 visit_type_TestStruct(v, NULL, &p, &err);
885 error_free_or_abort(&err);
886 g_assert(!p);
887
888 v = visitor_input_test_init(data, "{}");
889 visit_type_strList(v, NULL, &q, &err);
890 error_free_or_abort(&err);
891 assert(!q);
892
893 /* Make sure primitives and struct cannot be confused */
894
895 v = visitor_input_test_init(data, "1");
896 visit_type_TestStruct(v, NULL, &p, &err);
897 error_free_or_abort(&err);
898 g_assert(!p);
899
900 v = visitor_input_test_init(data, "{}");
901 visit_type_int(v, NULL, &i, &err);
902 error_free_or_abort(&err);
903
904 /* Make sure primitives and arrays cannot be confused */
905
906 v = visitor_input_test_init(data, "1");
907 visit_type_strList(v, NULL, &q, &err);
908 error_free_or_abort(&err);
909 assert(!q);
910
911 v = visitor_input_test_init(data, "[]");
912 visit_type_int(v, NULL, &i, &err);
913 error_free_or_abort(&err);
914 }
915
916 static void test_visitor_in_fail_struct(TestInputVisitorData *data,
917 const void *unused)
918 {
919 TestStruct *p = NULL;
920 Error *err = NULL;
921 Visitor *v;
922
923 v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }");
924
925 visit_type_TestStruct(v, NULL, &p, &err);
926 error_free_or_abort(&err);
927 g_assert(!p);
928 }
929
930 static void test_visitor_in_fail_struct_nested(TestInputVisitorData *data,
931 const void *unused)
932 {
933 UserDefTwo *udp = NULL;
934 Error *err = NULL;
935 Visitor *v;
936
937 v = visitor_input_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}");
938
939 visit_type_UserDefTwo(v, NULL, &udp, &err);
940 error_free_or_abort(&err);
941 g_assert(!udp);
942 }
943
944 static void test_visitor_in_fail_struct_in_list(TestInputVisitorData *data,
945 const void *unused)
946 {
947 UserDefOneList *head = NULL;
948 Error *err = NULL;
949 Visitor *v;
950
951 v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]");
952
953 visit_type_UserDefOneList(v, NULL, &head, &err);
954 error_free_or_abort(&err);
955 g_assert(!head);
956 }
957
958 static void test_visitor_in_fail_struct_missing(TestInputVisitorData *data,
959 const void *unused)
960 {
961 Error *err = NULL;
962 Visitor *v;
963 QObject *any;
964 QNull *null;
965 GenericAlternate *alt;
966 bool present;
967 int en;
968 int64_t i64;
969 uint32_t u32;
970 int8_t i8;
971 char *str;
972 double dbl;
973
974 v = visitor_input_test_init(data, "{ 'sub': [ {} ] }");
975 visit_start_struct(v, NULL, NULL, 0, &error_abort);
976 visit_start_struct(v, "struct", NULL, 0, &err);
977 error_free_or_abort(&err);
978 visit_start_list(v, "list", NULL, 0, &err);
979 error_free_or_abort(&err);
980 visit_start_alternate(v, "alternate", &alt, sizeof(*alt), &err);
981 error_free_or_abort(&err);
982 visit_optional(v, "optional", &present);
983 g_assert(!present);
984 visit_type_enum(v, "enum", &en, &EnumOne_lookup, &err);
985 error_free_or_abort(&err);
986 visit_type_int(v, "i64", &i64, &err);
987 error_free_or_abort(&err);
988 visit_type_uint32(v, "u32", &u32, &err);
989 error_free_or_abort(&err);
990 visit_type_int8(v, "i8", &i8, &err);
991 error_free_or_abort(&err);
992 visit_type_str(v, "i8", &str, &err);
993 error_free_or_abort(&err);
994 visit_type_number(v, "dbl", &dbl, &err);
995 error_free_or_abort(&err);
996 visit_type_any(v, "any", &any, &err);
997 error_free_or_abort(&err);
998 visit_type_null(v, "null", &null, &err);
999 error_free_or_abort(&err);
1000 visit_start_list(v, "sub", NULL, 0, &error_abort);
1001 visit_start_struct(v, NULL, NULL, 0, &error_abort);
1002 visit_type_int(v, "i64", &i64, &err);
1003 error_free_or_abort(&err);
1004 visit_end_struct(v, NULL);
1005 visit_end_list(v, NULL);
1006 visit_end_struct(v, NULL);
1007 }
1008
1009 static void test_visitor_in_fail_list(TestInputVisitorData *data,
1010 const void *unused)
1011 {
1012 int64_t i64 = -1;
1013 Error *err = NULL;
1014 Visitor *v;
1015
1016 /* Unvisited list tail */
1017
1018 v = visitor_input_test_init(data, "[ 1, 2, 3 ]");
1019
1020 visit_start_list(v, NULL, NULL, 0, &error_abort);
1021 visit_type_int(v, NULL, &i64, &error_abort);
1022 g_assert_cmpint(i64, ==, 1);
1023 visit_type_int(v, NULL, &i64, &error_abort);
1024 g_assert_cmpint(i64, ==, 2);
1025 visit_check_list(v, &err);
1026 error_free_or_abort(&err);
1027 visit_end_list(v, NULL);
1028
1029 /* Visit beyond end of list */
1030 v = visitor_input_test_init(data, "[]");
1031
1032 visit_start_list(v, NULL, NULL, 0, &error_abort);
1033 visit_type_int(v, NULL, &i64, &err);
1034 error_free_or_abort(&err);
1035 visit_end_list(v, NULL);
1036 }
1037
1038 static void test_visitor_in_fail_list_nested(TestInputVisitorData *data,
1039 const void *unused)
1040 {
1041 int64_t i64 = -1;
1042 Error *err = NULL;
1043 Visitor *v;
1044
1045 /* Unvisited nested list tail */
1046
1047 v = visitor_input_test_init(data, "[ 0, [ 1, 2, 3 ] ]");
1048
1049 visit_start_list(v, NULL, NULL, 0, &error_abort);
1050 visit_type_int(v, NULL, &i64, &error_abort);
1051 g_assert_cmpint(i64, ==, 0);
1052 visit_start_list(v, NULL, NULL, 0, &error_abort);
1053 visit_type_int(v, NULL, &i64, &error_abort);
1054 g_assert_cmpint(i64, ==, 1);
1055 visit_check_list(v, &err);
1056 error_free_or_abort(&err);
1057 visit_end_list(v, NULL);
1058 visit_check_list(v, &error_abort);
1059 visit_end_list(v, NULL);
1060 }
1061
1062 static void test_visitor_in_fail_union_flat(TestInputVisitorData *data,
1063 const void *unused)
1064 {
1065 UserDefFlatUnion *tmp = NULL;
1066 Error *err = NULL;
1067 Visitor *v;
1068
1069 v = visitor_input_test_init(data, "{ 'enum1': 'value2', 'string': 'c', 'integer': 41, 'boolean': true }");
1070
1071 visit_type_UserDefFlatUnion(v, NULL, &tmp, &err);
1072 error_free_or_abort(&err);
1073 g_assert(!tmp);
1074 }
1075
1076 static void test_visitor_in_fail_union_flat_no_discrim(TestInputVisitorData *data,
1077 const void *unused)
1078 {
1079 UserDefFlatUnion2 *tmp = NULL;
1080 Error *err = NULL;
1081 Visitor *v;
1082
1083 /* test situation where discriminator field ('enum1' here) is missing */
1084 v = visitor_input_test_init(data, "{ 'integer': 42, 'string': 'c', 'string1': 'd', 'string2': 'e' }");
1085
1086 visit_type_UserDefFlatUnion2(v, NULL, &tmp, &err);
1087 error_free_or_abort(&err);
1088 g_assert(!tmp);
1089 }
1090
1091 static void test_visitor_in_fail_alternate(TestInputVisitorData *data,
1092 const void *unused)
1093 {
1094 UserDefAlternate *tmp;
1095 Visitor *v;
1096 Error *err = NULL;
1097
1098 v = visitor_input_test_init(data, "3.14");
1099
1100 visit_type_UserDefAlternate(v, NULL, &tmp, &err);
1101 error_free_or_abort(&err);
1102 g_assert(!tmp);
1103 }
1104
1105 static void do_test_visitor_in_qmp_introspect(TestInputVisitorData *data,
1106 const QLitObject *qlit)
1107 {
1108 g_autoptr(SchemaInfoList) schema = NULL;
1109 QObject *obj = qobject_from_qlit(qlit);
1110 Visitor *v;
1111
1112 v = qobject_input_visitor_new(obj);
1113
1114 visit_type_SchemaInfoList(v, NULL, &schema, &error_abort);
1115 g_assert(schema);
1116
1117 qobject_unref(obj);
1118 visit_free(v);
1119 }
1120
1121 static void test_visitor_in_qmp_introspect(TestInputVisitorData *data,
1122 const void *unused)
1123 {
1124 do_test_visitor_in_qmp_introspect(data, &test_qmp_schema_qlit);
1125 }
1126
1127 int main(int argc, char **argv)
1128 {
1129 g_test_init(&argc, &argv, NULL);
1130
1131 input_visitor_test_add("/visitor/input/int",
1132 NULL, test_visitor_in_int);
1133 input_visitor_test_add("/visitor/input/uint",
1134 NULL, test_visitor_in_uint);
1135 input_visitor_test_add("/visitor/input/int_overflow",
1136 NULL, test_visitor_in_int_overflow);
1137 input_visitor_test_add("/visitor/input/int_keyval",
1138 NULL, test_visitor_in_int_keyval);
1139 input_visitor_test_add("/visitor/input/int_str_keyval",
1140 NULL, test_visitor_in_int_str_keyval);
1141 input_visitor_test_add("/visitor/input/int_str_fail",
1142 NULL, test_visitor_in_int_str_fail);
1143 input_visitor_test_add("/visitor/input/bool",
1144 NULL, test_visitor_in_bool);
1145 input_visitor_test_add("/visitor/input/bool_keyval",
1146 NULL, test_visitor_in_bool_keyval);
1147 input_visitor_test_add("/visitor/input/bool_str_keyval",
1148 NULL, test_visitor_in_bool_str_keyval);
1149 input_visitor_test_add("/visitor/input/bool_str_fail",
1150 NULL, test_visitor_in_bool_str_fail);
1151 input_visitor_test_add("/visitor/input/number",
1152 NULL, test_visitor_in_number);
1153 input_visitor_test_add("/visitor/input/large_number",
1154 NULL, test_visitor_in_large_number);
1155 input_visitor_test_add("/visitor/input/number_keyval",
1156 NULL, test_visitor_in_number_keyval);
1157 input_visitor_test_add("/visitor/input/number_str_keyval",
1158 NULL, test_visitor_in_number_str_keyval);
1159 input_visitor_test_add("/visitor/input/number_str_fail",
1160 NULL, test_visitor_in_number_str_fail);
1161 input_visitor_test_add("/visitor/input/size_str_keyval",
1162 NULL, test_visitor_in_size_str_keyval);
1163 input_visitor_test_add("/visitor/input/size_str_fail",
1164 NULL, test_visitor_in_size_str_fail);
1165 input_visitor_test_add("/visitor/input/string",
1166 NULL, test_visitor_in_string);
1167 input_visitor_test_add("/visitor/input/enum",
1168 NULL, test_visitor_in_enum);
1169 input_visitor_test_add("/visitor/input/struct",
1170 NULL, test_visitor_in_struct);
1171 input_visitor_test_add("/visitor/input/struct-nested",
1172 NULL, test_visitor_in_struct_nested);
1173 input_visitor_test_add("/visitor/input/list2",
1174 NULL, test_visitor_in_list_struct);
1175 input_visitor_test_add("/visitor/input/list",
1176 NULL, test_visitor_in_list);
1177 input_visitor_test_add("/visitor/input/any",
1178 NULL, test_visitor_in_any);
1179 input_visitor_test_add("/visitor/input/null",
1180 NULL, test_visitor_in_null);
1181 input_visitor_test_add("/visitor/input/union-flat",
1182 NULL, test_visitor_in_union_flat);
1183 input_visitor_test_add("/visitor/input/alternate",
1184 NULL, test_visitor_in_alternate);
1185 input_visitor_test_add("/visitor/input/errors",
1186 NULL, test_visitor_in_errors);
1187 input_visitor_test_add("/visitor/input/wrong-type",
1188 NULL, test_visitor_in_wrong_type);
1189 input_visitor_test_add("/visitor/input/alternate-number",
1190 NULL, test_visitor_in_alternate_number);
1191 input_visitor_test_add("/visitor/input/fail/struct",
1192 NULL, test_visitor_in_fail_struct);
1193 input_visitor_test_add("/visitor/input/fail/struct-nested",
1194 NULL, test_visitor_in_fail_struct_nested);
1195 input_visitor_test_add("/visitor/input/fail/struct-in-list",
1196 NULL, test_visitor_in_fail_struct_in_list);
1197 input_visitor_test_add("/visitor/input/fail/struct-missing",
1198 NULL, test_visitor_in_fail_struct_missing);
1199 input_visitor_test_add("/visitor/input/fail/list",
1200 NULL, test_visitor_in_fail_list);
1201 input_visitor_test_add("/visitor/input/fail/list-nested",
1202 NULL, test_visitor_in_fail_list_nested);
1203 input_visitor_test_add("/visitor/input/fail/union-flat",
1204 NULL, test_visitor_in_fail_union_flat);
1205 input_visitor_test_add("/visitor/input/fail/union-flat-no-discriminator",
1206 NULL, test_visitor_in_fail_union_flat_no_discrim);
1207 input_visitor_test_add("/visitor/input/fail/alternate",
1208 NULL, test_visitor_in_fail_alternate);
1209 input_visitor_test_add("/visitor/input/qapi-introspect",
1210 NULL, test_visitor_in_qmp_introspect);
1211
1212 g_test_run();
1213
1214 return 0;
1215 }