qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

test-visitor-serialization.c (30011B)


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