xref: /qemu/tests/unit/test-visitor-serialization.c (revision 2a02c1398a47e75aa6963baf7dbfa68a54dc2e41)
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-visit.h"
19da34e65cSMarkus Armbruster #include "qapi/error.h"
20c7eb39cbSEric Blake #include "qapi/qmp/qjson.h"
21fc81fa1eSMarkus Armbruster #include "qapi/qmp/qstring.h"
22b3db211fSDaniel P. Berrange #include "qapi/qobject-input-visitor.h"
23b3db211fSDaniel P. Berrange #include "qapi/qobject-output-visitor.h"
240d30b0a2SMichael Roth #include "qapi/string-input-visitor.h"
250d30b0a2SMichael Roth #include "qapi/string-output-visitor.h"
268addacddSMichael Roth #include "qapi/dealloc-visitor.h"
278addacddSMichael Roth 
288addacddSMichael Roth enum PrimitiveTypeKind {
298addacddSMichael Roth     PTYPE_STRING = 0,
308addacddSMichael Roth     PTYPE_BOOLEAN,
318addacddSMichael Roth     PTYPE_NUMBER,
328addacddSMichael Roth     PTYPE_INTEGER,
338addacddSMichael Roth     PTYPE_U8,
348addacddSMichael Roth     PTYPE_U16,
358addacddSMichael Roth     PTYPE_U32,
368addacddSMichael Roth     PTYPE_U64,
378addacddSMichael Roth     PTYPE_S8,
388addacddSMichael Roth     PTYPE_S16,
398addacddSMichael Roth     PTYPE_S32,
408addacddSMichael Roth     PTYPE_S64,
418addacddSMichael Roth     PTYPE_EOL,
428addacddSMichael Roth };
432d496105SMichael Roth 
442d496105SMichael Roth typedef struct PrimitiveType {
452d496105SMichael Roth     union {
462d496105SMichael Roth         const char *string;
472d496105SMichael Roth         bool boolean;
482d496105SMichael Roth         double number;
492d496105SMichael Roth         int64_t integer;
502d496105SMichael Roth         uint8_t u8;
512d496105SMichael Roth         uint16_t u16;
522d496105SMichael Roth         uint32_t u32;
532d496105SMichael Roth         uint64_t u64;
542d496105SMichael Roth         int8_t s8;
552d496105SMichael Roth         int16_t s16;
562d496105SMichael Roth         int32_t s32;
572d496105SMichael Roth         int64_t s64;
582d496105SMichael Roth         intmax_t max;
592d496105SMichael Roth     } value;
608addacddSMichael Roth     enum PrimitiveTypeKind type;
612d496105SMichael Roth     const char *description;
622d496105SMichael Roth } PrimitiveType;
632d496105SMichael Roth 
648addacddSMichael Roth typedef struct PrimitiveList {
658addacddSMichael Roth     union {
668addacddSMichael Roth         strList *strings;
678addacddSMichael Roth         boolList *booleans;
688addacddSMichael Roth         numberList *numbers;
698addacddSMichael Roth         intList *integers;
708addacddSMichael Roth         int8List *s8_integers;
718addacddSMichael Roth         int16List *s16_integers;
728addacddSMichael Roth         int32List *s32_integers;
738addacddSMichael Roth         int64List *s64_integers;
748addacddSMichael Roth         uint8List *u8_integers;
758addacddSMichael Roth         uint16List *u16_integers;
768addacddSMichael Roth         uint32List *u32_integers;
778addacddSMichael Roth         uint64List *u64_integers;
788addacddSMichael Roth     } value;
798addacddSMichael Roth     enum PrimitiveTypeKind type;
808addacddSMichael Roth     const char *description;
818addacddSMichael Roth } PrimitiveList;
828addacddSMichael Roth 
832d496105SMichael Roth /* test helpers */
842d496105SMichael Roth 
858addacddSMichael Roth typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
868addacddSMichael Roth 
878addacddSMichael Roth static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
888addacddSMichael Roth {
892c0ef9f4SEric Blake     Visitor *v = qapi_dealloc_visitor_new();
908addacddSMichael Roth 
912c0ef9f4SEric Blake     visit(v, &native_in, errp);
928addacddSMichael Roth 
932c0ef9f4SEric Blake     visit_free(v);
948addacddSMichael Roth }
958addacddSMichael Roth 
962d496105SMichael Roth static void visit_primitive_type(Visitor *v, void **native, Error **errp)
972d496105SMichael Roth {
982d496105SMichael Roth     PrimitiveType *pt = *native;
992d496105SMichael Roth     switch(pt->type) {
1002d496105SMichael Roth     case PTYPE_STRING:
10151e72bc1SEric Blake         visit_type_str(v, NULL, (char **)&pt->value.string, errp);
1022d496105SMichael Roth         break;
1032d496105SMichael Roth     case PTYPE_BOOLEAN:
10451e72bc1SEric Blake         visit_type_bool(v, NULL, &pt->value.boolean, errp);
1052d496105SMichael Roth         break;
1062d496105SMichael Roth     case PTYPE_NUMBER:
10751e72bc1SEric Blake         visit_type_number(v, NULL, &pt->value.number, errp);
1082d496105SMichael Roth         break;
1092d496105SMichael Roth     case PTYPE_INTEGER:
11051e72bc1SEric Blake         visit_type_int(v, NULL, &pt->value.integer, errp);
1112d496105SMichael Roth         break;
1122d496105SMichael Roth     case PTYPE_U8:
11351e72bc1SEric Blake         visit_type_uint8(v, NULL, &pt->value.u8, errp);
1142d496105SMichael Roth         break;
1152d496105SMichael Roth     case PTYPE_U16:
11651e72bc1SEric Blake         visit_type_uint16(v, NULL, &pt->value.u16, errp);
1172d496105SMichael Roth         break;
1182d496105SMichael Roth     case PTYPE_U32:
11951e72bc1SEric Blake         visit_type_uint32(v, NULL, &pt->value.u32, errp);
1202d496105SMichael Roth         break;
1212d496105SMichael Roth     case PTYPE_U64:
12251e72bc1SEric Blake         visit_type_uint64(v, NULL, &pt->value.u64, errp);
1232d496105SMichael Roth         break;
1242d496105SMichael Roth     case PTYPE_S8:
12551e72bc1SEric Blake         visit_type_int8(v, NULL, &pt->value.s8, errp);
1262d496105SMichael Roth         break;
1272d496105SMichael Roth     case PTYPE_S16:
12851e72bc1SEric Blake         visit_type_int16(v, NULL, &pt->value.s16, errp);
1292d496105SMichael Roth         break;
1302d496105SMichael Roth     case PTYPE_S32:
13151e72bc1SEric Blake         visit_type_int32(v, NULL, &pt->value.s32, errp);
1322d496105SMichael Roth         break;
1332d496105SMichael Roth     case PTYPE_S64:
13451e72bc1SEric Blake         visit_type_int64(v, NULL, &pt->value.s64, errp);
1352d496105SMichael Roth         break;
1362d496105SMichael Roth     case PTYPE_EOL:
137dfc6f865SStefan Weil         g_assert_not_reached();
1382d496105SMichael Roth     }
1392d496105SMichael Roth }
1402d496105SMichael Roth 
1418addacddSMichael Roth static void visit_primitive_list(Visitor *v, void **native, Error **errp)
1428addacddSMichael Roth {
1438addacddSMichael Roth     PrimitiveList *pl = *native;
1448addacddSMichael Roth     switch (pl->type) {
1458addacddSMichael Roth     case PTYPE_STRING:
14651e72bc1SEric Blake         visit_type_strList(v, NULL, &pl->value.strings, errp);
1478addacddSMichael Roth         break;
1488addacddSMichael Roth     case PTYPE_BOOLEAN:
14951e72bc1SEric Blake         visit_type_boolList(v, NULL, &pl->value.booleans, errp);
1508addacddSMichael Roth         break;
1518addacddSMichael Roth     case PTYPE_NUMBER:
15251e72bc1SEric Blake         visit_type_numberList(v, NULL, &pl->value.numbers, errp);
1538addacddSMichael Roth         break;
1548addacddSMichael Roth     case PTYPE_INTEGER:
15551e72bc1SEric Blake         visit_type_intList(v, NULL, &pl->value.integers, errp);
1568addacddSMichael Roth         break;
1578addacddSMichael Roth     case PTYPE_S8:
15851e72bc1SEric Blake         visit_type_int8List(v, NULL, &pl->value.s8_integers, errp);
1598addacddSMichael Roth         break;
1608addacddSMichael Roth     case PTYPE_S16:
16151e72bc1SEric Blake         visit_type_int16List(v, NULL, &pl->value.s16_integers, errp);
1628addacddSMichael Roth         break;
1638addacddSMichael Roth     case PTYPE_S32:
16451e72bc1SEric Blake         visit_type_int32List(v, NULL, &pl->value.s32_integers, errp);
1658addacddSMichael Roth         break;
1668addacddSMichael Roth     case PTYPE_S64:
16751e72bc1SEric Blake         visit_type_int64List(v, NULL, &pl->value.s64_integers, errp);
1688addacddSMichael Roth         break;
1698addacddSMichael Roth     case PTYPE_U8:
17051e72bc1SEric Blake         visit_type_uint8List(v, NULL, &pl->value.u8_integers, errp);
1718addacddSMichael Roth         break;
1728addacddSMichael Roth     case PTYPE_U16:
17351e72bc1SEric Blake         visit_type_uint16List(v, NULL, &pl->value.u16_integers, errp);
1748addacddSMichael Roth         break;
1758addacddSMichael Roth     case PTYPE_U32:
17651e72bc1SEric Blake         visit_type_uint32List(v, NULL, &pl->value.u32_integers, errp);
1778addacddSMichael Roth         break;
1788addacddSMichael Roth     case PTYPE_U64:
17951e72bc1SEric Blake         visit_type_uint64List(v, NULL, &pl->value.u64_integers, errp);
1808addacddSMichael Roth         break;
1818addacddSMichael Roth     default:
182dfc6f865SStefan Weil         g_assert_not_reached();
1838addacddSMichael Roth     }
1848addacddSMichael Roth }
1858addacddSMichael Roth 
1862d496105SMichael Roth 
1872d496105SMichael Roth static TestStruct *struct_create(void)
1882d496105SMichael Roth {
1892d496105SMichael Roth     TestStruct *ts = g_malloc0(sizeof(*ts));
1902d496105SMichael Roth     ts->integer = -42;
1912d496105SMichael Roth     ts->boolean = true;
1922d496105SMichael Roth     ts->string = strdup("test string");
1932d496105SMichael Roth     return ts;
1942d496105SMichael Roth }
1952d496105SMichael Roth 
1962d496105SMichael Roth static void struct_compare(TestStruct *ts1, TestStruct *ts2)
1972d496105SMichael Roth {
1982d496105SMichael Roth     g_assert(ts1);
1992d496105SMichael Roth     g_assert(ts2);
2002d496105SMichael Roth     g_assert_cmpint(ts1->integer, ==, ts2->integer);
2012d496105SMichael Roth     g_assert(ts1->boolean == ts2->boolean);
2022d496105SMichael Roth     g_assert_cmpstr(ts1->string, ==, ts2->string);
2032d496105SMichael Roth }
2042d496105SMichael Roth 
2052d496105SMichael Roth static void struct_cleanup(TestStruct *ts)
2062d496105SMichael Roth {
2072d496105SMichael Roth     g_free(ts->string);
2082d496105SMichael Roth     g_free(ts);
2092d496105SMichael Roth }
2102d496105SMichael Roth 
2112d496105SMichael Roth static void visit_struct(Visitor *v, void **native, Error **errp)
2122d496105SMichael Roth {
21351e72bc1SEric Blake     visit_type_TestStruct(v, NULL, (TestStruct **)native, errp);
2142d496105SMichael Roth }
2152d496105SMichael Roth 
216b6fcf32dSEric Blake static UserDefTwo *nested_struct_create(void)
2172d496105SMichael Roth {
218b6fcf32dSEric Blake     UserDefTwo *udnp = g_malloc0(sizeof(*udnp));
2192d496105SMichael Roth     udnp->string0 = strdup("test_string0");
2206446a592SEric Blake     udnp->dict1 = g_malloc0(sizeof(*udnp->dict1));
2216446a592SEric Blake     udnp->dict1->string1 = strdup("test_string1");
2226446a592SEric Blake     udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2));
2236446a592SEric Blake     udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1);
224ddf21908SEric Blake     udnp->dict1->dict2->userdef->integer = 42;
2256446a592SEric Blake     udnp->dict1->dict2->userdef->string = strdup("test_string");
2266446a592SEric Blake     udnp->dict1->dict2->string = strdup("test_string2");
2276446a592SEric Blake     udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3));
2286446a592SEric Blake     udnp->dict1->has_dict3 = true;
2296446a592SEric Blake     udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1);
230ddf21908SEric Blake     udnp->dict1->dict3->userdef->integer = 43;
2316446a592SEric Blake     udnp->dict1->dict3->userdef->string = strdup("test_string");
2326446a592SEric Blake     udnp->dict1->dict3->string = strdup("test_string3");
2332d496105SMichael Roth     return udnp;
2342d496105SMichael Roth }
2352d496105SMichael Roth 
236b6fcf32dSEric Blake static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2)
2372d496105SMichael Roth {
2382d496105SMichael Roth     g_assert(udnp1);
2392d496105SMichael Roth     g_assert(udnp2);
2402d496105SMichael Roth     g_assert_cmpstr(udnp1->string0, ==, udnp2->string0);
2416446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1);
242ddf21908SEric Blake     g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==,
243ddf21908SEric Blake                     udnp2->dict1->dict2->userdef->integer);
2446446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==,
2456446a592SEric Blake                     udnp2->dict1->dict2->userdef->string);
2466446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict2->string, ==,
2476446a592SEric Blake                     udnp2->dict1->dict2->string);
2486446a592SEric Blake     g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3);
249ddf21908SEric Blake     g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==,
250ddf21908SEric Blake                     udnp2->dict1->dict3->userdef->integer);
2516446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==,
2526446a592SEric Blake                     udnp2->dict1->dict3->userdef->string);
2536446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict3->string, ==,
2546446a592SEric Blake                     udnp2->dict1->dict3->string);
2552d496105SMichael Roth }
2562d496105SMichael Roth 
257b6fcf32dSEric Blake static void nested_struct_cleanup(UserDefTwo *udnp)
2582d496105SMichael Roth {
259b6fcf32dSEric Blake     qapi_free_UserDefTwo(udnp);
2602d496105SMichael Roth }
2612d496105SMichael Roth 
2622d496105SMichael Roth static void visit_nested_struct(Visitor *v, void **native, Error **errp)
2632d496105SMichael Roth {
26451e72bc1SEric Blake     visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp);
2652d496105SMichael Roth }
2662d496105SMichael Roth 
2672d496105SMichael Roth static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
2682d496105SMichael Roth {
26951e72bc1SEric Blake     visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp);
2702d496105SMichael Roth }
2712d496105SMichael Roth 
2722d496105SMichael Roth /* test cases */
2732d496105SMichael Roth 
2742d496105SMichael Roth typedef enum VisitorCapabilities {
2752d496105SMichael Roth     VCAP_PRIMITIVES = 1,
2762d496105SMichael Roth     VCAP_STRUCTURES = 2,
2772d496105SMichael Roth     VCAP_LISTS = 4,
2788addacddSMichael Roth     VCAP_PRIMITIVE_LISTS = 8,
2792d496105SMichael Roth } VisitorCapabilities;
2802d496105SMichael Roth 
2812d496105SMichael Roth typedef struct SerializeOps {
2822d496105SMichael Roth     void (*serialize)(void *native_in, void **datap,
2832d496105SMichael Roth                       VisitorFunc visit, Error **errp);
2842d496105SMichael Roth     void (*deserialize)(void **native_out, void *datap,
2852d496105SMichael Roth                             VisitorFunc visit, Error **errp);
2862d496105SMichael Roth     void (*cleanup)(void *datap);
2872d496105SMichael Roth     const char *type;
2882d496105SMichael Roth     VisitorCapabilities caps;
2892d496105SMichael Roth } SerializeOps;
2902d496105SMichael Roth 
2912d496105SMichael Roth typedef struct TestArgs {
2922d496105SMichael Roth     const SerializeOps *ops;
2932d496105SMichael Roth     void *test_data;
2942d496105SMichael Roth } TestArgs;
2952d496105SMichael Roth 
2962d496105SMichael Roth static void test_primitives(gconstpointer opaque)
2972d496105SMichael Roth {
2982d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
2992d496105SMichael Roth     const SerializeOps *ops = args->ops;
3002d496105SMichael Roth     PrimitiveType *pt = args->test_data;
3012d496105SMichael Roth     PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
3022d496105SMichael Roth     void *serialize_data;
3032d496105SMichael Roth 
3042d496105SMichael Roth     pt_copy->type = pt->type;
3053f66f764SEric Blake     ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort);
3063f66f764SEric Blake     ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type,
3073f66f764SEric Blake                      &error_abort);
3082d496105SMichael Roth 
3092d496105SMichael Roth     g_assert(pt_copy != NULL);
3102d496105SMichael Roth     if (pt->type == PTYPE_STRING) {
3112d496105SMichael Roth         g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
3122bd01ac1SStefan Berger         g_free((char *)pt_copy->value.string);
3132d496105SMichael Roth     } else if (pt->type == PTYPE_NUMBER) {
314*2a02c139SMarkus Armbruster         g_assert_cmpfloat(pt->value.number, ==, pt_copy->value.number);
3152d496105SMichael Roth     } else if (pt->type == PTYPE_BOOLEAN) {
3162d496105SMichael Roth         g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max);
3172d496105SMichael Roth     } else {
3182d496105SMichael Roth         g_assert_cmpint(pt->value.max, ==, pt_copy->value.max);
3192d496105SMichael Roth     }
3202d496105SMichael Roth 
3212d496105SMichael Roth     ops->cleanup(serialize_data);
3222d496105SMichael Roth     g_free(args);
3232bd01ac1SStefan Berger     g_free(pt_copy);
3242d496105SMichael Roth }
3252d496105SMichael Roth 
3268addacddSMichael Roth static void test_primitive_lists(gconstpointer opaque)
3278addacddSMichael Roth {
3288addacddSMichael Roth     TestArgs *args = (TestArgs *) opaque;
3298addacddSMichael Roth     const SerializeOps *ops = args->ops;
3308addacddSMichael Roth     PrimitiveType *pt = args->test_data;
331748bfb4eSStefan Weil     PrimitiveList pl = { .value = { NULL } };
332748bfb4eSStefan Weil     PrimitiveList pl_copy = { .value = { NULL } };
3338addacddSMichael Roth     PrimitiveList *pl_copy_ptr = &pl_copy;
3348addacddSMichael Roth     void *serialize_data;
3358addacddSMichael Roth     void *cur_head = NULL;
3368addacddSMichael Roth     int i;
3378addacddSMichael Roth 
3388addacddSMichael Roth     pl.type = pl_copy.type = pt->type;
3398addacddSMichael Roth 
3408addacddSMichael Roth     /* build up our list of primitive types */
3418addacddSMichael Roth     for (i = 0; i < 32; i++) {
3428addacddSMichael Roth         switch (pl.type) {
3438addacddSMichael Roth         case PTYPE_STRING: {
34454aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.strings, g_strdup(pt->value.string));
3458addacddSMichael Roth             break;
3468addacddSMichael Roth         }
3478addacddSMichael Roth         case PTYPE_INTEGER: {
34854aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.integers, pt->value.integer);
3498addacddSMichael Roth             break;
3508addacddSMichael Roth         }
3518addacddSMichael Roth         case PTYPE_S8: {
35254aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.s8_integers, pt->value.s8);
3538addacddSMichael Roth             break;
3548addacddSMichael Roth         }
3558addacddSMichael Roth         case PTYPE_S16: {
35654aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.s16_integers, pt->value.s16);
3578addacddSMichael Roth             break;
3588addacddSMichael Roth         }
3598addacddSMichael Roth         case PTYPE_S32: {
36054aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.s32_integers, pt->value.s32);
3618addacddSMichael Roth             break;
3628addacddSMichael Roth         }
3638addacddSMichael Roth         case PTYPE_S64: {
36454aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.s64_integers, pt->value.s64);
3658addacddSMichael Roth             break;
3668addacddSMichael Roth         }
3678addacddSMichael Roth         case PTYPE_U8: {
36854aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.u8_integers, pt->value.u8);
3698addacddSMichael Roth             break;
3708addacddSMichael Roth         }
3718addacddSMichael Roth         case PTYPE_U16: {
37254aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.u16_integers, pt->value.u16);
3738addacddSMichael Roth             break;
3748addacddSMichael Roth         }
3758addacddSMichael Roth         case PTYPE_U32: {
37654aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.u32_integers, pt->value.u32);
3778addacddSMichael Roth             break;
3788addacddSMichael Roth         }
3798addacddSMichael Roth         case PTYPE_U64: {
38054aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.u64_integers, pt->value.u64);
3818addacddSMichael Roth             break;
3828addacddSMichael Roth         }
3838addacddSMichael Roth         case PTYPE_NUMBER: {
38454aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.numbers, pt->value.number);
3858addacddSMichael Roth             break;
3868addacddSMichael Roth         }
3878addacddSMichael Roth         case PTYPE_BOOLEAN: {
38854aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.booleans, pt->value.boolean);
3898addacddSMichael Roth             break;
3908addacddSMichael Roth         }
3918addacddSMichael Roth         default:
392dfc6f865SStefan Weil             g_assert_not_reached();
3938addacddSMichael Roth         }
3948addacddSMichael Roth     }
3958addacddSMichael Roth 
3963f66f764SEric Blake     ops->serialize((void **)&pl, &serialize_data, visit_primitive_list,
3973f66f764SEric Blake                    &error_abort);
3983f66f764SEric Blake     ops->deserialize((void **)&pl_copy_ptr, serialize_data,
3993f66f764SEric Blake                      visit_primitive_list, &error_abort);
4008addacddSMichael Roth 
4018addacddSMichael Roth     i = 0;
4028addacddSMichael Roth 
4038addacddSMichael Roth     /* compare our deserialized list of primitives to the original */
4048addacddSMichael Roth     do {
4058addacddSMichael Roth         switch (pl_copy.type) {
4068addacddSMichael Roth         case PTYPE_STRING: {
4078addacddSMichael Roth             strList *ptr;
4088addacddSMichael Roth             if (cur_head) {
4098addacddSMichael Roth                 ptr = cur_head;
4108addacddSMichael Roth                 cur_head = ptr->next;
4118addacddSMichael Roth             } else {
4128addacddSMichael Roth                 cur_head = ptr = pl_copy.value.strings;
4138addacddSMichael Roth             }
4148addacddSMichael Roth             g_assert_cmpstr(pt->value.string, ==, ptr->value);
4158addacddSMichael Roth             break;
4168addacddSMichael Roth         }
4178addacddSMichael Roth         case PTYPE_INTEGER: {
4188addacddSMichael Roth             intList *ptr;
4198addacddSMichael Roth             if (cur_head) {
4208addacddSMichael Roth                 ptr = cur_head;
4218addacddSMichael Roth                 cur_head = ptr->next;
4228addacddSMichael Roth             } else {
4238addacddSMichael Roth                 cur_head = ptr = pl_copy.value.integers;
4248addacddSMichael Roth             }
4258addacddSMichael Roth             g_assert_cmpint(pt->value.integer, ==, ptr->value);
4268addacddSMichael Roth             break;
4278addacddSMichael Roth         }
4288addacddSMichael Roth         case PTYPE_S8: {
4298addacddSMichael Roth             int8List *ptr;
4308addacddSMichael Roth             if (cur_head) {
4318addacddSMichael Roth                 ptr = cur_head;
4328addacddSMichael Roth                 cur_head = ptr->next;
4338addacddSMichael Roth             } else {
4348addacddSMichael Roth                 cur_head = ptr = pl_copy.value.s8_integers;
4358addacddSMichael Roth             }
4368addacddSMichael Roth             g_assert_cmpint(pt->value.s8, ==, ptr->value);
4378addacddSMichael Roth             break;
4388addacddSMichael Roth         }
4398addacddSMichael Roth         case PTYPE_S16: {
4408addacddSMichael Roth             int16List *ptr;
4418addacddSMichael Roth             if (cur_head) {
4428addacddSMichael Roth                 ptr = cur_head;
4438addacddSMichael Roth                 cur_head = ptr->next;
4448addacddSMichael Roth             } else {
4458addacddSMichael Roth                 cur_head = ptr = pl_copy.value.s16_integers;
4468addacddSMichael Roth             }
4478addacddSMichael Roth             g_assert_cmpint(pt->value.s16, ==, ptr->value);
4488addacddSMichael Roth             break;
4498addacddSMichael Roth         }
4508addacddSMichael Roth         case PTYPE_S32: {
4518addacddSMichael Roth             int32List *ptr;
4528addacddSMichael Roth             if (cur_head) {
4538addacddSMichael Roth                 ptr = cur_head;
4548addacddSMichael Roth                 cur_head = ptr->next;
4558addacddSMichael Roth             } else {
4568addacddSMichael Roth                 cur_head = ptr = pl_copy.value.s32_integers;
4578addacddSMichael Roth             }
4588addacddSMichael Roth             g_assert_cmpint(pt->value.s32, ==, ptr->value);
4598addacddSMichael Roth             break;
4608addacddSMichael Roth         }
4618addacddSMichael Roth         case PTYPE_S64: {
4628addacddSMichael Roth             int64List *ptr;
4638addacddSMichael Roth             if (cur_head) {
4648addacddSMichael Roth                 ptr = cur_head;
4658addacddSMichael Roth                 cur_head = ptr->next;
4668addacddSMichael Roth             } else {
4678addacddSMichael Roth                 cur_head = ptr = pl_copy.value.s64_integers;
4688addacddSMichael Roth             }
4698addacddSMichael Roth             g_assert_cmpint(pt->value.s64, ==, ptr->value);
4708addacddSMichael Roth             break;
4718addacddSMichael Roth         }
4728addacddSMichael Roth         case PTYPE_U8: {
4738addacddSMichael Roth             uint8List *ptr;
4748addacddSMichael Roth             if (cur_head) {
4758addacddSMichael Roth                 ptr = cur_head;
4768addacddSMichael Roth                 cur_head = ptr->next;
4778addacddSMichael Roth             } else {
4788addacddSMichael Roth                 cur_head = ptr = pl_copy.value.u8_integers;
4798addacddSMichael Roth             }
4808addacddSMichael Roth             g_assert_cmpint(pt->value.u8, ==, ptr->value);
4818addacddSMichael Roth             break;
4828addacddSMichael Roth         }
4838addacddSMichael Roth         case PTYPE_U16: {
4848addacddSMichael Roth             uint16List *ptr;
4858addacddSMichael Roth             if (cur_head) {
4868addacddSMichael Roth                 ptr = cur_head;
4878addacddSMichael Roth                 cur_head = ptr->next;
4888addacddSMichael Roth             } else {
4898addacddSMichael Roth                 cur_head = ptr = pl_copy.value.u16_integers;
4908addacddSMichael Roth             }
4918addacddSMichael Roth             g_assert_cmpint(pt->value.u16, ==, ptr->value);
4928addacddSMichael Roth             break;
4938addacddSMichael Roth         }
4948addacddSMichael Roth         case PTYPE_U32: {
4958addacddSMichael Roth             uint32List *ptr;
4968addacddSMichael Roth             if (cur_head) {
4978addacddSMichael Roth                 ptr = cur_head;
4988addacddSMichael Roth                 cur_head = ptr->next;
4998addacddSMichael Roth             } else {
5008addacddSMichael Roth                 cur_head = ptr = pl_copy.value.u32_integers;
5018addacddSMichael Roth             }
5028addacddSMichael Roth             g_assert_cmpint(pt->value.u32, ==, ptr->value);
5038addacddSMichael Roth             break;
5048addacddSMichael Roth         }
5058addacddSMichael Roth         case PTYPE_U64: {
5068addacddSMichael Roth             uint64List *ptr;
5078addacddSMichael Roth             if (cur_head) {
5088addacddSMichael Roth                 ptr = cur_head;
5098addacddSMichael Roth                 cur_head = ptr->next;
5108addacddSMichael Roth             } else {
5118addacddSMichael Roth                 cur_head = ptr = pl_copy.value.u64_integers;
5128addacddSMichael Roth             }
5138addacddSMichael Roth             g_assert_cmpint(pt->value.u64, ==, ptr->value);
5148addacddSMichael Roth             break;
5158addacddSMichael Roth         }
5168addacddSMichael Roth         case PTYPE_NUMBER: {
5178addacddSMichael Roth             numberList *ptr;
5188addacddSMichael Roth             GString *double_expected = g_string_new("");
5198addacddSMichael Roth             GString *double_actual = g_string_new("");
5208addacddSMichael Roth             if (cur_head) {
5218addacddSMichael Roth                 ptr = cur_head;
5228addacddSMichael Roth                 cur_head = ptr->next;
5238addacddSMichael Roth             } else {
5248addacddSMichael Roth                 cur_head = ptr = pl_copy.value.numbers;
5258addacddSMichael Roth             }
5268addacddSMichael Roth             /* we serialize with %f for our reference visitors, so rather than
5278addacddSMichael Roth              * fuzzy floating math to test "equality", just compare the
5288addacddSMichael Roth              * formatted values
5298addacddSMichael Roth              */
5308addacddSMichael Roth             g_string_printf(double_expected, "%.6f", pt->value.number);
5318addacddSMichael Roth             g_string_printf(double_actual, "%.6f", ptr->value);
5328addacddSMichael Roth             g_assert_cmpstr(double_actual->str, ==, double_expected->str);
5338addacddSMichael Roth             g_string_free(double_expected, true);
5348addacddSMichael Roth             g_string_free(double_actual, true);
5358addacddSMichael Roth             break;
5368addacddSMichael Roth         }
5378addacddSMichael Roth         case PTYPE_BOOLEAN: {
5388addacddSMichael Roth             boolList *ptr;
5398addacddSMichael Roth             if (cur_head) {
5408addacddSMichael Roth                 ptr = cur_head;
5418addacddSMichael Roth                 cur_head = ptr->next;
5428addacddSMichael Roth             } else {
5438addacddSMichael Roth                 cur_head = ptr = pl_copy.value.booleans;
5448addacddSMichael Roth             }
5458addacddSMichael Roth             g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
5468addacddSMichael Roth             break;
5478addacddSMichael Roth         }
5488addacddSMichael Roth         default:
549dfc6f865SStefan Weil             g_assert_not_reached();
5508addacddSMichael Roth         }
5518addacddSMichael Roth         i++;
5528addacddSMichael Roth     } while (cur_head);
5538addacddSMichael Roth 
5548addacddSMichael Roth     g_assert_cmpint(i, ==, 33);
5558addacddSMichael Roth 
5568addacddSMichael Roth     ops->cleanup(serialize_data);
5573f66f764SEric Blake     dealloc_helper(&pl, visit_primitive_list, &error_abort);
5583f66f764SEric Blake     dealloc_helper(&pl_copy, visit_primitive_list, &error_abort);
5598addacddSMichael Roth     g_free(args);
5608addacddSMichael Roth }
5618addacddSMichael Roth 
5622d496105SMichael Roth static void test_struct(gconstpointer opaque)
5632d496105SMichael Roth {
5642d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
5652d496105SMichael Roth     const SerializeOps *ops = args->ops;
5662d496105SMichael Roth     TestStruct *ts = struct_create();
5672d496105SMichael Roth     TestStruct *ts_copy = NULL;
5682d496105SMichael Roth     void *serialize_data;
5692d496105SMichael Roth 
5703f66f764SEric Blake     ops->serialize(ts, &serialize_data, visit_struct, &error_abort);
5713f66f764SEric Blake     ops->deserialize((void **)&ts_copy, serialize_data, visit_struct,
5723f66f764SEric Blake                      &error_abort);
5732d496105SMichael Roth 
5742d496105SMichael Roth     struct_compare(ts, ts_copy);
5752d496105SMichael Roth 
5762d496105SMichael Roth     struct_cleanup(ts);
5772d496105SMichael Roth     struct_cleanup(ts_copy);
5782d496105SMichael Roth 
5792d496105SMichael Roth     ops->cleanup(serialize_data);
5802d496105SMichael Roth     g_free(args);
5812d496105SMichael Roth }
5822d496105SMichael Roth 
5832d496105SMichael Roth static void test_nested_struct(gconstpointer opaque)
5842d496105SMichael Roth {
5852d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
5862d496105SMichael Roth     const SerializeOps *ops = args->ops;
587b6fcf32dSEric Blake     UserDefTwo *udnp = nested_struct_create();
588b6fcf32dSEric Blake     UserDefTwo *udnp_copy = NULL;
5892d496105SMichael Roth     void *serialize_data;
5902d496105SMichael Roth 
5913f66f764SEric Blake     ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort);
592b6fcf32dSEric Blake     ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct,
5933f66f764SEric Blake                      &error_abort);
5942d496105SMichael Roth 
5952d496105SMichael Roth     nested_struct_compare(udnp, udnp_copy);
5962d496105SMichael Roth 
5972d496105SMichael Roth     nested_struct_cleanup(udnp);
5982d496105SMichael Roth     nested_struct_cleanup(udnp_copy);
5992d496105SMichael Roth 
6002d496105SMichael Roth     ops->cleanup(serialize_data);
6012d496105SMichael Roth     g_free(args);
6022d496105SMichael Roth }
6032d496105SMichael Roth 
6042d496105SMichael Roth static void test_nested_struct_list(gconstpointer opaque)
6052d496105SMichael Roth {
6062d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
6072d496105SMichael Roth     const SerializeOps *ops = args->ops;
608b6fcf32dSEric Blake     UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL;
6092d496105SMichael Roth     void *serialize_data;
6102d496105SMichael Roth     int i = 0;
6112d496105SMichael Roth 
6122d496105SMichael Roth     for (i = 0; i < 8; i++) {
61354aa3de7SEric Blake         QAPI_LIST_PREPEND(listp, nested_struct_create());
6142d496105SMichael Roth     }
6152d496105SMichael Roth 
6163f66f764SEric Blake     ops->serialize(listp, &serialize_data, visit_nested_struct_list,
6173f66f764SEric Blake                    &error_abort);
6182d496105SMichael Roth     ops->deserialize((void **)&listp_copy, serialize_data,
6193f66f764SEric Blake                      visit_nested_struct_list, &error_abort);
6202d496105SMichael Roth 
6212d496105SMichael Roth     tmp = listp;
6222d496105SMichael Roth     tmp_copy = listp_copy;
6232d496105SMichael Roth     while (listp_copy) {
6242d496105SMichael Roth         g_assert(listp);
6252d496105SMichael Roth         nested_struct_compare(listp->value, listp_copy->value);
6262d496105SMichael Roth         listp = listp->next;
6272d496105SMichael Roth         listp_copy = listp_copy->next;
6282d496105SMichael Roth     }
6292d496105SMichael Roth 
630b6fcf32dSEric Blake     qapi_free_UserDefTwoList(tmp);
631b6fcf32dSEric Blake     qapi_free_UserDefTwoList(tmp_copy);
6322d496105SMichael Roth 
6332d496105SMichael Roth     ops->cleanup(serialize_data);
6342d496105SMichael Roth     g_free(args);
6352d496105SMichael Roth }
6362d496105SMichael Roth 
637748bfb4eSStefan Weil static PrimitiveType pt_values[] = {
6382d496105SMichael Roth     /* string tests */
6392d496105SMichael Roth     {
6402d496105SMichael Roth         .description = "string_empty",
6412d496105SMichael Roth         .type = PTYPE_STRING,
6422d496105SMichael Roth         .value.string = "",
6432d496105SMichael Roth     },
6442d496105SMichael Roth     {
6452d496105SMichael Roth         .description = "string_whitespace",
6462d496105SMichael Roth         .type = PTYPE_STRING,
6472d496105SMichael Roth         .value.string = "a b  c\td",
6482d496105SMichael Roth     },
6492d496105SMichael Roth     {
6502d496105SMichael Roth         .description = "string_newlines",
6512d496105SMichael Roth         .type = PTYPE_STRING,
6522d496105SMichael Roth         .value.string = "a\nb\n",
6532d496105SMichael Roth     },
6542d496105SMichael Roth     {
6552d496105SMichael Roth         .description = "string_commas",
6562d496105SMichael Roth         .type = PTYPE_STRING,
6572d496105SMichael Roth         .value.string = "a,b, c,d",
6582d496105SMichael Roth     },
6592d496105SMichael Roth     {
6602d496105SMichael Roth         .description = "string_single_quoted",
6612d496105SMichael Roth         .type = PTYPE_STRING,
6622d496105SMichael Roth         .value.string = "'a b',cd",
6632d496105SMichael Roth     },
6642d496105SMichael Roth     {
6652d496105SMichael Roth         .description = "string_double_quoted",
6662d496105SMichael Roth         .type = PTYPE_STRING,
6672d496105SMichael Roth         .value.string = "\"a b\",cd",
6682d496105SMichael Roth     },
6692d496105SMichael Roth     /* boolean tests */
6702d496105SMichael Roth     {
6712d496105SMichael Roth         .description = "boolean_true1",
6722d496105SMichael Roth         .type = PTYPE_BOOLEAN,
6732d496105SMichael Roth         .value.boolean = true,
6742d496105SMichael Roth     },
6752d496105SMichael Roth     {
6762d496105SMichael Roth         .description = "boolean_true2",
6772d496105SMichael Roth         .type = PTYPE_BOOLEAN,
6782d496105SMichael Roth         .value.boolean = 8,
6792d496105SMichael Roth     },
6802d496105SMichael Roth     {
6812d496105SMichael Roth         .description = "boolean_true3",
6822d496105SMichael Roth         .type = PTYPE_BOOLEAN,
6832d496105SMichael Roth         .value.boolean = -1,
6842d496105SMichael Roth     },
6852d496105SMichael Roth     {
6862d496105SMichael Roth         .description = "boolean_false1",
6872d496105SMichael Roth         .type = PTYPE_BOOLEAN,
6882d496105SMichael Roth         .value.boolean = false,
6892d496105SMichael Roth     },
6902d496105SMichael Roth     {
6912d496105SMichael Roth         .description = "boolean_false2",
6922d496105SMichael Roth         .type = PTYPE_BOOLEAN,
6932d496105SMichael Roth         .value.boolean = 0,
6942d496105SMichael Roth     },
6952d496105SMichael Roth     /* number tests (double) */
6962d496105SMichael Roth     {
6972d496105SMichael Roth         .description = "number_sanity1",
6982d496105SMichael Roth         .type = PTYPE_NUMBER,
6992d496105SMichael Roth         .value.number = -1,
7002d496105SMichael Roth     },
7012d496105SMichael Roth     {
7022d496105SMichael Roth         .description = "number_sanity2",
7032d496105SMichael Roth         .type = PTYPE_NUMBER,
704*2a02c139SMarkus Armbruster         .value.number = 3.141593,
7052d496105SMichael Roth     },
7062d496105SMichael Roth     {
7072d496105SMichael Roth         .description = "number_min",
7082d496105SMichael Roth         .type = PTYPE_NUMBER,
7092d496105SMichael Roth         .value.number = DBL_MIN,
7102d496105SMichael Roth     },
7112d496105SMichael Roth     {
7122d496105SMichael Roth         .description = "number_max",
7132d496105SMichael Roth         .type = PTYPE_NUMBER,
7142d496105SMichael Roth         .value.number = DBL_MAX,
7152d496105SMichael Roth     },
7162d496105SMichael Roth     /* integer tests (int64) */
7172d496105SMichael Roth     {
7182d496105SMichael Roth         .description = "integer_sanity1",
7192d496105SMichael Roth         .type = PTYPE_INTEGER,
7202d496105SMichael Roth         .value.integer = -1,
7212d496105SMichael Roth     },
7222d496105SMichael Roth     {
7232d496105SMichael Roth         .description = "integer_sanity2",
7242d496105SMichael Roth         .type = PTYPE_INTEGER,
7252d496105SMichael Roth         .value.integer = INT64_MAX / 2 + 1,
7262d496105SMichael Roth     },
7272d496105SMichael Roth     {
7282d496105SMichael Roth         .description = "integer_min",
7292d496105SMichael Roth         .type = PTYPE_INTEGER,
7302d496105SMichael Roth         .value.integer = INT64_MIN,
7312d496105SMichael Roth     },
7322d496105SMichael Roth     {
7332d496105SMichael Roth         .description = "integer_max",
7342d496105SMichael Roth         .type = PTYPE_INTEGER,
7352d496105SMichael Roth         .value.integer = INT64_MAX,
7362d496105SMichael Roth     },
7372d496105SMichael Roth     /* uint8 tests */
7382d496105SMichael Roth     {
7392d496105SMichael Roth         .description = "uint8_sanity1",
7402d496105SMichael Roth         .type = PTYPE_U8,
7412d496105SMichael Roth         .value.u8 = 1,
7422d496105SMichael Roth     },
7432d496105SMichael Roth     {
7442d496105SMichael Roth         .description = "uint8_sanity2",
7452d496105SMichael Roth         .type = PTYPE_U8,
7462d496105SMichael Roth         .value.u8 = UINT8_MAX / 2 + 1,
7472d496105SMichael Roth     },
7482d496105SMichael Roth     {
7492d496105SMichael Roth         .description = "uint8_min",
7502d496105SMichael Roth         .type = PTYPE_U8,
7512d496105SMichael Roth         .value.u8 = 0,
7522d496105SMichael Roth     },
7532d496105SMichael Roth     {
7542d496105SMichael Roth         .description = "uint8_max",
7552d496105SMichael Roth         .type = PTYPE_U8,
7562d496105SMichael Roth         .value.u8 = UINT8_MAX,
7572d496105SMichael Roth     },
7582d496105SMichael Roth     /* uint16 tests */
7592d496105SMichael Roth     {
7602d496105SMichael Roth         .description = "uint16_sanity1",
7612d496105SMichael Roth         .type = PTYPE_U16,
7622d496105SMichael Roth         .value.u16 = 1,
7632d496105SMichael Roth     },
7642d496105SMichael Roth     {
7652d496105SMichael Roth         .description = "uint16_sanity2",
7662d496105SMichael Roth         .type = PTYPE_U16,
7672d496105SMichael Roth         .value.u16 = UINT16_MAX / 2 + 1,
7682d496105SMichael Roth     },
7692d496105SMichael Roth     {
7702d496105SMichael Roth         .description = "uint16_min",
7712d496105SMichael Roth         .type = PTYPE_U16,
7722d496105SMichael Roth         .value.u16 = 0,
7732d496105SMichael Roth     },
7742d496105SMichael Roth     {
7752d496105SMichael Roth         .description = "uint16_max",
7762d496105SMichael Roth         .type = PTYPE_U16,
7772d496105SMichael Roth         .value.u16 = UINT16_MAX,
7782d496105SMichael Roth     },
7792d496105SMichael Roth     /* uint32 tests */
7802d496105SMichael Roth     {
7812d496105SMichael Roth         .description = "uint32_sanity1",
7822d496105SMichael Roth         .type = PTYPE_U32,
7832d496105SMichael Roth         .value.u32 = 1,
7842d496105SMichael Roth     },
7852d496105SMichael Roth     {
7862d496105SMichael Roth         .description = "uint32_sanity2",
7872d496105SMichael Roth         .type = PTYPE_U32,
7882d496105SMichael Roth         .value.u32 = UINT32_MAX / 2 + 1,
7892d496105SMichael Roth     },
7902d496105SMichael Roth     {
7912d496105SMichael Roth         .description = "uint32_min",
7922d496105SMichael Roth         .type = PTYPE_U32,
7932d496105SMichael Roth         .value.u32 = 0,
7942d496105SMichael Roth     },
7952d496105SMichael Roth     {
7962d496105SMichael Roth         .description = "uint32_max",
7972d496105SMichael Roth         .type = PTYPE_U32,
7982d496105SMichael Roth         .value.u32 = UINT32_MAX,
7992d496105SMichael Roth     },
8002d496105SMichael Roth     /* uint64 tests */
8012d496105SMichael Roth     {
8022d496105SMichael Roth         .description = "uint64_sanity1",
8032d496105SMichael Roth         .type = PTYPE_U64,
8042d496105SMichael Roth         .value.u64 = 1,
8052d496105SMichael Roth     },
8062d496105SMichael Roth     {
8072d496105SMichael Roth         .description = "uint64_sanity2",
8082d496105SMichael Roth         .type = PTYPE_U64,
8092d496105SMichael Roth         .value.u64 = UINT64_MAX / 2 + 1,
8102d496105SMichael Roth     },
8112d496105SMichael Roth     {
8122d496105SMichael Roth         .description = "uint64_min",
8132d496105SMichael Roth         .type = PTYPE_U64,
8142d496105SMichael Roth         .value.u64 = 0,
8152d496105SMichael Roth     },
8162d496105SMichael Roth     {
8172d496105SMichael Roth         .description = "uint64_max",
8182d496105SMichael Roth         .type = PTYPE_U64,
8192d496105SMichael Roth         .value.u64 = UINT64_MAX,
8202d496105SMichael Roth     },
8212d496105SMichael Roth     /* int8 tests */
8222d496105SMichael Roth     {
8232d496105SMichael Roth         .description = "int8_sanity1",
8242d496105SMichael Roth         .type = PTYPE_S8,
8252d496105SMichael Roth         .value.s8 = -1,
8262d496105SMichael Roth     },
8272d496105SMichael Roth     {
8282d496105SMichael Roth         .description = "int8_sanity2",
8292d496105SMichael Roth         .type = PTYPE_S8,
8302d496105SMichael Roth         .value.s8 = INT8_MAX / 2 + 1,
8312d496105SMichael Roth     },
8322d496105SMichael Roth     {
8332d496105SMichael Roth         .description = "int8_min",
8342d496105SMichael Roth         .type = PTYPE_S8,
8352d496105SMichael Roth         .value.s8 = INT8_MIN,
8362d496105SMichael Roth     },
8372d496105SMichael Roth     {
8382d496105SMichael Roth         .description = "int8_max",
8392d496105SMichael Roth         .type = PTYPE_S8,
8402d496105SMichael Roth         .value.s8 = INT8_MAX,
8412d496105SMichael Roth     },
8422d496105SMichael Roth     /* int16 tests */
8432d496105SMichael Roth     {
8442d496105SMichael Roth         .description = "int16_sanity1",
8452d496105SMichael Roth         .type = PTYPE_S16,
8462d496105SMichael Roth         .value.s16 = -1,
8472d496105SMichael Roth     },
8482d496105SMichael Roth     {
8492d496105SMichael Roth         .description = "int16_sanity2",
8502d496105SMichael Roth         .type = PTYPE_S16,
8512d496105SMichael Roth         .value.s16 = INT16_MAX / 2 + 1,
8522d496105SMichael Roth     },
8532d496105SMichael Roth     {
8542d496105SMichael Roth         .description = "int16_min",
8552d496105SMichael Roth         .type = PTYPE_S16,
8562d496105SMichael Roth         .value.s16 = INT16_MIN,
8572d496105SMichael Roth     },
8582d496105SMichael Roth     {
8592d496105SMichael Roth         .description = "int16_max",
8602d496105SMichael Roth         .type = PTYPE_S16,
8612d496105SMichael Roth         .value.s16 = INT16_MAX,
8622d496105SMichael Roth     },
8632d496105SMichael Roth     /* int32 tests */
8642d496105SMichael Roth     {
8652d496105SMichael Roth         .description = "int32_sanity1",
8662d496105SMichael Roth         .type = PTYPE_S32,
8672d496105SMichael Roth         .value.s32 = -1,
8682d496105SMichael Roth     },
8692d496105SMichael Roth     {
8702d496105SMichael Roth         .description = "int32_sanity2",
8712d496105SMichael Roth         .type = PTYPE_S32,
8722d496105SMichael Roth         .value.s32 = INT32_MAX / 2 + 1,
8732d496105SMichael Roth     },
8742d496105SMichael Roth     {
8752d496105SMichael Roth         .description = "int32_min",
8762d496105SMichael Roth         .type = PTYPE_S32,
8772d496105SMichael Roth         .value.s32 = INT32_MIN,
8782d496105SMichael Roth     },
8792d496105SMichael Roth     {
8802d496105SMichael Roth         .description = "int32_max",
8812d496105SMichael Roth         .type = PTYPE_S32,
8822d496105SMichael Roth         .value.s32 = INT32_MAX,
8832d496105SMichael Roth     },
8842d496105SMichael Roth     /* int64 tests */
8852d496105SMichael Roth     {
8862d496105SMichael Roth         .description = "int64_sanity1",
8872d496105SMichael Roth         .type = PTYPE_S64,
8882d496105SMichael Roth         .value.s64 = -1,
8892d496105SMichael Roth     },
8902d496105SMichael Roth     {
8912d496105SMichael Roth         .description = "int64_sanity2",
8922d496105SMichael Roth         .type = PTYPE_S64,
8932d496105SMichael Roth         .value.s64 = INT64_MAX / 2 + 1,
8942d496105SMichael Roth     },
8952d496105SMichael Roth     {
8962d496105SMichael Roth         .description = "int64_min",
8972d496105SMichael Roth         .type = PTYPE_S64,
8982d496105SMichael Roth         .value.s64 = INT64_MIN,
8992d496105SMichael Roth     },
9002d496105SMichael Roth     {
9012d496105SMichael Roth         .description = "int64_max",
9022d496105SMichael Roth         .type = PTYPE_S64,
9032d496105SMichael Roth         .value.s64 = INT64_MAX,
9042d496105SMichael Roth     },
9052d496105SMichael Roth     { .type = PTYPE_EOL }
9062d496105SMichael Roth };
9072d496105SMichael Roth 
9082d496105SMichael Roth /* visitor-specific op implementations */
9092d496105SMichael Roth 
9102d496105SMichael Roth typedef struct QmpSerializeData {
9113b098d56SEric Blake     Visitor *qov;
9123b098d56SEric Blake     QObject *obj;
913b70ce101SEric Blake     Visitor *qiv;
9142d496105SMichael Roth } QmpSerializeData;
9152d496105SMichael Roth 
9162d496105SMichael Roth static void qmp_serialize(void *native_in, void **datap,
9172d496105SMichael Roth                           VisitorFunc visit, Error **errp)
9182d496105SMichael Roth {
9192d496105SMichael Roth     QmpSerializeData *d = g_malloc0(sizeof(*d));
9202d496105SMichael Roth 
9217d5e199aSDaniel P. Berrange     d->qov = qobject_output_visitor_new(&d->obj);
9223b098d56SEric Blake     visit(d->qov, &native_in, errp);
9232d496105SMichael Roth     *datap = d;
9242d496105SMichael Roth }
9252d496105SMichael Roth 
9262d496105SMichael Roth static void qmp_deserialize(void **native_out, void *datap,
9272d496105SMichael Roth                             VisitorFunc visit, Error **errp)
9282d496105SMichael Roth {
9292d496105SMichael Roth     QmpSerializeData *d = datap;
930ad7f375dSMichael Roth     QString *output_json;
931ad7f375dSMichael Roth     QObject *obj_orig, *obj;
932ad7f375dSMichael Roth 
9333b098d56SEric Blake     visit_complete(d->qov, &d->obj);
9343b098d56SEric Blake     obj_orig = d->obj;
935ad7f375dSMichael Roth     output_json = qobject_to_json(obj_orig);
93602146d27SMarkus Armbruster     obj = qobject_from_json(qstring_get_str(output_json), &error_abort);
9372d496105SMichael Roth 
938cb3e7f08SMarc-André Lureau     qobject_unref(output_json);
939048abb7bSMarkus Armbruster     d->qiv = qobject_input_visitor_new(obj);
940cb3e7f08SMarc-André Lureau     qobject_unref(obj_orig);
941cb3e7f08SMarc-André Lureau     qobject_unref(obj);
942b70ce101SEric Blake     visit(d->qiv, native_out, errp);
9432d496105SMichael Roth }
9442d496105SMichael Roth 
9452d496105SMichael Roth static void qmp_cleanup(void *datap)
9462d496105SMichael Roth {
9472d496105SMichael Roth     QmpSerializeData *d = datap;
9483b098d56SEric Blake     visit_free(d->qov);
949b70ce101SEric Blake     visit_free(d->qiv);
9502bd01ac1SStefan Berger 
9512bd01ac1SStefan Berger     g_free(d);
9522d496105SMichael Roth }
9532d496105SMichael Roth 
9540d30b0a2SMichael Roth typedef struct StringSerializeData {
9552bd01ac1SStefan Berger     char *string;
9563b098d56SEric Blake     Visitor *sov;
9577a0525c7SEric Blake     Visitor *siv;
9580d30b0a2SMichael Roth } StringSerializeData;
9590d30b0a2SMichael Roth 
9600d30b0a2SMichael Roth static void string_serialize(void *native_in, void **datap,
9610d30b0a2SMichael Roth                              VisitorFunc visit, Error **errp)
9620d30b0a2SMichael Roth {
9630d30b0a2SMichael Roth     StringSerializeData *d = g_malloc0(sizeof(*d));
9640d30b0a2SMichael Roth 
9653b098d56SEric Blake     d->sov = string_output_visitor_new(false, &d->string);
9663b098d56SEric Blake     visit(d->sov, &native_in, errp);
9670d30b0a2SMichael Roth     *datap = d;
9680d30b0a2SMichael Roth }
9690d30b0a2SMichael Roth 
9700d30b0a2SMichael Roth static void string_deserialize(void **native_out, void *datap,
9710d30b0a2SMichael Roth                                VisitorFunc visit, Error **errp)
9720d30b0a2SMichael Roth {
9730d30b0a2SMichael Roth     StringSerializeData *d = datap;
9740d30b0a2SMichael Roth 
9753b098d56SEric Blake     visit_complete(d->sov, &d->string);
9762bd01ac1SStefan Berger     d->siv = string_input_visitor_new(d->string);
9777a0525c7SEric Blake     visit(d->siv, native_out, errp);
9780d30b0a2SMichael Roth }
9790d30b0a2SMichael Roth 
9800d30b0a2SMichael Roth static void string_cleanup(void *datap)
9810d30b0a2SMichael Roth {
9820d30b0a2SMichael Roth     StringSerializeData *d = datap;
9832bd01ac1SStefan Berger 
9843b098d56SEric Blake     visit_free(d->sov);
9857a0525c7SEric Blake     visit_free(d->siv);
9862bd01ac1SStefan Berger     g_free(d->string);
9872bd01ac1SStefan Berger     g_free(d);
9880d30b0a2SMichael Roth }
9890d30b0a2SMichael Roth 
9902d496105SMichael Roth /* visitor registration, test harness */
9912d496105SMichael Roth 
9922d496105SMichael Roth /* note: to function interchangeably as a serialization mechanism your
9932d496105SMichael Roth  * visitor test implementation should pass the test cases for all visitor
9942d496105SMichael Roth  * capabilities: primitives, structures, and lists
9952d496105SMichael Roth  */
9962d496105SMichael Roth static const SerializeOps visitors[] = {
9972d496105SMichael Roth     {
9982d496105SMichael Roth         .type = "QMP",
9992d496105SMichael Roth         .serialize = qmp_serialize,
10002d496105SMichael Roth         .deserialize = qmp_deserialize,
10012d496105SMichael Roth         .cleanup = qmp_cleanup,
10028addacddSMichael Roth         .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
10038addacddSMichael Roth                 VCAP_PRIMITIVE_LISTS
10042d496105SMichael Roth     },
10050d30b0a2SMichael Roth     {
10060d30b0a2SMichael Roth         .type = "String",
10070d30b0a2SMichael Roth         .serialize = string_serialize,
10080d30b0a2SMichael Roth         .deserialize = string_deserialize,
10090d30b0a2SMichael Roth         .cleanup = string_cleanup,
10100d30b0a2SMichael Roth         .caps = VCAP_PRIMITIVES
10110d30b0a2SMichael Roth     },
10122d496105SMichael Roth     { NULL }
10132d496105SMichael Roth };
10142d496105SMichael Roth 
10152d496105SMichael Roth static void add_visitor_type(const SerializeOps *ops)
10162d496105SMichael Roth {
1017fdf235baSEric Blake     char testname_prefix[32];
10182d496105SMichael Roth     char testname[128];
10192d496105SMichael Roth     TestArgs *args;
10202d496105SMichael Roth     int i = 0;
10212d496105SMichael Roth 
10222d496105SMichael Roth     sprintf(testname_prefix, "/visitor/serialization/%s", ops->type);
10232d496105SMichael Roth 
10242d496105SMichael Roth     if (ops->caps & VCAP_PRIMITIVES) {
10252d496105SMichael Roth         while (pt_values[i].type != PTYPE_EOL) {
10262d496105SMichael Roth             sprintf(testname, "%s/primitives/%s", testname_prefix,
10272d496105SMichael Roth                     pt_values[i].description);
10282d496105SMichael Roth             args = g_malloc0(sizeof(*args));
10292d496105SMichael Roth             args->ops = ops;
10302d496105SMichael Roth             args->test_data = &pt_values[i];
10312d496105SMichael Roth             g_test_add_data_func(testname, args, test_primitives);
10322d496105SMichael Roth             i++;
10332d496105SMichael Roth         }
10342d496105SMichael Roth     }
10352d496105SMichael Roth 
10362d496105SMichael Roth     if (ops->caps & VCAP_STRUCTURES) {
10372d496105SMichael Roth         sprintf(testname, "%s/struct", testname_prefix);
10382d496105SMichael Roth         args = g_malloc0(sizeof(*args));
10392d496105SMichael Roth         args->ops = ops;
10402d496105SMichael Roth         args->test_data = NULL;
10412d496105SMichael Roth         g_test_add_data_func(testname, args, test_struct);
10422d496105SMichael Roth 
10432d496105SMichael Roth         sprintf(testname, "%s/nested_struct", testname_prefix);
10442d496105SMichael Roth         args = g_malloc0(sizeof(*args));
10452d496105SMichael Roth         args->ops = ops;
10462d496105SMichael Roth         args->test_data = NULL;
10472d496105SMichael Roth         g_test_add_data_func(testname, args, test_nested_struct);
10482d496105SMichael Roth     }
10492d496105SMichael Roth 
10502d496105SMichael Roth     if (ops->caps & VCAP_LISTS) {
10512d496105SMichael Roth         sprintf(testname, "%s/nested_struct_list", testname_prefix);
10522d496105SMichael Roth         args = g_malloc0(sizeof(*args));
10532d496105SMichael Roth         args->ops = ops;
10542d496105SMichael Roth         args->test_data = NULL;
10552d496105SMichael Roth         g_test_add_data_func(testname, args, test_nested_struct_list);
10562d496105SMichael Roth     }
10578addacddSMichael Roth 
10588addacddSMichael Roth     if (ops->caps & VCAP_PRIMITIVE_LISTS) {
10598addacddSMichael Roth         i = 0;
10608addacddSMichael Roth         while (pt_values[i].type != PTYPE_EOL) {
10618addacddSMichael Roth             sprintf(testname, "%s/primitive_list/%s", testname_prefix,
10628addacddSMichael Roth                     pt_values[i].description);
10638addacddSMichael Roth             args = g_malloc0(sizeof(*args));
10648addacddSMichael Roth             args->ops = ops;
10658addacddSMichael Roth             args->test_data = &pt_values[i];
10668addacddSMichael Roth             g_test_add_data_func(testname, args, test_primitive_lists);
10678addacddSMichael Roth             i++;
10688addacddSMichael Roth         }
10698addacddSMichael Roth     }
10702d496105SMichael Roth }
10712d496105SMichael Roth 
10722d496105SMichael Roth int main(int argc, char **argv)
10732d496105SMichael Roth {
10742d496105SMichael Roth     int i = 0;
10752d496105SMichael Roth 
10762d496105SMichael Roth     g_test_init(&argc, &argv, NULL);
10772d496105SMichael Roth 
10782d496105SMichael Roth     while (visitors[i].type != NULL) {
10792d496105SMichael Roth         add_visitor_type(&visitors[i]);
10802d496105SMichael Roth         i++;
10812d496105SMichael Roth     }
10822d496105SMichael Roth 
10832d496105SMichael Roth     g_test_run();
10842d496105SMichael Roth 
10852d496105SMichael Roth     return 0;
10862d496105SMichael Roth }
1087