qemu/tests/unit/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 <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    } value;
  59    enum PrimitiveTypeKind type;
  60    const char *description;
  61} PrimitiveType;
  62
  63typedef 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
  84typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
  85
  86static 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
  95static 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
 140static 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
 186static 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
 195static 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
 204static void struct_cleanup(TestStruct *ts)
 205{
 206    g_free(ts->string);
 207    g_free(ts);
 208}
 209
 210static void visit_struct(Visitor *v, void **native, Error **errp)
 211{
 212    visit_type_TestStruct(v, NULL, (TestStruct **)native, errp);
 213}
 214
 215static 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
 235static 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
 256static void nested_struct_cleanup(UserDefTwo *udnp)
 257{
 258    qapi_free_UserDefTwo(udnp);
 259}
 260
 261static void visit_nested_struct(Visitor *v, void **native, Error **errp)
 262{
 263    visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp);
 264}
 265
 266static 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
 273typedef enum VisitorCapabilities {
 274    VCAP_PRIMITIVES = 1,
 275    VCAP_STRUCTURES = 2,
 276    VCAP_LISTS = 4,
 277    VCAP_PRIMITIVE_LISTS = 8,
 278} VisitorCapabilities;
 279
 280typedef 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
 290typedef struct TestArgs {
 291    const SerializeOps *ops;
 292    void *test_data;
 293} TestArgs;
 294
 295static 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
 356static 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
 592static 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
 613static 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
 634static 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
 667static 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
 940typedef struct QmpSerializeData {
 941    Visitor *qov;
 942    QObject *obj;
 943    Visitor *qiv;
 944} QmpSerializeData;
 945
 946static 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
 956static 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
 975static 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
 984typedef struct StringSerializeData {
 985    char *string;
 986    Visitor *sov;
 987    Visitor *siv;
 988} StringSerializeData;
 989
 990static 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
1000static 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
1010static 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 */
1026static 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
1045static 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
1102int 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