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