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 GCC_FMT_ATTR(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 GCC_FMT_ATTR(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 } 1216