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 <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}
1188