12d496105SMichael Roth /* 22d496105SMichael Roth * Unit-tests for visitor-based serialization 32d496105SMichael Roth * 42d496105SMichael Roth * Copyright IBM, Corp. 2012 52d496105SMichael Roth * 62d496105SMichael Roth * Authors: 72d496105SMichael Roth * Michael Roth <mdroth@linux.vnet.ibm.com> 82d496105SMichael Roth * 92d496105SMichael Roth * This work is licensed under the terms of the GNU GPL, version 2 or later. 102d496105SMichael Roth * See the COPYING file in the top-level directory. 112d496105SMichael Roth */ 122d496105SMichael Roth 132d496105SMichael Roth #include <glib.h> 142d496105SMichael Roth #include <stdlib.h> 152d496105SMichael Roth #include <stdint.h> 162d496105SMichael Roth #include <float.h> 1779ee7df8SPaolo Bonzini 1879ee7df8SPaolo Bonzini #include "qemu-common.h" 192d496105SMichael Roth #include "test-qapi-types.h" 202d496105SMichael Roth #include "test-qapi-visit.h" 217b1b5d19SPaolo Bonzini #include "qapi/qmp/types.h" 222d496105SMichael Roth #include "qapi/qmp-input-visitor.h" 232d496105SMichael Roth #include "qapi/qmp-output-visitor.h" 240d30b0a2SMichael Roth #include "qapi/string-input-visitor.h" 250d30b0a2SMichael Roth #include "qapi/string-output-visitor.h" 262d496105SMichael Roth 272d496105SMichael Roth typedef struct PrimitiveType { 282d496105SMichael Roth union { 292d496105SMichael Roth const char *string; 302d496105SMichael Roth bool boolean; 312d496105SMichael Roth double number; 322d496105SMichael Roth int64_t integer; 332d496105SMichael Roth uint8_t u8; 342d496105SMichael Roth uint16_t u16; 352d496105SMichael Roth uint32_t u32; 362d496105SMichael Roth uint64_t u64; 372d496105SMichael Roth int8_t s8; 382d496105SMichael Roth int16_t s16; 392d496105SMichael Roth int32_t s32; 402d496105SMichael Roth int64_t s64; 412d496105SMichael Roth intmax_t max; 422d496105SMichael Roth } value; 432d496105SMichael Roth enum { 442d496105SMichael Roth PTYPE_STRING = 0, 452d496105SMichael Roth PTYPE_BOOLEAN, 462d496105SMichael Roth PTYPE_NUMBER, 472d496105SMichael Roth PTYPE_INTEGER, 482d496105SMichael Roth PTYPE_U8, 492d496105SMichael Roth PTYPE_U16, 502d496105SMichael Roth PTYPE_U32, 512d496105SMichael Roth PTYPE_U64, 522d496105SMichael Roth PTYPE_S8, 532d496105SMichael Roth PTYPE_S16, 542d496105SMichael Roth PTYPE_S32, 552d496105SMichael Roth PTYPE_S64, 562d496105SMichael Roth PTYPE_EOL, 572d496105SMichael Roth } type; 582d496105SMichael Roth const char *description; 592d496105SMichael Roth } PrimitiveType; 602d496105SMichael Roth 612d496105SMichael Roth /* test helpers */ 622d496105SMichael Roth 632d496105SMichael Roth static void visit_primitive_type(Visitor *v, void **native, Error **errp) 642d496105SMichael Roth { 652d496105SMichael Roth PrimitiveType *pt = *native; 662d496105SMichael Roth switch(pt->type) { 672d496105SMichael Roth case PTYPE_STRING: 682d496105SMichael Roth visit_type_str(v, (char **)&pt->value.string, NULL, errp); 692d496105SMichael Roth break; 702d496105SMichael Roth case PTYPE_BOOLEAN: 712d496105SMichael Roth visit_type_bool(v, &pt->value.boolean, NULL, errp); 722d496105SMichael Roth break; 732d496105SMichael Roth case PTYPE_NUMBER: 742d496105SMichael Roth visit_type_number(v, &pt->value.number, NULL, errp); 752d496105SMichael Roth break; 762d496105SMichael Roth case PTYPE_INTEGER: 772d496105SMichael Roth visit_type_int(v, &pt->value.integer, NULL, errp); 782d496105SMichael Roth break; 792d496105SMichael Roth case PTYPE_U8: 802d496105SMichael Roth visit_type_uint8(v, &pt->value.u8, NULL, errp); 812d496105SMichael Roth break; 822d496105SMichael Roth case PTYPE_U16: 832d496105SMichael Roth visit_type_uint16(v, &pt->value.u16, NULL, errp); 842d496105SMichael Roth break; 852d496105SMichael Roth case PTYPE_U32: 862d496105SMichael Roth visit_type_uint32(v, &pt->value.u32, NULL, errp); 872d496105SMichael Roth break; 882d496105SMichael Roth case PTYPE_U64: 892d496105SMichael Roth visit_type_uint64(v, &pt->value.u64, NULL, errp); 902d496105SMichael Roth break; 912d496105SMichael Roth case PTYPE_S8: 922d496105SMichael Roth visit_type_int8(v, &pt->value.s8, NULL, errp); 932d496105SMichael Roth break; 942d496105SMichael Roth case PTYPE_S16: 952d496105SMichael Roth visit_type_int16(v, &pt->value.s16, NULL, errp); 962d496105SMichael Roth break; 972d496105SMichael Roth case PTYPE_S32: 982d496105SMichael Roth visit_type_int32(v, &pt->value.s32, NULL, errp); 992d496105SMichael Roth break; 1002d496105SMichael Roth case PTYPE_S64: 1012d496105SMichael Roth visit_type_int64(v, &pt->value.s64, NULL, errp); 1022d496105SMichael Roth break; 1032d496105SMichael Roth case PTYPE_EOL: 1042d496105SMichael Roth g_assert(false); 1052d496105SMichael Roth } 1062d496105SMichael Roth } 1072d496105SMichael Roth 1082d496105SMichael Roth typedef struct TestStruct 1092d496105SMichael Roth { 1102d496105SMichael Roth int64_t integer; 1112d496105SMichael Roth bool boolean; 1122d496105SMichael Roth char *string; 1132d496105SMichael Roth } TestStruct; 1142d496105SMichael Roth 1152d496105SMichael Roth static void visit_type_TestStruct(Visitor *v, TestStruct **obj, 1162d496105SMichael Roth const char *name, Error **errp) 1172d496105SMichael Roth { 1182d496105SMichael Roth visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), errp); 1192d496105SMichael Roth 1202d496105SMichael Roth visit_type_int(v, &(*obj)->integer, "integer", errp); 1212d496105SMichael Roth visit_type_bool(v, &(*obj)->boolean, "boolean", errp); 1222d496105SMichael Roth visit_type_str(v, &(*obj)->string, "string", errp); 1232d496105SMichael Roth 1242d496105SMichael Roth visit_end_struct(v, errp); 1252d496105SMichael Roth } 1262d496105SMichael Roth 1272d496105SMichael Roth static TestStruct *struct_create(void) 1282d496105SMichael Roth { 1292d496105SMichael Roth TestStruct *ts = g_malloc0(sizeof(*ts)); 1302d496105SMichael Roth ts->integer = -42; 1312d496105SMichael Roth ts->boolean = true; 1322d496105SMichael Roth ts->string = strdup("test string"); 1332d496105SMichael Roth return ts; 1342d496105SMichael Roth } 1352d496105SMichael Roth 1362d496105SMichael Roth static void struct_compare(TestStruct *ts1, TestStruct *ts2) 1372d496105SMichael Roth { 1382d496105SMichael Roth g_assert(ts1); 1392d496105SMichael Roth g_assert(ts2); 1402d496105SMichael Roth g_assert_cmpint(ts1->integer, ==, ts2->integer); 1412d496105SMichael Roth g_assert(ts1->boolean == ts2->boolean); 1422d496105SMichael Roth g_assert_cmpstr(ts1->string, ==, ts2->string); 1432d496105SMichael Roth } 1442d496105SMichael Roth 1452d496105SMichael Roth static void struct_cleanup(TestStruct *ts) 1462d496105SMichael Roth { 1472d496105SMichael Roth g_free(ts->string); 1482d496105SMichael Roth g_free(ts); 1492d496105SMichael Roth } 1502d496105SMichael Roth 1512d496105SMichael Roth static void visit_struct(Visitor *v, void **native, Error **errp) 1522d496105SMichael Roth { 1532d496105SMichael Roth visit_type_TestStruct(v, (TestStruct **)native, NULL, errp); 1542d496105SMichael Roth } 1552d496105SMichael Roth 1562d496105SMichael Roth static UserDefNested *nested_struct_create(void) 1572d496105SMichael Roth { 1582d496105SMichael Roth UserDefNested *udnp = g_malloc0(sizeof(*udnp)); 1592d496105SMichael Roth udnp->string0 = strdup("test_string0"); 1602d496105SMichael Roth udnp->dict1.string1 = strdup("test_string1"); 1612d496105SMichael Roth udnp->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne)); 1622d496105SMichael Roth udnp->dict1.dict2.userdef1->integer = 42; 1632d496105SMichael Roth udnp->dict1.dict2.userdef1->string = strdup("test_string"); 1642d496105SMichael Roth udnp->dict1.dict2.string2 = strdup("test_string2"); 1652d496105SMichael Roth udnp->dict1.has_dict3 = true; 1662d496105SMichael Roth udnp->dict1.dict3.userdef2 = g_malloc0(sizeof(UserDefOne)); 1672d496105SMichael Roth udnp->dict1.dict3.userdef2->integer = 43; 1682d496105SMichael Roth udnp->dict1.dict3.userdef2->string = strdup("test_string"); 1692d496105SMichael Roth udnp->dict1.dict3.string3 = strdup("test_string3"); 1702d496105SMichael Roth return udnp; 1712d496105SMichael Roth } 1722d496105SMichael Roth 1732d496105SMichael Roth static void nested_struct_compare(UserDefNested *udnp1, UserDefNested *udnp2) 1742d496105SMichael Roth { 1752d496105SMichael Roth g_assert(udnp1); 1762d496105SMichael Roth g_assert(udnp2); 1772d496105SMichael Roth g_assert_cmpstr(udnp1->string0, ==, udnp2->string0); 1782d496105SMichael Roth g_assert_cmpstr(udnp1->dict1.string1, ==, udnp2->dict1.string1); 1792d496105SMichael Roth g_assert_cmpint(udnp1->dict1.dict2.userdef1->integer, ==, 1802d496105SMichael Roth udnp2->dict1.dict2.userdef1->integer); 1812d496105SMichael Roth g_assert_cmpstr(udnp1->dict1.dict2.userdef1->string, ==, 1822d496105SMichael Roth udnp2->dict1.dict2.userdef1->string); 1832d496105SMichael Roth g_assert_cmpstr(udnp1->dict1.dict2.string2, ==, udnp2->dict1.dict2.string2); 1842d496105SMichael Roth g_assert(udnp1->dict1.has_dict3 == udnp2->dict1.has_dict3); 1852d496105SMichael Roth g_assert_cmpint(udnp1->dict1.dict3.userdef2->integer, ==, 1862d496105SMichael Roth udnp2->dict1.dict3.userdef2->integer); 1872d496105SMichael Roth g_assert_cmpstr(udnp1->dict1.dict3.userdef2->string, ==, 1882d496105SMichael Roth udnp2->dict1.dict3.userdef2->string); 1892d496105SMichael Roth g_assert_cmpstr(udnp1->dict1.dict3.string3, ==, udnp2->dict1.dict3.string3); 1902d496105SMichael Roth } 1912d496105SMichael Roth 1922d496105SMichael Roth static void nested_struct_cleanup(UserDefNested *udnp) 1932d496105SMichael Roth { 1942d496105SMichael Roth qapi_free_UserDefNested(udnp); 1952d496105SMichael Roth } 1962d496105SMichael Roth 1972d496105SMichael Roth static void visit_nested_struct(Visitor *v, void **native, Error **errp) 1982d496105SMichael Roth { 1992d496105SMichael Roth visit_type_UserDefNested(v, (UserDefNested **)native, NULL, errp); 2002d496105SMichael Roth } 2012d496105SMichael Roth 2022d496105SMichael Roth static void visit_nested_struct_list(Visitor *v, void **native, Error **errp) 2032d496105SMichael Roth { 2042d496105SMichael Roth visit_type_UserDefNestedList(v, (UserDefNestedList **)native, NULL, errp); 2052d496105SMichael Roth } 2062d496105SMichael Roth 2072d496105SMichael Roth /* test cases */ 2082d496105SMichael Roth 2092d496105SMichael Roth typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp); 2102d496105SMichael Roth 2112d496105SMichael Roth typedef enum VisitorCapabilities { 2122d496105SMichael Roth VCAP_PRIMITIVES = 1, 2132d496105SMichael Roth VCAP_STRUCTURES = 2, 2142d496105SMichael Roth VCAP_LISTS = 4, 2152d496105SMichael Roth } VisitorCapabilities; 2162d496105SMichael Roth 2172d496105SMichael Roth typedef struct SerializeOps { 2182d496105SMichael Roth void (*serialize)(void *native_in, void **datap, 2192d496105SMichael Roth VisitorFunc visit, Error **errp); 2202d496105SMichael Roth void (*deserialize)(void **native_out, void *datap, 2212d496105SMichael Roth VisitorFunc visit, Error **errp); 2222d496105SMichael Roth void (*cleanup)(void *datap); 2232d496105SMichael Roth const char *type; 2242d496105SMichael Roth VisitorCapabilities caps; 2252d496105SMichael Roth } SerializeOps; 2262d496105SMichael Roth 2272d496105SMichael Roth typedef struct TestArgs { 2282d496105SMichael Roth const SerializeOps *ops; 2292d496105SMichael Roth void *test_data; 2302d496105SMichael Roth } TestArgs; 2312d496105SMichael Roth 2322d496105SMichael Roth #define FLOAT_STRING_PRECISION 6 /* corresponding to n in %.nf formatting */ 2332d496105SMichael Roth static gsize calc_float_string_storage(double value) 2342d496105SMichael Roth { 2352d496105SMichael Roth int whole_value = value; 2362d496105SMichael Roth gsize i = 0; 2372d496105SMichael Roth do { 2382d496105SMichael Roth i++; 2392d496105SMichael Roth } while (whole_value /= 10); 2402d496105SMichael Roth return i + 2 + FLOAT_STRING_PRECISION; 2412d496105SMichael Roth } 2422d496105SMichael Roth 2432d496105SMichael Roth static void test_primitives(gconstpointer opaque) 2442d496105SMichael Roth { 2452d496105SMichael Roth TestArgs *args = (TestArgs *) opaque; 2462d496105SMichael Roth const SerializeOps *ops = args->ops; 2472d496105SMichael Roth PrimitiveType *pt = args->test_data; 2482d496105SMichael Roth PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy)); 2492d496105SMichael Roth Error *err = NULL; 2502d496105SMichael Roth void *serialize_data; 2512d496105SMichael Roth char *double1, *double2; 2522d496105SMichael Roth 2532d496105SMichael Roth pt_copy->type = pt->type; 2542d496105SMichael Roth ops->serialize(pt, &serialize_data, visit_primitive_type, &err); 2552d496105SMichael Roth ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type, &err); 2562d496105SMichael Roth 2572d496105SMichael Roth g_assert(err == NULL); 2582d496105SMichael Roth g_assert(pt_copy != NULL); 2592d496105SMichael Roth if (pt->type == PTYPE_STRING) { 2602d496105SMichael Roth g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string); 2612bd01ac1SStefan Berger g_free((char *)pt_copy->value.string); 2622d496105SMichael Roth } else if (pt->type == PTYPE_NUMBER) { 2632d496105SMichael Roth /* we serialize with %f for our reference visitors, so rather than fuzzy 2642d496105SMichael Roth * floating math to test "equality", just compare the formatted values 2652d496105SMichael Roth */ 2662d496105SMichael Roth double1 = g_malloc0(calc_float_string_storage(pt->value.number)); 2672d496105SMichael Roth double2 = g_malloc0(calc_float_string_storage(pt_copy->value.number)); 2682d496105SMichael Roth g_assert_cmpstr(double1, ==, double2); 2692d496105SMichael Roth g_free(double1); 2702d496105SMichael Roth g_free(double2); 2712d496105SMichael Roth } else if (pt->type == PTYPE_BOOLEAN) { 2722d496105SMichael Roth g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max); 2732d496105SMichael Roth } else { 2742d496105SMichael Roth g_assert_cmpint(pt->value.max, ==, pt_copy->value.max); 2752d496105SMichael Roth } 2762d496105SMichael Roth 2772d496105SMichael Roth ops->cleanup(serialize_data); 2782d496105SMichael Roth g_free(args); 2792bd01ac1SStefan Berger g_free(pt_copy); 2802d496105SMichael Roth } 2812d496105SMichael Roth 2822d496105SMichael Roth static void test_struct(gconstpointer opaque) 2832d496105SMichael Roth { 2842d496105SMichael Roth TestArgs *args = (TestArgs *) opaque; 2852d496105SMichael Roth const SerializeOps *ops = args->ops; 2862d496105SMichael Roth TestStruct *ts = struct_create(); 2872d496105SMichael Roth TestStruct *ts_copy = NULL; 2882d496105SMichael Roth Error *err = NULL; 2892d496105SMichael Roth void *serialize_data; 2902d496105SMichael Roth 2912d496105SMichael Roth ops->serialize(ts, &serialize_data, visit_struct, &err); 2922d496105SMichael Roth ops->deserialize((void **)&ts_copy, serialize_data, visit_struct, &err); 2932d496105SMichael Roth 2942d496105SMichael Roth g_assert(err == NULL); 2952d496105SMichael Roth struct_compare(ts, ts_copy); 2962d496105SMichael Roth 2972d496105SMichael Roth struct_cleanup(ts); 2982d496105SMichael Roth struct_cleanup(ts_copy); 2992d496105SMichael Roth 3002d496105SMichael Roth ops->cleanup(serialize_data); 3012d496105SMichael Roth g_free(args); 3022d496105SMichael Roth } 3032d496105SMichael Roth 3042d496105SMichael Roth static void test_nested_struct(gconstpointer opaque) 3052d496105SMichael Roth { 3062d496105SMichael Roth TestArgs *args = (TestArgs *) opaque; 3072d496105SMichael Roth const SerializeOps *ops = args->ops; 3082d496105SMichael Roth UserDefNested *udnp = nested_struct_create(); 3092d496105SMichael Roth UserDefNested *udnp_copy = NULL; 3102d496105SMichael Roth Error *err = NULL; 3112d496105SMichael Roth void *serialize_data; 3122d496105SMichael Roth 3132d496105SMichael Roth ops->serialize(udnp, &serialize_data, visit_nested_struct, &err); 3142d496105SMichael Roth ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct, &err); 3152d496105SMichael Roth 3162d496105SMichael Roth g_assert(err == NULL); 3172d496105SMichael Roth nested_struct_compare(udnp, udnp_copy); 3182d496105SMichael Roth 3192d496105SMichael Roth nested_struct_cleanup(udnp); 3202d496105SMichael Roth nested_struct_cleanup(udnp_copy); 3212d496105SMichael Roth 3222d496105SMichael Roth ops->cleanup(serialize_data); 3232d496105SMichael Roth g_free(args); 3242d496105SMichael Roth } 3252d496105SMichael Roth 3262d496105SMichael Roth static void test_nested_struct_list(gconstpointer opaque) 3272d496105SMichael Roth { 3282d496105SMichael Roth TestArgs *args = (TestArgs *) opaque; 3292d496105SMichael Roth const SerializeOps *ops = args->ops; 3302d496105SMichael Roth UserDefNestedList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL; 3312d496105SMichael Roth Error *err = NULL; 3322d496105SMichael Roth void *serialize_data; 3332d496105SMichael Roth int i = 0; 3342d496105SMichael Roth 3352d496105SMichael Roth for (i = 0; i < 8; i++) { 3362d496105SMichael Roth tmp = g_malloc0(sizeof(UserDefNestedList)); 3372d496105SMichael Roth tmp->value = nested_struct_create(); 3382d496105SMichael Roth tmp->next = listp; 3392d496105SMichael Roth listp = tmp; 3402d496105SMichael Roth } 3412d496105SMichael Roth 3422d496105SMichael Roth ops->serialize(listp, &serialize_data, visit_nested_struct_list, &err); 3432d496105SMichael Roth ops->deserialize((void **)&listp_copy, serialize_data, 3442d496105SMichael Roth visit_nested_struct_list, &err); 3452d496105SMichael Roth 3462d496105SMichael Roth g_assert(err == NULL); 3472d496105SMichael Roth 3482d496105SMichael Roth tmp = listp; 3492d496105SMichael Roth tmp_copy = listp_copy; 3502d496105SMichael Roth while (listp_copy) { 3512d496105SMichael Roth g_assert(listp); 3522d496105SMichael Roth nested_struct_compare(listp->value, listp_copy->value); 3532d496105SMichael Roth listp = listp->next; 3542d496105SMichael Roth listp_copy = listp_copy->next; 3552d496105SMichael Roth } 3562d496105SMichael Roth 3572d496105SMichael Roth qapi_free_UserDefNestedList(tmp); 3582d496105SMichael Roth qapi_free_UserDefNestedList(tmp_copy); 3592d496105SMichael Roth 3602d496105SMichael Roth ops->cleanup(serialize_data); 3612d496105SMichael Roth g_free(args); 3622d496105SMichael Roth } 3632d496105SMichael Roth 3642d496105SMichael Roth PrimitiveType pt_values[] = { 3652d496105SMichael Roth /* string tests */ 3662d496105SMichael Roth { 3672d496105SMichael Roth .description = "string_empty", 3682d496105SMichael Roth .type = PTYPE_STRING, 3692d496105SMichael Roth .value.string = "", 3702d496105SMichael Roth }, 3712d496105SMichael Roth { 3722d496105SMichael Roth .description = "string_whitespace", 3732d496105SMichael Roth .type = PTYPE_STRING, 3742d496105SMichael Roth .value.string = "a b c\td", 3752d496105SMichael Roth }, 3762d496105SMichael Roth { 3772d496105SMichael Roth .description = "string_newlines", 3782d496105SMichael Roth .type = PTYPE_STRING, 3792d496105SMichael Roth .value.string = "a\nb\n", 3802d496105SMichael Roth }, 3812d496105SMichael Roth { 3822d496105SMichael Roth .description = "string_commas", 3832d496105SMichael Roth .type = PTYPE_STRING, 3842d496105SMichael Roth .value.string = "a,b, c,d", 3852d496105SMichael Roth }, 3862d496105SMichael Roth { 3872d496105SMichael Roth .description = "string_single_quoted", 3882d496105SMichael Roth .type = PTYPE_STRING, 3892d496105SMichael Roth .value.string = "'a b',cd", 3902d496105SMichael Roth }, 3912d496105SMichael Roth { 3922d496105SMichael Roth .description = "string_double_quoted", 3932d496105SMichael Roth .type = PTYPE_STRING, 3942d496105SMichael Roth .value.string = "\"a b\",cd", 3952d496105SMichael Roth }, 3962d496105SMichael Roth /* boolean tests */ 3972d496105SMichael Roth { 3982d496105SMichael Roth .description = "boolean_true1", 3992d496105SMichael Roth .type = PTYPE_BOOLEAN, 4002d496105SMichael Roth .value.boolean = true, 4012d496105SMichael Roth }, 4022d496105SMichael Roth { 4032d496105SMichael Roth .description = "boolean_true2", 4042d496105SMichael Roth .type = PTYPE_BOOLEAN, 4052d496105SMichael Roth .value.boolean = 8, 4062d496105SMichael Roth }, 4072d496105SMichael Roth { 4082d496105SMichael Roth .description = "boolean_true3", 4092d496105SMichael Roth .type = PTYPE_BOOLEAN, 4102d496105SMichael Roth .value.boolean = -1, 4112d496105SMichael Roth }, 4122d496105SMichael Roth { 4132d496105SMichael Roth .description = "boolean_false1", 4142d496105SMichael Roth .type = PTYPE_BOOLEAN, 4152d496105SMichael Roth .value.boolean = false, 4162d496105SMichael Roth }, 4172d496105SMichael Roth { 4182d496105SMichael Roth .description = "boolean_false2", 4192d496105SMichael Roth .type = PTYPE_BOOLEAN, 4202d496105SMichael Roth .value.boolean = 0, 4212d496105SMichael Roth }, 4222d496105SMichael Roth /* number tests (double) */ 4232d496105SMichael Roth /* note: we format these to %.6f before comparing, since that's how 4242d496105SMichael Roth * we serialize them and it doesn't make sense to check precision 4252d496105SMichael Roth * beyond that. 4262d496105SMichael Roth */ 4272d496105SMichael Roth { 4282d496105SMichael Roth .description = "number_sanity1", 4292d496105SMichael Roth .type = PTYPE_NUMBER, 4302d496105SMichael Roth .value.number = -1, 4312d496105SMichael Roth }, 4322d496105SMichael Roth { 4332d496105SMichael Roth .description = "number_sanity2", 4342d496105SMichael Roth .type = PTYPE_NUMBER, 4352d496105SMichael Roth .value.number = 3.14159265, 4362d496105SMichael Roth }, 4372d496105SMichael Roth { 4382d496105SMichael Roth .description = "number_min", 4392d496105SMichael Roth .type = PTYPE_NUMBER, 4402d496105SMichael Roth .value.number = DBL_MIN, 4412d496105SMichael Roth }, 4422d496105SMichael Roth { 4432d496105SMichael Roth .description = "number_max", 4442d496105SMichael Roth .type = PTYPE_NUMBER, 4452d496105SMichael Roth .value.number = DBL_MAX, 4462d496105SMichael Roth }, 4472d496105SMichael Roth /* integer tests (int64) */ 4482d496105SMichael Roth { 4492d496105SMichael Roth .description = "integer_sanity1", 4502d496105SMichael Roth .type = PTYPE_INTEGER, 4512d496105SMichael Roth .value.integer = -1, 4522d496105SMichael Roth }, 4532d496105SMichael Roth { 4542d496105SMichael Roth .description = "integer_sanity2", 4552d496105SMichael Roth .type = PTYPE_INTEGER, 4562d496105SMichael Roth .value.integer = INT64_MAX / 2 + 1, 4572d496105SMichael Roth }, 4582d496105SMichael Roth { 4592d496105SMichael Roth .description = "integer_min", 4602d496105SMichael Roth .type = PTYPE_INTEGER, 4612d496105SMichael Roth .value.integer = INT64_MIN, 4622d496105SMichael Roth }, 4632d496105SMichael Roth { 4642d496105SMichael Roth .description = "integer_max", 4652d496105SMichael Roth .type = PTYPE_INTEGER, 4662d496105SMichael Roth .value.integer = INT64_MAX, 4672d496105SMichael Roth }, 4682d496105SMichael Roth /* uint8 tests */ 4692d496105SMichael Roth { 4702d496105SMichael Roth .description = "uint8_sanity1", 4712d496105SMichael Roth .type = PTYPE_U8, 4722d496105SMichael Roth .value.u8 = 1, 4732d496105SMichael Roth }, 4742d496105SMichael Roth { 4752d496105SMichael Roth .description = "uint8_sanity2", 4762d496105SMichael Roth .type = PTYPE_U8, 4772d496105SMichael Roth .value.u8 = UINT8_MAX / 2 + 1, 4782d496105SMichael Roth }, 4792d496105SMichael Roth { 4802d496105SMichael Roth .description = "uint8_min", 4812d496105SMichael Roth .type = PTYPE_U8, 4822d496105SMichael Roth .value.u8 = 0, 4832d496105SMichael Roth }, 4842d496105SMichael Roth { 4852d496105SMichael Roth .description = "uint8_max", 4862d496105SMichael Roth .type = PTYPE_U8, 4872d496105SMichael Roth .value.u8 = UINT8_MAX, 4882d496105SMichael Roth }, 4892d496105SMichael Roth /* uint16 tests */ 4902d496105SMichael Roth { 4912d496105SMichael Roth .description = "uint16_sanity1", 4922d496105SMichael Roth .type = PTYPE_U16, 4932d496105SMichael Roth .value.u16 = 1, 4942d496105SMichael Roth }, 4952d496105SMichael Roth { 4962d496105SMichael Roth .description = "uint16_sanity2", 4972d496105SMichael Roth .type = PTYPE_U16, 4982d496105SMichael Roth .value.u16 = UINT16_MAX / 2 + 1, 4992d496105SMichael Roth }, 5002d496105SMichael Roth { 5012d496105SMichael Roth .description = "uint16_min", 5022d496105SMichael Roth .type = PTYPE_U16, 5032d496105SMichael Roth .value.u16 = 0, 5042d496105SMichael Roth }, 5052d496105SMichael Roth { 5062d496105SMichael Roth .description = "uint16_max", 5072d496105SMichael Roth .type = PTYPE_U16, 5082d496105SMichael Roth .value.u16 = UINT16_MAX, 5092d496105SMichael Roth }, 5102d496105SMichael Roth /* uint32 tests */ 5112d496105SMichael Roth { 5122d496105SMichael Roth .description = "uint32_sanity1", 5132d496105SMichael Roth .type = PTYPE_U32, 5142d496105SMichael Roth .value.u32 = 1, 5152d496105SMichael Roth }, 5162d496105SMichael Roth { 5172d496105SMichael Roth .description = "uint32_sanity2", 5182d496105SMichael Roth .type = PTYPE_U32, 5192d496105SMichael Roth .value.u32 = UINT32_MAX / 2 + 1, 5202d496105SMichael Roth }, 5212d496105SMichael Roth { 5222d496105SMichael Roth .description = "uint32_min", 5232d496105SMichael Roth .type = PTYPE_U32, 5242d496105SMichael Roth .value.u32 = 0, 5252d496105SMichael Roth }, 5262d496105SMichael Roth { 5272d496105SMichael Roth .description = "uint32_max", 5282d496105SMichael Roth .type = PTYPE_U32, 5292d496105SMichael Roth .value.u32 = UINT32_MAX, 5302d496105SMichael Roth }, 5312d496105SMichael Roth /* uint64 tests */ 5322d496105SMichael Roth { 5332d496105SMichael Roth .description = "uint64_sanity1", 5342d496105SMichael Roth .type = PTYPE_U64, 5352d496105SMichael Roth .value.u64 = 1, 5362d496105SMichael Roth }, 5372d496105SMichael Roth { 5382d496105SMichael Roth .description = "uint64_sanity2", 5392d496105SMichael Roth .type = PTYPE_U64, 5402d496105SMichael Roth .value.u64 = UINT64_MAX / 2 + 1, 5412d496105SMichael Roth }, 5422d496105SMichael Roth { 5432d496105SMichael Roth .description = "uint64_min", 5442d496105SMichael Roth .type = PTYPE_U64, 5452d496105SMichael Roth .value.u64 = 0, 5462d496105SMichael Roth }, 5472d496105SMichael Roth { 5482d496105SMichael Roth .description = "uint64_max", 5492d496105SMichael Roth .type = PTYPE_U64, 5502d496105SMichael Roth .value.u64 = UINT64_MAX, 5512d496105SMichael Roth }, 5522d496105SMichael Roth /* int8 tests */ 5532d496105SMichael Roth { 5542d496105SMichael Roth .description = "int8_sanity1", 5552d496105SMichael Roth .type = PTYPE_S8, 5562d496105SMichael Roth .value.s8 = -1, 5572d496105SMichael Roth }, 5582d496105SMichael Roth { 5592d496105SMichael Roth .description = "int8_sanity2", 5602d496105SMichael Roth .type = PTYPE_S8, 5612d496105SMichael Roth .value.s8 = INT8_MAX / 2 + 1, 5622d496105SMichael Roth }, 5632d496105SMichael Roth { 5642d496105SMichael Roth .description = "int8_min", 5652d496105SMichael Roth .type = PTYPE_S8, 5662d496105SMichael Roth .value.s8 = INT8_MIN, 5672d496105SMichael Roth }, 5682d496105SMichael Roth { 5692d496105SMichael Roth .description = "int8_max", 5702d496105SMichael Roth .type = PTYPE_S8, 5712d496105SMichael Roth .value.s8 = INT8_MAX, 5722d496105SMichael Roth }, 5732d496105SMichael Roth /* int16 tests */ 5742d496105SMichael Roth { 5752d496105SMichael Roth .description = "int16_sanity1", 5762d496105SMichael Roth .type = PTYPE_S16, 5772d496105SMichael Roth .value.s16 = -1, 5782d496105SMichael Roth }, 5792d496105SMichael Roth { 5802d496105SMichael Roth .description = "int16_sanity2", 5812d496105SMichael Roth .type = PTYPE_S16, 5822d496105SMichael Roth .value.s16 = INT16_MAX / 2 + 1, 5832d496105SMichael Roth }, 5842d496105SMichael Roth { 5852d496105SMichael Roth .description = "int16_min", 5862d496105SMichael Roth .type = PTYPE_S16, 5872d496105SMichael Roth .value.s16 = INT16_MIN, 5882d496105SMichael Roth }, 5892d496105SMichael Roth { 5902d496105SMichael Roth .description = "int16_max", 5912d496105SMichael Roth .type = PTYPE_S16, 5922d496105SMichael Roth .value.s16 = INT16_MAX, 5932d496105SMichael Roth }, 5942d496105SMichael Roth /* int32 tests */ 5952d496105SMichael Roth { 5962d496105SMichael Roth .description = "int32_sanity1", 5972d496105SMichael Roth .type = PTYPE_S32, 5982d496105SMichael Roth .value.s32 = -1, 5992d496105SMichael Roth }, 6002d496105SMichael Roth { 6012d496105SMichael Roth .description = "int32_sanity2", 6022d496105SMichael Roth .type = PTYPE_S32, 6032d496105SMichael Roth .value.s32 = INT32_MAX / 2 + 1, 6042d496105SMichael Roth }, 6052d496105SMichael Roth { 6062d496105SMichael Roth .description = "int32_min", 6072d496105SMichael Roth .type = PTYPE_S32, 6082d496105SMichael Roth .value.s32 = INT32_MIN, 6092d496105SMichael Roth }, 6102d496105SMichael Roth { 6112d496105SMichael Roth .description = "int32_max", 6122d496105SMichael Roth .type = PTYPE_S32, 6132d496105SMichael Roth .value.s32 = INT32_MAX, 6142d496105SMichael Roth }, 6152d496105SMichael Roth /* int64 tests */ 6162d496105SMichael Roth { 6172d496105SMichael Roth .description = "int64_sanity1", 6182d496105SMichael Roth .type = PTYPE_S64, 6192d496105SMichael Roth .value.s64 = -1, 6202d496105SMichael Roth }, 6212d496105SMichael Roth { 6222d496105SMichael Roth .description = "int64_sanity2", 6232d496105SMichael Roth .type = PTYPE_S64, 6242d496105SMichael Roth .value.s64 = INT64_MAX / 2 + 1, 6252d496105SMichael Roth }, 6262d496105SMichael Roth { 6272d496105SMichael Roth .description = "int64_min", 6282d496105SMichael Roth .type = PTYPE_S64, 6292d496105SMichael Roth .value.s64 = INT64_MIN, 6302d496105SMichael Roth }, 6312d496105SMichael Roth { 6322d496105SMichael Roth .description = "int64_max", 6332d496105SMichael Roth .type = PTYPE_S64, 6342d496105SMichael Roth .value.s64 = INT64_MAX, 6352d496105SMichael Roth }, 6362d496105SMichael Roth { .type = PTYPE_EOL } 6372d496105SMichael Roth }; 6382d496105SMichael Roth 6392d496105SMichael Roth /* visitor-specific op implementations */ 6402d496105SMichael Roth 6412d496105SMichael Roth typedef struct QmpSerializeData { 6422d496105SMichael Roth QmpOutputVisitor *qov; 6432d496105SMichael Roth QmpInputVisitor *qiv; 6442d496105SMichael Roth } QmpSerializeData; 6452d496105SMichael Roth 6462d496105SMichael Roth static void qmp_serialize(void *native_in, void **datap, 6472d496105SMichael Roth VisitorFunc visit, Error **errp) 6482d496105SMichael Roth { 6492d496105SMichael Roth QmpSerializeData *d = g_malloc0(sizeof(*d)); 6502d496105SMichael Roth 6512d496105SMichael Roth d->qov = qmp_output_visitor_new(); 6522d496105SMichael Roth visit(qmp_output_get_visitor(d->qov), &native_in, errp); 6532d496105SMichael Roth *datap = d; 6542d496105SMichael Roth } 6552d496105SMichael Roth 6562d496105SMichael Roth static void qmp_deserialize(void **native_out, void *datap, 6572d496105SMichael Roth VisitorFunc visit, Error **errp) 6582d496105SMichael Roth { 6592d496105SMichael Roth QmpSerializeData *d = datap; 660*ad7f375dSMichael Roth QString *output_json; 661*ad7f375dSMichael Roth QObject *obj_orig, *obj; 662*ad7f375dSMichael Roth 663*ad7f375dSMichael Roth obj_orig = qmp_output_get_qobject(d->qov); 664*ad7f375dSMichael Roth output_json = qobject_to_json(obj_orig); 665*ad7f375dSMichael Roth obj = qobject_from_json(qstring_get_str(output_json)); 6662d496105SMichael Roth 6672d496105SMichael Roth QDECREF(output_json); 6682d496105SMichael Roth d->qiv = qmp_input_visitor_new(obj); 669*ad7f375dSMichael Roth qobject_decref(obj_orig); 6702bd01ac1SStefan Berger qobject_decref(obj); 6712d496105SMichael Roth visit(qmp_input_get_visitor(d->qiv), native_out, errp); 6722d496105SMichael Roth } 6732d496105SMichael Roth 6742d496105SMichael Roth static void qmp_cleanup(void *datap) 6752d496105SMichael Roth { 6762d496105SMichael Roth QmpSerializeData *d = datap; 6772d496105SMichael Roth qmp_output_visitor_cleanup(d->qov); 6782d496105SMichael Roth qmp_input_visitor_cleanup(d->qiv); 6792bd01ac1SStefan Berger 6802bd01ac1SStefan Berger g_free(d); 6812d496105SMichael Roth } 6822d496105SMichael Roth 6830d30b0a2SMichael Roth typedef struct StringSerializeData { 6842bd01ac1SStefan Berger char *string; 6850d30b0a2SMichael Roth StringOutputVisitor *sov; 6860d30b0a2SMichael Roth StringInputVisitor *siv; 6870d30b0a2SMichael Roth } StringSerializeData; 6880d30b0a2SMichael Roth 6890d30b0a2SMichael Roth static void string_serialize(void *native_in, void **datap, 6900d30b0a2SMichael Roth VisitorFunc visit, Error **errp) 6910d30b0a2SMichael Roth { 6920d30b0a2SMichael Roth StringSerializeData *d = g_malloc0(sizeof(*d)); 6930d30b0a2SMichael Roth 6940d30b0a2SMichael Roth d->sov = string_output_visitor_new(); 6950d30b0a2SMichael Roth visit(string_output_get_visitor(d->sov), &native_in, errp); 6960d30b0a2SMichael Roth *datap = d; 6970d30b0a2SMichael Roth } 6980d30b0a2SMichael Roth 6990d30b0a2SMichael Roth static void string_deserialize(void **native_out, void *datap, 7000d30b0a2SMichael Roth VisitorFunc visit, Error **errp) 7010d30b0a2SMichael Roth { 7020d30b0a2SMichael Roth StringSerializeData *d = datap; 7030d30b0a2SMichael Roth 7042bd01ac1SStefan Berger d->string = string_output_get_string(d->sov); 7052bd01ac1SStefan Berger d->siv = string_input_visitor_new(d->string); 7060d30b0a2SMichael Roth visit(string_input_get_visitor(d->siv), native_out, errp); 7070d30b0a2SMichael Roth } 7080d30b0a2SMichael Roth 7090d30b0a2SMichael Roth static void string_cleanup(void *datap) 7100d30b0a2SMichael Roth { 7110d30b0a2SMichael Roth StringSerializeData *d = datap; 7122bd01ac1SStefan Berger 7130d30b0a2SMichael Roth string_output_visitor_cleanup(d->sov); 7140d30b0a2SMichael Roth string_input_visitor_cleanup(d->siv); 7152bd01ac1SStefan Berger g_free(d->string); 7162bd01ac1SStefan Berger g_free(d); 7170d30b0a2SMichael Roth } 7180d30b0a2SMichael Roth 7192d496105SMichael Roth /* visitor registration, test harness */ 7202d496105SMichael Roth 7212d496105SMichael Roth /* note: to function interchangeably as a serialization mechanism your 7222d496105SMichael Roth * visitor test implementation should pass the test cases for all visitor 7232d496105SMichael Roth * capabilities: primitives, structures, and lists 7242d496105SMichael Roth */ 7252d496105SMichael Roth static const SerializeOps visitors[] = { 7262d496105SMichael Roth { 7272d496105SMichael Roth .type = "QMP", 7282d496105SMichael Roth .serialize = qmp_serialize, 7292d496105SMichael Roth .deserialize = qmp_deserialize, 7302d496105SMichael Roth .cleanup = qmp_cleanup, 7312d496105SMichael Roth .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS 7322d496105SMichael Roth }, 7330d30b0a2SMichael Roth { 7340d30b0a2SMichael Roth .type = "String", 7350d30b0a2SMichael Roth .serialize = string_serialize, 7360d30b0a2SMichael Roth .deserialize = string_deserialize, 7370d30b0a2SMichael Roth .cleanup = string_cleanup, 7380d30b0a2SMichael Roth .caps = VCAP_PRIMITIVES 7390d30b0a2SMichael Roth }, 7402d496105SMichael Roth { NULL } 7412d496105SMichael Roth }; 7422d496105SMichael Roth 7432d496105SMichael Roth static void add_visitor_type(const SerializeOps *ops) 7442d496105SMichael Roth { 7452d496105SMichael Roth char testname_prefix[128]; 7462d496105SMichael Roth char testname[128]; 7472d496105SMichael Roth TestArgs *args; 7482d496105SMichael Roth int i = 0; 7492d496105SMichael Roth 7502d496105SMichael Roth sprintf(testname_prefix, "/visitor/serialization/%s", ops->type); 7512d496105SMichael Roth 7522d496105SMichael Roth if (ops->caps & VCAP_PRIMITIVES) { 7532d496105SMichael Roth while (pt_values[i].type != PTYPE_EOL) { 7542d496105SMichael Roth sprintf(testname, "%s/primitives/%s", testname_prefix, 7552d496105SMichael Roth pt_values[i].description); 7562d496105SMichael Roth args = g_malloc0(sizeof(*args)); 7572d496105SMichael Roth args->ops = ops; 7582d496105SMichael Roth args->test_data = &pt_values[i]; 7592d496105SMichael Roth g_test_add_data_func(testname, args, test_primitives); 7602d496105SMichael Roth i++; 7612d496105SMichael Roth } 7622d496105SMichael Roth } 7632d496105SMichael Roth 7642d496105SMichael Roth if (ops->caps & VCAP_STRUCTURES) { 7652d496105SMichael Roth sprintf(testname, "%s/struct", testname_prefix); 7662d496105SMichael Roth args = g_malloc0(sizeof(*args)); 7672d496105SMichael Roth args->ops = ops; 7682d496105SMichael Roth args->test_data = NULL; 7692d496105SMichael Roth g_test_add_data_func(testname, args, test_struct); 7702d496105SMichael Roth 7712d496105SMichael Roth sprintf(testname, "%s/nested_struct", testname_prefix); 7722d496105SMichael Roth args = g_malloc0(sizeof(*args)); 7732d496105SMichael Roth args->ops = ops; 7742d496105SMichael Roth args->test_data = NULL; 7752d496105SMichael Roth g_test_add_data_func(testname, args, test_nested_struct); 7762d496105SMichael Roth } 7772d496105SMichael Roth 7782d496105SMichael Roth if (ops->caps & VCAP_LISTS) { 7792d496105SMichael Roth sprintf(testname, "%s/nested_struct_list", testname_prefix); 7802d496105SMichael Roth args = g_malloc0(sizeof(*args)); 7812d496105SMichael Roth args->ops = ops; 7822d496105SMichael Roth args->test_data = NULL; 7832d496105SMichael Roth g_test_add_data_func(testname, args, test_nested_struct_list); 7842d496105SMichael Roth } 7852d496105SMichael Roth } 7862d496105SMichael Roth 7872d496105SMichael Roth int main(int argc, char **argv) 7882d496105SMichael Roth { 7892d496105SMichael Roth int i = 0; 7902d496105SMichael Roth 7912d496105SMichael Roth g_test_init(&argc, &argv, NULL); 7922d496105SMichael Roth 7932d496105SMichael Roth while (visitors[i].type != NULL) { 7942d496105SMichael Roth add_visitor_type(&visitors[i]); 7952d496105SMichael Roth i++; 7962d496105SMichael Roth } 7972d496105SMichael Roth 7982d496105SMichael Roth g_test_run(); 7992d496105SMichael Roth 8002d496105SMichael Roth return 0; 8012d496105SMichael Roth } 802