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->dict3->userdef = g_new0(UserDefOne, 1); 186 ud2->dict1->dict3->userdef->string = g_strdup(string); 187 ud2->dict1->dict3->userdef->integer = value; 188 ud2->dict1->dict3->string = g_strdup(strings[3]); 189 190 visit_type_UserDefTwo(data->ov, "unused", &ud2, &error_abort); 191 192 qdict = qobject_to(QDict, visitor_get(data)); 193 g_assert(qdict); 194 g_assert_cmpint(qdict_size(qdict), ==, 2); 195 g_assert_cmpstr(qdict_get_str(qdict, "string0"), ==, strings[0]); 196 197 dict1 = qdict_get_qdict(qdict, "dict1"); 198 g_assert_cmpint(qdict_size(dict1), ==, 3); 199 g_assert_cmpstr(qdict_get_str(dict1, "string1"), ==, strings[1]); 200 201 dict2 = qdict_get_qdict(dict1, "dict2"); 202 g_assert_cmpint(qdict_size(dict2), ==, 2); 203 g_assert_cmpstr(qdict_get_str(dict2, "string"), ==, strings[2]); 204 userdef = qdict_get_qdict(dict2, "userdef"); 205 g_assert_cmpint(qdict_size(userdef), ==, 2); 206 g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value); 207 g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string); 208 209 dict3 = qdict_get_qdict(dict1, "dict3"); 210 g_assert_cmpint(qdict_size(dict3), ==, 2); 211 g_assert_cmpstr(qdict_get_str(dict3, "string"), ==, strings[3]); 212 userdef = qdict_get_qdict(dict3, "userdef"); 213 g_assert_cmpint(qdict_size(userdef), ==, 2); 214 g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value); 215 g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string); 216 217 qapi_free_UserDefTwo(ud2); 218 } 219 220 static void test_visitor_out_list(TestOutputVisitorData *data, 221 const void *unused) 222 { 223 const char *value_str = "list value"; 224 TestStruct *value; 225 TestStructList *head = NULL; 226 const int max_items = 10; 227 bool value_bool = true; 228 int value_int = 10; 229 QListEntry *entry; 230 QList *qlist; 231 int i; 232 233 /* Build the list in reverse order... */ 234 for (i = 0; i < max_items; i++) { 235 value = g_malloc0(sizeof(*value)); 236 value->integer = value_int + (max_items - i - 1); 237 value->boolean = value_bool; 238 value->string = g_strdup(value_str); 239 240 QAPI_LIST_PREPEND(head, value); 241 } 242 243 visit_type_TestStructList(data->ov, NULL, &head, &error_abort); 244 245 qlist = qobject_to(QList, visitor_get(data)); 246 g_assert(qlist); 247 g_assert(!qlist_empty(qlist)); 248 249 /* ...and ensure that the visitor sees it in order */ 250 i = 0; 251 QLIST_FOREACH_ENTRY(qlist, entry) { 252 QDict *qdict; 253 254 qdict = qobject_to(QDict, entry->value); 255 g_assert(qdict); 256 g_assert_cmpint(qdict_size(qdict), ==, 3); 257 g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int + i); 258 g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool); 259 g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, value_str); 260 i++; 261 } 262 g_assert_cmpint(i, ==, max_items); 263 264 qapi_free_TestStructList(head); 265 } 266 267 static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data, 268 const void *unused) 269 { 270 UserDefTwo *value; 271 UserDefTwoList *head = NULL; 272 const char string[] = "foo bar"; 273 int i, max_count = 1024; 274 275 for (i = 0; i < max_count; i++) { 276 value = g_malloc0(sizeof(*value)); 277 278 value->string0 = g_strdup(string); 279 value->dict1 = g_new0(UserDefTwoDict, 1); 280 value->dict1->string1 = g_strdup(string); 281 value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1); 282 value->dict1->dict2->userdef = g_new0(UserDefOne, 1); 283 value->dict1->dict2->userdef->string = g_strdup(string); 284 value->dict1->dict2->userdef->integer = 42; 285 value->dict1->dict2->string = g_strdup(string); 286 287 QAPI_LIST_PREPEND(head, value); 288 } 289 290 qapi_free_UserDefTwoList(head); 291 } 292 293 static void test_visitor_out_any(TestOutputVisitorData *data, 294 const void *unused) 295 { 296 QObject *qobj; 297 QNum *qnum; 298 QBool *qbool; 299 QString *qstring; 300 QDict *qdict; 301 int64_t val; 302 303 qobj = QOBJECT(qnum_from_int(-42)); 304 visit_type_any(data->ov, NULL, &qobj, &error_abort); 305 qnum = qobject_to(QNum, visitor_get(data)); 306 g_assert(qnum); 307 g_assert(qnum_get_try_int(qnum, &val)); 308 g_assert_cmpint(val, ==, -42); 309 qobject_unref(qobj); 310 311 visitor_reset(data); 312 qdict = qdict_new(); 313 qdict_put_int(qdict, "integer", -42); 314 qdict_put_bool(qdict, "boolean", true); 315 qdict_put_str(qdict, "string", "foo"); 316 qobj = QOBJECT(qdict); 317 visit_type_any(data->ov, NULL, &qobj, &error_abort); 318 qobject_unref(qobj); 319 qdict = qobject_to(QDict, visitor_get(data)); 320 g_assert(qdict); 321 qnum = qobject_to(QNum, qdict_get(qdict, "integer")); 322 g_assert(qnum); 323 g_assert(qnum_get_try_int(qnum, &val)); 324 g_assert_cmpint(val, ==, -42); 325 qbool = qobject_to(QBool, qdict_get(qdict, "boolean")); 326 g_assert(qbool); 327 g_assert(qbool_get_bool(qbool) == true); 328 qstring = qobject_to(QString, qdict_get(qdict, "string")); 329 g_assert(qstring); 330 g_assert_cmpstr(qstring_get_str(qstring), ==, "foo"); 331 } 332 333 static void test_visitor_out_union_flat(TestOutputVisitorData *data, 334 const void *unused) 335 { 336 QDict *qdict; 337 338 UserDefFlatUnion *tmp = g_new0(UserDefFlatUnion, 1); 339 tmp->enum1 = ENUM_ONE_VALUE1; 340 tmp->string = g_strdup("str"); 341 tmp->integer = 41; 342 tmp->u.value1.boolean = true; 343 344 visit_type_UserDefFlatUnion(data->ov, NULL, &tmp, &error_abort); 345 qdict = qobject_to(QDict, visitor_get(data)); 346 g_assert(qdict); 347 g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1"); 348 g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str"); 349 g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41); 350 g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true); 351 352 qapi_free_UserDefFlatUnion(tmp); 353 } 354 355 static void test_visitor_out_alternate(TestOutputVisitorData *data, 356 const void *unused) 357 { 358 UserDefAlternate *tmp; 359 QNum *qnum; 360 QString *qstr; 361 QDict *qdict; 362 int64_t val; 363 364 tmp = g_new0(UserDefAlternate, 1); 365 tmp->type = QTYPE_QNUM; 366 tmp->u.i = 42; 367 368 visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); 369 qnum = qobject_to(QNum, visitor_get(data)); 370 g_assert(qnum); 371 g_assert(qnum_get_try_int(qnum, &val)); 372 g_assert_cmpint(val, ==, 42); 373 374 qapi_free_UserDefAlternate(tmp); 375 376 visitor_reset(data); 377 tmp = g_new0(UserDefAlternate, 1); 378 tmp->type = QTYPE_QSTRING; 379 tmp->u.e = ENUM_ONE_VALUE1; 380 381 visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); 382 qstr = qobject_to(QString, visitor_get(data)); 383 g_assert(qstr); 384 g_assert_cmpstr(qstring_get_str(qstr), ==, "value1"); 385 386 qapi_free_UserDefAlternate(tmp); 387 388 visitor_reset(data); 389 tmp = g_new0(UserDefAlternate, 1); 390 tmp->type = QTYPE_QNULL; 391 tmp->u.n = qnull(); 392 393 visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); 394 g_assert_cmpint(qobject_type(visitor_get(data)), ==, QTYPE_QNULL); 395 396 qapi_free_UserDefAlternate(tmp); 397 398 visitor_reset(data); 399 tmp = g_new0(UserDefAlternate, 1); 400 tmp->type = QTYPE_QDICT; 401 tmp->u.udfu.integer = 1; 402 tmp->u.udfu.string = g_strdup("str"); 403 tmp->u.udfu.enum1 = ENUM_ONE_VALUE1; 404 tmp->u.udfu.u.value1.boolean = true; 405 406 visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); 407 qdict = qobject_to(QDict, visitor_get(data)); 408 g_assert(qdict); 409 g_assert_cmpint(qdict_size(qdict), ==, 4); 410 g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 1); 411 g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str"); 412 g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1"); 413 g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true); 414 415 qapi_free_UserDefAlternate(tmp); 416 } 417 418 static void test_visitor_out_null(TestOutputVisitorData *data, 419 const void *unused) 420 { 421 QNull *null = NULL; 422 QDict *qdict; 423 QObject *nil; 424 425 visit_start_struct(data->ov, NULL, NULL, 0, &error_abort); 426 visit_type_null(data->ov, "a", &null, &error_abort); 427 visit_check_struct(data->ov, &error_abort); 428 visit_end_struct(data->ov, NULL); 429 qdict = qobject_to(QDict, visitor_get(data)); 430 g_assert(qdict); 431 g_assert_cmpint(qdict_size(qdict), ==, 1); 432 nil = qdict_get(qdict, "a"); 433 g_assert(nil); 434 g_assert(qobject_type(nil) == QTYPE_QNULL); 435 } 436 437 static void test_visitor_out_list_struct(TestOutputVisitorData *data, 438 const void *unused) 439 { 440 const char *int_member[] = { 441 "integer", "s8", "s16", "s32", "s64", "u8", "u16", "u32", "u64" }; 442 g_autoptr(ArrayStruct) arrs = g_new0(ArrayStruct, 1); 443 int i, j; 444 QDict *qdict; 445 QList *qlist; 446 QListEntry *e; 447 448 for (i = 31; i >= 0; i--) { 449 QAPI_LIST_PREPEND(arrs->integer, i); 450 } 451 452 for (i = 31; i >= 0; i--) { 453 QAPI_LIST_PREPEND(arrs->s8, i); 454 } 455 456 for (i = 31; i >= 0; i--) { 457 QAPI_LIST_PREPEND(arrs->s16, i); 458 } 459 460 for (i = 31; i >= 0; i--) { 461 QAPI_LIST_PREPEND(arrs->s32, i); 462 } 463 464 for (i = 31; i >= 0; i--) { 465 QAPI_LIST_PREPEND(arrs->s64, i); 466 } 467 468 for (i = 31; i >= 0; i--) { 469 QAPI_LIST_PREPEND(arrs->u8, i); 470 } 471 472 for (i = 31; i >= 0; i--) { 473 QAPI_LIST_PREPEND(arrs->u16, i); 474 } 475 476 for (i = 31; i >= 0; i--) { 477 QAPI_LIST_PREPEND(arrs->u32, i); 478 } 479 480 for (i = 31; i >= 0; i--) { 481 QAPI_LIST_PREPEND(arrs->u64, i); 482 } 483 484 for (i = 31; i >= 0; i--) { 485 QAPI_LIST_PREPEND(arrs->number, (double)i / 3); 486 } 487 488 for (i = 31; i >= 0; i--) { 489 QAPI_LIST_PREPEND(arrs->boolean, QEMU_IS_ALIGNED(i, 3)); 490 } 491 492 for (i = 31; i >= 0; i--) { 493 QAPI_LIST_PREPEND(arrs->string, g_strdup_printf("%d", i)); 494 } 495 496 visit_type_ArrayStruct(data->ov, NULL, &arrs, &error_abort); 497 498 qdict = qobject_to(QDict, visitor_get(data)); 499 g_assert(qdict); 500 501 for (i = 0; i < G_N_ELEMENTS(int_member); i++) { 502 qlist = qdict_get_qlist(qdict, int_member[i]); 503 g_assert(qlist); 504 j = 0; 505 QLIST_FOREACH_ENTRY(qlist, e) { 506 QNum *qvalue = qobject_to(QNum, qlist_entry_obj(e)); 507 g_assert(qvalue); 508 g_assert_cmpint(qnum_get_int(qvalue), ==, j); 509 j++; 510 } 511 } 512 513 qlist = qdict_get_qlist(qdict, "number"); 514 g_assert(qlist); 515 i = 0; 516 QLIST_FOREACH_ENTRY(qlist, e) { 517 QNum *qvalue = qobject_to(QNum, qlist_entry_obj(e)); 518 char expected[32], actual[32]; 519 520 g_assert(qvalue); 521 sprintf(expected, "%.6f", (double)i / 3); 522 sprintf(actual, "%.6f", qnum_get_double(qvalue)); 523 g_assert_cmpstr(actual, ==, expected); 524 i++; 525 } 526 527 qlist = qdict_get_qlist(qdict, "boolean"); 528 g_assert(qlist); 529 i = 0; 530 QLIST_FOREACH_ENTRY(qlist, e) { 531 QBool *qvalue = qobject_to(QBool, qlist_entry_obj(e)); 532 g_assert(qvalue); 533 g_assert_cmpint(qbool_get_bool(qvalue), ==, i % 3 == 0); 534 i++; 535 } 536 537 qlist = qdict_get_qlist(qdict, "string"); 538 g_assert(qlist); 539 i = 0; 540 QLIST_FOREACH_ENTRY(qlist, e) { 541 QString *qvalue = qobject_to(QString, qlist_entry_obj(e)); 542 char expected[32]; 543 544 g_assert(qvalue); 545 sprintf(expected, "%d", i); 546 g_assert_cmpstr(qstring_get_str(qvalue), ==, expected); 547 i++; 548 } 549 } 550 551 static void output_visitor_test_add(const char *testpath, 552 TestOutputVisitorData *data, 553 void (*test_func)(TestOutputVisitorData *data, const void *user_data)) 554 { 555 g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup, 556 test_func, visitor_output_teardown); 557 } 558 559 int main(int argc, char **argv) 560 { 561 TestOutputVisitorData out_visitor_data; 562 563 g_test_init(&argc, &argv, NULL); 564 565 output_visitor_test_add("/visitor/output/int", 566 &out_visitor_data, test_visitor_out_int); 567 output_visitor_test_add("/visitor/output/bool", 568 &out_visitor_data, test_visitor_out_bool); 569 output_visitor_test_add("/visitor/output/number", 570 &out_visitor_data, test_visitor_out_number); 571 output_visitor_test_add("/visitor/output/string", 572 &out_visitor_data, test_visitor_out_string); 573 output_visitor_test_add("/visitor/output/no-string", 574 &out_visitor_data, test_visitor_out_no_string); 575 output_visitor_test_add("/visitor/output/enum", 576 &out_visitor_data, test_visitor_out_enum); 577 output_visitor_test_add("/visitor/output/struct", 578 &out_visitor_data, test_visitor_out_struct); 579 output_visitor_test_add("/visitor/output/struct-nested", 580 &out_visitor_data, test_visitor_out_struct_nested); 581 output_visitor_test_add("/visitor/output/list", 582 &out_visitor_data, test_visitor_out_list); 583 output_visitor_test_add("/visitor/output/any", 584 &out_visitor_data, test_visitor_out_any); 585 output_visitor_test_add("/visitor/output/list-qapi-free", 586 &out_visitor_data, test_visitor_out_list_qapi_free); 587 output_visitor_test_add("/visitor/output/union-flat", 588 &out_visitor_data, test_visitor_out_union_flat); 589 output_visitor_test_add("/visitor/output/alternate", 590 &out_visitor_data, test_visitor_out_alternate); 591 output_visitor_test_add("/visitor/output/null", 592 &out_visitor_data, test_visitor_out_null); 593 output_visitor_test_add("/visitor/output/list_struct", 594 &out_visitor_data, test_visitor_out_list_struct); 595 596 g_test_run(); 597 598 return 0; 599 } 600