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