1 /* 2 * Unit-tests for visitor-based serialization 3 * 4 * Copyright (C) 2014-2015 Red Hat, Inc. 5 * Copyright IBM, Corp. 2012 6 * 7 * Authors: 8 * Michael Roth <mdroth@linux.vnet.ibm.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 #include <float.h> 16 17 #include "qemu-common.h" 18 #include "test-qapi-visit.h" 19 #include "qapi/error.h" 20 #include "qapi/qmp/qjson.h" 21 #include "qapi/qmp/qstring.h" 22 #include "qapi/qobject-input-visitor.h" 23 #include "qapi/qobject-output-visitor.h" 24 #include "qapi/string-input-visitor.h" 25 #include "qapi/string-output-visitor.h" 26 #include "qapi/dealloc-visitor.h" 27 28 enum PrimitiveTypeKind { 29 PTYPE_STRING = 0, 30 PTYPE_BOOLEAN, 31 PTYPE_NUMBER, 32 PTYPE_INTEGER, 33 PTYPE_U8, 34 PTYPE_U16, 35 PTYPE_U32, 36 PTYPE_U64, 37 PTYPE_S8, 38 PTYPE_S16, 39 PTYPE_S32, 40 PTYPE_S64, 41 PTYPE_EOL, 42 }; 43 44 typedef struct PrimitiveType { 45 union { 46 const char *string; 47 bool boolean; 48 double number; 49 int64_t integer; 50 uint8_t u8; 51 uint16_t u16; 52 uint32_t u32; 53 uint64_t u64; 54 int8_t s8; 55 int16_t s16; 56 int32_t s32; 57 int64_t s64; 58 } value; 59 enum PrimitiveTypeKind type; 60 const char *description; 61 } PrimitiveType; 62 63 typedef struct PrimitiveList { 64 union { 65 strList *strings; 66 boolList *booleans; 67 numberList *numbers; 68 intList *integers; 69 int8List *s8_integers; 70 int16List *s16_integers; 71 int32List *s32_integers; 72 int64List *s64_integers; 73 uint8List *u8_integers; 74 uint16List *u16_integers; 75 uint32List *u32_integers; 76 uint64List *u64_integers; 77 } value; 78 enum PrimitiveTypeKind type; 79 const char *description; 80 } PrimitiveList; 81 82 /* test helpers */ 83 84 typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp); 85 86 static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp) 87 { 88 Visitor *v = qapi_dealloc_visitor_new(); 89 90 visit(v, &native_in, errp); 91 92 visit_free(v); 93 } 94 95 static void visit_primitive_type(Visitor *v, void **native, Error **errp) 96 { 97 PrimitiveType *pt = *native; 98 switch(pt->type) { 99 case PTYPE_STRING: 100 visit_type_str(v, NULL, (char **)&pt->value.string, errp); 101 break; 102 case PTYPE_BOOLEAN: 103 visit_type_bool(v, NULL, &pt->value.boolean, errp); 104 break; 105 case PTYPE_NUMBER: 106 visit_type_number(v, NULL, &pt->value.number, errp); 107 break; 108 case PTYPE_INTEGER: 109 visit_type_int(v, NULL, &pt->value.integer, errp); 110 break; 111 case PTYPE_U8: 112 visit_type_uint8(v, NULL, &pt->value.u8, errp); 113 break; 114 case PTYPE_U16: 115 visit_type_uint16(v, NULL, &pt->value.u16, errp); 116 break; 117 case PTYPE_U32: 118 visit_type_uint32(v, NULL, &pt->value.u32, errp); 119 break; 120 case PTYPE_U64: 121 visit_type_uint64(v, NULL, &pt->value.u64, errp); 122 break; 123 case PTYPE_S8: 124 visit_type_int8(v, NULL, &pt->value.s8, errp); 125 break; 126 case PTYPE_S16: 127 visit_type_int16(v, NULL, &pt->value.s16, errp); 128 break; 129 case PTYPE_S32: 130 visit_type_int32(v, NULL, &pt->value.s32, errp); 131 break; 132 case PTYPE_S64: 133 visit_type_int64(v, NULL, &pt->value.s64, errp); 134 break; 135 case PTYPE_EOL: 136 g_assert_not_reached(); 137 } 138 } 139 140 static void visit_primitive_list(Visitor *v, void **native, Error **errp) 141 { 142 PrimitiveList *pl = *native; 143 switch (pl->type) { 144 case PTYPE_STRING: 145 visit_type_strList(v, NULL, &pl->value.strings, errp); 146 break; 147 case PTYPE_BOOLEAN: 148 visit_type_boolList(v, NULL, &pl->value.booleans, errp); 149 break; 150 case PTYPE_NUMBER: 151 visit_type_numberList(v, NULL, &pl->value.numbers, errp); 152 break; 153 case PTYPE_INTEGER: 154 visit_type_intList(v, NULL, &pl->value.integers, errp); 155 break; 156 case PTYPE_S8: 157 visit_type_int8List(v, NULL, &pl->value.s8_integers, errp); 158 break; 159 case PTYPE_S16: 160 visit_type_int16List(v, NULL, &pl->value.s16_integers, errp); 161 break; 162 case PTYPE_S32: 163 visit_type_int32List(v, NULL, &pl->value.s32_integers, errp); 164 break; 165 case PTYPE_S64: 166 visit_type_int64List(v, NULL, &pl->value.s64_integers, errp); 167 break; 168 case PTYPE_U8: 169 visit_type_uint8List(v, NULL, &pl->value.u8_integers, errp); 170 break; 171 case PTYPE_U16: 172 visit_type_uint16List(v, NULL, &pl->value.u16_integers, errp); 173 break; 174 case PTYPE_U32: 175 visit_type_uint32List(v, NULL, &pl->value.u32_integers, errp); 176 break; 177 case PTYPE_U64: 178 visit_type_uint64List(v, NULL, &pl->value.u64_integers, errp); 179 break; 180 default: 181 g_assert_not_reached(); 182 } 183 } 184 185 186 static TestStruct *struct_create(void) 187 { 188 TestStruct *ts = g_malloc0(sizeof(*ts)); 189 ts->integer = -42; 190 ts->boolean = true; 191 ts->string = strdup("test string"); 192 return ts; 193 } 194 195 static void struct_compare(TestStruct *ts1, TestStruct *ts2) 196 { 197 g_assert(ts1); 198 g_assert(ts2); 199 g_assert_cmpint(ts1->integer, ==, ts2->integer); 200 g_assert(ts1->boolean == ts2->boolean); 201 g_assert_cmpstr(ts1->string, ==, ts2->string); 202 } 203 204 static void struct_cleanup(TestStruct *ts) 205 { 206 g_free(ts->string); 207 g_free(ts); 208 } 209 210 static void visit_struct(Visitor *v, void **native, Error **errp) 211 { 212 visit_type_TestStruct(v, NULL, (TestStruct **)native, errp); 213 } 214 215 static UserDefTwo *nested_struct_create(void) 216 { 217 UserDefTwo *udnp = g_malloc0(sizeof(*udnp)); 218 udnp->string0 = strdup("test_string0"); 219 udnp->dict1 = g_malloc0(sizeof(*udnp->dict1)); 220 udnp->dict1->string1 = strdup("test_string1"); 221 udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2)); 222 udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1); 223 udnp->dict1->dict2->userdef->integer = 42; 224 udnp->dict1->dict2->userdef->string = strdup("test_string"); 225 udnp->dict1->dict2->string = strdup("test_string2"); 226 udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3)); 227 udnp->dict1->has_dict3 = true; 228 udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1); 229 udnp->dict1->dict3->userdef->integer = 43; 230 udnp->dict1->dict3->userdef->string = strdup("test_string"); 231 udnp->dict1->dict3->string = strdup("test_string3"); 232 return udnp; 233 } 234 235 static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2) 236 { 237 g_assert(udnp1); 238 g_assert(udnp2); 239 g_assert_cmpstr(udnp1->string0, ==, udnp2->string0); 240 g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1); 241 g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==, 242 udnp2->dict1->dict2->userdef->integer); 243 g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==, 244 udnp2->dict1->dict2->userdef->string); 245 g_assert_cmpstr(udnp1->dict1->dict2->string, ==, 246 udnp2->dict1->dict2->string); 247 g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3); 248 g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==, 249 udnp2->dict1->dict3->userdef->integer); 250 g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==, 251 udnp2->dict1->dict3->userdef->string); 252 g_assert_cmpstr(udnp1->dict1->dict3->string, ==, 253 udnp2->dict1->dict3->string); 254 } 255 256 static void nested_struct_cleanup(UserDefTwo *udnp) 257 { 258 qapi_free_UserDefTwo(udnp); 259 } 260 261 static void visit_nested_struct(Visitor *v, void **native, Error **errp) 262 { 263 visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp); 264 } 265 266 static void visit_nested_struct_list(Visitor *v, void **native, Error **errp) 267 { 268 visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp); 269 } 270 271 /* test cases */ 272 273 typedef enum VisitorCapabilities { 274 VCAP_PRIMITIVES = 1, 275 VCAP_STRUCTURES = 2, 276 VCAP_LISTS = 4, 277 VCAP_PRIMITIVE_LISTS = 8, 278 } VisitorCapabilities; 279 280 typedef struct SerializeOps { 281 void (*serialize)(void *native_in, void **datap, 282 VisitorFunc visit, Error **errp); 283 void (*deserialize)(void **native_out, void *datap, 284 VisitorFunc visit, Error **errp); 285 void (*cleanup)(void *datap); 286 const char *type; 287 VisitorCapabilities caps; 288 } SerializeOps; 289 290 typedef struct TestArgs { 291 const SerializeOps *ops; 292 void *test_data; 293 } TestArgs; 294 295 static void test_primitives(gconstpointer opaque) 296 { 297 TestArgs *args = (TestArgs *) opaque; 298 const SerializeOps *ops = args->ops; 299 PrimitiveType *pt = args->test_data; 300 PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy)); 301 void *serialize_data; 302 303 pt_copy->type = pt->type; 304 ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort); 305 ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type, 306 &error_abort); 307 308 g_assert(pt_copy != NULL); 309 switch (pt->type) { 310 case PTYPE_STRING: 311 g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string); 312 g_free((char *)pt_copy->value.string); 313 break; 314 case PTYPE_BOOLEAN: 315 g_assert_cmpint(pt->value.boolean, ==, pt->value.boolean); 316 break; 317 case PTYPE_NUMBER: 318 g_assert_cmpfloat(pt->value.number, ==, pt_copy->value.number); 319 break; 320 case PTYPE_INTEGER: 321 g_assert_cmpint(pt->value.integer, ==, pt_copy->value.integer); 322 break; 323 case PTYPE_U8: 324 g_assert_cmpuint(pt->value.u8, ==, pt_copy->value.u8); 325 break; 326 case PTYPE_U16: 327 g_assert_cmpuint(pt->value.u16, ==, pt_copy->value.u16); 328 break; 329 case PTYPE_U32: 330 g_assert_cmpuint(pt->value.u32, ==, pt_copy->value.u32); 331 break; 332 case PTYPE_U64: 333 g_assert_cmpuint(pt->value.u64, ==, pt_copy->value.u64); 334 break; 335 case PTYPE_S8: 336 g_assert_cmpint(pt->value.s8, ==, pt_copy->value.s8); 337 break; 338 case PTYPE_S16: 339 g_assert_cmpint(pt->value.s16, ==, pt_copy->value.s16); 340 break; 341 case PTYPE_S32: 342 g_assert_cmpint(pt->value.s32, ==, pt_copy->value.s32); 343 break; 344 case PTYPE_S64: 345 g_assert_cmpint(pt->value.s64, ==, pt_copy->value.s64); 346 break; 347 case PTYPE_EOL: 348 g_assert_not_reached(); 349 } 350 351 ops->cleanup(serialize_data); 352 g_free(args); 353 g_free(pt_copy); 354 } 355 356 static void test_primitive_lists(gconstpointer opaque) 357 { 358 TestArgs *args = (TestArgs *) opaque; 359 const SerializeOps *ops = args->ops; 360 PrimitiveType *pt = args->test_data; 361 PrimitiveList pl = { .value = { NULL } }; 362 PrimitiveList pl_copy = { .value = { NULL } }; 363 PrimitiveList *pl_copy_ptr = &pl_copy; 364 void *serialize_data; 365 void *cur_head = NULL; 366 int i; 367 368 pl.type = pl_copy.type = pt->type; 369 370 /* build up our list of primitive types */ 371 for (i = 0; i < 32; i++) { 372 switch (pl.type) { 373 case PTYPE_STRING: { 374 QAPI_LIST_PREPEND(pl.value.strings, g_strdup(pt->value.string)); 375 break; 376 } 377 case PTYPE_INTEGER: { 378 QAPI_LIST_PREPEND(pl.value.integers, pt->value.integer); 379 break; 380 } 381 case PTYPE_S8: { 382 QAPI_LIST_PREPEND(pl.value.s8_integers, pt->value.s8); 383 break; 384 } 385 case PTYPE_S16: { 386 QAPI_LIST_PREPEND(pl.value.s16_integers, pt->value.s16); 387 break; 388 } 389 case PTYPE_S32: { 390 QAPI_LIST_PREPEND(pl.value.s32_integers, pt->value.s32); 391 break; 392 } 393 case PTYPE_S64: { 394 QAPI_LIST_PREPEND(pl.value.s64_integers, pt->value.s64); 395 break; 396 } 397 case PTYPE_U8: { 398 QAPI_LIST_PREPEND(pl.value.u8_integers, pt->value.u8); 399 break; 400 } 401 case PTYPE_U16: { 402 QAPI_LIST_PREPEND(pl.value.u16_integers, pt->value.u16); 403 break; 404 } 405 case PTYPE_U32: { 406 QAPI_LIST_PREPEND(pl.value.u32_integers, pt->value.u32); 407 break; 408 } 409 case PTYPE_U64: { 410 QAPI_LIST_PREPEND(pl.value.u64_integers, pt->value.u64); 411 break; 412 } 413 case PTYPE_NUMBER: { 414 QAPI_LIST_PREPEND(pl.value.numbers, pt->value.number); 415 break; 416 } 417 case PTYPE_BOOLEAN: { 418 QAPI_LIST_PREPEND(pl.value.booleans, pt->value.boolean); 419 break; 420 } 421 default: 422 g_assert_not_reached(); 423 } 424 } 425 426 ops->serialize((void **)&pl, &serialize_data, visit_primitive_list, 427 &error_abort); 428 ops->deserialize((void **)&pl_copy_ptr, serialize_data, 429 visit_primitive_list, &error_abort); 430 431 i = 0; 432 433 /* compare our deserialized list of primitives to the original */ 434 do { 435 switch (pl_copy.type) { 436 case PTYPE_STRING: { 437 strList *ptr; 438 if (cur_head) { 439 ptr = cur_head; 440 cur_head = ptr->next; 441 } else { 442 cur_head = ptr = pl_copy.value.strings; 443 } 444 g_assert_cmpstr(pt->value.string, ==, ptr->value); 445 break; 446 } 447 case PTYPE_INTEGER: { 448 intList *ptr; 449 if (cur_head) { 450 ptr = cur_head; 451 cur_head = ptr->next; 452 } else { 453 cur_head = ptr = pl_copy.value.integers; 454 } 455 g_assert_cmpint(pt->value.integer, ==, ptr->value); 456 break; 457 } 458 case PTYPE_S8: { 459 int8List *ptr; 460 if (cur_head) { 461 ptr = cur_head; 462 cur_head = ptr->next; 463 } else { 464 cur_head = ptr = pl_copy.value.s8_integers; 465 } 466 g_assert_cmpint(pt->value.s8, ==, ptr->value); 467 break; 468 } 469 case PTYPE_S16: { 470 int16List *ptr; 471 if (cur_head) { 472 ptr = cur_head; 473 cur_head = ptr->next; 474 } else { 475 cur_head = ptr = pl_copy.value.s16_integers; 476 } 477 g_assert_cmpint(pt->value.s16, ==, ptr->value); 478 break; 479 } 480 case PTYPE_S32: { 481 int32List *ptr; 482 if (cur_head) { 483 ptr = cur_head; 484 cur_head = ptr->next; 485 } else { 486 cur_head = ptr = pl_copy.value.s32_integers; 487 } 488 g_assert_cmpint(pt->value.s32, ==, ptr->value); 489 break; 490 } 491 case PTYPE_S64: { 492 int64List *ptr; 493 if (cur_head) { 494 ptr = cur_head; 495 cur_head = ptr->next; 496 } else { 497 cur_head = ptr = pl_copy.value.s64_integers; 498 } 499 g_assert_cmpint(pt->value.s64, ==, ptr->value); 500 break; 501 } 502 case PTYPE_U8: { 503 uint8List *ptr; 504 if (cur_head) { 505 ptr = cur_head; 506 cur_head = ptr->next; 507 } else { 508 cur_head = ptr = pl_copy.value.u8_integers; 509 } 510 g_assert_cmpint(pt->value.u8, ==, ptr->value); 511 break; 512 } 513 case PTYPE_U16: { 514 uint16List *ptr; 515 if (cur_head) { 516 ptr = cur_head; 517 cur_head = ptr->next; 518 } else { 519 cur_head = ptr = pl_copy.value.u16_integers; 520 } 521 g_assert_cmpint(pt->value.u16, ==, ptr->value); 522 break; 523 } 524 case PTYPE_U32: { 525 uint32List *ptr; 526 if (cur_head) { 527 ptr = cur_head; 528 cur_head = ptr->next; 529 } else { 530 cur_head = ptr = pl_copy.value.u32_integers; 531 } 532 g_assert_cmpint(pt->value.u32, ==, ptr->value); 533 break; 534 } 535 case PTYPE_U64: { 536 uint64List *ptr; 537 if (cur_head) { 538 ptr = cur_head; 539 cur_head = ptr->next; 540 } else { 541 cur_head = ptr = pl_copy.value.u64_integers; 542 } 543 g_assert_cmpint(pt->value.u64, ==, ptr->value); 544 break; 545 } 546 case PTYPE_NUMBER: { 547 numberList *ptr; 548 GString *double_expected = g_string_new(""); 549 GString *double_actual = g_string_new(""); 550 if (cur_head) { 551 ptr = cur_head; 552 cur_head = ptr->next; 553 } else { 554 cur_head = ptr = pl_copy.value.numbers; 555 } 556 /* we serialize with %f for our reference visitors, so rather than 557 * fuzzy floating math to test "equality", just compare the 558 * formatted values 559 */ 560 g_string_printf(double_expected, "%.6f", pt->value.number); 561 g_string_printf(double_actual, "%.6f", ptr->value); 562 g_assert_cmpstr(double_actual->str, ==, double_expected->str); 563 g_string_free(double_expected, true); 564 g_string_free(double_actual, true); 565 break; 566 } 567 case PTYPE_BOOLEAN: { 568 boolList *ptr; 569 if (cur_head) { 570 ptr = cur_head; 571 cur_head = ptr->next; 572 } else { 573 cur_head = ptr = pl_copy.value.booleans; 574 } 575 g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value); 576 break; 577 } 578 default: 579 g_assert_not_reached(); 580 } 581 i++; 582 } while (cur_head); 583 584 g_assert_cmpint(i, ==, 33); 585 586 ops->cleanup(serialize_data); 587 dealloc_helper(&pl, visit_primitive_list, &error_abort); 588 dealloc_helper(&pl_copy, visit_primitive_list, &error_abort); 589 g_free(args); 590 } 591 592 static void test_struct(gconstpointer opaque) 593 { 594 TestArgs *args = (TestArgs *) opaque; 595 const SerializeOps *ops = args->ops; 596 TestStruct *ts = struct_create(); 597 TestStruct *ts_copy = NULL; 598 void *serialize_data; 599 600 ops->serialize(ts, &serialize_data, visit_struct, &error_abort); 601 ops->deserialize((void **)&ts_copy, serialize_data, visit_struct, 602 &error_abort); 603 604 struct_compare(ts, ts_copy); 605 606 struct_cleanup(ts); 607 struct_cleanup(ts_copy); 608 609 ops->cleanup(serialize_data); 610 g_free(args); 611 } 612 613 static void test_nested_struct(gconstpointer opaque) 614 { 615 TestArgs *args = (TestArgs *) opaque; 616 const SerializeOps *ops = args->ops; 617 UserDefTwo *udnp = nested_struct_create(); 618 UserDefTwo *udnp_copy = NULL; 619 void *serialize_data; 620 621 ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort); 622 ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct, 623 &error_abort); 624 625 nested_struct_compare(udnp, udnp_copy); 626 627 nested_struct_cleanup(udnp); 628 nested_struct_cleanup(udnp_copy); 629 630 ops->cleanup(serialize_data); 631 g_free(args); 632 } 633 634 static void test_nested_struct_list(gconstpointer opaque) 635 { 636 TestArgs *args = (TestArgs *) opaque; 637 const SerializeOps *ops = args->ops; 638 UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL; 639 void *serialize_data; 640 int i = 0; 641 642 for (i = 0; i < 8; i++) { 643 QAPI_LIST_PREPEND(listp, nested_struct_create()); 644 } 645 646 ops->serialize(listp, &serialize_data, visit_nested_struct_list, 647 &error_abort); 648 ops->deserialize((void **)&listp_copy, serialize_data, 649 visit_nested_struct_list, &error_abort); 650 651 tmp = listp; 652 tmp_copy = listp_copy; 653 while (listp_copy) { 654 g_assert(listp); 655 nested_struct_compare(listp->value, listp_copy->value); 656 listp = listp->next; 657 listp_copy = listp_copy->next; 658 } 659 660 qapi_free_UserDefTwoList(tmp); 661 qapi_free_UserDefTwoList(tmp_copy); 662 663 ops->cleanup(serialize_data); 664 g_free(args); 665 } 666 667 static PrimitiveType pt_values[] = { 668 /* string tests */ 669 { 670 .description = "string_empty", 671 .type = PTYPE_STRING, 672 .value.string = "", 673 }, 674 { 675 .description = "string_whitespace", 676 .type = PTYPE_STRING, 677 .value.string = "a b c\td", 678 }, 679 { 680 .description = "string_newlines", 681 .type = PTYPE_STRING, 682 .value.string = "a\nb\n", 683 }, 684 { 685 .description = "string_commas", 686 .type = PTYPE_STRING, 687 .value.string = "a,b, c,d", 688 }, 689 { 690 .description = "string_single_quoted", 691 .type = PTYPE_STRING, 692 .value.string = "'a b',cd", 693 }, 694 { 695 .description = "string_double_quoted", 696 .type = PTYPE_STRING, 697 .value.string = "\"a b\",cd", 698 }, 699 /* boolean tests */ 700 { 701 .description = "boolean_true1", 702 .type = PTYPE_BOOLEAN, 703 .value.boolean = true, 704 }, 705 { 706 .description = "boolean_true2", 707 .type = PTYPE_BOOLEAN, 708 .value.boolean = 8, 709 }, 710 { 711 .description = "boolean_true3", 712 .type = PTYPE_BOOLEAN, 713 .value.boolean = -1, 714 }, 715 { 716 .description = "boolean_false1", 717 .type = PTYPE_BOOLEAN, 718 .value.boolean = false, 719 }, 720 { 721 .description = "boolean_false2", 722 .type = PTYPE_BOOLEAN, 723 .value.boolean = 0, 724 }, 725 /* number tests (double) */ 726 { 727 .description = "number_sanity1", 728 .type = PTYPE_NUMBER, 729 .value.number = -1, 730 }, 731 { 732 .description = "number_sanity2", 733 .type = PTYPE_NUMBER, 734 .value.number = 3.141593, 735 }, 736 { 737 .description = "number_min", 738 .type = PTYPE_NUMBER, 739 .value.number = DBL_MIN, 740 }, 741 { 742 .description = "number_max", 743 .type = PTYPE_NUMBER, 744 .value.number = DBL_MAX, 745 }, 746 /* integer tests (int64) */ 747 { 748 .description = "integer_sanity1", 749 .type = PTYPE_INTEGER, 750 .value.integer = -1, 751 }, 752 { 753 .description = "integer_sanity2", 754 .type = PTYPE_INTEGER, 755 .value.integer = INT64_MAX / 2 + 1, 756 }, 757 { 758 .description = "integer_min", 759 .type = PTYPE_INTEGER, 760 .value.integer = INT64_MIN, 761 }, 762 { 763 .description = "integer_max", 764 .type = PTYPE_INTEGER, 765 .value.integer = INT64_MAX, 766 }, 767 /* uint8 tests */ 768 { 769 .description = "uint8_sanity1", 770 .type = PTYPE_U8, 771 .value.u8 = 1, 772 }, 773 { 774 .description = "uint8_sanity2", 775 .type = PTYPE_U8, 776 .value.u8 = UINT8_MAX / 2 + 1, 777 }, 778 { 779 .description = "uint8_min", 780 .type = PTYPE_U8, 781 .value.u8 = 0, 782 }, 783 { 784 .description = "uint8_max", 785 .type = PTYPE_U8, 786 .value.u8 = UINT8_MAX, 787 }, 788 /* uint16 tests */ 789 { 790 .description = "uint16_sanity1", 791 .type = PTYPE_U16, 792 .value.u16 = 1, 793 }, 794 { 795 .description = "uint16_sanity2", 796 .type = PTYPE_U16, 797 .value.u16 = UINT16_MAX / 2 + 1, 798 }, 799 { 800 .description = "uint16_min", 801 .type = PTYPE_U16, 802 .value.u16 = 0, 803 }, 804 { 805 .description = "uint16_max", 806 .type = PTYPE_U16, 807 .value.u16 = UINT16_MAX, 808 }, 809 /* uint32 tests */ 810 { 811 .description = "uint32_sanity1", 812 .type = PTYPE_U32, 813 .value.u32 = 1, 814 }, 815 { 816 .description = "uint32_sanity2", 817 .type = PTYPE_U32, 818 .value.u32 = UINT32_MAX / 2 + 1, 819 }, 820 { 821 .description = "uint32_min", 822 .type = PTYPE_U32, 823 .value.u32 = 0, 824 }, 825 { 826 .description = "uint32_max", 827 .type = PTYPE_U32, 828 .value.u32 = UINT32_MAX, 829 }, 830 /* uint64 tests */ 831 { 832 .description = "uint64_sanity1", 833 .type = PTYPE_U64, 834 .value.u64 = 1, 835 }, 836 { 837 .description = "uint64_sanity2", 838 .type = PTYPE_U64, 839 .value.u64 = UINT64_MAX / 2 + 1, 840 }, 841 { 842 .description = "uint64_min", 843 .type = PTYPE_U64, 844 .value.u64 = 0, 845 }, 846 { 847 .description = "uint64_max", 848 .type = PTYPE_U64, 849 .value.u64 = UINT64_MAX, 850 }, 851 /* int8 tests */ 852 { 853 .description = "int8_sanity1", 854 .type = PTYPE_S8, 855 .value.s8 = -1, 856 }, 857 { 858 .description = "int8_sanity2", 859 .type = PTYPE_S8, 860 .value.s8 = INT8_MAX / 2 + 1, 861 }, 862 { 863 .description = "int8_min", 864 .type = PTYPE_S8, 865 .value.s8 = INT8_MIN, 866 }, 867 { 868 .description = "int8_max", 869 .type = PTYPE_S8, 870 .value.s8 = INT8_MAX, 871 }, 872 /* int16 tests */ 873 { 874 .description = "int16_sanity1", 875 .type = PTYPE_S16, 876 .value.s16 = -1, 877 }, 878 { 879 .description = "int16_sanity2", 880 .type = PTYPE_S16, 881 .value.s16 = INT16_MAX / 2 + 1, 882 }, 883 { 884 .description = "int16_min", 885 .type = PTYPE_S16, 886 .value.s16 = INT16_MIN, 887 }, 888 { 889 .description = "int16_max", 890 .type = PTYPE_S16, 891 .value.s16 = INT16_MAX, 892 }, 893 /* int32 tests */ 894 { 895 .description = "int32_sanity1", 896 .type = PTYPE_S32, 897 .value.s32 = -1, 898 }, 899 { 900 .description = "int32_sanity2", 901 .type = PTYPE_S32, 902 .value.s32 = INT32_MAX / 2 + 1, 903 }, 904 { 905 .description = "int32_min", 906 .type = PTYPE_S32, 907 .value.s32 = INT32_MIN, 908 }, 909 { 910 .description = "int32_max", 911 .type = PTYPE_S32, 912 .value.s32 = INT32_MAX, 913 }, 914 /* int64 tests */ 915 { 916 .description = "int64_sanity1", 917 .type = PTYPE_S64, 918 .value.s64 = -1, 919 }, 920 { 921 .description = "int64_sanity2", 922 .type = PTYPE_S64, 923 .value.s64 = INT64_MAX / 2 + 1, 924 }, 925 { 926 .description = "int64_min", 927 .type = PTYPE_S64, 928 .value.s64 = INT64_MIN, 929 }, 930 { 931 .description = "int64_max", 932 .type = PTYPE_S64, 933 .value.s64 = INT64_MAX, 934 }, 935 { .type = PTYPE_EOL } 936 }; 937 938 /* visitor-specific op implementations */ 939 940 typedef struct QmpSerializeData { 941 Visitor *qov; 942 QObject *obj; 943 Visitor *qiv; 944 } QmpSerializeData; 945 946 static void qmp_serialize(void *native_in, void **datap, 947 VisitorFunc visit, Error **errp) 948 { 949 QmpSerializeData *d = g_malloc0(sizeof(*d)); 950 951 d->qov = qobject_output_visitor_new(&d->obj); 952 visit(d->qov, &native_in, errp); 953 *datap = d; 954 } 955 956 static void qmp_deserialize(void **native_out, void *datap, 957 VisitorFunc visit, Error **errp) 958 { 959 QmpSerializeData *d = datap; 960 GString *output_json; 961 QObject *obj_orig, *obj; 962 963 visit_complete(d->qov, &d->obj); 964 obj_orig = d->obj; 965 output_json = qobject_to_json(obj_orig); 966 obj = qobject_from_json(output_json->str, &error_abort); 967 968 g_string_free(output_json, true); 969 d->qiv = qobject_input_visitor_new(obj); 970 qobject_unref(obj_orig); 971 qobject_unref(obj); 972 visit(d->qiv, native_out, errp); 973 } 974 975 static void qmp_cleanup(void *datap) 976 { 977 QmpSerializeData *d = datap; 978 visit_free(d->qov); 979 visit_free(d->qiv); 980 981 g_free(d); 982 } 983 984 typedef struct StringSerializeData { 985 char *string; 986 Visitor *sov; 987 Visitor *siv; 988 } StringSerializeData; 989 990 static void string_serialize(void *native_in, void **datap, 991 VisitorFunc visit, Error **errp) 992 { 993 StringSerializeData *d = g_malloc0(sizeof(*d)); 994 995 d->sov = string_output_visitor_new(false, &d->string); 996 visit(d->sov, &native_in, errp); 997 *datap = d; 998 } 999 1000 static void string_deserialize(void **native_out, void *datap, 1001 VisitorFunc visit, Error **errp) 1002 { 1003 StringSerializeData *d = datap; 1004 1005 visit_complete(d->sov, &d->string); 1006 d->siv = string_input_visitor_new(d->string); 1007 visit(d->siv, native_out, errp); 1008 } 1009 1010 static void string_cleanup(void *datap) 1011 { 1012 StringSerializeData *d = datap; 1013 1014 visit_free(d->sov); 1015 visit_free(d->siv); 1016 g_free(d->string); 1017 g_free(d); 1018 } 1019 1020 /* visitor registration, test harness */ 1021 1022 /* note: to function interchangeably as a serialization mechanism your 1023 * visitor test implementation should pass the test cases for all visitor 1024 * capabilities: primitives, structures, and lists 1025 */ 1026 static const SerializeOps visitors[] = { 1027 { 1028 .type = "QMP", 1029 .serialize = qmp_serialize, 1030 .deserialize = qmp_deserialize, 1031 .cleanup = qmp_cleanup, 1032 .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS | 1033 VCAP_PRIMITIVE_LISTS 1034 }, 1035 { 1036 .type = "String", 1037 .serialize = string_serialize, 1038 .deserialize = string_deserialize, 1039 .cleanup = string_cleanup, 1040 .caps = VCAP_PRIMITIVES 1041 }, 1042 { NULL } 1043 }; 1044 1045 static void add_visitor_type(const SerializeOps *ops) 1046 { 1047 char testname_prefix[32]; 1048 char testname[128]; 1049 TestArgs *args; 1050 int i = 0; 1051 1052 sprintf(testname_prefix, "/visitor/serialization/%s", ops->type); 1053 1054 if (ops->caps & VCAP_PRIMITIVES) { 1055 while (pt_values[i].type != PTYPE_EOL) { 1056 sprintf(testname, "%s/primitives/%s", testname_prefix, 1057 pt_values[i].description); 1058 args = g_malloc0(sizeof(*args)); 1059 args->ops = ops; 1060 args->test_data = &pt_values[i]; 1061 g_test_add_data_func(testname, args, test_primitives); 1062 i++; 1063 } 1064 } 1065 1066 if (ops->caps & VCAP_STRUCTURES) { 1067 sprintf(testname, "%s/struct", testname_prefix); 1068 args = g_malloc0(sizeof(*args)); 1069 args->ops = ops; 1070 args->test_data = NULL; 1071 g_test_add_data_func(testname, args, test_struct); 1072 1073 sprintf(testname, "%s/nested_struct", testname_prefix); 1074 args = g_malloc0(sizeof(*args)); 1075 args->ops = ops; 1076 args->test_data = NULL; 1077 g_test_add_data_func(testname, args, test_nested_struct); 1078 } 1079 1080 if (ops->caps & VCAP_LISTS) { 1081 sprintf(testname, "%s/nested_struct_list", testname_prefix); 1082 args = g_malloc0(sizeof(*args)); 1083 args->ops = ops; 1084 args->test_data = NULL; 1085 g_test_add_data_func(testname, args, test_nested_struct_list); 1086 } 1087 1088 if (ops->caps & VCAP_PRIMITIVE_LISTS) { 1089 i = 0; 1090 while (pt_values[i].type != PTYPE_EOL) { 1091 sprintf(testname, "%s/primitive_list/%s", testname_prefix, 1092 pt_values[i].description); 1093 args = g_malloc0(sizeof(*args)); 1094 args->ops = ops; 1095 args->test_data = &pt_values[i]; 1096 g_test_add_data_func(testname, args, test_primitive_lists); 1097 i++; 1098 } 1099 } 1100 } 1101 1102 int main(int argc, char **argv) 1103 { 1104 int i = 0; 1105 1106 g_test_init(&argc, &argv, NULL); 1107 1108 while (visitors[i].type != NULL) { 1109 add_visitor_type(&visitors[i]); 1110 i++; 1111 } 1112 1113 g_test_run(); 1114 1115 return 0; 1116 } 1117