xref: /qemu/tests/unit/test-visitor-serialization.c (revision 3b098d56979d2f7fd707c5be85555d114353a28d)
12d496105SMichael Roth /*
22d496105SMichael Roth  * Unit-tests for visitor-based serialization
32d496105SMichael Roth  *
46446a592SEric Blake  * Copyright (C) 2014-2015 Red Hat, Inc.
52d496105SMichael Roth  * Copyright IBM, Corp. 2012
62d496105SMichael Roth  *
72d496105SMichael Roth  * Authors:
82d496105SMichael Roth  *  Michael Roth <mdroth@linux.vnet.ibm.com>
92d496105SMichael Roth  *
102d496105SMichael Roth  * This work is licensed under the terms of the GNU GPL, version 2 or later.
112d496105SMichael Roth  * See the COPYING file in the top-level directory.
122d496105SMichael Roth  */
132d496105SMichael Roth 
14681c28a3SPeter Maydell #include "qemu/osdep.h"
152d496105SMichael Roth #include <float.h>
1679ee7df8SPaolo Bonzini 
1779ee7df8SPaolo Bonzini #include "qemu-common.h"
182d496105SMichael Roth #include "test-qapi-types.h"
192d496105SMichael Roth #include "test-qapi-visit.h"
20da34e65cSMarkus Armbruster #include "qapi/error.h"
217b1b5d19SPaolo Bonzini #include "qapi/qmp/types.h"
22c7eb39cbSEric Blake #include "qapi/qmp/qjson.h"
232d496105SMichael Roth #include "qapi/qmp-input-visitor.h"
242d496105SMichael Roth #include "qapi/qmp-output-visitor.h"
250d30b0a2SMichael Roth #include "qapi/string-input-visitor.h"
260d30b0a2SMichael Roth #include "qapi/string-output-visitor.h"
278addacddSMichael Roth #include "qapi-types.h"
288addacddSMichael Roth #include "qapi-visit.h"
298addacddSMichael Roth #include "qapi/dealloc-visitor.h"
308addacddSMichael Roth 
318addacddSMichael Roth enum PrimitiveTypeKind {
328addacddSMichael Roth     PTYPE_STRING = 0,
338addacddSMichael Roth     PTYPE_BOOLEAN,
348addacddSMichael Roth     PTYPE_NUMBER,
358addacddSMichael Roth     PTYPE_INTEGER,
368addacddSMichael Roth     PTYPE_U8,
378addacddSMichael Roth     PTYPE_U16,
388addacddSMichael Roth     PTYPE_U32,
398addacddSMichael Roth     PTYPE_U64,
408addacddSMichael Roth     PTYPE_S8,
418addacddSMichael Roth     PTYPE_S16,
428addacddSMichael Roth     PTYPE_S32,
438addacddSMichael Roth     PTYPE_S64,
448addacddSMichael Roth     PTYPE_EOL,
458addacddSMichael Roth };
462d496105SMichael Roth 
472d496105SMichael Roth typedef struct PrimitiveType {
482d496105SMichael Roth     union {
492d496105SMichael Roth         const char *string;
502d496105SMichael Roth         bool boolean;
512d496105SMichael Roth         double number;
522d496105SMichael Roth         int64_t integer;
532d496105SMichael Roth         uint8_t u8;
542d496105SMichael Roth         uint16_t u16;
552d496105SMichael Roth         uint32_t u32;
562d496105SMichael Roth         uint64_t u64;
572d496105SMichael Roth         int8_t s8;
582d496105SMichael Roth         int16_t s16;
592d496105SMichael Roth         int32_t s32;
602d496105SMichael Roth         int64_t s64;
612d496105SMichael Roth         intmax_t max;
622d496105SMichael Roth     } value;
638addacddSMichael Roth     enum PrimitiveTypeKind type;
642d496105SMichael Roth     const char *description;
652d496105SMichael Roth } PrimitiveType;
662d496105SMichael Roth 
678addacddSMichael Roth typedef struct PrimitiveList {
688addacddSMichael Roth     union {
698addacddSMichael Roth         strList *strings;
708addacddSMichael Roth         boolList *booleans;
718addacddSMichael Roth         numberList *numbers;
728addacddSMichael Roth         intList *integers;
738addacddSMichael Roth         int8List *s8_integers;
748addacddSMichael Roth         int16List *s16_integers;
758addacddSMichael Roth         int32List *s32_integers;
768addacddSMichael Roth         int64List *s64_integers;
778addacddSMichael Roth         uint8List *u8_integers;
788addacddSMichael Roth         uint16List *u16_integers;
798addacddSMichael Roth         uint32List *u32_integers;
808addacddSMichael Roth         uint64List *u64_integers;
818addacddSMichael Roth     } value;
828addacddSMichael Roth     enum PrimitiveTypeKind type;
838addacddSMichael Roth     const char *description;
848addacddSMichael Roth } PrimitiveList;
858addacddSMichael Roth 
862d496105SMichael Roth /* test helpers */
872d496105SMichael Roth 
888addacddSMichael Roth typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
898addacddSMichael Roth 
908addacddSMichael Roth static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
918addacddSMichael Roth {
922c0ef9f4SEric Blake     Visitor *v = qapi_dealloc_visitor_new();
938addacddSMichael Roth 
942c0ef9f4SEric Blake     visit(v, &native_in, errp);
958addacddSMichael Roth 
962c0ef9f4SEric Blake     visit_free(v);
978addacddSMichael Roth }
988addacddSMichael Roth 
992d496105SMichael Roth static void visit_primitive_type(Visitor *v, void **native, Error **errp)
1002d496105SMichael Roth {
1012d496105SMichael Roth     PrimitiveType *pt = *native;
1022d496105SMichael Roth     switch(pt->type) {
1032d496105SMichael Roth     case PTYPE_STRING:
10451e72bc1SEric Blake         visit_type_str(v, NULL, (char **)&pt->value.string, errp);
1052d496105SMichael Roth         break;
1062d496105SMichael Roth     case PTYPE_BOOLEAN:
10751e72bc1SEric Blake         visit_type_bool(v, NULL, &pt->value.boolean, errp);
1082d496105SMichael Roth         break;
1092d496105SMichael Roth     case PTYPE_NUMBER:
11051e72bc1SEric Blake         visit_type_number(v, NULL, &pt->value.number, errp);
1112d496105SMichael Roth         break;
1122d496105SMichael Roth     case PTYPE_INTEGER:
11351e72bc1SEric Blake         visit_type_int(v, NULL, &pt->value.integer, errp);
1142d496105SMichael Roth         break;
1152d496105SMichael Roth     case PTYPE_U8:
11651e72bc1SEric Blake         visit_type_uint8(v, NULL, &pt->value.u8, errp);
1172d496105SMichael Roth         break;
1182d496105SMichael Roth     case PTYPE_U16:
11951e72bc1SEric Blake         visit_type_uint16(v, NULL, &pt->value.u16, errp);
1202d496105SMichael Roth         break;
1212d496105SMichael Roth     case PTYPE_U32:
12251e72bc1SEric Blake         visit_type_uint32(v, NULL, &pt->value.u32, errp);
1232d496105SMichael Roth         break;
1242d496105SMichael Roth     case PTYPE_U64:
12551e72bc1SEric Blake         visit_type_uint64(v, NULL, &pt->value.u64, errp);
1262d496105SMichael Roth         break;
1272d496105SMichael Roth     case PTYPE_S8:
12851e72bc1SEric Blake         visit_type_int8(v, NULL, &pt->value.s8, errp);
1292d496105SMichael Roth         break;
1302d496105SMichael Roth     case PTYPE_S16:
13151e72bc1SEric Blake         visit_type_int16(v, NULL, &pt->value.s16, errp);
1322d496105SMichael Roth         break;
1332d496105SMichael Roth     case PTYPE_S32:
13451e72bc1SEric Blake         visit_type_int32(v, NULL, &pt->value.s32, errp);
1352d496105SMichael Roth         break;
1362d496105SMichael Roth     case PTYPE_S64:
13751e72bc1SEric Blake         visit_type_int64(v, NULL, &pt->value.s64, errp);
1382d496105SMichael Roth         break;
1392d496105SMichael Roth     case PTYPE_EOL:
140dfc6f865SStefan Weil         g_assert_not_reached();
1412d496105SMichael Roth     }
1422d496105SMichael Roth }
1432d496105SMichael Roth 
1448addacddSMichael Roth static void visit_primitive_list(Visitor *v, void **native, Error **errp)
1458addacddSMichael Roth {
1468addacddSMichael Roth     PrimitiveList *pl = *native;
1478addacddSMichael Roth     switch (pl->type) {
1488addacddSMichael Roth     case PTYPE_STRING:
14951e72bc1SEric Blake         visit_type_strList(v, NULL, &pl->value.strings, errp);
1508addacddSMichael Roth         break;
1518addacddSMichael Roth     case PTYPE_BOOLEAN:
15251e72bc1SEric Blake         visit_type_boolList(v, NULL, &pl->value.booleans, errp);
1538addacddSMichael Roth         break;
1548addacddSMichael Roth     case PTYPE_NUMBER:
15551e72bc1SEric Blake         visit_type_numberList(v, NULL, &pl->value.numbers, errp);
1568addacddSMichael Roth         break;
1578addacddSMichael Roth     case PTYPE_INTEGER:
15851e72bc1SEric Blake         visit_type_intList(v, NULL, &pl->value.integers, errp);
1598addacddSMichael Roth         break;
1608addacddSMichael Roth     case PTYPE_S8:
16151e72bc1SEric Blake         visit_type_int8List(v, NULL, &pl->value.s8_integers, errp);
1628addacddSMichael Roth         break;
1638addacddSMichael Roth     case PTYPE_S16:
16451e72bc1SEric Blake         visit_type_int16List(v, NULL, &pl->value.s16_integers, errp);
1658addacddSMichael Roth         break;
1668addacddSMichael Roth     case PTYPE_S32:
16751e72bc1SEric Blake         visit_type_int32List(v, NULL, &pl->value.s32_integers, errp);
1688addacddSMichael Roth         break;
1698addacddSMichael Roth     case PTYPE_S64:
17051e72bc1SEric Blake         visit_type_int64List(v, NULL, &pl->value.s64_integers, errp);
1718addacddSMichael Roth         break;
1728addacddSMichael Roth     case PTYPE_U8:
17351e72bc1SEric Blake         visit_type_uint8List(v, NULL, &pl->value.u8_integers, errp);
1748addacddSMichael Roth         break;
1758addacddSMichael Roth     case PTYPE_U16:
17651e72bc1SEric Blake         visit_type_uint16List(v, NULL, &pl->value.u16_integers, errp);
1778addacddSMichael Roth         break;
1788addacddSMichael Roth     case PTYPE_U32:
17951e72bc1SEric Blake         visit_type_uint32List(v, NULL, &pl->value.u32_integers, errp);
1808addacddSMichael Roth         break;
1818addacddSMichael Roth     case PTYPE_U64:
18251e72bc1SEric Blake         visit_type_uint64List(v, NULL, &pl->value.u64_integers, errp);
1838addacddSMichael Roth         break;
1848addacddSMichael Roth     default:
185dfc6f865SStefan Weil         g_assert_not_reached();
1868addacddSMichael Roth     }
1878addacddSMichael Roth }
1888addacddSMichael Roth 
1892d496105SMichael Roth 
1902d496105SMichael Roth static TestStruct *struct_create(void)
1912d496105SMichael Roth {
1922d496105SMichael Roth     TestStruct *ts = g_malloc0(sizeof(*ts));
1932d496105SMichael Roth     ts->integer = -42;
1942d496105SMichael Roth     ts->boolean = true;
1952d496105SMichael Roth     ts->string = strdup("test string");
1962d496105SMichael Roth     return ts;
1972d496105SMichael Roth }
1982d496105SMichael Roth 
1992d496105SMichael Roth static void struct_compare(TestStruct *ts1, TestStruct *ts2)
2002d496105SMichael Roth {
2012d496105SMichael Roth     g_assert(ts1);
2022d496105SMichael Roth     g_assert(ts2);
2032d496105SMichael Roth     g_assert_cmpint(ts1->integer, ==, ts2->integer);
2042d496105SMichael Roth     g_assert(ts1->boolean == ts2->boolean);
2052d496105SMichael Roth     g_assert_cmpstr(ts1->string, ==, ts2->string);
2062d496105SMichael Roth }
2072d496105SMichael Roth 
2082d496105SMichael Roth static void struct_cleanup(TestStruct *ts)
2092d496105SMichael Roth {
2102d496105SMichael Roth     g_free(ts->string);
2112d496105SMichael Roth     g_free(ts);
2122d496105SMichael Roth }
2132d496105SMichael Roth 
2142d496105SMichael Roth static void visit_struct(Visitor *v, void **native, Error **errp)
2152d496105SMichael Roth {
21651e72bc1SEric Blake     visit_type_TestStruct(v, NULL, (TestStruct **)native, errp);
2172d496105SMichael Roth }
2182d496105SMichael Roth 
219b6fcf32dSEric Blake static UserDefTwo *nested_struct_create(void)
2202d496105SMichael Roth {
221b6fcf32dSEric Blake     UserDefTwo *udnp = g_malloc0(sizeof(*udnp));
2222d496105SMichael Roth     udnp->string0 = strdup("test_string0");
2236446a592SEric Blake     udnp->dict1 = g_malloc0(sizeof(*udnp->dict1));
2246446a592SEric Blake     udnp->dict1->string1 = strdup("test_string1");
2256446a592SEric Blake     udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2));
2266446a592SEric Blake     udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1);
227ddf21908SEric Blake     udnp->dict1->dict2->userdef->integer = 42;
2286446a592SEric Blake     udnp->dict1->dict2->userdef->string = strdup("test_string");
2296446a592SEric Blake     udnp->dict1->dict2->string = strdup("test_string2");
2306446a592SEric Blake     udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3));
2316446a592SEric Blake     udnp->dict1->has_dict3 = true;
2326446a592SEric Blake     udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1);
233ddf21908SEric Blake     udnp->dict1->dict3->userdef->integer = 43;
2346446a592SEric Blake     udnp->dict1->dict3->userdef->string = strdup("test_string");
2356446a592SEric Blake     udnp->dict1->dict3->string = strdup("test_string3");
2362d496105SMichael Roth     return udnp;
2372d496105SMichael Roth }
2382d496105SMichael Roth 
239b6fcf32dSEric Blake static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2)
2402d496105SMichael Roth {
2412d496105SMichael Roth     g_assert(udnp1);
2422d496105SMichael Roth     g_assert(udnp2);
2432d496105SMichael Roth     g_assert_cmpstr(udnp1->string0, ==, udnp2->string0);
2446446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1);
245ddf21908SEric Blake     g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==,
246ddf21908SEric Blake                     udnp2->dict1->dict2->userdef->integer);
2476446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==,
2486446a592SEric Blake                     udnp2->dict1->dict2->userdef->string);
2496446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict2->string, ==,
2506446a592SEric Blake                     udnp2->dict1->dict2->string);
2516446a592SEric Blake     g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3);
252ddf21908SEric Blake     g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==,
253ddf21908SEric Blake                     udnp2->dict1->dict3->userdef->integer);
2546446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==,
2556446a592SEric Blake                     udnp2->dict1->dict3->userdef->string);
2566446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict3->string, ==,
2576446a592SEric Blake                     udnp2->dict1->dict3->string);
2582d496105SMichael Roth }
2592d496105SMichael Roth 
260b6fcf32dSEric Blake static void nested_struct_cleanup(UserDefTwo *udnp)
2612d496105SMichael Roth {
262b6fcf32dSEric Blake     qapi_free_UserDefTwo(udnp);
2632d496105SMichael Roth }
2642d496105SMichael Roth 
2652d496105SMichael Roth static void visit_nested_struct(Visitor *v, void **native, Error **errp)
2662d496105SMichael Roth {
26751e72bc1SEric Blake     visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp);
2682d496105SMichael Roth }
2692d496105SMichael Roth 
2702d496105SMichael Roth static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
2712d496105SMichael Roth {
27251e72bc1SEric Blake     visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp);
2732d496105SMichael Roth }
2742d496105SMichael Roth 
2752d496105SMichael Roth /* test cases */
2762d496105SMichael Roth 
2772d496105SMichael Roth typedef enum VisitorCapabilities {
2782d496105SMichael Roth     VCAP_PRIMITIVES = 1,
2792d496105SMichael Roth     VCAP_STRUCTURES = 2,
2802d496105SMichael Roth     VCAP_LISTS = 4,
2818addacddSMichael Roth     VCAP_PRIMITIVE_LISTS = 8,
2822d496105SMichael Roth } VisitorCapabilities;
2832d496105SMichael Roth 
2842d496105SMichael Roth typedef struct SerializeOps {
2852d496105SMichael Roth     void (*serialize)(void *native_in, void **datap,
2862d496105SMichael Roth                       VisitorFunc visit, Error **errp);
2872d496105SMichael Roth     void (*deserialize)(void **native_out, void *datap,
2882d496105SMichael Roth                             VisitorFunc visit, Error **errp);
2892d496105SMichael Roth     void (*cleanup)(void *datap);
2902d496105SMichael Roth     const char *type;
2912d496105SMichael Roth     VisitorCapabilities caps;
2922d496105SMichael Roth } SerializeOps;
2932d496105SMichael Roth 
2942d496105SMichael Roth typedef struct TestArgs {
2952d496105SMichael Roth     const SerializeOps *ops;
2962d496105SMichael Roth     void *test_data;
2972d496105SMichael Roth } TestArgs;
2982d496105SMichael Roth 
2992d496105SMichael Roth static void test_primitives(gconstpointer opaque)
3002d496105SMichael Roth {
3012d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
3022d496105SMichael Roth     const SerializeOps *ops = args->ops;
3032d496105SMichael Roth     PrimitiveType *pt = args->test_data;
3042d496105SMichael Roth     PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
3052d496105SMichael Roth     void *serialize_data;
3062d496105SMichael Roth 
3072d496105SMichael Roth     pt_copy->type = pt->type;
3083f66f764SEric Blake     ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort);
3093f66f764SEric Blake     ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type,
3103f66f764SEric Blake                      &error_abort);
3112d496105SMichael Roth 
3122d496105SMichael Roth     g_assert(pt_copy != NULL);
3132d496105SMichael Roth     if (pt->type == PTYPE_STRING) {
3142d496105SMichael Roth         g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
3152bd01ac1SStefan Berger         g_free((char *)pt_copy->value.string);
3162d496105SMichael Roth     } else if (pt->type == PTYPE_NUMBER) {
317089f26bbSMichael Roth         GString *double_expected = g_string_new("");
318089f26bbSMichael Roth         GString *double_actual = g_string_new("");
3192d496105SMichael Roth         /* we serialize with %f for our reference visitors, so rather than fuzzy
3202d496105SMichael Roth          * floating math to test "equality", just compare the formatted values
3212d496105SMichael Roth          */
322089f26bbSMichael Roth         g_string_printf(double_expected, "%.6f", pt->value.number);
323089f26bbSMichael Roth         g_string_printf(double_actual, "%.6f", pt_copy->value.number);
324089f26bbSMichael Roth         g_assert_cmpstr(double_actual->str, ==, double_expected->str);
325089f26bbSMichael Roth 
326089f26bbSMichael Roth         g_string_free(double_expected, true);
327089f26bbSMichael Roth         g_string_free(double_actual, true);
3282d496105SMichael Roth     } else if (pt->type == PTYPE_BOOLEAN) {
3292d496105SMichael Roth         g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max);
3302d496105SMichael Roth     } else {
3312d496105SMichael Roth         g_assert_cmpint(pt->value.max, ==, pt_copy->value.max);
3322d496105SMichael Roth     }
3332d496105SMichael Roth 
3342d496105SMichael Roth     ops->cleanup(serialize_data);
3352d496105SMichael Roth     g_free(args);
3362bd01ac1SStefan Berger     g_free(pt_copy);
3372d496105SMichael Roth }
3382d496105SMichael Roth 
3398addacddSMichael Roth static void test_primitive_lists(gconstpointer opaque)
3408addacddSMichael Roth {
3418addacddSMichael Roth     TestArgs *args = (TestArgs *) opaque;
3428addacddSMichael Roth     const SerializeOps *ops = args->ops;
3438addacddSMichael Roth     PrimitiveType *pt = args->test_data;
344748bfb4eSStefan Weil     PrimitiveList pl = { .value = { NULL } };
345748bfb4eSStefan Weil     PrimitiveList pl_copy = { .value = { NULL } };
3468addacddSMichael Roth     PrimitiveList *pl_copy_ptr = &pl_copy;
3478addacddSMichael Roth     void *serialize_data;
3488addacddSMichael Roth     void *cur_head = NULL;
3498addacddSMichael Roth     int i;
3508addacddSMichael Roth 
3518addacddSMichael Roth     pl.type = pl_copy.type = pt->type;
3528addacddSMichael Roth 
3538addacddSMichael Roth     /* build up our list of primitive types */
3548addacddSMichael Roth     for (i = 0; i < 32; i++) {
3558addacddSMichael Roth         switch (pl.type) {
3568addacddSMichael Roth         case PTYPE_STRING: {
3578addacddSMichael Roth             strList *tmp = g_new0(strList, 1);
3588addacddSMichael Roth             tmp->value = g_strdup(pt->value.string);
3598addacddSMichael Roth             if (pl.value.strings == NULL) {
3608addacddSMichael Roth                 pl.value.strings = tmp;
3618addacddSMichael Roth             } else {
3628addacddSMichael Roth                 tmp->next = pl.value.strings;
3638addacddSMichael Roth                 pl.value.strings = tmp;
3648addacddSMichael Roth             }
3658addacddSMichael Roth             break;
3668addacddSMichael Roth         }
3678addacddSMichael Roth         case PTYPE_INTEGER: {
3688addacddSMichael Roth             intList *tmp = g_new0(intList, 1);
3698addacddSMichael Roth             tmp->value = pt->value.integer;
3708addacddSMichael Roth             if (pl.value.integers == NULL) {
3718addacddSMichael Roth                 pl.value.integers = tmp;
3728addacddSMichael Roth             } else {
3738addacddSMichael Roth                 tmp->next = pl.value.integers;
3748addacddSMichael Roth                 pl.value.integers = tmp;
3758addacddSMichael Roth             }
3768addacddSMichael Roth             break;
3778addacddSMichael Roth         }
3788addacddSMichael Roth         case PTYPE_S8: {
3798addacddSMichael Roth             int8List *tmp = g_new0(int8List, 1);
3808addacddSMichael Roth             tmp->value = pt->value.s8;
3818addacddSMichael Roth             if (pl.value.s8_integers == NULL) {
3828addacddSMichael Roth                 pl.value.s8_integers = tmp;
3838addacddSMichael Roth             } else {
3848addacddSMichael Roth                 tmp->next = pl.value.s8_integers;
3858addacddSMichael Roth                 pl.value.s8_integers = tmp;
3868addacddSMichael Roth             }
3878addacddSMichael Roth             break;
3888addacddSMichael Roth         }
3898addacddSMichael Roth         case PTYPE_S16: {
3908addacddSMichael Roth             int16List *tmp = g_new0(int16List, 1);
3918addacddSMichael Roth             tmp->value = pt->value.s16;
3928addacddSMichael Roth             if (pl.value.s16_integers == NULL) {
3938addacddSMichael Roth                 pl.value.s16_integers = tmp;
3948addacddSMichael Roth             } else {
3958addacddSMichael Roth                 tmp->next = pl.value.s16_integers;
3968addacddSMichael Roth                 pl.value.s16_integers = tmp;
3978addacddSMichael Roth             }
3988addacddSMichael Roth             break;
3998addacddSMichael Roth         }
4008addacddSMichael Roth         case PTYPE_S32: {
4018addacddSMichael Roth             int32List *tmp = g_new0(int32List, 1);
4028addacddSMichael Roth             tmp->value = pt->value.s32;
4038addacddSMichael Roth             if (pl.value.s32_integers == NULL) {
4048addacddSMichael Roth                 pl.value.s32_integers = tmp;
4058addacddSMichael Roth             } else {
4068addacddSMichael Roth                 tmp->next = pl.value.s32_integers;
4078addacddSMichael Roth                 pl.value.s32_integers = tmp;
4088addacddSMichael Roth             }
4098addacddSMichael Roth             break;
4108addacddSMichael Roth         }
4118addacddSMichael Roth         case PTYPE_S64: {
4128addacddSMichael Roth             int64List *tmp = g_new0(int64List, 1);
4138addacddSMichael Roth             tmp->value = pt->value.s64;
4148addacddSMichael Roth             if (pl.value.s64_integers == NULL) {
4158addacddSMichael Roth                 pl.value.s64_integers = tmp;
4168addacddSMichael Roth             } else {
4178addacddSMichael Roth                 tmp->next = pl.value.s64_integers;
4188addacddSMichael Roth                 pl.value.s64_integers = tmp;
4198addacddSMichael Roth             }
4208addacddSMichael Roth             break;
4218addacddSMichael Roth         }
4228addacddSMichael Roth         case PTYPE_U8: {
4238addacddSMichael Roth             uint8List *tmp = g_new0(uint8List, 1);
4248addacddSMichael Roth             tmp->value = pt->value.u8;
4258addacddSMichael Roth             if (pl.value.u8_integers == NULL) {
4268addacddSMichael Roth                 pl.value.u8_integers = tmp;
4278addacddSMichael Roth             } else {
4288addacddSMichael Roth                 tmp->next = pl.value.u8_integers;
4298addacddSMichael Roth                 pl.value.u8_integers = tmp;
4308addacddSMichael Roth             }
4318addacddSMichael Roth             break;
4328addacddSMichael Roth         }
4338addacddSMichael Roth         case PTYPE_U16: {
4348addacddSMichael Roth             uint16List *tmp = g_new0(uint16List, 1);
4358addacddSMichael Roth             tmp->value = pt->value.u16;
4368addacddSMichael Roth             if (pl.value.u16_integers == NULL) {
4378addacddSMichael Roth                 pl.value.u16_integers = tmp;
4388addacddSMichael Roth             } else {
4398addacddSMichael Roth                 tmp->next = pl.value.u16_integers;
4408addacddSMichael Roth                 pl.value.u16_integers = tmp;
4418addacddSMichael Roth             }
4428addacddSMichael Roth             break;
4438addacddSMichael Roth         }
4448addacddSMichael Roth         case PTYPE_U32: {
4458addacddSMichael Roth             uint32List *tmp = g_new0(uint32List, 1);
4468addacddSMichael Roth             tmp->value = pt->value.u32;
4478addacddSMichael Roth             if (pl.value.u32_integers == NULL) {
4488addacddSMichael Roth                 pl.value.u32_integers = tmp;
4498addacddSMichael Roth             } else {
4508addacddSMichael Roth                 tmp->next = pl.value.u32_integers;
4518addacddSMichael Roth                 pl.value.u32_integers = tmp;
4528addacddSMichael Roth             }
4538addacddSMichael Roth             break;
4548addacddSMichael Roth         }
4558addacddSMichael Roth         case PTYPE_U64: {
4568addacddSMichael Roth             uint64List *tmp = g_new0(uint64List, 1);
4578addacddSMichael Roth             tmp->value = pt->value.u64;
4588addacddSMichael Roth             if (pl.value.u64_integers == NULL) {
4598addacddSMichael Roth                 pl.value.u64_integers = tmp;
4608addacddSMichael Roth             } else {
4618addacddSMichael Roth                 tmp->next = pl.value.u64_integers;
4628addacddSMichael Roth                 pl.value.u64_integers = tmp;
4638addacddSMichael Roth             }
4648addacddSMichael Roth             break;
4658addacddSMichael Roth         }
4668addacddSMichael Roth         case PTYPE_NUMBER: {
4678addacddSMichael Roth             numberList *tmp = g_new0(numberList, 1);
4688addacddSMichael Roth             tmp->value = pt->value.number;
4698addacddSMichael Roth             if (pl.value.numbers == NULL) {
4708addacddSMichael Roth                 pl.value.numbers = tmp;
4718addacddSMichael Roth             } else {
4728addacddSMichael Roth                 tmp->next = pl.value.numbers;
4738addacddSMichael Roth                 pl.value.numbers = tmp;
4748addacddSMichael Roth             }
4758addacddSMichael Roth             break;
4768addacddSMichael Roth         }
4778addacddSMichael Roth         case PTYPE_BOOLEAN: {
4788addacddSMichael Roth             boolList *tmp = g_new0(boolList, 1);
4798addacddSMichael Roth             tmp->value = pt->value.boolean;
4808addacddSMichael Roth             if (pl.value.booleans == NULL) {
4818addacddSMichael Roth                 pl.value.booleans = tmp;
4828addacddSMichael Roth             } else {
4838addacddSMichael Roth                 tmp->next = pl.value.booleans;
4848addacddSMichael Roth                 pl.value.booleans = tmp;
4858addacddSMichael Roth             }
4868addacddSMichael Roth             break;
4878addacddSMichael Roth         }
4888addacddSMichael Roth         default:
489dfc6f865SStefan Weil             g_assert_not_reached();
4908addacddSMichael Roth         }
4918addacddSMichael Roth     }
4928addacddSMichael Roth 
4933f66f764SEric Blake     ops->serialize((void **)&pl, &serialize_data, visit_primitive_list,
4943f66f764SEric Blake                    &error_abort);
4953f66f764SEric Blake     ops->deserialize((void **)&pl_copy_ptr, serialize_data,
4963f66f764SEric Blake                      visit_primitive_list, &error_abort);
4978addacddSMichael Roth 
4988addacddSMichael Roth     i = 0;
4998addacddSMichael Roth 
5008addacddSMichael Roth     /* compare our deserialized list of primitives to the original */
5018addacddSMichael Roth     do {
5028addacddSMichael Roth         switch (pl_copy.type) {
5038addacddSMichael Roth         case PTYPE_STRING: {
5048addacddSMichael Roth             strList *ptr;
5058addacddSMichael Roth             if (cur_head) {
5068addacddSMichael Roth                 ptr = cur_head;
5078addacddSMichael Roth                 cur_head = ptr->next;
5088addacddSMichael Roth             } else {
5098addacddSMichael Roth                 cur_head = ptr = pl_copy.value.strings;
5108addacddSMichael Roth             }
5118addacddSMichael Roth             g_assert_cmpstr(pt->value.string, ==, ptr->value);
5128addacddSMichael Roth             break;
5138addacddSMichael Roth         }
5148addacddSMichael Roth         case PTYPE_INTEGER: {
5158addacddSMichael Roth             intList *ptr;
5168addacddSMichael Roth             if (cur_head) {
5178addacddSMichael Roth                 ptr = cur_head;
5188addacddSMichael Roth                 cur_head = ptr->next;
5198addacddSMichael Roth             } else {
5208addacddSMichael Roth                 cur_head = ptr = pl_copy.value.integers;
5218addacddSMichael Roth             }
5228addacddSMichael Roth             g_assert_cmpint(pt->value.integer, ==, ptr->value);
5238addacddSMichael Roth             break;
5248addacddSMichael Roth         }
5258addacddSMichael Roth         case PTYPE_S8: {
5268addacddSMichael Roth             int8List *ptr;
5278addacddSMichael Roth             if (cur_head) {
5288addacddSMichael Roth                 ptr = cur_head;
5298addacddSMichael Roth                 cur_head = ptr->next;
5308addacddSMichael Roth             } else {
5318addacddSMichael Roth                 cur_head = ptr = pl_copy.value.s8_integers;
5328addacddSMichael Roth             }
5338addacddSMichael Roth             g_assert_cmpint(pt->value.s8, ==, ptr->value);
5348addacddSMichael Roth             break;
5358addacddSMichael Roth         }
5368addacddSMichael Roth         case PTYPE_S16: {
5378addacddSMichael Roth             int16List *ptr;
5388addacddSMichael Roth             if (cur_head) {
5398addacddSMichael Roth                 ptr = cur_head;
5408addacddSMichael Roth                 cur_head = ptr->next;
5418addacddSMichael Roth             } else {
5428addacddSMichael Roth                 cur_head = ptr = pl_copy.value.s16_integers;
5438addacddSMichael Roth             }
5448addacddSMichael Roth             g_assert_cmpint(pt->value.s16, ==, ptr->value);
5458addacddSMichael Roth             break;
5468addacddSMichael Roth         }
5478addacddSMichael Roth         case PTYPE_S32: {
5488addacddSMichael Roth             int32List *ptr;
5498addacddSMichael Roth             if (cur_head) {
5508addacddSMichael Roth                 ptr = cur_head;
5518addacddSMichael Roth                 cur_head = ptr->next;
5528addacddSMichael Roth             } else {
5538addacddSMichael Roth                 cur_head = ptr = pl_copy.value.s32_integers;
5548addacddSMichael Roth             }
5558addacddSMichael Roth             g_assert_cmpint(pt->value.s32, ==, ptr->value);
5568addacddSMichael Roth             break;
5578addacddSMichael Roth         }
5588addacddSMichael Roth         case PTYPE_S64: {
5598addacddSMichael Roth             int64List *ptr;
5608addacddSMichael Roth             if (cur_head) {
5618addacddSMichael Roth                 ptr = cur_head;
5628addacddSMichael Roth                 cur_head = ptr->next;
5638addacddSMichael Roth             } else {
5648addacddSMichael Roth                 cur_head = ptr = pl_copy.value.s64_integers;
5658addacddSMichael Roth             }
5668addacddSMichael Roth             g_assert_cmpint(pt->value.s64, ==, ptr->value);
5678addacddSMichael Roth             break;
5688addacddSMichael Roth         }
5698addacddSMichael Roth         case PTYPE_U8: {
5708addacddSMichael Roth             uint8List *ptr;
5718addacddSMichael Roth             if (cur_head) {
5728addacddSMichael Roth                 ptr = cur_head;
5738addacddSMichael Roth                 cur_head = ptr->next;
5748addacddSMichael Roth             } else {
5758addacddSMichael Roth                 cur_head = ptr = pl_copy.value.u8_integers;
5768addacddSMichael Roth             }
5778addacddSMichael Roth             g_assert_cmpint(pt->value.u8, ==, ptr->value);
5788addacddSMichael Roth             break;
5798addacddSMichael Roth         }
5808addacddSMichael Roth         case PTYPE_U16: {
5818addacddSMichael Roth             uint16List *ptr;
5828addacddSMichael Roth             if (cur_head) {
5838addacddSMichael Roth                 ptr = cur_head;
5848addacddSMichael Roth                 cur_head = ptr->next;
5858addacddSMichael Roth             } else {
5868addacddSMichael Roth                 cur_head = ptr = pl_copy.value.u16_integers;
5878addacddSMichael Roth             }
5888addacddSMichael Roth             g_assert_cmpint(pt->value.u16, ==, ptr->value);
5898addacddSMichael Roth             break;
5908addacddSMichael Roth         }
5918addacddSMichael Roth         case PTYPE_U32: {
5928addacddSMichael Roth             uint32List *ptr;
5938addacddSMichael Roth             if (cur_head) {
5948addacddSMichael Roth                 ptr = cur_head;
5958addacddSMichael Roth                 cur_head = ptr->next;
5968addacddSMichael Roth             } else {
5978addacddSMichael Roth                 cur_head = ptr = pl_copy.value.u32_integers;
5988addacddSMichael Roth             }
5998addacddSMichael Roth             g_assert_cmpint(pt->value.u32, ==, ptr->value);
6008addacddSMichael Roth             break;
6018addacddSMichael Roth         }
6028addacddSMichael Roth         case PTYPE_U64: {
6038addacddSMichael Roth             uint64List *ptr;
6048addacddSMichael Roth             if (cur_head) {
6058addacddSMichael Roth                 ptr = cur_head;
6068addacddSMichael Roth                 cur_head = ptr->next;
6078addacddSMichael Roth             } else {
6088addacddSMichael Roth                 cur_head = ptr = pl_copy.value.u64_integers;
6098addacddSMichael Roth             }
6108addacddSMichael Roth             g_assert_cmpint(pt->value.u64, ==, ptr->value);
6118addacddSMichael Roth             break;
6128addacddSMichael Roth         }
6138addacddSMichael Roth         case PTYPE_NUMBER: {
6148addacddSMichael Roth             numberList *ptr;
6158addacddSMichael Roth             GString *double_expected = g_string_new("");
6168addacddSMichael Roth             GString *double_actual = g_string_new("");
6178addacddSMichael Roth             if (cur_head) {
6188addacddSMichael Roth                 ptr = cur_head;
6198addacddSMichael Roth                 cur_head = ptr->next;
6208addacddSMichael Roth             } else {
6218addacddSMichael Roth                 cur_head = ptr = pl_copy.value.numbers;
6228addacddSMichael Roth             }
6238addacddSMichael Roth             /* we serialize with %f for our reference visitors, so rather than
6248addacddSMichael Roth              * fuzzy floating math to test "equality", just compare the
6258addacddSMichael Roth              * formatted values
6268addacddSMichael Roth              */
6278addacddSMichael Roth             g_string_printf(double_expected, "%.6f", pt->value.number);
6288addacddSMichael Roth             g_string_printf(double_actual, "%.6f", ptr->value);
6298addacddSMichael Roth             g_assert_cmpstr(double_actual->str, ==, double_expected->str);
6308addacddSMichael Roth             g_string_free(double_expected, true);
6318addacddSMichael Roth             g_string_free(double_actual, true);
6328addacddSMichael Roth             break;
6338addacddSMichael Roth         }
6348addacddSMichael Roth         case PTYPE_BOOLEAN: {
6358addacddSMichael Roth             boolList *ptr;
6368addacddSMichael Roth             if (cur_head) {
6378addacddSMichael Roth                 ptr = cur_head;
6388addacddSMichael Roth                 cur_head = ptr->next;
6398addacddSMichael Roth             } else {
6408addacddSMichael Roth                 cur_head = ptr = pl_copy.value.booleans;
6418addacddSMichael Roth             }
6428addacddSMichael Roth             g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
6438addacddSMichael Roth             break;
6448addacddSMichael Roth         }
6458addacddSMichael Roth         default:
646dfc6f865SStefan Weil             g_assert_not_reached();
6478addacddSMichael Roth         }
6488addacddSMichael Roth         i++;
6498addacddSMichael Roth     } while (cur_head);
6508addacddSMichael Roth 
6518addacddSMichael Roth     g_assert_cmpint(i, ==, 33);
6528addacddSMichael Roth 
6538addacddSMichael Roth     ops->cleanup(serialize_data);
6543f66f764SEric Blake     dealloc_helper(&pl, visit_primitive_list, &error_abort);
6553f66f764SEric Blake     dealloc_helper(&pl_copy, visit_primitive_list, &error_abort);
6568addacddSMichael Roth     g_free(args);
6578addacddSMichael Roth }
6588addacddSMichael Roth 
6592d496105SMichael Roth static void test_struct(gconstpointer opaque)
6602d496105SMichael Roth {
6612d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
6622d496105SMichael Roth     const SerializeOps *ops = args->ops;
6632d496105SMichael Roth     TestStruct *ts = struct_create();
6642d496105SMichael Roth     TestStruct *ts_copy = NULL;
6652d496105SMichael Roth     void *serialize_data;
6662d496105SMichael Roth 
6673f66f764SEric Blake     ops->serialize(ts, &serialize_data, visit_struct, &error_abort);
6683f66f764SEric Blake     ops->deserialize((void **)&ts_copy, serialize_data, visit_struct,
6693f66f764SEric Blake                      &error_abort);
6702d496105SMichael Roth 
6712d496105SMichael Roth     struct_compare(ts, ts_copy);
6722d496105SMichael Roth 
6732d496105SMichael Roth     struct_cleanup(ts);
6742d496105SMichael Roth     struct_cleanup(ts_copy);
6752d496105SMichael Roth 
6762d496105SMichael Roth     ops->cleanup(serialize_data);
6772d496105SMichael Roth     g_free(args);
6782d496105SMichael Roth }
6792d496105SMichael Roth 
6802d496105SMichael Roth static void test_nested_struct(gconstpointer opaque)
6812d496105SMichael Roth {
6822d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
6832d496105SMichael Roth     const SerializeOps *ops = args->ops;
684b6fcf32dSEric Blake     UserDefTwo *udnp = nested_struct_create();
685b6fcf32dSEric Blake     UserDefTwo *udnp_copy = NULL;
6862d496105SMichael Roth     void *serialize_data;
6872d496105SMichael Roth 
6883f66f764SEric Blake     ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort);
689b6fcf32dSEric Blake     ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct,
6903f66f764SEric Blake                      &error_abort);
6912d496105SMichael Roth 
6922d496105SMichael Roth     nested_struct_compare(udnp, udnp_copy);
6932d496105SMichael Roth 
6942d496105SMichael Roth     nested_struct_cleanup(udnp);
6952d496105SMichael Roth     nested_struct_cleanup(udnp_copy);
6962d496105SMichael Roth 
6972d496105SMichael Roth     ops->cleanup(serialize_data);
6982d496105SMichael Roth     g_free(args);
6992d496105SMichael Roth }
7002d496105SMichael Roth 
7012d496105SMichael Roth static void test_nested_struct_list(gconstpointer opaque)
7022d496105SMichael Roth {
7032d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
7042d496105SMichael Roth     const SerializeOps *ops = args->ops;
705b6fcf32dSEric Blake     UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL;
7062d496105SMichael Roth     void *serialize_data;
7072d496105SMichael Roth     int i = 0;
7082d496105SMichael Roth 
7092d496105SMichael Roth     for (i = 0; i < 8; i++) {
710b6fcf32dSEric Blake         tmp = g_new0(UserDefTwoList, 1);
7112d496105SMichael Roth         tmp->value = nested_struct_create();
7122d496105SMichael Roth         tmp->next = listp;
7132d496105SMichael Roth         listp = tmp;
7142d496105SMichael Roth     }
7152d496105SMichael Roth 
7163f66f764SEric Blake     ops->serialize(listp, &serialize_data, visit_nested_struct_list,
7173f66f764SEric Blake                    &error_abort);
7182d496105SMichael Roth     ops->deserialize((void **)&listp_copy, serialize_data,
7193f66f764SEric Blake                      visit_nested_struct_list, &error_abort);
7202d496105SMichael Roth 
7212d496105SMichael Roth     tmp = listp;
7222d496105SMichael Roth     tmp_copy = listp_copy;
7232d496105SMichael Roth     while (listp_copy) {
7242d496105SMichael Roth         g_assert(listp);
7252d496105SMichael Roth         nested_struct_compare(listp->value, listp_copy->value);
7262d496105SMichael Roth         listp = listp->next;
7272d496105SMichael Roth         listp_copy = listp_copy->next;
7282d496105SMichael Roth     }
7292d496105SMichael Roth 
730b6fcf32dSEric Blake     qapi_free_UserDefTwoList(tmp);
731b6fcf32dSEric Blake     qapi_free_UserDefTwoList(tmp_copy);
7322d496105SMichael Roth 
7332d496105SMichael Roth     ops->cleanup(serialize_data);
7342d496105SMichael Roth     g_free(args);
7352d496105SMichael Roth }
7362d496105SMichael Roth 
737748bfb4eSStefan Weil static PrimitiveType pt_values[] = {
7382d496105SMichael Roth     /* string tests */
7392d496105SMichael Roth     {
7402d496105SMichael Roth         .description = "string_empty",
7412d496105SMichael Roth         .type = PTYPE_STRING,
7422d496105SMichael Roth         .value.string = "",
7432d496105SMichael Roth     },
7442d496105SMichael Roth     {
7452d496105SMichael Roth         .description = "string_whitespace",
7462d496105SMichael Roth         .type = PTYPE_STRING,
7472d496105SMichael Roth         .value.string = "a b  c\td",
7482d496105SMichael Roth     },
7492d496105SMichael Roth     {
7502d496105SMichael Roth         .description = "string_newlines",
7512d496105SMichael Roth         .type = PTYPE_STRING,
7522d496105SMichael Roth         .value.string = "a\nb\n",
7532d496105SMichael Roth     },
7542d496105SMichael Roth     {
7552d496105SMichael Roth         .description = "string_commas",
7562d496105SMichael Roth         .type = PTYPE_STRING,
7572d496105SMichael Roth         .value.string = "a,b, c,d",
7582d496105SMichael Roth     },
7592d496105SMichael Roth     {
7602d496105SMichael Roth         .description = "string_single_quoted",
7612d496105SMichael Roth         .type = PTYPE_STRING,
7622d496105SMichael Roth         .value.string = "'a b',cd",
7632d496105SMichael Roth     },
7642d496105SMichael Roth     {
7652d496105SMichael Roth         .description = "string_double_quoted",
7662d496105SMichael Roth         .type = PTYPE_STRING,
7672d496105SMichael Roth         .value.string = "\"a b\",cd",
7682d496105SMichael Roth     },
7692d496105SMichael Roth     /* boolean tests */
7702d496105SMichael Roth     {
7712d496105SMichael Roth         .description = "boolean_true1",
7722d496105SMichael Roth         .type = PTYPE_BOOLEAN,
7732d496105SMichael Roth         .value.boolean = true,
7742d496105SMichael Roth     },
7752d496105SMichael Roth     {
7762d496105SMichael Roth         .description = "boolean_true2",
7772d496105SMichael Roth         .type = PTYPE_BOOLEAN,
7782d496105SMichael Roth         .value.boolean = 8,
7792d496105SMichael Roth     },
7802d496105SMichael Roth     {
7812d496105SMichael Roth         .description = "boolean_true3",
7822d496105SMichael Roth         .type = PTYPE_BOOLEAN,
7832d496105SMichael Roth         .value.boolean = -1,
7842d496105SMichael Roth     },
7852d496105SMichael Roth     {
7862d496105SMichael Roth         .description = "boolean_false1",
7872d496105SMichael Roth         .type = PTYPE_BOOLEAN,
7882d496105SMichael Roth         .value.boolean = false,
7892d496105SMichael Roth     },
7902d496105SMichael Roth     {
7912d496105SMichael Roth         .description = "boolean_false2",
7922d496105SMichael Roth         .type = PTYPE_BOOLEAN,
7932d496105SMichael Roth         .value.boolean = 0,
7942d496105SMichael Roth     },
7952d496105SMichael Roth     /* number tests (double) */
7962d496105SMichael Roth     /* note: we format these to %.6f before comparing, since that's how
7972d496105SMichael Roth      * we serialize them and it doesn't make sense to check precision
7982d496105SMichael Roth      * beyond that.
7992d496105SMichael Roth      */
8002d496105SMichael Roth     {
8012d496105SMichael Roth         .description = "number_sanity1",
8022d496105SMichael Roth         .type = PTYPE_NUMBER,
8032d496105SMichael Roth         .value.number = -1,
8042d496105SMichael Roth     },
8052d496105SMichael Roth     {
8062d496105SMichael Roth         .description = "number_sanity2",
8072d496105SMichael Roth         .type = PTYPE_NUMBER,
8082d496105SMichael Roth         .value.number = 3.14159265,
8092d496105SMichael Roth     },
8102d496105SMichael Roth     {
8112d496105SMichael Roth         .description = "number_min",
8122d496105SMichael Roth         .type = PTYPE_NUMBER,
8132d496105SMichael Roth         .value.number = DBL_MIN,
8142d496105SMichael Roth     },
8152d496105SMichael Roth     {
8162d496105SMichael Roth         .description = "number_max",
8172d496105SMichael Roth         .type = PTYPE_NUMBER,
8182d496105SMichael Roth         .value.number = DBL_MAX,
8192d496105SMichael Roth     },
8202d496105SMichael Roth     /* integer tests (int64) */
8212d496105SMichael Roth     {
8222d496105SMichael Roth         .description = "integer_sanity1",
8232d496105SMichael Roth         .type = PTYPE_INTEGER,
8242d496105SMichael Roth         .value.integer = -1,
8252d496105SMichael Roth     },
8262d496105SMichael Roth     {
8272d496105SMichael Roth         .description = "integer_sanity2",
8282d496105SMichael Roth         .type = PTYPE_INTEGER,
8292d496105SMichael Roth         .value.integer = INT64_MAX / 2 + 1,
8302d496105SMichael Roth     },
8312d496105SMichael Roth     {
8322d496105SMichael Roth         .description = "integer_min",
8332d496105SMichael Roth         .type = PTYPE_INTEGER,
8342d496105SMichael Roth         .value.integer = INT64_MIN,
8352d496105SMichael Roth     },
8362d496105SMichael Roth     {
8372d496105SMichael Roth         .description = "integer_max",
8382d496105SMichael Roth         .type = PTYPE_INTEGER,
8392d496105SMichael Roth         .value.integer = INT64_MAX,
8402d496105SMichael Roth     },
8412d496105SMichael Roth     /* uint8 tests */
8422d496105SMichael Roth     {
8432d496105SMichael Roth         .description = "uint8_sanity1",
8442d496105SMichael Roth         .type = PTYPE_U8,
8452d496105SMichael Roth         .value.u8 = 1,
8462d496105SMichael Roth     },
8472d496105SMichael Roth     {
8482d496105SMichael Roth         .description = "uint8_sanity2",
8492d496105SMichael Roth         .type = PTYPE_U8,
8502d496105SMichael Roth         .value.u8 = UINT8_MAX / 2 + 1,
8512d496105SMichael Roth     },
8522d496105SMichael Roth     {
8532d496105SMichael Roth         .description = "uint8_min",
8542d496105SMichael Roth         .type = PTYPE_U8,
8552d496105SMichael Roth         .value.u8 = 0,
8562d496105SMichael Roth     },
8572d496105SMichael Roth     {
8582d496105SMichael Roth         .description = "uint8_max",
8592d496105SMichael Roth         .type = PTYPE_U8,
8602d496105SMichael Roth         .value.u8 = UINT8_MAX,
8612d496105SMichael Roth     },
8622d496105SMichael Roth     /* uint16 tests */
8632d496105SMichael Roth     {
8642d496105SMichael Roth         .description = "uint16_sanity1",
8652d496105SMichael Roth         .type = PTYPE_U16,
8662d496105SMichael Roth         .value.u16 = 1,
8672d496105SMichael Roth     },
8682d496105SMichael Roth     {
8692d496105SMichael Roth         .description = "uint16_sanity2",
8702d496105SMichael Roth         .type = PTYPE_U16,
8712d496105SMichael Roth         .value.u16 = UINT16_MAX / 2 + 1,
8722d496105SMichael Roth     },
8732d496105SMichael Roth     {
8742d496105SMichael Roth         .description = "uint16_min",
8752d496105SMichael Roth         .type = PTYPE_U16,
8762d496105SMichael Roth         .value.u16 = 0,
8772d496105SMichael Roth     },
8782d496105SMichael Roth     {
8792d496105SMichael Roth         .description = "uint16_max",
8802d496105SMichael Roth         .type = PTYPE_U16,
8812d496105SMichael Roth         .value.u16 = UINT16_MAX,
8822d496105SMichael Roth     },
8832d496105SMichael Roth     /* uint32 tests */
8842d496105SMichael Roth     {
8852d496105SMichael Roth         .description = "uint32_sanity1",
8862d496105SMichael Roth         .type = PTYPE_U32,
8872d496105SMichael Roth         .value.u32 = 1,
8882d496105SMichael Roth     },
8892d496105SMichael Roth     {
8902d496105SMichael Roth         .description = "uint32_sanity2",
8912d496105SMichael Roth         .type = PTYPE_U32,
8922d496105SMichael Roth         .value.u32 = UINT32_MAX / 2 + 1,
8932d496105SMichael Roth     },
8942d496105SMichael Roth     {
8952d496105SMichael Roth         .description = "uint32_min",
8962d496105SMichael Roth         .type = PTYPE_U32,
8972d496105SMichael Roth         .value.u32 = 0,
8982d496105SMichael Roth     },
8992d496105SMichael Roth     {
9002d496105SMichael Roth         .description = "uint32_max",
9012d496105SMichael Roth         .type = PTYPE_U32,
9022d496105SMichael Roth         .value.u32 = UINT32_MAX,
9032d496105SMichael Roth     },
9042d496105SMichael Roth     /* uint64 tests */
9052d496105SMichael Roth     {
9062d496105SMichael Roth         .description = "uint64_sanity1",
9072d496105SMichael Roth         .type = PTYPE_U64,
9082d496105SMichael Roth         .value.u64 = 1,
9092d496105SMichael Roth     },
9102d496105SMichael Roth     {
9112d496105SMichael Roth         .description = "uint64_sanity2",
9122d496105SMichael Roth         .type = PTYPE_U64,
9132d496105SMichael Roth         .value.u64 = UINT64_MAX / 2 + 1,
9142d496105SMichael Roth     },
9152d496105SMichael Roth     {
9162d496105SMichael Roth         .description = "uint64_min",
9172d496105SMichael Roth         .type = PTYPE_U64,
9182d496105SMichael Roth         .value.u64 = 0,
9192d496105SMichael Roth     },
9202d496105SMichael Roth     {
9212d496105SMichael Roth         .description = "uint64_max",
9222d496105SMichael Roth         .type = PTYPE_U64,
9232d496105SMichael Roth         .value.u64 = UINT64_MAX,
9242d496105SMichael Roth     },
9252d496105SMichael Roth     /* int8 tests */
9262d496105SMichael Roth     {
9272d496105SMichael Roth         .description = "int8_sanity1",
9282d496105SMichael Roth         .type = PTYPE_S8,
9292d496105SMichael Roth         .value.s8 = -1,
9302d496105SMichael Roth     },
9312d496105SMichael Roth     {
9322d496105SMichael Roth         .description = "int8_sanity2",
9332d496105SMichael Roth         .type = PTYPE_S8,
9342d496105SMichael Roth         .value.s8 = INT8_MAX / 2 + 1,
9352d496105SMichael Roth     },
9362d496105SMichael Roth     {
9372d496105SMichael Roth         .description = "int8_min",
9382d496105SMichael Roth         .type = PTYPE_S8,
9392d496105SMichael Roth         .value.s8 = INT8_MIN,
9402d496105SMichael Roth     },
9412d496105SMichael Roth     {
9422d496105SMichael Roth         .description = "int8_max",
9432d496105SMichael Roth         .type = PTYPE_S8,
9442d496105SMichael Roth         .value.s8 = INT8_MAX,
9452d496105SMichael Roth     },
9462d496105SMichael Roth     /* int16 tests */
9472d496105SMichael Roth     {
9482d496105SMichael Roth         .description = "int16_sanity1",
9492d496105SMichael Roth         .type = PTYPE_S16,
9502d496105SMichael Roth         .value.s16 = -1,
9512d496105SMichael Roth     },
9522d496105SMichael Roth     {
9532d496105SMichael Roth         .description = "int16_sanity2",
9542d496105SMichael Roth         .type = PTYPE_S16,
9552d496105SMichael Roth         .value.s16 = INT16_MAX / 2 + 1,
9562d496105SMichael Roth     },
9572d496105SMichael Roth     {
9582d496105SMichael Roth         .description = "int16_min",
9592d496105SMichael Roth         .type = PTYPE_S16,
9602d496105SMichael Roth         .value.s16 = INT16_MIN,
9612d496105SMichael Roth     },
9622d496105SMichael Roth     {
9632d496105SMichael Roth         .description = "int16_max",
9642d496105SMichael Roth         .type = PTYPE_S16,
9652d496105SMichael Roth         .value.s16 = INT16_MAX,
9662d496105SMichael Roth     },
9672d496105SMichael Roth     /* int32 tests */
9682d496105SMichael Roth     {
9692d496105SMichael Roth         .description = "int32_sanity1",
9702d496105SMichael Roth         .type = PTYPE_S32,
9712d496105SMichael Roth         .value.s32 = -1,
9722d496105SMichael Roth     },
9732d496105SMichael Roth     {
9742d496105SMichael Roth         .description = "int32_sanity2",
9752d496105SMichael Roth         .type = PTYPE_S32,
9762d496105SMichael Roth         .value.s32 = INT32_MAX / 2 + 1,
9772d496105SMichael Roth     },
9782d496105SMichael Roth     {
9792d496105SMichael Roth         .description = "int32_min",
9802d496105SMichael Roth         .type = PTYPE_S32,
9812d496105SMichael Roth         .value.s32 = INT32_MIN,
9822d496105SMichael Roth     },
9832d496105SMichael Roth     {
9842d496105SMichael Roth         .description = "int32_max",
9852d496105SMichael Roth         .type = PTYPE_S32,
9862d496105SMichael Roth         .value.s32 = INT32_MAX,
9872d496105SMichael Roth     },
9882d496105SMichael Roth     /* int64 tests */
9892d496105SMichael Roth     {
9902d496105SMichael Roth         .description = "int64_sanity1",
9912d496105SMichael Roth         .type = PTYPE_S64,
9922d496105SMichael Roth         .value.s64 = -1,
9932d496105SMichael Roth     },
9942d496105SMichael Roth     {
9952d496105SMichael Roth         .description = "int64_sanity2",
9962d496105SMichael Roth         .type = PTYPE_S64,
9972d496105SMichael Roth         .value.s64 = INT64_MAX / 2 + 1,
9982d496105SMichael Roth     },
9992d496105SMichael Roth     {
10002d496105SMichael Roth         .description = "int64_min",
10012d496105SMichael Roth         .type = PTYPE_S64,
10022d496105SMichael Roth         .value.s64 = INT64_MIN,
10032d496105SMichael Roth     },
10042d496105SMichael Roth     {
10052d496105SMichael Roth         .description = "int64_max",
10062d496105SMichael Roth         .type = PTYPE_S64,
10072d496105SMichael Roth         .value.s64 = INT64_MAX,
10082d496105SMichael Roth     },
10092d496105SMichael Roth     { .type = PTYPE_EOL }
10102d496105SMichael Roth };
10112d496105SMichael Roth 
10122d496105SMichael Roth /* visitor-specific op implementations */
10132d496105SMichael Roth 
10142d496105SMichael Roth typedef struct QmpSerializeData {
1015*3b098d56SEric Blake     Visitor *qov;
1016*3b098d56SEric Blake     QObject *obj;
1017b70ce101SEric Blake     Visitor *qiv;
10182d496105SMichael Roth } QmpSerializeData;
10192d496105SMichael Roth 
10202d496105SMichael Roth static void qmp_serialize(void *native_in, void **datap,
10212d496105SMichael Roth                           VisitorFunc visit, Error **errp)
10222d496105SMichael Roth {
10232d496105SMichael Roth     QmpSerializeData *d = g_malloc0(sizeof(*d));
10242d496105SMichael Roth 
1025*3b098d56SEric Blake     d->qov = qmp_output_visitor_new(&d->obj);
1026*3b098d56SEric Blake     visit(d->qov, &native_in, errp);
10272d496105SMichael Roth     *datap = d;
10282d496105SMichael Roth }
10292d496105SMichael Roth 
10302d496105SMichael Roth static void qmp_deserialize(void **native_out, void *datap,
10312d496105SMichael Roth                             VisitorFunc visit, Error **errp)
10322d496105SMichael Roth {
10332d496105SMichael Roth     QmpSerializeData *d = datap;
1034ad7f375dSMichael Roth     QString *output_json;
1035ad7f375dSMichael Roth     QObject *obj_orig, *obj;
1036ad7f375dSMichael Roth 
1037*3b098d56SEric Blake     visit_complete(d->qov, &d->obj);
1038*3b098d56SEric Blake     obj_orig = d->obj;
1039ad7f375dSMichael Roth     output_json = qobject_to_json(obj_orig);
1040ad7f375dSMichael Roth     obj = qobject_from_json(qstring_get_str(output_json));
10412d496105SMichael Roth 
10422d496105SMichael Roth     QDECREF(output_json);
1043240f64b6SEric Blake     d->qiv = qmp_input_visitor_new(obj, true);
1044ad7f375dSMichael Roth     qobject_decref(obj_orig);
10452bd01ac1SStefan Berger     qobject_decref(obj);
1046b70ce101SEric Blake     visit(d->qiv, native_out, errp);
10472d496105SMichael Roth }
10482d496105SMichael Roth 
10492d496105SMichael Roth static void qmp_cleanup(void *datap)
10502d496105SMichael Roth {
10512d496105SMichael Roth     QmpSerializeData *d = datap;
1052*3b098d56SEric Blake     visit_free(d->qov);
1053b70ce101SEric Blake     visit_free(d->qiv);
10542bd01ac1SStefan Berger 
10552bd01ac1SStefan Berger     g_free(d);
10562d496105SMichael Roth }
10572d496105SMichael Roth 
10580d30b0a2SMichael Roth typedef struct StringSerializeData {
10592bd01ac1SStefan Berger     char *string;
1060*3b098d56SEric Blake     Visitor *sov;
10617a0525c7SEric Blake     Visitor *siv;
10620d30b0a2SMichael Roth } StringSerializeData;
10630d30b0a2SMichael Roth 
10640d30b0a2SMichael Roth static void string_serialize(void *native_in, void **datap,
10650d30b0a2SMichael Roth                              VisitorFunc visit, Error **errp)
10660d30b0a2SMichael Roth {
10670d30b0a2SMichael Roth     StringSerializeData *d = g_malloc0(sizeof(*d));
10680d30b0a2SMichael Roth 
1069*3b098d56SEric Blake     d->sov = string_output_visitor_new(false, &d->string);
1070*3b098d56SEric Blake     visit(d->sov, &native_in, errp);
10710d30b0a2SMichael Roth     *datap = d;
10720d30b0a2SMichael Roth }
10730d30b0a2SMichael Roth 
10740d30b0a2SMichael Roth static void string_deserialize(void **native_out, void *datap,
10750d30b0a2SMichael Roth                                VisitorFunc visit, Error **errp)
10760d30b0a2SMichael Roth {
10770d30b0a2SMichael Roth     StringSerializeData *d = datap;
10780d30b0a2SMichael Roth 
1079*3b098d56SEric Blake     visit_complete(d->sov, &d->string);
10802bd01ac1SStefan Berger     d->siv = string_input_visitor_new(d->string);
10817a0525c7SEric Blake     visit(d->siv, native_out, errp);
10820d30b0a2SMichael Roth }
10830d30b0a2SMichael Roth 
10840d30b0a2SMichael Roth static void string_cleanup(void *datap)
10850d30b0a2SMichael Roth {
10860d30b0a2SMichael Roth     StringSerializeData *d = datap;
10872bd01ac1SStefan Berger 
1088*3b098d56SEric Blake     visit_free(d->sov);
10897a0525c7SEric Blake     visit_free(d->siv);
10902bd01ac1SStefan Berger     g_free(d->string);
10912bd01ac1SStefan Berger     g_free(d);
10920d30b0a2SMichael Roth }
10930d30b0a2SMichael Roth 
10942d496105SMichael Roth /* visitor registration, test harness */
10952d496105SMichael Roth 
10962d496105SMichael Roth /* note: to function interchangeably as a serialization mechanism your
10972d496105SMichael Roth  * visitor test implementation should pass the test cases for all visitor
10982d496105SMichael Roth  * capabilities: primitives, structures, and lists
10992d496105SMichael Roth  */
11002d496105SMichael Roth static const SerializeOps visitors[] = {
11012d496105SMichael Roth     {
11022d496105SMichael Roth         .type = "QMP",
11032d496105SMichael Roth         .serialize = qmp_serialize,
11042d496105SMichael Roth         .deserialize = qmp_deserialize,
11052d496105SMichael Roth         .cleanup = qmp_cleanup,
11068addacddSMichael Roth         .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
11078addacddSMichael Roth                 VCAP_PRIMITIVE_LISTS
11082d496105SMichael Roth     },
11090d30b0a2SMichael Roth     {
11100d30b0a2SMichael Roth         .type = "String",
11110d30b0a2SMichael Roth         .serialize = string_serialize,
11120d30b0a2SMichael Roth         .deserialize = string_deserialize,
11130d30b0a2SMichael Roth         .cleanup = string_cleanup,
11140d30b0a2SMichael Roth         .caps = VCAP_PRIMITIVES
11150d30b0a2SMichael Roth     },
11162d496105SMichael Roth     { NULL }
11172d496105SMichael Roth };
11182d496105SMichael Roth 
11192d496105SMichael Roth static void add_visitor_type(const SerializeOps *ops)
11202d496105SMichael Roth {
11212d496105SMichael Roth     char testname_prefix[128];
11222d496105SMichael Roth     char testname[128];
11232d496105SMichael Roth     TestArgs *args;
11242d496105SMichael Roth     int i = 0;
11252d496105SMichael Roth 
11262d496105SMichael Roth     sprintf(testname_prefix, "/visitor/serialization/%s", ops->type);
11272d496105SMichael Roth 
11282d496105SMichael Roth     if (ops->caps & VCAP_PRIMITIVES) {
11292d496105SMichael Roth         while (pt_values[i].type != PTYPE_EOL) {
11302d496105SMichael Roth             sprintf(testname, "%s/primitives/%s", testname_prefix,
11312d496105SMichael Roth                     pt_values[i].description);
11322d496105SMichael Roth             args = g_malloc0(sizeof(*args));
11332d496105SMichael Roth             args->ops = ops;
11342d496105SMichael Roth             args->test_data = &pt_values[i];
11352d496105SMichael Roth             g_test_add_data_func(testname, args, test_primitives);
11362d496105SMichael Roth             i++;
11372d496105SMichael Roth         }
11382d496105SMichael Roth     }
11392d496105SMichael Roth 
11402d496105SMichael Roth     if (ops->caps & VCAP_STRUCTURES) {
11412d496105SMichael Roth         sprintf(testname, "%s/struct", testname_prefix);
11422d496105SMichael Roth         args = g_malloc0(sizeof(*args));
11432d496105SMichael Roth         args->ops = ops;
11442d496105SMichael Roth         args->test_data = NULL;
11452d496105SMichael Roth         g_test_add_data_func(testname, args, test_struct);
11462d496105SMichael Roth 
11472d496105SMichael Roth         sprintf(testname, "%s/nested_struct", testname_prefix);
11482d496105SMichael Roth         args = g_malloc0(sizeof(*args));
11492d496105SMichael Roth         args->ops = ops;
11502d496105SMichael Roth         args->test_data = NULL;
11512d496105SMichael Roth         g_test_add_data_func(testname, args, test_nested_struct);
11522d496105SMichael Roth     }
11532d496105SMichael Roth 
11542d496105SMichael Roth     if (ops->caps & VCAP_LISTS) {
11552d496105SMichael Roth         sprintf(testname, "%s/nested_struct_list", testname_prefix);
11562d496105SMichael Roth         args = g_malloc0(sizeof(*args));
11572d496105SMichael Roth         args->ops = ops;
11582d496105SMichael Roth         args->test_data = NULL;
11592d496105SMichael Roth         g_test_add_data_func(testname, args, test_nested_struct_list);
11602d496105SMichael Roth     }
11618addacddSMichael Roth 
11628addacddSMichael Roth     if (ops->caps & VCAP_PRIMITIVE_LISTS) {
11638addacddSMichael Roth         i = 0;
11648addacddSMichael Roth         while (pt_values[i].type != PTYPE_EOL) {
11658addacddSMichael Roth             sprintf(testname, "%s/primitive_list/%s", testname_prefix,
11668addacddSMichael Roth                     pt_values[i].description);
11678addacddSMichael Roth             args = g_malloc0(sizeof(*args));
11688addacddSMichael Roth             args->ops = ops;
11698addacddSMichael Roth             args->test_data = &pt_values[i];
11708addacddSMichael Roth             g_test_add_data_func(testname, args, test_primitive_lists);
11718addacddSMichael Roth             i++;
11728addacddSMichael Roth         }
11738addacddSMichael Roth     }
11742d496105SMichael Roth }
11752d496105SMichael Roth 
11762d496105SMichael Roth int main(int argc, char **argv)
11772d496105SMichael Roth {
11782d496105SMichael Roth     int i = 0;
11792d496105SMichael Roth 
11802d496105SMichael Roth     g_test_init(&argc, &argv, NULL);
11812d496105SMichael Roth 
11822d496105SMichael Roth     while (visitors[i].type != NULL) {
11832d496105SMichael Roth         add_visitor_type(&visitors[i]);
11842d496105SMichael Roth         i++;
11852d496105SMichael Roth     }
11862d496105SMichael Roth 
11872d496105SMichael Roth     g_test_run();
11882d496105SMichael Roth 
11892d496105SMichael Roth     return 0;
11902d496105SMichael Roth }
1191