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