xref: /qemu/tests/unit/test-visitor-serialization.c (revision ac9e723fb6baaf9d9afa31f81c57f38ef7610616)
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 
172d496105SMichael Roth #include "test-qapi-visit.h"
18da34e65cSMarkus Armbruster #include "qapi/error.h"
19c7eb39cbSEric Blake #include "qapi/qmp/qjson.h"
20fc81fa1eSMarkus Armbruster #include "qapi/qmp/qstring.h"
21b3db211fSDaniel P. Berrange #include "qapi/qobject-input-visitor.h"
22b3db211fSDaniel P. Berrange #include "qapi/qobject-output-visitor.h"
230d30b0a2SMichael Roth #include "qapi/string-input-visitor.h"
240d30b0a2SMichael Roth #include "qapi/string-output-visitor.h"
258addacddSMichael Roth #include "qapi/dealloc-visitor.h"
268addacddSMichael Roth 
278addacddSMichael Roth enum PrimitiveTypeKind {
288addacddSMichael Roth     PTYPE_STRING = 0,
298addacddSMichael Roth     PTYPE_BOOLEAN,
308addacddSMichael Roth     PTYPE_NUMBER,
318addacddSMichael Roth     PTYPE_INTEGER,
328addacddSMichael Roth     PTYPE_U8,
338addacddSMichael Roth     PTYPE_U16,
348addacddSMichael Roth     PTYPE_U32,
358addacddSMichael Roth     PTYPE_U64,
368addacddSMichael Roth     PTYPE_S8,
378addacddSMichael Roth     PTYPE_S16,
388addacddSMichael Roth     PTYPE_S32,
398addacddSMichael Roth     PTYPE_S64,
408addacddSMichael Roth     PTYPE_EOL,
418addacddSMichael Roth };
422d496105SMichael Roth 
432d496105SMichael Roth typedef struct PrimitiveType {
442d496105SMichael Roth     union {
452d496105SMichael Roth         const char *string;
462d496105SMichael Roth         bool boolean;
472d496105SMichael Roth         double number;
482d496105SMichael Roth         int64_t integer;
492d496105SMichael Roth         uint8_t u8;
502d496105SMichael Roth         uint16_t u16;
512d496105SMichael Roth         uint32_t u32;
522d496105SMichael Roth         uint64_t u64;
532d496105SMichael Roth         int8_t s8;
542d496105SMichael Roth         int16_t s16;
552d496105SMichael Roth         int32_t s32;
562d496105SMichael Roth         int64_t s64;
572d496105SMichael Roth     } value;
588addacddSMichael Roth     enum PrimitiveTypeKind type;
592d496105SMichael Roth     const char *description;
602d496105SMichael Roth } PrimitiveType;
612d496105SMichael Roth 
628addacddSMichael Roth typedef struct PrimitiveList {
638addacddSMichael Roth     union {
648addacddSMichael Roth         strList *strings;
658addacddSMichael Roth         boolList *booleans;
668addacddSMichael Roth         numberList *numbers;
678addacddSMichael Roth         intList *integers;
688addacddSMichael Roth         int8List *s8_integers;
698addacddSMichael Roth         int16List *s16_integers;
708addacddSMichael Roth         int32List *s32_integers;
718addacddSMichael Roth         int64List *s64_integers;
728addacddSMichael Roth         uint8List *u8_integers;
738addacddSMichael Roth         uint16List *u16_integers;
748addacddSMichael Roth         uint32List *u32_integers;
758addacddSMichael Roth         uint64List *u64_integers;
768addacddSMichael Roth     } value;
778addacddSMichael Roth     enum PrimitiveTypeKind type;
788addacddSMichael Roth     const char *description;
798addacddSMichael Roth } PrimitiveList;
808addacddSMichael Roth 
812d496105SMichael Roth /* test helpers */
822d496105SMichael Roth 
838addacddSMichael Roth typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
848addacddSMichael Roth 
858addacddSMichael Roth static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
868addacddSMichael Roth {
872c0ef9f4SEric Blake     Visitor *v = qapi_dealloc_visitor_new();
888addacddSMichael Roth 
892c0ef9f4SEric Blake     visit(v, &native_in, errp);
908addacddSMichael Roth 
912c0ef9f4SEric Blake     visit_free(v);
928addacddSMichael Roth }
938addacddSMichael Roth 
942d496105SMichael Roth static void visit_primitive_type(Visitor *v, void **native, Error **errp)
952d496105SMichael Roth {
962d496105SMichael Roth     PrimitiveType *pt = *native;
972d496105SMichael Roth     switch(pt->type) {
982d496105SMichael Roth     case PTYPE_STRING:
9951e72bc1SEric Blake         visit_type_str(v, NULL, (char **)&pt->value.string, errp);
1002d496105SMichael Roth         break;
1012d496105SMichael Roth     case PTYPE_BOOLEAN:
10251e72bc1SEric Blake         visit_type_bool(v, NULL, &pt->value.boolean, errp);
1032d496105SMichael Roth         break;
1042d496105SMichael Roth     case PTYPE_NUMBER:
10551e72bc1SEric Blake         visit_type_number(v, NULL, &pt->value.number, errp);
1062d496105SMichael Roth         break;
1072d496105SMichael Roth     case PTYPE_INTEGER:
10851e72bc1SEric Blake         visit_type_int(v, NULL, &pt->value.integer, errp);
1092d496105SMichael Roth         break;
1102d496105SMichael Roth     case PTYPE_U8:
11151e72bc1SEric Blake         visit_type_uint8(v, NULL, &pt->value.u8, errp);
1122d496105SMichael Roth         break;
1132d496105SMichael Roth     case PTYPE_U16:
11451e72bc1SEric Blake         visit_type_uint16(v, NULL, &pt->value.u16, errp);
1152d496105SMichael Roth         break;
1162d496105SMichael Roth     case PTYPE_U32:
11751e72bc1SEric Blake         visit_type_uint32(v, NULL, &pt->value.u32, errp);
1182d496105SMichael Roth         break;
1192d496105SMichael Roth     case PTYPE_U64:
12051e72bc1SEric Blake         visit_type_uint64(v, NULL, &pt->value.u64, errp);
1212d496105SMichael Roth         break;
1222d496105SMichael Roth     case PTYPE_S8:
12351e72bc1SEric Blake         visit_type_int8(v, NULL, &pt->value.s8, errp);
1242d496105SMichael Roth         break;
1252d496105SMichael Roth     case PTYPE_S16:
12651e72bc1SEric Blake         visit_type_int16(v, NULL, &pt->value.s16, errp);
1272d496105SMichael Roth         break;
1282d496105SMichael Roth     case PTYPE_S32:
12951e72bc1SEric Blake         visit_type_int32(v, NULL, &pt->value.s32, errp);
1302d496105SMichael Roth         break;
1312d496105SMichael Roth     case PTYPE_S64:
13251e72bc1SEric Blake         visit_type_int64(v, NULL, &pt->value.s64, errp);
1332d496105SMichael Roth         break;
1342d496105SMichael Roth     case PTYPE_EOL:
135dfc6f865SStefan Weil         g_assert_not_reached();
1362d496105SMichael Roth     }
1372d496105SMichael Roth }
1382d496105SMichael Roth 
1398addacddSMichael Roth static void visit_primitive_list(Visitor *v, void **native, Error **errp)
1408addacddSMichael Roth {
1418addacddSMichael Roth     PrimitiveList *pl = *native;
1428addacddSMichael Roth     switch (pl->type) {
1438addacddSMichael Roth     case PTYPE_STRING:
14451e72bc1SEric Blake         visit_type_strList(v, NULL, &pl->value.strings, errp);
1458addacddSMichael Roth         break;
1468addacddSMichael Roth     case PTYPE_BOOLEAN:
14751e72bc1SEric Blake         visit_type_boolList(v, NULL, &pl->value.booleans, errp);
1488addacddSMichael Roth         break;
1498addacddSMichael Roth     case PTYPE_NUMBER:
15051e72bc1SEric Blake         visit_type_numberList(v, NULL, &pl->value.numbers, errp);
1518addacddSMichael Roth         break;
1528addacddSMichael Roth     case PTYPE_INTEGER:
15351e72bc1SEric Blake         visit_type_intList(v, NULL, &pl->value.integers, errp);
1548addacddSMichael Roth         break;
1558addacddSMichael Roth     case PTYPE_S8:
15651e72bc1SEric Blake         visit_type_int8List(v, NULL, &pl->value.s8_integers, errp);
1578addacddSMichael Roth         break;
1588addacddSMichael Roth     case PTYPE_S16:
15951e72bc1SEric Blake         visit_type_int16List(v, NULL, &pl->value.s16_integers, errp);
1608addacddSMichael Roth         break;
1618addacddSMichael Roth     case PTYPE_S32:
16251e72bc1SEric Blake         visit_type_int32List(v, NULL, &pl->value.s32_integers, errp);
1638addacddSMichael Roth         break;
1648addacddSMichael Roth     case PTYPE_S64:
16551e72bc1SEric Blake         visit_type_int64List(v, NULL, &pl->value.s64_integers, errp);
1668addacddSMichael Roth         break;
1678addacddSMichael Roth     case PTYPE_U8:
16851e72bc1SEric Blake         visit_type_uint8List(v, NULL, &pl->value.u8_integers, errp);
1698addacddSMichael Roth         break;
1708addacddSMichael Roth     case PTYPE_U16:
17151e72bc1SEric Blake         visit_type_uint16List(v, NULL, &pl->value.u16_integers, errp);
1728addacddSMichael Roth         break;
1738addacddSMichael Roth     case PTYPE_U32:
17451e72bc1SEric Blake         visit_type_uint32List(v, NULL, &pl->value.u32_integers, errp);
1758addacddSMichael Roth         break;
1768addacddSMichael Roth     case PTYPE_U64:
17751e72bc1SEric Blake         visit_type_uint64List(v, NULL, &pl->value.u64_integers, errp);
1788addacddSMichael Roth         break;
1798addacddSMichael Roth     default:
180dfc6f865SStefan Weil         g_assert_not_reached();
1818addacddSMichael Roth     }
1828addacddSMichael Roth }
1838addacddSMichael Roth 
1842d496105SMichael Roth 
1852d496105SMichael Roth static TestStruct *struct_create(void)
1862d496105SMichael Roth {
1872d496105SMichael Roth     TestStruct *ts = g_malloc0(sizeof(*ts));
1882d496105SMichael Roth     ts->integer = -42;
1892d496105SMichael Roth     ts->boolean = true;
1902d496105SMichael Roth     ts->string = strdup("test string");
1912d496105SMichael Roth     return ts;
1922d496105SMichael Roth }
1932d496105SMichael Roth 
1942d496105SMichael Roth static void struct_compare(TestStruct *ts1, TestStruct *ts2)
1952d496105SMichael Roth {
1962d496105SMichael Roth     g_assert(ts1);
1972d496105SMichael Roth     g_assert(ts2);
1982d496105SMichael Roth     g_assert_cmpint(ts1->integer, ==, ts2->integer);
1992d496105SMichael Roth     g_assert(ts1->boolean == ts2->boolean);
2002d496105SMichael Roth     g_assert_cmpstr(ts1->string, ==, ts2->string);
2012d496105SMichael Roth }
2022d496105SMichael Roth 
2032d496105SMichael Roth static void struct_cleanup(TestStruct *ts)
2042d496105SMichael Roth {
2052d496105SMichael Roth     g_free(ts->string);
2062d496105SMichael Roth     g_free(ts);
2072d496105SMichael Roth }
2082d496105SMichael Roth 
2092d496105SMichael Roth static void visit_struct(Visitor *v, void **native, Error **errp)
2102d496105SMichael Roth {
21151e72bc1SEric Blake     visit_type_TestStruct(v, NULL, (TestStruct **)native, errp);
2122d496105SMichael Roth }
2132d496105SMichael Roth 
214b6fcf32dSEric Blake static UserDefTwo *nested_struct_create(void)
2152d496105SMichael Roth {
216b6fcf32dSEric Blake     UserDefTwo *udnp = g_malloc0(sizeof(*udnp));
2172d496105SMichael Roth     udnp->string0 = strdup("test_string0");
2186446a592SEric Blake     udnp->dict1 = g_malloc0(sizeof(*udnp->dict1));
2196446a592SEric Blake     udnp->dict1->string1 = strdup("test_string1");
2206446a592SEric Blake     udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2));
2216446a592SEric Blake     udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1);
222ddf21908SEric Blake     udnp->dict1->dict2->userdef->integer = 42;
2236446a592SEric Blake     udnp->dict1->dict2->userdef->string = strdup("test_string");
2246446a592SEric Blake     udnp->dict1->dict2->string = strdup("test_string2");
2256446a592SEric Blake     udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3));
2266446a592SEric Blake     udnp->dict1->has_dict3 = true;
2276446a592SEric Blake     udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1);
228ddf21908SEric Blake     udnp->dict1->dict3->userdef->integer = 43;
2296446a592SEric Blake     udnp->dict1->dict3->userdef->string = strdup("test_string");
2306446a592SEric Blake     udnp->dict1->dict3->string = strdup("test_string3");
2312d496105SMichael Roth     return udnp;
2322d496105SMichael Roth }
2332d496105SMichael Roth 
234b6fcf32dSEric Blake static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2)
2352d496105SMichael Roth {
2362d496105SMichael Roth     g_assert(udnp1);
2372d496105SMichael Roth     g_assert(udnp2);
2382d496105SMichael Roth     g_assert_cmpstr(udnp1->string0, ==, udnp2->string0);
2396446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1);
240ddf21908SEric Blake     g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==,
241ddf21908SEric Blake                     udnp2->dict1->dict2->userdef->integer);
2426446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==,
2436446a592SEric Blake                     udnp2->dict1->dict2->userdef->string);
2446446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict2->string, ==,
2456446a592SEric Blake                     udnp2->dict1->dict2->string);
2466446a592SEric Blake     g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3);
247ddf21908SEric Blake     g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==,
248ddf21908SEric Blake                     udnp2->dict1->dict3->userdef->integer);
2496446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==,
2506446a592SEric Blake                     udnp2->dict1->dict3->userdef->string);
2516446a592SEric Blake     g_assert_cmpstr(udnp1->dict1->dict3->string, ==,
2526446a592SEric Blake                     udnp2->dict1->dict3->string);
2532d496105SMichael Roth }
2542d496105SMichael Roth 
255b6fcf32dSEric Blake static void nested_struct_cleanup(UserDefTwo *udnp)
2562d496105SMichael Roth {
257b6fcf32dSEric Blake     qapi_free_UserDefTwo(udnp);
2582d496105SMichael Roth }
2592d496105SMichael Roth 
2602d496105SMichael Roth static void visit_nested_struct(Visitor *v, void **native, Error **errp)
2612d496105SMichael Roth {
26251e72bc1SEric Blake     visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp);
2632d496105SMichael Roth }
2642d496105SMichael Roth 
2652d496105SMichael Roth static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
2662d496105SMichael Roth {
26751e72bc1SEric Blake     visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp);
2682d496105SMichael Roth }
2692d496105SMichael Roth 
2702d496105SMichael Roth /* test cases */
2712d496105SMichael Roth 
2722d496105SMichael Roth typedef enum VisitorCapabilities {
2732d496105SMichael Roth     VCAP_PRIMITIVES = 1,
2742d496105SMichael Roth     VCAP_STRUCTURES = 2,
2752d496105SMichael Roth     VCAP_LISTS = 4,
2768addacddSMichael Roth     VCAP_PRIMITIVE_LISTS = 8,
2772d496105SMichael Roth } VisitorCapabilities;
2782d496105SMichael Roth 
2792d496105SMichael Roth typedef struct SerializeOps {
2802d496105SMichael Roth     void (*serialize)(void *native_in, void **datap,
2812d496105SMichael Roth                       VisitorFunc visit, Error **errp);
2822d496105SMichael Roth     void (*deserialize)(void **native_out, void *datap,
2832d496105SMichael Roth                             VisitorFunc visit, Error **errp);
2842d496105SMichael Roth     void (*cleanup)(void *datap);
2852d496105SMichael Roth     const char *type;
2862d496105SMichael Roth     VisitorCapabilities caps;
2872d496105SMichael Roth } SerializeOps;
2882d496105SMichael Roth 
2892d496105SMichael Roth typedef struct TestArgs {
2902d496105SMichael Roth     const SerializeOps *ops;
2912d496105SMichael Roth     void *test_data;
2922d496105SMichael Roth } TestArgs;
2932d496105SMichael Roth 
2942d496105SMichael Roth static void test_primitives(gconstpointer opaque)
2952d496105SMichael Roth {
2962d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
2972d496105SMichael Roth     const SerializeOps *ops = args->ops;
2982d496105SMichael Roth     PrimitiveType *pt = args->test_data;
2992d496105SMichael Roth     PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
3002d496105SMichael Roth     void *serialize_data;
3012d496105SMichael Roth 
3022d496105SMichael Roth     pt_copy->type = pt->type;
3033f66f764SEric Blake     ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort);
3043f66f764SEric Blake     ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type,
3053f66f764SEric Blake                      &error_abort);
3062d496105SMichael Roth 
3072d496105SMichael Roth     g_assert(pt_copy != NULL);
30828f1c1f6SMarkus Armbruster     switch (pt->type) {
30928f1c1f6SMarkus Armbruster     case PTYPE_STRING:
3102d496105SMichael Roth         g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
3112bd01ac1SStefan Berger         g_free((char *)pt_copy->value.string);
31228f1c1f6SMarkus Armbruster         break;
31328f1c1f6SMarkus Armbruster     case PTYPE_BOOLEAN:
31428f1c1f6SMarkus Armbruster         g_assert_cmpint(pt->value.boolean, ==, pt->value.boolean);
31528f1c1f6SMarkus Armbruster         break;
31628f1c1f6SMarkus Armbruster     case PTYPE_NUMBER:
3172a02c139SMarkus Armbruster         g_assert_cmpfloat(pt->value.number, ==, pt_copy->value.number);
31828f1c1f6SMarkus Armbruster         break;
31928f1c1f6SMarkus Armbruster     case PTYPE_INTEGER:
32028f1c1f6SMarkus Armbruster         g_assert_cmpint(pt->value.integer, ==, pt_copy->value.integer);
32128f1c1f6SMarkus Armbruster         break;
32228f1c1f6SMarkus Armbruster     case PTYPE_U8:
32328f1c1f6SMarkus Armbruster         g_assert_cmpuint(pt->value.u8, ==, pt_copy->value.u8);
32428f1c1f6SMarkus Armbruster         break;
32528f1c1f6SMarkus Armbruster     case PTYPE_U16:
32628f1c1f6SMarkus Armbruster         g_assert_cmpuint(pt->value.u16, ==, pt_copy->value.u16);
32728f1c1f6SMarkus Armbruster         break;
32828f1c1f6SMarkus Armbruster     case PTYPE_U32:
32928f1c1f6SMarkus Armbruster         g_assert_cmpuint(pt->value.u32, ==, pt_copy->value.u32);
33028f1c1f6SMarkus Armbruster         break;
33128f1c1f6SMarkus Armbruster     case PTYPE_U64:
33228f1c1f6SMarkus Armbruster         g_assert_cmpuint(pt->value.u64, ==, pt_copy->value.u64);
33328f1c1f6SMarkus Armbruster         break;
33428f1c1f6SMarkus Armbruster     case PTYPE_S8:
33528f1c1f6SMarkus Armbruster         g_assert_cmpint(pt->value.s8, ==, pt_copy->value.s8);
33628f1c1f6SMarkus Armbruster         break;
33728f1c1f6SMarkus Armbruster     case PTYPE_S16:
33828f1c1f6SMarkus Armbruster         g_assert_cmpint(pt->value.s16, ==, pt_copy->value.s16);
33928f1c1f6SMarkus Armbruster         break;
34028f1c1f6SMarkus Armbruster     case PTYPE_S32:
34128f1c1f6SMarkus Armbruster         g_assert_cmpint(pt->value.s32, ==, pt_copy->value.s32);
34228f1c1f6SMarkus Armbruster         break;
34328f1c1f6SMarkus Armbruster     case PTYPE_S64:
34428f1c1f6SMarkus Armbruster         g_assert_cmpint(pt->value.s64, ==, pt_copy->value.s64);
34528f1c1f6SMarkus Armbruster         break;
34628f1c1f6SMarkus Armbruster     case PTYPE_EOL:
34728f1c1f6SMarkus Armbruster         g_assert_not_reached();
3482d496105SMichael Roth     }
3492d496105SMichael Roth 
3502d496105SMichael Roth     ops->cleanup(serialize_data);
3512d496105SMichael Roth     g_free(args);
3522bd01ac1SStefan Berger     g_free(pt_copy);
3532d496105SMichael Roth }
3542d496105SMichael Roth 
3558addacddSMichael Roth static void test_primitive_lists(gconstpointer opaque)
3568addacddSMichael Roth {
3578addacddSMichael Roth     TestArgs *args = (TestArgs *) opaque;
3588addacddSMichael Roth     const SerializeOps *ops = args->ops;
3598addacddSMichael Roth     PrimitiveType *pt = args->test_data;
360748bfb4eSStefan Weil     PrimitiveList pl = { .value = { NULL } };
361748bfb4eSStefan Weil     PrimitiveList pl_copy = { .value = { NULL } };
3628addacddSMichael Roth     PrimitiveList *pl_copy_ptr = &pl_copy;
3638addacddSMichael Roth     void *serialize_data;
3648addacddSMichael Roth     void *cur_head = NULL;
3658addacddSMichael Roth     int i;
3668addacddSMichael Roth 
3678addacddSMichael Roth     pl.type = pl_copy.type = pt->type;
3688addacddSMichael Roth 
3698addacddSMichael Roth     /* build up our list of primitive types */
3708addacddSMichael Roth     for (i = 0; i < 32; i++) {
3718addacddSMichael Roth         switch (pl.type) {
3728addacddSMichael Roth         case PTYPE_STRING: {
37354aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.strings, g_strdup(pt->value.string));
3748addacddSMichael Roth             break;
3758addacddSMichael Roth         }
3768addacddSMichael Roth         case PTYPE_INTEGER: {
37754aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.integers, pt->value.integer);
3788addacddSMichael Roth             break;
3798addacddSMichael Roth         }
3808addacddSMichael Roth         case PTYPE_S8: {
38154aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.s8_integers, pt->value.s8);
3828addacddSMichael Roth             break;
3838addacddSMichael Roth         }
3848addacddSMichael Roth         case PTYPE_S16: {
38554aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.s16_integers, pt->value.s16);
3868addacddSMichael Roth             break;
3878addacddSMichael Roth         }
3888addacddSMichael Roth         case PTYPE_S32: {
38954aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.s32_integers, pt->value.s32);
3908addacddSMichael Roth             break;
3918addacddSMichael Roth         }
3928addacddSMichael Roth         case PTYPE_S64: {
39354aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.s64_integers, pt->value.s64);
3948addacddSMichael Roth             break;
3958addacddSMichael Roth         }
3968addacddSMichael Roth         case PTYPE_U8: {
39754aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.u8_integers, pt->value.u8);
3988addacddSMichael Roth             break;
3998addacddSMichael Roth         }
4008addacddSMichael Roth         case PTYPE_U16: {
40154aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.u16_integers, pt->value.u16);
4028addacddSMichael Roth             break;
4038addacddSMichael Roth         }
4048addacddSMichael Roth         case PTYPE_U32: {
40554aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.u32_integers, pt->value.u32);
4068addacddSMichael Roth             break;
4078addacddSMichael Roth         }
4088addacddSMichael Roth         case PTYPE_U64: {
40954aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.u64_integers, pt->value.u64);
4108addacddSMichael Roth             break;
4118addacddSMichael Roth         }
4128addacddSMichael Roth         case PTYPE_NUMBER: {
41354aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.numbers, pt->value.number);
4148addacddSMichael Roth             break;
4158addacddSMichael Roth         }
4168addacddSMichael Roth         case PTYPE_BOOLEAN: {
41754aa3de7SEric Blake             QAPI_LIST_PREPEND(pl.value.booleans, pt->value.boolean);
4188addacddSMichael Roth             break;
4198addacddSMichael Roth         }
4208addacddSMichael Roth         default:
421dfc6f865SStefan Weil             g_assert_not_reached();
4228addacddSMichael Roth         }
4238addacddSMichael Roth     }
4248addacddSMichael Roth 
4253f66f764SEric Blake     ops->serialize((void **)&pl, &serialize_data, visit_primitive_list,
4263f66f764SEric Blake                    &error_abort);
4273f66f764SEric Blake     ops->deserialize((void **)&pl_copy_ptr, serialize_data,
4283f66f764SEric Blake                      visit_primitive_list, &error_abort);
4298addacddSMichael Roth 
430*ac9e723fSPaolo Bonzini 
431*ac9e723fSPaolo Bonzini     switch (pl_copy.type) {
432*ac9e723fSPaolo Bonzini     case PTYPE_STRING:
433*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.strings;
434*ac9e723fSPaolo Bonzini         break;
435*ac9e723fSPaolo Bonzini     case PTYPE_INTEGER:
436*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.integers;
437*ac9e723fSPaolo Bonzini         break;
438*ac9e723fSPaolo Bonzini     case PTYPE_S8:
439*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.s8_integers;
440*ac9e723fSPaolo Bonzini         break;
441*ac9e723fSPaolo Bonzini     case PTYPE_S16:
442*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.s16_integers;
443*ac9e723fSPaolo Bonzini         break;
444*ac9e723fSPaolo Bonzini     case PTYPE_S32:
445*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.s32_integers;
446*ac9e723fSPaolo Bonzini         break;
447*ac9e723fSPaolo Bonzini     case PTYPE_S64:
448*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.s64_integers;
449*ac9e723fSPaolo Bonzini         break;
450*ac9e723fSPaolo Bonzini     case PTYPE_U8:
451*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.u8_integers;
452*ac9e723fSPaolo Bonzini         break;
453*ac9e723fSPaolo Bonzini     case PTYPE_U16:
454*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.u16_integers;
455*ac9e723fSPaolo Bonzini         break;
456*ac9e723fSPaolo Bonzini     case PTYPE_U32:
457*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.u32_integers;
458*ac9e723fSPaolo Bonzini         break;
459*ac9e723fSPaolo Bonzini     case PTYPE_U64:
460*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.u64_integers;
461*ac9e723fSPaolo Bonzini         break;
462*ac9e723fSPaolo Bonzini     case PTYPE_NUMBER:
463*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.numbers;
464*ac9e723fSPaolo Bonzini         break;
465*ac9e723fSPaolo Bonzini     case PTYPE_BOOLEAN:
466*ac9e723fSPaolo Bonzini         cur_head = pl_copy.value.booleans;
467*ac9e723fSPaolo Bonzini         break;
468*ac9e723fSPaolo Bonzini     default:
469*ac9e723fSPaolo Bonzini         g_assert_not_reached();
470*ac9e723fSPaolo Bonzini     }
4718addacddSMichael Roth 
4728addacddSMichael Roth     /* compare our deserialized list of primitives to the original */
473*ac9e723fSPaolo Bonzini     i = 0;
474*ac9e723fSPaolo Bonzini     while (cur_head) {
4758addacddSMichael Roth         switch (pl_copy.type) {
4768addacddSMichael Roth         case PTYPE_STRING: {
477*ac9e723fSPaolo Bonzini             strList *ptr = cur_head;
4788addacddSMichael Roth             cur_head = ptr->next;
4798addacddSMichael Roth             g_assert_cmpstr(pt->value.string, ==, ptr->value);
4808addacddSMichael Roth             break;
4818addacddSMichael Roth         }
4828addacddSMichael Roth         case PTYPE_INTEGER: {
483*ac9e723fSPaolo Bonzini             intList *ptr = cur_head;
4848addacddSMichael Roth             cur_head = ptr->next;
4858addacddSMichael Roth             g_assert_cmpint(pt->value.integer, ==, ptr->value);
4868addacddSMichael Roth             break;
4878addacddSMichael Roth         }
4888addacddSMichael Roth         case PTYPE_S8: {
489*ac9e723fSPaolo Bonzini             int8List *ptr = cur_head;
4908addacddSMichael Roth             cur_head = ptr->next;
4918addacddSMichael Roth             g_assert_cmpint(pt->value.s8, ==, ptr->value);
4928addacddSMichael Roth             break;
4938addacddSMichael Roth         }
4948addacddSMichael Roth         case PTYPE_S16: {
495*ac9e723fSPaolo Bonzini             int16List *ptr = cur_head;
4968addacddSMichael Roth             cur_head = ptr->next;
4978addacddSMichael Roth             g_assert_cmpint(pt->value.s16, ==, ptr->value);
4988addacddSMichael Roth             break;
4998addacddSMichael Roth         }
5008addacddSMichael Roth         case PTYPE_S32: {
501*ac9e723fSPaolo Bonzini             int32List *ptr = cur_head;
5028addacddSMichael Roth             cur_head = ptr->next;
5038addacddSMichael Roth             g_assert_cmpint(pt->value.s32, ==, ptr->value);
5048addacddSMichael Roth             break;
5058addacddSMichael Roth         }
5068addacddSMichael Roth         case PTYPE_S64: {
507*ac9e723fSPaolo Bonzini             int64List *ptr = cur_head;
5088addacddSMichael Roth             cur_head = ptr->next;
5098addacddSMichael Roth             g_assert_cmpint(pt->value.s64, ==, ptr->value);
5108addacddSMichael Roth             break;
5118addacddSMichael Roth         }
5128addacddSMichael Roth         case PTYPE_U8: {
513*ac9e723fSPaolo Bonzini             uint8List *ptr = cur_head;
5148addacddSMichael Roth             cur_head = ptr->next;
5158addacddSMichael Roth             g_assert_cmpint(pt->value.u8, ==, ptr->value);
5168addacddSMichael Roth             break;
5178addacddSMichael Roth         }
5188addacddSMichael Roth         case PTYPE_U16: {
519*ac9e723fSPaolo Bonzini             uint16List *ptr = cur_head;
5208addacddSMichael Roth             cur_head = ptr->next;
5218addacddSMichael Roth             g_assert_cmpint(pt->value.u16, ==, ptr->value);
5228addacddSMichael Roth             break;
5238addacddSMichael Roth         }
5248addacddSMichael Roth         case PTYPE_U32: {
525*ac9e723fSPaolo Bonzini             uint32List *ptr = cur_head;
5268addacddSMichael Roth             cur_head = ptr->next;
5278addacddSMichael Roth             g_assert_cmpint(pt->value.u32, ==, ptr->value);
5288addacddSMichael Roth             break;
5298addacddSMichael Roth         }
5308addacddSMichael Roth         case PTYPE_U64: {
531*ac9e723fSPaolo Bonzini             uint64List *ptr = cur_head;
5328addacddSMichael Roth             cur_head = ptr->next;
5338addacddSMichael Roth             g_assert_cmpint(pt->value.u64, ==, ptr->value);
5348addacddSMichael Roth             break;
5358addacddSMichael Roth         }
5368addacddSMichael Roth         case PTYPE_NUMBER: {
5378addacddSMichael Roth             GString *double_expected = g_string_new("");
5388addacddSMichael Roth             GString *double_actual = g_string_new("");
539*ac9e723fSPaolo Bonzini             numberList *ptr = cur_head;
5408addacddSMichael Roth             cur_head = ptr->next;
5418addacddSMichael Roth             /* we serialize with %f for our reference visitors, so rather than
5428addacddSMichael Roth              * fuzzy floating math to test "equality", just compare the
5438addacddSMichael Roth              * formatted values
5448addacddSMichael Roth              */
5458addacddSMichael Roth             g_string_printf(double_expected, "%.6f", pt->value.number);
5468addacddSMichael Roth             g_string_printf(double_actual, "%.6f", ptr->value);
5478addacddSMichael Roth             g_assert_cmpstr(double_actual->str, ==, double_expected->str);
5488addacddSMichael Roth             g_string_free(double_expected, true);
5498addacddSMichael Roth             g_string_free(double_actual, true);
5508addacddSMichael Roth             break;
5518addacddSMichael Roth         }
5528addacddSMichael Roth         case PTYPE_BOOLEAN: {
553*ac9e723fSPaolo Bonzini             boolList *ptr = cur_head;
5548addacddSMichael Roth             cur_head = ptr->next;
5558addacddSMichael Roth             g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
5568addacddSMichael Roth             break;
5578addacddSMichael Roth         }
5588addacddSMichael Roth         default:
559dfc6f865SStefan Weil             g_assert_not_reached();
5608addacddSMichael Roth         }
5618addacddSMichael Roth         i++;
562*ac9e723fSPaolo Bonzini     }
5638addacddSMichael Roth 
564*ac9e723fSPaolo Bonzini     g_assert_cmpint(i, ==, 32);
5658addacddSMichael Roth 
5668addacddSMichael Roth     ops->cleanup(serialize_data);
5673f66f764SEric Blake     dealloc_helper(&pl, visit_primitive_list, &error_abort);
5683f66f764SEric Blake     dealloc_helper(&pl_copy, visit_primitive_list, &error_abort);
5698addacddSMichael Roth     g_free(args);
5708addacddSMichael Roth }
5718addacddSMichael Roth 
5722d496105SMichael Roth static void test_struct(gconstpointer opaque)
5732d496105SMichael Roth {
5742d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
5752d496105SMichael Roth     const SerializeOps *ops = args->ops;
5762d496105SMichael Roth     TestStruct *ts = struct_create();
5772d496105SMichael Roth     TestStruct *ts_copy = NULL;
5782d496105SMichael Roth     void *serialize_data;
5792d496105SMichael Roth 
5803f66f764SEric Blake     ops->serialize(ts, &serialize_data, visit_struct, &error_abort);
5813f66f764SEric Blake     ops->deserialize((void **)&ts_copy, serialize_data, visit_struct,
5823f66f764SEric Blake                      &error_abort);
5832d496105SMichael Roth 
5842d496105SMichael Roth     struct_compare(ts, ts_copy);
5852d496105SMichael Roth 
5862d496105SMichael Roth     struct_cleanup(ts);
5872d496105SMichael Roth     struct_cleanup(ts_copy);
5882d496105SMichael Roth 
5892d496105SMichael Roth     ops->cleanup(serialize_data);
5902d496105SMichael Roth     g_free(args);
5912d496105SMichael Roth }
5922d496105SMichael Roth 
5932d496105SMichael Roth static void test_nested_struct(gconstpointer opaque)
5942d496105SMichael Roth {
5952d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
5962d496105SMichael Roth     const SerializeOps *ops = args->ops;
597b6fcf32dSEric Blake     UserDefTwo *udnp = nested_struct_create();
598b6fcf32dSEric Blake     UserDefTwo *udnp_copy = NULL;
5992d496105SMichael Roth     void *serialize_data;
6002d496105SMichael Roth 
6013f66f764SEric Blake     ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort);
602b6fcf32dSEric Blake     ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct,
6033f66f764SEric Blake                      &error_abort);
6042d496105SMichael Roth 
6052d496105SMichael Roth     nested_struct_compare(udnp, udnp_copy);
6062d496105SMichael Roth 
6072d496105SMichael Roth     nested_struct_cleanup(udnp);
6082d496105SMichael Roth     nested_struct_cleanup(udnp_copy);
6092d496105SMichael Roth 
6102d496105SMichael Roth     ops->cleanup(serialize_data);
6112d496105SMichael Roth     g_free(args);
6122d496105SMichael Roth }
6132d496105SMichael Roth 
6142d496105SMichael Roth static void test_nested_struct_list(gconstpointer opaque)
6152d496105SMichael Roth {
6162d496105SMichael Roth     TestArgs *args = (TestArgs *) opaque;
6172d496105SMichael Roth     const SerializeOps *ops = args->ops;
618b6fcf32dSEric Blake     UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL;
6192d496105SMichael Roth     void *serialize_data;
6202d496105SMichael Roth     int i = 0;
6212d496105SMichael Roth 
6222d496105SMichael Roth     for (i = 0; i < 8; i++) {
62354aa3de7SEric Blake         QAPI_LIST_PREPEND(listp, nested_struct_create());
6242d496105SMichael Roth     }
6252d496105SMichael Roth 
6263f66f764SEric Blake     ops->serialize(listp, &serialize_data, visit_nested_struct_list,
6273f66f764SEric Blake                    &error_abort);
6282d496105SMichael Roth     ops->deserialize((void **)&listp_copy, serialize_data,
6293f66f764SEric Blake                      visit_nested_struct_list, &error_abort);
6302d496105SMichael Roth 
6312d496105SMichael Roth     tmp = listp;
6322d496105SMichael Roth     tmp_copy = listp_copy;
6332d496105SMichael Roth     while (listp_copy) {
6342d496105SMichael Roth         g_assert(listp);
6352d496105SMichael Roth         nested_struct_compare(listp->value, listp_copy->value);
6362d496105SMichael Roth         listp = listp->next;
6372d496105SMichael Roth         listp_copy = listp_copy->next;
6382d496105SMichael Roth     }
6392d496105SMichael Roth 
640b6fcf32dSEric Blake     qapi_free_UserDefTwoList(tmp);
641b6fcf32dSEric Blake     qapi_free_UserDefTwoList(tmp_copy);
6422d496105SMichael Roth 
6432d496105SMichael Roth     ops->cleanup(serialize_data);
6442d496105SMichael Roth     g_free(args);
6452d496105SMichael Roth }
6462d496105SMichael Roth 
647748bfb4eSStefan Weil static PrimitiveType pt_values[] = {
6482d496105SMichael Roth     /* string tests */
6492d496105SMichael Roth     {
6502d496105SMichael Roth         .description = "string_empty",
6512d496105SMichael Roth         .type = PTYPE_STRING,
6522d496105SMichael Roth         .value.string = "",
6532d496105SMichael Roth     },
6542d496105SMichael Roth     {
6552d496105SMichael Roth         .description = "string_whitespace",
6562d496105SMichael Roth         .type = PTYPE_STRING,
6572d496105SMichael Roth         .value.string = "a b  c\td",
6582d496105SMichael Roth     },
6592d496105SMichael Roth     {
6602d496105SMichael Roth         .description = "string_newlines",
6612d496105SMichael Roth         .type = PTYPE_STRING,
6622d496105SMichael Roth         .value.string = "a\nb\n",
6632d496105SMichael Roth     },
6642d496105SMichael Roth     {
6652d496105SMichael Roth         .description = "string_commas",
6662d496105SMichael Roth         .type = PTYPE_STRING,
6672d496105SMichael Roth         .value.string = "a,b, c,d",
6682d496105SMichael Roth     },
6692d496105SMichael Roth     {
6702d496105SMichael Roth         .description = "string_single_quoted",
6712d496105SMichael Roth         .type = PTYPE_STRING,
6722d496105SMichael Roth         .value.string = "'a b',cd",
6732d496105SMichael Roth     },
6742d496105SMichael Roth     {
6752d496105SMichael Roth         .description = "string_double_quoted",
6762d496105SMichael Roth         .type = PTYPE_STRING,
6772d496105SMichael Roth         .value.string = "\"a b\",cd",
6782d496105SMichael Roth     },
6792d496105SMichael Roth     /* boolean tests */
6802d496105SMichael Roth     {
6812d496105SMichael Roth         .description = "boolean_true1",
6822d496105SMichael Roth         .type = PTYPE_BOOLEAN,
6832d496105SMichael Roth         .value.boolean = true,
6842d496105SMichael Roth     },
6852d496105SMichael Roth     {
6862d496105SMichael Roth         .description = "boolean_true2",
6872d496105SMichael Roth         .type = PTYPE_BOOLEAN,
6882d496105SMichael Roth         .value.boolean = 8,
6892d496105SMichael Roth     },
6902d496105SMichael Roth     {
6912d496105SMichael Roth         .description = "boolean_true3",
6922d496105SMichael Roth         .type = PTYPE_BOOLEAN,
6932d496105SMichael Roth         .value.boolean = -1,
6942d496105SMichael Roth     },
6952d496105SMichael Roth     {
6962d496105SMichael Roth         .description = "boolean_false1",
6972d496105SMichael Roth         .type = PTYPE_BOOLEAN,
6982d496105SMichael Roth         .value.boolean = false,
6992d496105SMichael Roth     },
7002d496105SMichael Roth     {
7012d496105SMichael Roth         .description = "boolean_false2",
7022d496105SMichael Roth         .type = PTYPE_BOOLEAN,
7032d496105SMichael Roth         .value.boolean = 0,
7042d496105SMichael Roth     },
7052d496105SMichael Roth     /* number tests (double) */
7062d496105SMichael Roth     {
7072d496105SMichael Roth         .description = "number_sanity1",
7082d496105SMichael Roth         .type = PTYPE_NUMBER,
7092d496105SMichael Roth         .value.number = -1,
7102d496105SMichael Roth     },
7112d496105SMichael Roth     {
7122d496105SMichael Roth         .description = "number_sanity2",
7132d496105SMichael Roth         .type = PTYPE_NUMBER,
7142a02c139SMarkus Armbruster         .value.number = 3.141593,
7152d496105SMichael Roth     },
7162d496105SMichael Roth     {
7172d496105SMichael Roth         .description = "number_min",
7182d496105SMichael Roth         .type = PTYPE_NUMBER,
7192d496105SMichael Roth         .value.number = DBL_MIN,
7202d496105SMichael Roth     },
7212d496105SMichael Roth     {
7222d496105SMichael Roth         .description = "number_max",
7232d496105SMichael Roth         .type = PTYPE_NUMBER,
7242d496105SMichael Roth         .value.number = DBL_MAX,
7252d496105SMichael Roth     },
7262d496105SMichael Roth     /* integer tests (int64) */
7272d496105SMichael Roth     {
7282d496105SMichael Roth         .description = "integer_sanity1",
7292d496105SMichael Roth         .type = PTYPE_INTEGER,
7302d496105SMichael Roth         .value.integer = -1,
7312d496105SMichael Roth     },
7322d496105SMichael Roth     {
7332d496105SMichael Roth         .description = "integer_sanity2",
7342d496105SMichael Roth         .type = PTYPE_INTEGER,
7352d496105SMichael Roth         .value.integer = INT64_MAX / 2 + 1,
7362d496105SMichael Roth     },
7372d496105SMichael Roth     {
7382d496105SMichael Roth         .description = "integer_min",
7392d496105SMichael Roth         .type = PTYPE_INTEGER,
7402d496105SMichael Roth         .value.integer = INT64_MIN,
7412d496105SMichael Roth     },
7422d496105SMichael Roth     {
7432d496105SMichael Roth         .description = "integer_max",
7442d496105SMichael Roth         .type = PTYPE_INTEGER,
7452d496105SMichael Roth         .value.integer = INT64_MAX,
7462d496105SMichael Roth     },
7472d496105SMichael Roth     /* uint8 tests */
7482d496105SMichael Roth     {
7492d496105SMichael Roth         .description = "uint8_sanity1",
7502d496105SMichael Roth         .type = PTYPE_U8,
7512d496105SMichael Roth         .value.u8 = 1,
7522d496105SMichael Roth     },
7532d496105SMichael Roth     {
7542d496105SMichael Roth         .description = "uint8_sanity2",
7552d496105SMichael Roth         .type = PTYPE_U8,
7562d496105SMichael Roth         .value.u8 = UINT8_MAX / 2 + 1,
7572d496105SMichael Roth     },
7582d496105SMichael Roth     {
7592d496105SMichael Roth         .description = "uint8_min",
7602d496105SMichael Roth         .type = PTYPE_U8,
7612d496105SMichael Roth         .value.u8 = 0,
7622d496105SMichael Roth     },
7632d496105SMichael Roth     {
7642d496105SMichael Roth         .description = "uint8_max",
7652d496105SMichael Roth         .type = PTYPE_U8,
7662d496105SMichael Roth         .value.u8 = UINT8_MAX,
7672d496105SMichael Roth     },
7682d496105SMichael Roth     /* uint16 tests */
7692d496105SMichael Roth     {
7702d496105SMichael Roth         .description = "uint16_sanity1",
7712d496105SMichael Roth         .type = PTYPE_U16,
7722d496105SMichael Roth         .value.u16 = 1,
7732d496105SMichael Roth     },
7742d496105SMichael Roth     {
7752d496105SMichael Roth         .description = "uint16_sanity2",
7762d496105SMichael Roth         .type = PTYPE_U16,
7772d496105SMichael Roth         .value.u16 = UINT16_MAX / 2 + 1,
7782d496105SMichael Roth     },
7792d496105SMichael Roth     {
7802d496105SMichael Roth         .description = "uint16_min",
7812d496105SMichael Roth         .type = PTYPE_U16,
7822d496105SMichael Roth         .value.u16 = 0,
7832d496105SMichael Roth     },
7842d496105SMichael Roth     {
7852d496105SMichael Roth         .description = "uint16_max",
7862d496105SMichael Roth         .type = PTYPE_U16,
7872d496105SMichael Roth         .value.u16 = UINT16_MAX,
7882d496105SMichael Roth     },
7892d496105SMichael Roth     /* uint32 tests */
7902d496105SMichael Roth     {
7912d496105SMichael Roth         .description = "uint32_sanity1",
7922d496105SMichael Roth         .type = PTYPE_U32,
7932d496105SMichael Roth         .value.u32 = 1,
7942d496105SMichael Roth     },
7952d496105SMichael Roth     {
7962d496105SMichael Roth         .description = "uint32_sanity2",
7972d496105SMichael Roth         .type = PTYPE_U32,
7982d496105SMichael Roth         .value.u32 = UINT32_MAX / 2 + 1,
7992d496105SMichael Roth     },
8002d496105SMichael Roth     {
8012d496105SMichael Roth         .description = "uint32_min",
8022d496105SMichael Roth         .type = PTYPE_U32,
8032d496105SMichael Roth         .value.u32 = 0,
8042d496105SMichael Roth     },
8052d496105SMichael Roth     {
8062d496105SMichael Roth         .description = "uint32_max",
8072d496105SMichael Roth         .type = PTYPE_U32,
8082d496105SMichael Roth         .value.u32 = UINT32_MAX,
8092d496105SMichael Roth     },
8102d496105SMichael Roth     /* uint64 tests */
8112d496105SMichael Roth     {
8122d496105SMichael Roth         .description = "uint64_sanity1",
8132d496105SMichael Roth         .type = PTYPE_U64,
8142d496105SMichael Roth         .value.u64 = 1,
8152d496105SMichael Roth     },
8162d496105SMichael Roth     {
8172d496105SMichael Roth         .description = "uint64_sanity2",
8182d496105SMichael Roth         .type = PTYPE_U64,
8192d496105SMichael Roth         .value.u64 = UINT64_MAX / 2 + 1,
8202d496105SMichael Roth     },
8212d496105SMichael Roth     {
8222d496105SMichael Roth         .description = "uint64_min",
8232d496105SMichael Roth         .type = PTYPE_U64,
8242d496105SMichael Roth         .value.u64 = 0,
8252d496105SMichael Roth     },
8262d496105SMichael Roth     {
8272d496105SMichael Roth         .description = "uint64_max",
8282d496105SMichael Roth         .type = PTYPE_U64,
8292d496105SMichael Roth         .value.u64 = UINT64_MAX,
8302d496105SMichael Roth     },
8312d496105SMichael Roth     /* int8 tests */
8322d496105SMichael Roth     {
8332d496105SMichael Roth         .description = "int8_sanity1",
8342d496105SMichael Roth         .type = PTYPE_S8,
8352d496105SMichael Roth         .value.s8 = -1,
8362d496105SMichael Roth     },
8372d496105SMichael Roth     {
8382d496105SMichael Roth         .description = "int8_sanity2",
8392d496105SMichael Roth         .type = PTYPE_S8,
8402d496105SMichael Roth         .value.s8 = INT8_MAX / 2 + 1,
8412d496105SMichael Roth     },
8422d496105SMichael Roth     {
8432d496105SMichael Roth         .description = "int8_min",
8442d496105SMichael Roth         .type = PTYPE_S8,
8452d496105SMichael Roth         .value.s8 = INT8_MIN,
8462d496105SMichael Roth     },
8472d496105SMichael Roth     {
8482d496105SMichael Roth         .description = "int8_max",
8492d496105SMichael Roth         .type = PTYPE_S8,
8502d496105SMichael Roth         .value.s8 = INT8_MAX,
8512d496105SMichael Roth     },
8522d496105SMichael Roth     /* int16 tests */
8532d496105SMichael Roth     {
8542d496105SMichael Roth         .description = "int16_sanity1",
8552d496105SMichael Roth         .type = PTYPE_S16,
8562d496105SMichael Roth         .value.s16 = -1,
8572d496105SMichael Roth     },
8582d496105SMichael Roth     {
8592d496105SMichael Roth         .description = "int16_sanity2",
8602d496105SMichael Roth         .type = PTYPE_S16,
8612d496105SMichael Roth         .value.s16 = INT16_MAX / 2 + 1,
8622d496105SMichael Roth     },
8632d496105SMichael Roth     {
8642d496105SMichael Roth         .description = "int16_min",
8652d496105SMichael Roth         .type = PTYPE_S16,
8662d496105SMichael Roth         .value.s16 = INT16_MIN,
8672d496105SMichael Roth     },
8682d496105SMichael Roth     {
8692d496105SMichael Roth         .description = "int16_max",
8702d496105SMichael Roth         .type = PTYPE_S16,
8712d496105SMichael Roth         .value.s16 = INT16_MAX,
8722d496105SMichael Roth     },
8732d496105SMichael Roth     /* int32 tests */
8742d496105SMichael Roth     {
8752d496105SMichael Roth         .description = "int32_sanity1",
8762d496105SMichael Roth         .type = PTYPE_S32,
8772d496105SMichael Roth         .value.s32 = -1,
8782d496105SMichael Roth     },
8792d496105SMichael Roth     {
8802d496105SMichael Roth         .description = "int32_sanity2",
8812d496105SMichael Roth         .type = PTYPE_S32,
8822d496105SMichael Roth         .value.s32 = INT32_MAX / 2 + 1,
8832d496105SMichael Roth     },
8842d496105SMichael Roth     {
8852d496105SMichael Roth         .description = "int32_min",
8862d496105SMichael Roth         .type = PTYPE_S32,
8872d496105SMichael Roth         .value.s32 = INT32_MIN,
8882d496105SMichael Roth     },
8892d496105SMichael Roth     {
8902d496105SMichael Roth         .description = "int32_max",
8912d496105SMichael Roth         .type = PTYPE_S32,
8922d496105SMichael Roth         .value.s32 = INT32_MAX,
8932d496105SMichael Roth     },
8942d496105SMichael Roth     /* int64 tests */
8952d496105SMichael Roth     {
8962d496105SMichael Roth         .description = "int64_sanity1",
8972d496105SMichael Roth         .type = PTYPE_S64,
8982d496105SMichael Roth         .value.s64 = -1,
8992d496105SMichael Roth     },
9002d496105SMichael Roth     {
9012d496105SMichael Roth         .description = "int64_sanity2",
9022d496105SMichael Roth         .type = PTYPE_S64,
9032d496105SMichael Roth         .value.s64 = INT64_MAX / 2 + 1,
9042d496105SMichael Roth     },
9052d496105SMichael Roth     {
9062d496105SMichael Roth         .description = "int64_min",
9072d496105SMichael Roth         .type = PTYPE_S64,
9082d496105SMichael Roth         .value.s64 = INT64_MIN,
9092d496105SMichael Roth     },
9102d496105SMichael Roth     {
9112d496105SMichael Roth         .description = "int64_max",
9122d496105SMichael Roth         .type = PTYPE_S64,
9132d496105SMichael Roth         .value.s64 = INT64_MAX,
9142d496105SMichael Roth     },
9152d496105SMichael Roth     { .type = PTYPE_EOL }
9162d496105SMichael Roth };
9172d496105SMichael Roth 
9182d496105SMichael Roth /* visitor-specific op implementations */
9192d496105SMichael Roth 
9202d496105SMichael Roth typedef struct QmpSerializeData {
9213b098d56SEric Blake     Visitor *qov;
9223b098d56SEric Blake     QObject *obj;
923b70ce101SEric Blake     Visitor *qiv;
9242d496105SMichael Roth } QmpSerializeData;
9252d496105SMichael Roth 
9262d496105SMichael Roth static void qmp_serialize(void *native_in, void **datap,
9272d496105SMichael Roth                           VisitorFunc visit, Error **errp)
9282d496105SMichael Roth {
9292d496105SMichael Roth     QmpSerializeData *d = g_malloc0(sizeof(*d));
9302d496105SMichael Roth 
9317d5e199aSDaniel P. Berrange     d->qov = qobject_output_visitor_new(&d->obj);
9323b098d56SEric Blake     visit(d->qov, &native_in, errp);
9332d496105SMichael Roth     *datap = d;
9342d496105SMichael Roth }
9352d496105SMichael Roth 
9362d496105SMichael Roth static void qmp_deserialize(void **native_out, void *datap,
9372d496105SMichael Roth                             VisitorFunc visit, Error **errp)
9382d496105SMichael Roth {
9392d496105SMichael Roth     QmpSerializeData *d = datap;
940eab3a467SMarkus Armbruster     GString *output_json;
941ad7f375dSMichael Roth     QObject *obj_orig, *obj;
942ad7f375dSMichael Roth 
9433b098d56SEric Blake     visit_complete(d->qov, &d->obj);
9443b098d56SEric Blake     obj_orig = d->obj;
945ad7f375dSMichael Roth     output_json = qobject_to_json(obj_orig);
946eab3a467SMarkus Armbruster     obj = qobject_from_json(output_json->str, &error_abort);
9472d496105SMichael Roth 
948eab3a467SMarkus Armbruster     g_string_free(output_json, true);
949048abb7bSMarkus Armbruster     d->qiv = qobject_input_visitor_new(obj);
950cb3e7f08SMarc-André Lureau     qobject_unref(obj_orig);
951cb3e7f08SMarc-André Lureau     qobject_unref(obj);
952b70ce101SEric Blake     visit(d->qiv, native_out, errp);
9532d496105SMichael Roth }
9542d496105SMichael Roth 
9552d496105SMichael Roth static void qmp_cleanup(void *datap)
9562d496105SMichael Roth {
9572d496105SMichael Roth     QmpSerializeData *d = datap;
9583b098d56SEric Blake     visit_free(d->qov);
959b70ce101SEric Blake     visit_free(d->qiv);
9602bd01ac1SStefan Berger 
9612bd01ac1SStefan Berger     g_free(d);
9622d496105SMichael Roth }
9632d496105SMichael Roth 
9640d30b0a2SMichael Roth typedef struct StringSerializeData {
9652bd01ac1SStefan Berger     char *string;
9663b098d56SEric Blake     Visitor *sov;
9677a0525c7SEric Blake     Visitor *siv;
9680d30b0a2SMichael Roth } StringSerializeData;
9690d30b0a2SMichael Roth 
9700d30b0a2SMichael Roth static void string_serialize(void *native_in, void **datap,
9710d30b0a2SMichael Roth                              VisitorFunc visit, Error **errp)
9720d30b0a2SMichael Roth {
9730d30b0a2SMichael Roth     StringSerializeData *d = g_malloc0(sizeof(*d));
9740d30b0a2SMichael Roth 
9753b098d56SEric Blake     d->sov = string_output_visitor_new(false, &d->string);
9763b098d56SEric Blake     visit(d->sov, &native_in, errp);
9770d30b0a2SMichael Roth     *datap = d;
9780d30b0a2SMichael Roth }
9790d30b0a2SMichael Roth 
9800d30b0a2SMichael Roth static void string_deserialize(void **native_out, void *datap,
9810d30b0a2SMichael Roth                                VisitorFunc visit, Error **errp)
9820d30b0a2SMichael Roth {
9830d30b0a2SMichael Roth     StringSerializeData *d = datap;
9840d30b0a2SMichael Roth 
9853b098d56SEric Blake     visit_complete(d->sov, &d->string);
9862bd01ac1SStefan Berger     d->siv = string_input_visitor_new(d->string);
9877a0525c7SEric Blake     visit(d->siv, native_out, errp);
9880d30b0a2SMichael Roth }
9890d30b0a2SMichael Roth 
9900d30b0a2SMichael Roth static void string_cleanup(void *datap)
9910d30b0a2SMichael Roth {
9920d30b0a2SMichael Roth     StringSerializeData *d = datap;
9932bd01ac1SStefan Berger 
9943b098d56SEric Blake     visit_free(d->sov);
9957a0525c7SEric Blake     visit_free(d->siv);
9962bd01ac1SStefan Berger     g_free(d->string);
9972bd01ac1SStefan Berger     g_free(d);
9980d30b0a2SMichael Roth }
9990d30b0a2SMichael Roth 
10002d496105SMichael Roth /* visitor registration, test harness */
10012d496105SMichael Roth 
10022d496105SMichael Roth /* note: to function interchangeably as a serialization mechanism your
10032d496105SMichael Roth  * visitor test implementation should pass the test cases for all visitor
10042d496105SMichael Roth  * capabilities: primitives, structures, and lists
10052d496105SMichael Roth  */
10062d496105SMichael Roth static const SerializeOps visitors[] = {
10072d496105SMichael Roth     {
10082d496105SMichael Roth         .type = "QMP",
10092d496105SMichael Roth         .serialize = qmp_serialize,
10102d496105SMichael Roth         .deserialize = qmp_deserialize,
10112d496105SMichael Roth         .cleanup = qmp_cleanup,
10128addacddSMichael Roth         .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
10138addacddSMichael Roth                 VCAP_PRIMITIVE_LISTS
10142d496105SMichael Roth     },
10150d30b0a2SMichael Roth     {
10160d30b0a2SMichael Roth         .type = "String",
10170d30b0a2SMichael Roth         .serialize = string_serialize,
10180d30b0a2SMichael Roth         .deserialize = string_deserialize,
10190d30b0a2SMichael Roth         .cleanup = string_cleanup,
10200d30b0a2SMichael Roth         .caps = VCAP_PRIMITIVES
10210d30b0a2SMichael Roth     },
10222d496105SMichael Roth     { NULL }
10232d496105SMichael Roth };
10242d496105SMichael Roth 
10252d496105SMichael Roth static void add_visitor_type(const SerializeOps *ops)
10262d496105SMichael Roth {
1027fdf235baSEric Blake     char testname_prefix[32];
10282d496105SMichael Roth     char testname[128];
10292d496105SMichael Roth     TestArgs *args;
10302d496105SMichael Roth     int i = 0;
10312d496105SMichael Roth 
10322d496105SMichael Roth     sprintf(testname_prefix, "/visitor/serialization/%s", ops->type);
10332d496105SMichael Roth 
10342d496105SMichael Roth     if (ops->caps & VCAP_PRIMITIVES) {
10352d496105SMichael Roth         while (pt_values[i].type != PTYPE_EOL) {
10362d496105SMichael Roth             sprintf(testname, "%s/primitives/%s", testname_prefix,
10372d496105SMichael Roth                     pt_values[i].description);
10382d496105SMichael Roth             args = g_malloc0(sizeof(*args));
10392d496105SMichael Roth             args->ops = ops;
10402d496105SMichael Roth             args->test_data = &pt_values[i];
10412d496105SMichael Roth             g_test_add_data_func(testname, args, test_primitives);
10422d496105SMichael Roth             i++;
10432d496105SMichael Roth         }
10442d496105SMichael Roth     }
10452d496105SMichael Roth 
10462d496105SMichael Roth     if (ops->caps & VCAP_STRUCTURES) {
10472d496105SMichael Roth         sprintf(testname, "%s/struct", testname_prefix);
10482d496105SMichael Roth         args = g_malloc0(sizeof(*args));
10492d496105SMichael Roth         args->ops = ops;
10502d496105SMichael Roth         args->test_data = NULL;
10512d496105SMichael Roth         g_test_add_data_func(testname, args, test_struct);
10522d496105SMichael Roth 
10532d496105SMichael Roth         sprintf(testname, "%s/nested_struct", testname_prefix);
10542d496105SMichael Roth         args = g_malloc0(sizeof(*args));
10552d496105SMichael Roth         args->ops = ops;
10562d496105SMichael Roth         args->test_data = NULL;
10572d496105SMichael Roth         g_test_add_data_func(testname, args, test_nested_struct);
10582d496105SMichael Roth     }
10592d496105SMichael Roth 
10602d496105SMichael Roth     if (ops->caps & VCAP_LISTS) {
10612d496105SMichael Roth         sprintf(testname, "%s/nested_struct_list", testname_prefix);
10622d496105SMichael Roth         args = g_malloc0(sizeof(*args));
10632d496105SMichael Roth         args->ops = ops;
10642d496105SMichael Roth         args->test_data = NULL;
10652d496105SMichael Roth         g_test_add_data_func(testname, args, test_nested_struct_list);
10662d496105SMichael Roth     }
10678addacddSMichael Roth 
10688addacddSMichael Roth     if (ops->caps & VCAP_PRIMITIVE_LISTS) {
10698addacddSMichael Roth         i = 0;
10708addacddSMichael Roth         while (pt_values[i].type != PTYPE_EOL) {
10718addacddSMichael Roth             sprintf(testname, "%s/primitive_list/%s", testname_prefix,
10728addacddSMichael Roth                     pt_values[i].description);
10738addacddSMichael Roth             args = g_malloc0(sizeof(*args));
10748addacddSMichael Roth             args->ops = ops;
10758addacddSMichael Roth             args->test_data = &pt_values[i];
10768addacddSMichael Roth             g_test_add_data_func(testname, args, test_primitive_lists);
10778addacddSMichael Roth             i++;
10788addacddSMichael Roth         }
10798addacddSMichael Roth     }
10802d496105SMichael Roth }
10812d496105SMichael Roth 
10822d496105SMichael Roth int main(int argc, char **argv)
10832d496105SMichael Roth {
10842d496105SMichael Roth     int i = 0;
10852d496105SMichael Roth 
10862d496105SMichael Roth     g_test_init(&argc, &argv, NULL);
10872d496105SMichael Roth 
10882d496105SMichael Roth     while (visitors[i].type != NULL) {
10892d496105SMichael Roth         add_visitor_type(&visitors[i]);
10902d496105SMichael Roth         i++;
10912d496105SMichael Roth     }
10922d496105SMichael Roth 
10932d496105SMichael Roth     g_test_run();
10942d496105SMichael Roth 
10952d496105SMichael Roth     return 0;
10962d496105SMichael Roth }
1097