2 * Unit-tests for visitor-based serialization
4 * Copyright (C) 2014-2015 Red Hat, Inc.
5 * Copyright IBM, Corp. 2012
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
18 #include "qemu-common.h"
19 #include "test-qapi-types.h"
20 #include "test-qapi-visit.h"
21 #include "qapi/error.h"
22 #include "qapi/qmp/types.h"
23 #include "qapi/qmp-input-visitor.h"
24 #include "qapi/qmp-output-visitor.h"
25 #include "qapi/string-input-visitor.h"
26 #include "qapi/string-output-visitor.h"
27 #include "qapi-types.h"
28 #include "qapi-visit.h"
29 #include "qapi/dealloc-visitor.h"
31 enum PrimitiveTypeKind {
47 typedef struct PrimitiveType {
63 enum PrimitiveTypeKind type;
64 const char *description;
67 typedef struct PrimitiveList {
73 int8List *s8_integers;
74 int16List *s16_integers;
75 int32List *s32_integers;
76 int64List *s64_integers;
77 uint8List *u8_integers;
78 uint16List *u16_integers;
79 uint32List *u32_integers;
80 uint64List *u64_integers;
82 enum PrimitiveTypeKind type;
83 const char *description;
88 typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
90 static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
92 QapiDeallocVisitor *qdv = qapi_dealloc_visitor_new();
94 visit(qapi_dealloc_get_visitor(qdv), &native_in, errp);
96 qapi_dealloc_visitor_cleanup(qdv);
99 static void visit_primitive_type(Visitor *v, void **native, Error **errp)
101 PrimitiveType *pt = *native;
104 visit_type_str(v, NULL, (char **)&pt->value.string, errp);
107 visit_type_bool(v, NULL, &pt->value.boolean, errp);
110 visit_type_number(v, NULL, &pt->value.number, errp);
113 visit_type_int(v, NULL, &pt->value.integer, errp);
116 visit_type_uint8(v, NULL, &pt->value.u8, errp);
119 visit_type_uint16(v, NULL, &pt->value.u16, errp);
122 visit_type_uint32(v, NULL, &pt->value.u32, errp);
125 visit_type_uint64(v, NULL, &pt->value.u64, errp);
128 visit_type_int8(v, NULL, &pt->value.s8, errp);
131 visit_type_int16(v, NULL, &pt->value.s16, errp);
134 visit_type_int32(v, NULL, &pt->value.s32, errp);
137 visit_type_int64(v, NULL, &pt->value.s64, errp);
140 g_assert_not_reached();
144 static void visit_primitive_list(Visitor *v, void **native, Error **errp)
146 PrimitiveList *pl = *native;
149 visit_type_strList(v, NULL, &pl->value.strings, errp);
152 visit_type_boolList(v, NULL, &pl->value.booleans, errp);
155 visit_type_numberList(v, NULL, &pl->value.numbers, errp);
158 visit_type_intList(v, NULL, &pl->value.integers, errp);
161 visit_type_int8List(v, NULL, &pl->value.s8_integers, errp);
164 visit_type_int16List(v, NULL, &pl->value.s16_integers, errp);
167 visit_type_int32List(v, NULL, &pl->value.s32_integers, errp);
170 visit_type_int64List(v, NULL, &pl->value.s64_integers, errp);
173 visit_type_uint8List(v, NULL, &pl->value.u8_integers, errp);
176 visit_type_uint16List(v, NULL, &pl->value.u16_integers, errp);
179 visit_type_uint32List(v, NULL, &pl->value.u32_integers, errp);
182 visit_type_uint64List(v, NULL, &pl->value.u64_integers, errp);
185 g_assert_not_reached();
190 static TestStruct *struct_create(void)
192 TestStruct *ts = g_malloc0(sizeof(*ts));
195 ts->string = strdup("test string");
199 static void struct_compare(TestStruct *ts1, TestStruct *ts2)
203 g_assert_cmpint(ts1->integer, ==, ts2->integer);
204 g_assert(ts1->boolean == ts2->boolean);
205 g_assert_cmpstr(ts1->string, ==, ts2->string);
208 static void struct_cleanup(TestStruct *ts)
214 static void visit_struct(Visitor *v, void **native, Error **errp)
216 visit_type_TestStruct(v, NULL, (TestStruct **)native, errp);
219 static UserDefTwo *nested_struct_create(void)
221 UserDefTwo *udnp = g_malloc0(sizeof(*udnp));
222 udnp->string0 = strdup("test_string0");
223 udnp->dict1 = g_malloc0(sizeof(*udnp->dict1));
224 udnp->dict1->string1 = strdup("test_string1");
225 udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2));
226 udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1);
227 udnp->dict1->dict2->userdef->integer = 42;
228 udnp->dict1->dict2->userdef->string = strdup("test_string");
229 udnp->dict1->dict2->string = strdup("test_string2");
230 udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3));
231 udnp->dict1->has_dict3 = true;
232 udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1);
233 udnp->dict1->dict3->userdef->integer = 43;
234 udnp->dict1->dict3->userdef->string = strdup("test_string");
235 udnp->dict1->dict3->string = strdup("test_string3");
239 static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2)
243 g_assert_cmpstr(udnp1->string0, ==, udnp2->string0);
244 g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1);
245 g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==,
246 udnp2->dict1->dict2->userdef->integer);
247 g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==,
248 udnp2->dict1->dict2->userdef->string);
249 g_assert_cmpstr(udnp1->dict1->dict2->string, ==,
250 udnp2->dict1->dict2->string);
251 g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3);
252 g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==,
253 udnp2->dict1->dict3->userdef->integer);
254 g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==,
255 udnp2->dict1->dict3->userdef->string);
256 g_assert_cmpstr(udnp1->dict1->dict3->string, ==,
257 udnp2->dict1->dict3->string);
260 static void nested_struct_cleanup(UserDefTwo *udnp)
262 qapi_free_UserDefTwo(udnp);
265 static void visit_nested_struct(Visitor *v, void **native, Error **errp)
267 visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp);
270 static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
272 visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp);
277 typedef enum VisitorCapabilities {
281 VCAP_PRIMITIVE_LISTS = 8,
282 } VisitorCapabilities;
284 typedef struct SerializeOps {
285 void (*serialize)(void *native_in, void **datap,
286 VisitorFunc visit, Error **errp);
287 void (*deserialize)(void **native_out, void *datap,
288 VisitorFunc visit, Error **errp);
289 void (*cleanup)(void *datap);
291 VisitorCapabilities caps;
294 typedef struct TestArgs {
295 const SerializeOps *ops;
299 static void test_primitives(gconstpointer opaque)
301 TestArgs *args = (TestArgs *) opaque;
302 const SerializeOps *ops = args->ops;
303 PrimitiveType *pt = args->test_data;
304 PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
305 void *serialize_data;
307 pt_copy->type = pt->type;
308 ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort);
309 ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type,
312 g_assert(pt_copy != NULL);
313 if (pt->type == PTYPE_STRING) {
314 g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
315 g_free((char *)pt_copy->value.string);
316 } else if (pt->type == PTYPE_NUMBER) {
317 GString *double_expected = g_string_new("");
318 GString *double_actual = g_string_new("");
319 /* we serialize with %f for our reference visitors, so rather than fuzzy
320 * floating math to test "equality", just compare the formatted values
322 g_string_printf(double_expected, "%.6f", pt->value.number);
323 g_string_printf(double_actual, "%.6f", pt_copy->value.number);
324 g_assert_cmpstr(double_actual->str, ==, double_expected->str);
326 g_string_free(double_expected, true);
327 g_string_free(double_actual, true);
328 } else if (pt->type == PTYPE_BOOLEAN) {
329 g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max);
331 g_assert_cmpint(pt->value.max, ==, pt_copy->value.max);
334 ops->cleanup(serialize_data);
339 static void test_primitive_lists(gconstpointer opaque)
341 TestArgs *args = (TestArgs *) opaque;
342 const SerializeOps *ops = args->ops;
343 PrimitiveType *pt = args->test_data;
344 PrimitiveList pl = { .value = { NULL } };
345 PrimitiveList pl_copy = { .value = { NULL } };
346 PrimitiveList *pl_copy_ptr = &pl_copy;
347 void *serialize_data;
348 void *cur_head = NULL;
351 pl.type = pl_copy.type = pt->type;
353 /* build up our list of primitive types */
354 for (i = 0; i < 32; i++) {
357 strList *tmp = g_new0(strList, 1);
358 tmp->value = g_strdup(pt->value.string);
359 if (pl.value.strings == NULL) {
360 pl.value.strings = tmp;
362 tmp->next = pl.value.strings;
363 pl.value.strings = tmp;
367 case PTYPE_INTEGER: {
368 intList *tmp = g_new0(intList, 1);
369 tmp->value = pt->value.integer;
370 if (pl.value.integers == NULL) {
371 pl.value.integers = tmp;
373 tmp->next = pl.value.integers;
374 pl.value.integers = tmp;
379 int8List *tmp = g_new0(int8List, 1);
380 tmp->value = pt->value.s8;
381 if (pl.value.s8_integers == NULL) {
382 pl.value.s8_integers = tmp;
384 tmp->next = pl.value.s8_integers;
385 pl.value.s8_integers = tmp;
390 int16List *tmp = g_new0(int16List, 1);
391 tmp->value = pt->value.s16;
392 if (pl.value.s16_integers == NULL) {
393 pl.value.s16_integers = tmp;
395 tmp->next = pl.value.s16_integers;
396 pl.value.s16_integers = tmp;
401 int32List *tmp = g_new0(int32List, 1);
402 tmp->value = pt->value.s32;
403 if (pl.value.s32_integers == NULL) {
404 pl.value.s32_integers = tmp;
406 tmp->next = pl.value.s32_integers;
407 pl.value.s32_integers = tmp;
412 int64List *tmp = g_new0(int64List, 1);
413 tmp->value = pt->value.s64;
414 if (pl.value.s64_integers == NULL) {
415 pl.value.s64_integers = tmp;
417 tmp->next = pl.value.s64_integers;
418 pl.value.s64_integers = tmp;
423 uint8List *tmp = g_new0(uint8List, 1);
424 tmp->value = pt->value.u8;
425 if (pl.value.u8_integers == NULL) {
426 pl.value.u8_integers = tmp;
428 tmp->next = pl.value.u8_integers;
429 pl.value.u8_integers = tmp;
434 uint16List *tmp = g_new0(uint16List, 1);
435 tmp->value = pt->value.u16;
436 if (pl.value.u16_integers == NULL) {
437 pl.value.u16_integers = tmp;
439 tmp->next = pl.value.u16_integers;
440 pl.value.u16_integers = tmp;
445 uint32List *tmp = g_new0(uint32List, 1);
446 tmp->value = pt->value.u32;
447 if (pl.value.u32_integers == NULL) {
448 pl.value.u32_integers = tmp;
450 tmp->next = pl.value.u32_integers;
451 pl.value.u32_integers = tmp;
456 uint64List *tmp = g_new0(uint64List, 1);
457 tmp->value = pt->value.u64;
458 if (pl.value.u64_integers == NULL) {
459 pl.value.u64_integers = tmp;
461 tmp->next = pl.value.u64_integers;
462 pl.value.u64_integers = tmp;
467 numberList *tmp = g_new0(numberList, 1);
468 tmp->value = pt->value.number;
469 if (pl.value.numbers == NULL) {
470 pl.value.numbers = tmp;
472 tmp->next = pl.value.numbers;
473 pl.value.numbers = tmp;
477 case PTYPE_BOOLEAN: {
478 boolList *tmp = g_new0(boolList, 1);
479 tmp->value = pt->value.boolean;
480 if (pl.value.booleans == NULL) {
481 pl.value.booleans = tmp;
483 tmp->next = pl.value.booleans;
484 pl.value.booleans = tmp;
489 g_assert_not_reached();
493 ops->serialize((void **)&pl, &serialize_data, visit_primitive_list,
495 ops->deserialize((void **)&pl_copy_ptr, serialize_data,
496 visit_primitive_list, &error_abort);
500 /* compare our deserialized list of primitives to the original */
502 switch (pl_copy.type) {
507 cur_head = ptr->next;
509 cur_head = ptr = pl_copy.value.strings;
511 g_assert_cmpstr(pt->value.string, ==, ptr->value);
514 case PTYPE_INTEGER: {
518 cur_head = ptr->next;
520 cur_head = ptr = pl_copy.value.integers;
522 g_assert_cmpint(pt->value.integer, ==, ptr->value);
529 cur_head = ptr->next;
531 cur_head = ptr = pl_copy.value.s8_integers;
533 g_assert_cmpint(pt->value.s8, ==, ptr->value);
540 cur_head = ptr->next;
542 cur_head = ptr = pl_copy.value.s16_integers;
544 g_assert_cmpint(pt->value.s16, ==, ptr->value);
551 cur_head = ptr->next;
553 cur_head = ptr = pl_copy.value.s32_integers;
555 g_assert_cmpint(pt->value.s32, ==, ptr->value);
562 cur_head = ptr->next;
564 cur_head = ptr = pl_copy.value.s64_integers;
566 g_assert_cmpint(pt->value.s64, ==, ptr->value);
573 cur_head = ptr->next;
575 cur_head = ptr = pl_copy.value.u8_integers;
577 g_assert_cmpint(pt->value.u8, ==, ptr->value);
584 cur_head = ptr->next;
586 cur_head = ptr = pl_copy.value.u16_integers;
588 g_assert_cmpint(pt->value.u16, ==, ptr->value);
595 cur_head = ptr->next;
597 cur_head = ptr = pl_copy.value.u32_integers;
599 g_assert_cmpint(pt->value.u32, ==, ptr->value);
606 cur_head = ptr->next;
608 cur_head = ptr = pl_copy.value.u64_integers;
610 g_assert_cmpint(pt->value.u64, ==, ptr->value);
615 GString *double_expected = g_string_new("");
616 GString *double_actual = g_string_new("");
619 cur_head = ptr->next;
621 cur_head = ptr = pl_copy.value.numbers;
623 /* we serialize with %f for our reference visitors, so rather than
624 * fuzzy floating math to test "equality", just compare the
627 g_string_printf(double_expected, "%.6f", pt->value.number);
628 g_string_printf(double_actual, "%.6f", ptr->value);
629 g_assert_cmpstr(double_actual->str, ==, double_expected->str);
630 g_string_free(double_expected, true);
631 g_string_free(double_actual, true);
634 case PTYPE_BOOLEAN: {
638 cur_head = ptr->next;
640 cur_head = ptr = pl_copy.value.booleans;
642 g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
646 g_assert_not_reached();
651 g_assert_cmpint(i, ==, 33);
653 ops->cleanup(serialize_data);
654 dealloc_helper(&pl, visit_primitive_list, &error_abort);
655 dealloc_helper(&pl_copy, visit_primitive_list, &error_abort);
659 static void test_struct(gconstpointer opaque)
661 TestArgs *args = (TestArgs *) opaque;
662 const SerializeOps *ops = args->ops;
663 TestStruct *ts = struct_create();
664 TestStruct *ts_copy = NULL;
665 void *serialize_data;
667 ops->serialize(ts, &serialize_data, visit_struct, &error_abort);
668 ops->deserialize((void **)&ts_copy, serialize_data, visit_struct,
671 struct_compare(ts, ts_copy);
674 struct_cleanup(ts_copy);
676 ops->cleanup(serialize_data);
680 static void test_nested_struct(gconstpointer opaque)
682 TestArgs *args = (TestArgs *) opaque;
683 const SerializeOps *ops = args->ops;
684 UserDefTwo *udnp = nested_struct_create();
685 UserDefTwo *udnp_copy = NULL;
686 void *serialize_data;
688 ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort);
689 ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct,
692 nested_struct_compare(udnp, udnp_copy);
694 nested_struct_cleanup(udnp);
695 nested_struct_cleanup(udnp_copy);
697 ops->cleanup(serialize_data);
701 static void test_nested_struct_list(gconstpointer opaque)
703 TestArgs *args = (TestArgs *) opaque;
704 const SerializeOps *ops = args->ops;
705 UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL;
706 void *serialize_data;
709 for (i = 0; i < 8; i++) {
710 tmp = g_new0(UserDefTwoList, 1);
711 tmp->value = nested_struct_create();
716 ops->serialize(listp, &serialize_data, visit_nested_struct_list,
718 ops->deserialize((void **)&listp_copy, serialize_data,
719 visit_nested_struct_list, &error_abort);
722 tmp_copy = listp_copy;
725 nested_struct_compare(listp->value, listp_copy->value);
727 listp_copy = listp_copy->next;
730 qapi_free_UserDefTwoList(tmp);
731 qapi_free_UserDefTwoList(tmp_copy);
733 ops->cleanup(serialize_data);
737 static PrimitiveType pt_values[] = {
740 .description = "string_empty",
741 .type = PTYPE_STRING,
745 .description = "string_whitespace",
746 .type = PTYPE_STRING,
747 .value.string = "a b c\td",
750 .description = "string_newlines",
751 .type = PTYPE_STRING,
752 .value.string = "a\nb\n",
755 .description = "string_commas",
756 .type = PTYPE_STRING,
757 .value.string = "a,b, c,d",
760 .description = "string_single_quoted",
761 .type = PTYPE_STRING,
762 .value.string = "'a b',cd",
765 .description = "string_double_quoted",
766 .type = PTYPE_STRING,
767 .value.string = "\"a b\",cd",
771 .description = "boolean_true1",
772 .type = PTYPE_BOOLEAN,
773 .value.boolean = true,
776 .description = "boolean_true2",
777 .type = PTYPE_BOOLEAN,
781 .description = "boolean_true3",
782 .type = PTYPE_BOOLEAN,
786 .description = "boolean_false1",
787 .type = PTYPE_BOOLEAN,
788 .value.boolean = false,
791 .description = "boolean_false2",
792 .type = PTYPE_BOOLEAN,
795 /* number tests (double) */
796 /* note: we format these to %.6f before comparing, since that's how
797 * we serialize them and it doesn't make sense to check precision
801 .description = "number_sanity1",
802 .type = PTYPE_NUMBER,
806 .description = "number_sanity2",
807 .type = PTYPE_NUMBER,
808 .value.number = 3.14159265,
811 .description = "number_min",
812 .type = PTYPE_NUMBER,
813 .value.number = DBL_MIN,
816 .description = "number_max",
817 .type = PTYPE_NUMBER,
818 .value.number = DBL_MAX,
820 /* integer tests (int64) */
822 .description = "integer_sanity1",
823 .type = PTYPE_INTEGER,
827 .description = "integer_sanity2",
828 .type = PTYPE_INTEGER,
829 .value.integer = INT64_MAX / 2 + 1,
832 .description = "integer_min",
833 .type = PTYPE_INTEGER,
834 .value.integer = INT64_MIN,
837 .description = "integer_max",
838 .type = PTYPE_INTEGER,
839 .value.integer = INT64_MAX,
843 .description = "uint8_sanity1",
848 .description = "uint8_sanity2",
850 .value.u8 = UINT8_MAX / 2 + 1,
853 .description = "uint8_min",
858 .description = "uint8_max",
860 .value.u8 = UINT8_MAX,
864 .description = "uint16_sanity1",
869 .description = "uint16_sanity2",
871 .value.u16 = UINT16_MAX / 2 + 1,
874 .description = "uint16_min",
879 .description = "uint16_max",
881 .value.u16 = UINT16_MAX,
885 .description = "uint32_sanity1",
890 .description = "uint32_sanity2",
892 .value.u32 = UINT32_MAX / 2 + 1,
895 .description = "uint32_min",
900 .description = "uint32_max",
902 .value.u32 = UINT32_MAX,
906 .description = "uint64_sanity1",
911 .description = "uint64_sanity2",
913 .value.u64 = UINT64_MAX / 2 + 1,
916 .description = "uint64_min",
921 .description = "uint64_max",
923 .value.u64 = UINT64_MAX,
927 .description = "int8_sanity1",
932 .description = "int8_sanity2",
934 .value.s8 = INT8_MAX / 2 + 1,
937 .description = "int8_min",
939 .value.s8 = INT8_MIN,
942 .description = "int8_max",
944 .value.s8 = INT8_MAX,
948 .description = "int16_sanity1",
953 .description = "int16_sanity2",
955 .value.s16 = INT16_MAX / 2 + 1,
958 .description = "int16_min",
960 .value.s16 = INT16_MIN,
963 .description = "int16_max",
965 .value.s16 = INT16_MAX,
969 .description = "int32_sanity1",
974 .description = "int32_sanity2",
976 .value.s32 = INT32_MAX / 2 + 1,
979 .description = "int32_min",
981 .value.s32 = INT32_MIN,
984 .description = "int32_max",
986 .value.s32 = INT32_MAX,
990 .description = "int64_sanity1",
995 .description = "int64_sanity2",
997 .value.s64 = INT64_MAX / 2 + 1,
1000 .description = "int64_min",
1002 .value.s64 = INT64_MIN,
1005 .description = "int64_max",
1007 .value.s64 = INT64_MAX,
1009 { .type = PTYPE_EOL }
1012 /* visitor-specific op implementations */
1014 typedef struct QmpSerializeData {
1015 QmpOutputVisitor *qov;
1016 QmpInputVisitor *qiv;
1019 static void qmp_serialize(void *native_in, void **datap,
1020 VisitorFunc visit, Error **errp)
1022 QmpSerializeData *d = g_malloc0(sizeof(*d));
1024 d->qov = qmp_output_visitor_new();
1025 visit(qmp_output_get_visitor(d->qov), &native_in, errp);
1029 static void qmp_deserialize(void **native_out, void *datap,
1030 VisitorFunc visit, Error **errp)
1032 QmpSerializeData *d = datap;
1033 QString *output_json;
1034 QObject *obj_orig, *obj;
1036 obj_orig = qmp_output_get_qobject(d->qov);
1037 output_json = qobject_to_json(obj_orig);
1038 obj = qobject_from_json(qstring_get_str(output_json));
1040 QDECREF(output_json);
1041 d->qiv = qmp_input_visitor_new(obj);
1042 qobject_decref(obj_orig);
1043 qobject_decref(obj);
1044 visit(qmp_input_get_visitor(d->qiv), native_out, errp);
1047 static void qmp_cleanup(void *datap)
1049 QmpSerializeData *d = datap;
1050 qmp_output_visitor_cleanup(d->qov);
1051 qmp_input_visitor_cleanup(d->qiv);
1056 typedef struct StringSerializeData {
1058 StringOutputVisitor *sov;
1059 StringInputVisitor *siv;
1060 } StringSerializeData;
1062 static void string_serialize(void *native_in, void **datap,
1063 VisitorFunc visit, Error **errp)
1065 StringSerializeData *d = g_malloc0(sizeof(*d));
1067 d->sov = string_output_visitor_new(false);
1068 visit(string_output_get_visitor(d->sov), &native_in, errp);
1072 static void string_deserialize(void **native_out, void *datap,
1073 VisitorFunc visit, Error **errp)
1075 StringSerializeData *d = datap;
1077 d->string = string_output_get_string(d->sov);
1078 d->siv = string_input_visitor_new(d->string);
1079 visit(string_input_get_visitor(d->siv), native_out, errp);
1082 static void string_cleanup(void *datap)
1084 StringSerializeData *d = datap;
1086 string_output_visitor_cleanup(d->sov);
1087 string_input_visitor_cleanup(d->siv);
1092 /* visitor registration, test harness */
1094 /* note: to function interchangeably as a serialization mechanism your
1095 * visitor test implementation should pass the test cases for all visitor
1096 * capabilities: primitives, structures, and lists
1098 static const SerializeOps visitors[] = {
1101 .serialize = qmp_serialize,
1102 .deserialize = qmp_deserialize,
1103 .cleanup = qmp_cleanup,
1104 .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
1105 VCAP_PRIMITIVE_LISTS
1109 .serialize = string_serialize,
1110 .deserialize = string_deserialize,
1111 .cleanup = string_cleanup,
1112 .caps = VCAP_PRIMITIVES
1117 static void add_visitor_type(const SerializeOps *ops)
1119 char testname_prefix[128];
1124 sprintf(testname_prefix, "/visitor/serialization/%s", ops->type);
1126 if (ops->caps & VCAP_PRIMITIVES) {
1127 while (pt_values[i].type != PTYPE_EOL) {
1128 sprintf(testname, "%s/primitives/%s", testname_prefix,
1129 pt_values[i].description);
1130 args = g_malloc0(sizeof(*args));
1132 args->test_data = &pt_values[i];
1133 g_test_add_data_func(testname, args, test_primitives);
1138 if (ops->caps & VCAP_STRUCTURES) {
1139 sprintf(testname, "%s/struct", testname_prefix);
1140 args = g_malloc0(sizeof(*args));
1142 args->test_data = NULL;
1143 g_test_add_data_func(testname, args, test_struct);
1145 sprintf(testname, "%s/nested_struct", testname_prefix);
1146 args = g_malloc0(sizeof(*args));
1148 args->test_data = NULL;
1149 g_test_add_data_func(testname, args, test_nested_struct);
1152 if (ops->caps & VCAP_LISTS) {
1153 sprintf(testname, "%s/nested_struct_list", testname_prefix);
1154 args = g_malloc0(sizeof(*args));
1156 args->test_data = NULL;
1157 g_test_add_data_func(testname, args, test_nested_struct_list);
1160 if (ops->caps & VCAP_PRIMITIVE_LISTS) {
1162 while (pt_values[i].type != PTYPE_EOL) {
1163 sprintf(testname, "%s/primitive_list/%s", testname_prefix,
1164 pt_values[i].description);
1165 args = g_malloc0(sizeof(*args));
1167 args->test_data = &pt_values[i];
1168 g_test_add_data_func(testname, args, test_primitive_lists);
1174 int main(int argc, char **argv)
1178 g_test_init(&argc, &argv, NULL);
1180 while (visitors[i].type != NULL) {
1181 add_visitor_type(&visitors[i]);