cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

test-visitor-serialization.c (30752B)


      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}