1 /* 2 * QObject Output Visitor unit-tests. 3 * 4 * Copyright (C) 2011-2016 Red Hat Inc. 5 * 6 * Authors: 7 * Luiz Capitulino <lcapitulino@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 15 #include "qemu-common.h" 16 #include "qapi/error.h" 17 #include "qapi/qobject-output-visitor.h" 18 #include "test-qapi-visit.h" 19 #include "qapi/qmp/qbool.h" 20 #include "qapi/qmp/qdict.h" 21 #include "qapi/qmp/qlist.h" 22 #include "qapi/qmp/qnull.h" 23 #include "qapi/qmp/qnum.h" 24 #include "qapi/qmp/qstring.h" 25 26 typedef struct TestOutputVisitorData { 27 Visitor *ov; 28 QObject *obj; 29 } TestOutputVisitorData; 30 31 static void visitor_output_setup(TestOutputVisitorData *data, 32 const void *unused) 33 { 34 data->ov = qobject_output_visitor_new(&data->obj); 35 g_assert(data->ov); 36 } 37 38 static void visitor_output_teardown(TestOutputVisitorData *data, 39 const void *unused) 40 { 41 visit_free(data->ov); 42 data->ov = NULL; 43 qobject_unref(data->obj); 44 data->obj = NULL; 45 } 46 47 static QObject *visitor_get(TestOutputVisitorData *data) 48 { 49 visit_complete(data->ov, &data->obj); 50 g_assert(data->obj); 51 return data->obj; 52 } 53 54 static void visitor_reset(TestOutputVisitorData *data) 55 { 56 visitor_output_teardown(data, NULL); 57 visitor_output_setup(data, NULL); 58 } 59 60 static void test_visitor_out_int(TestOutputVisitorData *data, 61 const void *unused) 62 { 63 int64_t value = -42; 64 int64_t val; 65 QNum *qnum; 66 67 visit_type_int(data->ov, NULL, &value, &error_abort); 68 69 qnum = qobject_to(QNum, visitor_get(data)); 70 g_assert(qnum); 71 g_assert(qnum_get_try_int(qnum, &val)); 72 g_assert_cmpint(val, ==, value); 73 } 74 75 static void test_visitor_out_bool(TestOutputVisitorData *data, 76 const void *unused) 77 { 78 bool value = true; 79 QBool *qbool; 80 81 visit_type_bool(data->ov, NULL, &value, &error_abort); 82 83 qbool = qobject_to(QBool, visitor_get(data)); 84 g_assert(qbool); 85 g_assert(qbool_get_bool(qbool) == value); 86 } 87 88 static void test_visitor_out_number(TestOutputVisitorData *data, 89 const void *unused) 90 { 91 double value = 3.14; 92 QNum *qnum; 93 94 visit_type_number(data->ov, NULL, &value, &error_abort); 95 96 qnum = qobject_to(QNum, visitor_get(data)); 97 g_assert(qnum); 98 g_assert(qnum_get_double(qnum) == value); 99 } 100 101 static void test_visitor_out_string(TestOutputVisitorData *data, 102 const void *unused) 103 { 104 char *string = (char *) "Q E M U"; 105 QString *qstr; 106 107 visit_type_str(data->ov, NULL, &string, &error_abort); 108 109 qstr = qobject_to(QString, visitor_get(data)); 110 g_assert(qstr); 111 g_assert_cmpstr(qstring_get_str(qstr), ==, string); 112 } 113 114 static void test_visitor_out_no_string(TestOutputVisitorData *data, 115 const void *unused) 116 { 117 char *string = NULL; 118 QString *qstr; 119 120 /* A null string should return "" */ 121 visit_type_str(data->ov, NULL, &string, &error_abort); 122 123 qstr = qobject_to(QString, visitor_get(data)); 124 g_assert(qstr); 125 g_assert_cmpstr(qstring_get_str(qstr), ==, ""); 126 } 127 128 static void test_visitor_out_enum(TestOutputVisitorData *data, 129 const void *unused) 130 { 131 EnumOne i; 132 QString *qstr; 133 134 for (i = 0; i < ENUM_ONE__MAX; i++) { 135 visit_type_EnumOne(data->ov, "unused", &i, &error_abort); 136 137 qstr = qobject_to(QString, visitor_get(data)); 138 g_assert(qstr); 139 g_assert_cmpstr(qstring_get_str(qstr), ==, EnumOne_str(i)); 140 visitor_reset(data); 141 } 142 } 143 144 static void test_visitor_out_struct(TestOutputVisitorData *data, 145 const void *unused) 146 { 147 TestStruct test_struct = { .integer = 42, 148 .boolean = false, 149 .string = (char *) "foo"}; 150 TestStruct *p = &test_struct; 151 QDict *qdict; 152 153 visit_type_TestStruct(data->ov, NULL, &p, &error_abort); 154 155 qdict = qobject_to(QDict, visitor_get(data)); 156 g_assert(qdict); 157 g_assert_cmpint(qdict_size(qdict), ==, 3); 158 g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42); 159 g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, false); 160 g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "foo"); 161 } 162 163 static void test_visitor_out_struct_nested(TestOutputVisitorData *data, 164 const void *unused) 165 { 166 int64_t value = 42; 167 UserDefTwo *ud2; 168 QDict *qdict, *dict1, *dict2, *dict3, *userdef; 169 const char *string = "user def string"; 170 const char *strings[] = { "forty two", "forty three", "forty four", 171 "forty five" }; 172 173 ud2 = g_malloc0(sizeof(*ud2)); 174 ud2->string0 = g_strdup(strings[0]); 175 176 ud2->dict1 = g_malloc0(sizeof(*ud2->dict1)); 177 ud2->dict1->string1 = g_strdup(strings[1]); 178 179 ud2->dict1->dict2 = g_malloc0(sizeof(*ud2->dict1->dict2)); 180 ud2->dict1->dict2->userdef = g_new0(UserDefOne, 1); 181 ud2->dict1->dict2->userdef->string = g_strdup(string); 182 ud2->dict1->dict2->userdef->integer = value; 183 ud2->dict1->dict2->string = g_strdup(strings[2]); 184 185 ud2->dict1->dict3 = g_malloc0(sizeof(*ud2->dict1->dict3)); 186 ud2->dict1->has_dict3 = true; 187 ud2->dict1->dict3->userdef = g_new0(UserDefOne, 1); 188 ud2->dict1->dict3->userdef->string = g_strdup(string); 189 ud2->dict1->dict3->userdef->integer = value; 190 ud2->dict1->dict3->string = g_strdup(strings[3]); 191 192 visit_type_UserDefTwo(data->ov, "unused", &ud2, &error_abort); 193 194 qdict = qobject_to(QDict, visitor_get(data)); 195 g_assert(qdict); 196 g_assert_cmpint(qdict_size(qdict), ==, 2); 197 g_assert_cmpstr(qdict_get_str(qdict, "string0"), ==, strings[0]); 198 199 dict1 = qdict_get_qdict(qdict, "dict1"); 200 g_assert_cmpint(qdict_size(dict1), ==, 3); 201 g_assert_cmpstr(qdict_get_str(dict1, "string1"), ==, strings[1]); 202 203 dict2 = qdict_get_qdict(dict1, "dict2"); 204 g_assert_cmpint(qdict_size(dict2), ==, 2); 205 g_assert_cmpstr(qdict_get_str(dict2, "string"), ==, strings[2]); 206 userdef = qdict_get_qdict(dict2, "userdef"); 207 g_assert_cmpint(qdict_size(userdef), ==, 2); 208 g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value); 209 g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string); 210 211 dict3 = qdict_get_qdict(dict1, "dict3"); 212 g_assert_cmpint(qdict_size(dict3), ==, 2); 213 g_assert_cmpstr(qdict_get_str(dict3, "string"), ==, strings[3]); 214 userdef = qdict_get_qdict(dict3, "userdef"); 215 g_assert_cmpint(qdict_size(userdef), ==, 2); 216 g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value); 217 g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string); 218 219 qapi_free_UserDefTwo(ud2); 220 } 221 222 static void test_visitor_out_list(TestOutputVisitorData *data, 223 const void *unused) 224 { 225 const char *value_str = "list value"; 226 TestStruct *value; 227 TestStructList *head = NULL; 228 const int max_items = 10; 229 bool value_bool = true; 230 int value_int = 10; 231 QListEntry *entry; 232 QList *qlist; 233 int i; 234 235 /* Build the list in reverse order... */ 236 for (i = 0; i < max_items; i++) { 237 value = g_malloc0(sizeof(*value)); 238 value->integer = value_int + (max_items - i - 1); 239 value->boolean = value_bool; 240 value->string = g_strdup(value_str); 241 242 QAPI_LIST_PREPEND(head, value); 243 } 244 245 visit_type_TestStructList(data->ov, NULL, &head, &error_abort); 246 247 qlist = qobject_to(QList, visitor_get(data)); 248 g_assert(qlist); 249 g_assert(!qlist_empty(qlist)); 250 251 /* ...and ensure that the visitor sees it in order */ 252 i = 0; 253 QLIST_FOREACH_ENTRY(qlist, entry) { 254 QDict *qdict; 255 256 qdict = qobject_to(QDict, entry->value); 257 g_assert(qdict); 258 g_assert_cmpint(qdict_size(qdict), ==, 3); 259 g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int + i); 260 g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool); 261 g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, value_str); 262 i++; 263 } 264 g_assert_cmpint(i, ==, max_items); 265 266 qapi_free_TestStructList(head); 267 } 268 269 static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data, 270 const void *unused) 271 { 272 UserDefTwo *value; 273 UserDefTwoList *head = NULL; 274 const char string[] = "foo bar"; 275 int i, max_count = 1024; 276 277 for (i = 0; i < max_count; i++) { 278 value = g_malloc0(sizeof(*value)); 279 280 value->string0 = g_strdup(string); 281 value->dict1 = g_new0(UserDefTwoDict, 1); 282 value->dict1->string1 = g_strdup(string); 283 value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1); 284 value->dict1->dict2->userdef = g_new0(UserDefOne, 1); 285 value->dict1->dict2->userdef->string = g_strdup(string); 286 value->dict1->dict2->userdef->integer = 42; 287 value->dict1->dict2->string = g_strdup(string); 288 value->dict1->has_dict3 = false; 289 290 QAPI_LIST_PREPEND(head, value); 291 } 292 293 qapi_free_UserDefTwoList(head); 294 } 295 296 static void test_visitor_out_any(TestOutputVisitorData *data, 297 const void *unused) 298 { 299 QObject *qobj; 300 QNum *qnum; 301 QBool *qbool; 302 QString *qstring; 303 QDict *qdict; 304 int64_t val; 305 306 qobj = QOBJECT(qnum_from_int(-42)); 307 visit_type_any(data->ov, NULL, &qobj, &error_abort); 308 qnum = qobject_to(QNum, visitor_get(data)); 309 g_assert(qnum); 310 g_assert(qnum_get_try_int(qnum, &val)); 311 g_assert_cmpint(val, ==, -42); 312 qobject_unref(qobj); 313 314 visitor_reset(data); 315 qdict = qdict_new(); 316 qdict_put_int(qdict, "integer", -42); 317 qdict_put_bool(qdict, "boolean", true); 318 qdict_put_str(qdict, "string", "foo"); 319 qobj = QOBJECT(qdict); 320 visit_type_any(data->ov, NULL, &qobj, &error_abort); 321 qobject_unref(qobj); 322 qdict = qobject_to(QDict, visitor_get(data)); 323 g_assert(qdict); 324 qnum = qobject_to(QNum, qdict_get(qdict, "integer")); 325 g_assert(qnum); 326 g_assert(qnum_get_try_int(qnum, &val)); 327 g_assert_cmpint(val, ==, -42); 328 qbool = qobject_to(QBool, qdict_get(qdict, "boolean")); 329 g_assert(qbool); 330 g_assert(qbool_get_bool(qbool) == true); 331 qstring = qobject_to(QString, qdict_get(qdict, "string")); 332 g_assert(qstring); 333 g_assert_cmpstr(qstring_get_str(qstring), ==, "foo"); 334 } 335 336 static void test_visitor_out_union_flat(TestOutputVisitorData *data, 337 const void *unused) 338 { 339 QDict *qdict; 340 341 UserDefFlatUnion *tmp = g_new0(UserDefFlatUnion, 1); 342 tmp->enum1 = ENUM_ONE_VALUE1; 343 tmp->string = g_strdup("str"); 344 tmp->integer = 41; 345 tmp->u.value1.boolean = true; 346 347 visit_type_UserDefFlatUnion(data->ov, NULL, &tmp, &error_abort); 348 qdict = qobject_to(QDict, visitor_get(data)); 349 g_assert(qdict); 350 g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1"); 351 g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str"); 352 g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41); 353 g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true); 354 355 qapi_free_UserDefFlatUnion(tmp); 356 } 357 358 static void test_visitor_out_alternate(TestOutputVisitorData *data, 359 const void *unused) 360 { 361 UserDefAlternate *tmp; 362 QNum *qnum; 363 QString *qstr; 364 QDict *qdict; 365 int64_t val; 366 367 tmp = g_new0(UserDefAlternate, 1); 368 tmp->type = QTYPE_QNUM; 369 tmp->u.i = 42; 370 371 visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); 372 qnum = qobject_to(QNum, visitor_get(data)); 373 g_assert(qnum); 374 g_assert(qnum_get_try_int(qnum, &val)); 375 g_assert_cmpint(val, ==, 42); 376 377 qapi_free_UserDefAlternate(tmp); 378 379 visitor_reset(data); 380 tmp = g_new0(UserDefAlternate, 1); 381 tmp->type = QTYPE_QSTRING; 382 tmp->u.e = ENUM_ONE_VALUE1; 383 384 visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); 385 qstr = qobject_to(QString, visitor_get(data)); 386 g_assert(qstr); 387 g_assert_cmpstr(qstring_get_str(qstr), ==, "value1"); 388 389 qapi_free_UserDefAlternate(tmp); 390 391 visitor_reset(data); 392 tmp = g_new0(UserDefAlternate, 1); 393 tmp->type = QTYPE_QNULL; 394 tmp->u.n = qnull(); 395 396 visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); 397 g_assert_cmpint(qobject_type(visitor_get(data)), ==, QTYPE_QNULL); 398 399 qapi_free_UserDefAlternate(tmp); 400 401 visitor_reset(data); 402 tmp = g_new0(UserDefAlternate, 1); 403 tmp->type = QTYPE_QDICT; 404 tmp->u.udfu.integer = 1; 405 tmp->u.udfu.string = g_strdup("str"); 406 tmp->u.udfu.enum1 = ENUM_ONE_VALUE1; 407 tmp->u.udfu.u.value1.boolean = true; 408 409 visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); 410 qdict = qobject_to(QDict, visitor_get(data)); 411 g_assert(qdict); 412 g_assert_cmpint(qdict_size(qdict), ==, 4); 413 g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 1); 414 g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str"); 415 g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1"); 416 g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true); 417 418 qapi_free_UserDefAlternate(tmp); 419 } 420 421 static void test_visitor_out_null(TestOutputVisitorData *data, 422 const void *unused) 423 { 424 QNull *null = NULL; 425 QDict *qdict; 426 QObject *nil; 427 428 visit_start_struct(data->ov, NULL, NULL, 0, &error_abort); 429 visit_type_null(data->ov, "a", &null, &error_abort); 430 visit_check_struct(data->ov, &error_abort); 431 visit_end_struct(data->ov, NULL); 432 qdict = qobject_to(QDict, visitor_get(data)); 433 g_assert(qdict); 434 g_assert_cmpint(qdict_size(qdict), ==, 1); 435 nil = qdict_get(qdict, "a"); 436 g_assert(nil); 437 g_assert(qobject_type(nil) == QTYPE_QNULL); 438 } 439 440 static void test_visitor_out_list_struct(TestOutputVisitorData *data, 441 const void *unused) 442 { 443 const char *int_member[] = { 444 "integer", "s8", "s16", "s32", "s64", "u8", "u16", "u32", "u64" }; 445 g_autoptr(ArrayStruct) arrs = g_new0(ArrayStruct, 1); 446 int i, j; 447 QDict *qdict; 448 QList *qlist; 449 QListEntry *e; 450 451 for (i = 31; i >= 0; i--) { 452 QAPI_LIST_PREPEND(arrs->integer, i); 453 } 454 455 for (i = 31; i >= 0; i--) { 456 QAPI_LIST_PREPEND(arrs->s8, i); 457 } 458 459 for (i = 31; i >= 0; i--) { 460 QAPI_LIST_PREPEND(arrs->s16, i); 461 } 462 463 for (i = 31; i >= 0; i--) { 464 QAPI_LIST_PREPEND(arrs->s32, i); 465 } 466 467 for (i = 31; i >= 0; i--) { 468 QAPI_LIST_PREPEND(arrs->s64, i); 469 } 470 471 for (i = 31; i >= 0; i--) { 472 QAPI_LIST_PREPEND(arrs->u8, i); 473 } 474 475 for (i = 31; i >= 0; i--) { 476 QAPI_LIST_PREPEND(arrs->u16, i); 477 } 478 479 for (i = 31; i >= 0; i--) { 480 QAPI_LIST_PREPEND(arrs->u32, i); 481 } 482 483 for (i = 31; i >= 0; i--) { 484 QAPI_LIST_PREPEND(arrs->u64, i); 485 } 486 487 for (i = 31; i >= 0; i--) { 488 QAPI_LIST_PREPEND(arrs->number, (double)i / 3); 489 } 490 491 for (i = 31; i >= 0; i--) { 492 QAPI_LIST_PREPEND(arrs->boolean, QEMU_IS_ALIGNED(i, 3)); 493 } 494 495 for (i = 31; i >= 0; i--) { 496 QAPI_LIST_PREPEND(arrs->string, g_strdup_printf("%d", i)); 497 } 498 499 visit_type_ArrayStruct(data->ov, NULL, &arrs, &error_abort); 500 501 qdict = qobject_to(QDict, visitor_get(data)); 502 g_assert(qdict); 503 504 for (i = 0; i < G_N_ELEMENTS(int_member); i++) { 505 qlist = qdict_get_qlist(qdict, int_member[i]); 506 g_assert(qlist); 507 j = 0; 508 QLIST_FOREACH_ENTRY(qlist, e) { 509 QNum *qvalue = qobject_to(QNum, qlist_entry_obj(e)); 510 g_assert(qvalue); 511 g_assert_cmpint(qnum_get_int(qvalue), ==, j); 512 j++; 513 } 514 } 515 516 qlist = qdict_get_qlist(qdict, "number"); 517 g_assert(qlist); 518 i = 0; 519 QLIST_FOREACH_ENTRY(qlist, e) { 520 QNum *qvalue = qobject_to(QNum, qlist_entry_obj(e)); 521 char expected[32], actual[32]; 522 523 g_assert(qvalue); 524 sprintf(expected, "%.6f", (double)i / 3); 525 sprintf(actual, "%.6f", qnum_get_double(qvalue)); 526 g_assert_cmpstr(actual, ==, expected); 527 i++; 528 } 529 530 qlist = qdict_get_qlist(qdict, "boolean"); 531 g_assert(qlist); 532 i = 0; 533 QLIST_FOREACH_ENTRY(qlist, e) { 534 QBool *qvalue = qobject_to(QBool, qlist_entry_obj(e)); 535 g_assert(qvalue); 536 g_assert_cmpint(qbool_get_bool(qvalue), ==, i % 3 == 0); 537 i++; 538 } 539 540 qlist = qdict_get_qlist(qdict, "string"); 541 g_assert(qlist); 542 i = 0; 543 QLIST_FOREACH_ENTRY(qlist, e) { 544 QString *qvalue = qobject_to(QString, qlist_entry_obj(e)); 545 char expected[32]; 546 547 g_assert(qvalue); 548 sprintf(expected, "%d", i); 549 g_assert_cmpstr(qstring_get_str(qvalue), ==, expected); 550 i++; 551 } 552 } 553 554 static void output_visitor_test_add(const char *testpath, 555 TestOutputVisitorData *data, 556 void (*test_func)(TestOutputVisitorData *data, const void *user_data)) 557 { 558 g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup, 559 test_func, visitor_output_teardown); 560 } 561 562 int main(int argc, char **argv) 563 { 564 TestOutputVisitorData out_visitor_data; 565 566 g_test_init(&argc, &argv, NULL); 567 568 output_visitor_test_add("/visitor/output/int", 569 &out_visitor_data, test_visitor_out_int); 570 output_visitor_test_add("/visitor/output/bool", 571 &out_visitor_data, test_visitor_out_bool); 572 output_visitor_test_add("/visitor/output/number", 573 &out_visitor_data, test_visitor_out_number); 574 output_visitor_test_add("/visitor/output/string", 575 &out_visitor_data, test_visitor_out_string); 576 output_visitor_test_add("/visitor/output/no-string", 577 &out_visitor_data, test_visitor_out_no_string); 578 output_visitor_test_add("/visitor/output/enum", 579 &out_visitor_data, test_visitor_out_enum); 580 output_visitor_test_add("/visitor/output/struct", 581 &out_visitor_data, test_visitor_out_struct); 582 output_visitor_test_add("/visitor/output/struct-nested", 583 &out_visitor_data, test_visitor_out_struct_nested); 584 output_visitor_test_add("/visitor/output/list", 585 &out_visitor_data, test_visitor_out_list); 586 output_visitor_test_add("/visitor/output/any", 587 &out_visitor_data, test_visitor_out_any); 588 output_visitor_test_add("/visitor/output/list-qapi-free", 589 &out_visitor_data, test_visitor_out_list_qapi_free); 590 output_visitor_test_add("/visitor/output/union-flat", 591 &out_visitor_data, test_visitor_out_union_flat); 592 output_visitor_test_add("/visitor/output/alternate", 593 &out_visitor_data, test_visitor_out_alternate); 594 output_visitor_test_add("/visitor/output/null", 595 &out_visitor_data, test_visitor_out_null); 596 output_visitor_test_add("/visitor/output/list_struct", 597 &out_visitor_data, test_visitor_out_list_struct); 598 599 g_test_run(); 600 601 return 0; 602 } 603