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