2 * Unit-tests for visitor-based serialization
4 * Copyright (C) 2014-2015 Red Hat, Inc.
5 * Copyright IBM, Corp. 2012
8 * Michael Roth <mdroth@linux.vnet.ibm.com>
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"
17 #include "qemu-common.h"
18 #include "test-qapi-visit.h"
19 #include "qapi/error.h"
20 #include "qapi/qmp/qjson.h"
21 #include "qapi/qmp/qstring.h"
22 #include "qapi/qobject-input-visitor.h"
23 #include "qapi/qobject-output-visitor.h"
24 #include "qapi/string-input-visitor.h"
25 #include "qapi/string-output-visitor.h"
26 #include "qapi/dealloc-visitor.h"
28 enum PrimitiveTypeKind
{
44 typedef struct PrimitiveType
{
59 enum PrimitiveTypeKind type
;
60 const char *description
;
63 typedef struct PrimitiveList
{
69 int8List
*s8_integers
;
70 int16List
*s16_integers
;
71 int32List
*s32_integers
;
72 int64List
*s64_integers
;
73 uint8List
*u8_integers
;
74 uint16List
*u16_integers
;
75 uint32List
*u32_integers
;
76 uint64List
*u64_integers
;
78 enum PrimitiveTypeKind type
;
79 const char *description
;
84 typedef void (*VisitorFunc
)(Visitor
*v
, void **native
, Error
**errp
);
86 static void dealloc_helper(void *native_in
, VisitorFunc visit
, Error
**errp
)
88 Visitor
*v
= qapi_dealloc_visitor_new();
90 visit(v
, &native_in
, errp
);
95 static void visit_primitive_type(Visitor
*v
, void **native
, Error
**errp
)
97 PrimitiveType
*pt
= *native
;
100 visit_type_str(v
, NULL
, (char **)&pt
->value
.string
, errp
);
103 visit_type_bool(v
, NULL
, &pt
->value
.boolean
, errp
);
106 visit_type_number(v
, NULL
, &pt
->value
.number
, errp
);
109 visit_type_int(v
, NULL
, &pt
->value
.integer
, errp
);
112 visit_type_uint8(v
, NULL
, &pt
->value
.u8
, errp
);
115 visit_type_uint16(v
, NULL
, &pt
->value
.u16
, errp
);
118 visit_type_uint32(v
, NULL
, &pt
->value
.u32
, errp
);
121 visit_type_uint64(v
, NULL
, &pt
->value
.u64
, errp
);
124 visit_type_int8(v
, NULL
, &pt
->value
.s8
, errp
);
127 visit_type_int16(v
, NULL
, &pt
->value
.s16
, errp
);
130 visit_type_int32(v
, NULL
, &pt
->value
.s32
, errp
);
133 visit_type_int64(v
, NULL
, &pt
->value
.s64
, errp
);
136 g_assert_not_reached();
140 static void visit_primitive_list(Visitor
*v
, void **native
, Error
**errp
)
142 PrimitiveList
*pl
= *native
;
145 visit_type_strList(v
, NULL
, &pl
->value
.strings
, errp
);
148 visit_type_boolList(v
, NULL
, &pl
->value
.booleans
, errp
);
151 visit_type_numberList(v
, NULL
, &pl
->value
.numbers
, errp
);
154 visit_type_intList(v
, NULL
, &pl
->value
.integers
, errp
);
157 visit_type_int8List(v
, NULL
, &pl
->value
.s8_integers
, errp
);
160 visit_type_int16List(v
, NULL
, &pl
->value
.s16_integers
, errp
);
163 visit_type_int32List(v
, NULL
, &pl
->value
.s32_integers
, errp
);
166 visit_type_int64List(v
, NULL
, &pl
->value
.s64_integers
, errp
);
169 visit_type_uint8List(v
, NULL
, &pl
->value
.u8_integers
, errp
);
172 visit_type_uint16List(v
, NULL
, &pl
->value
.u16_integers
, errp
);
175 visit_type_uint32List(v
, NULL
, &pl
->value
.u32_integers
, errp
);
178 visit_type_uint64List(v
, NULL
, &pl
->value
.u64_integers
, errp
);
181 g_assert_not_reached();
186 static TestStruct
*struct_create(void)
188 TestStruct
*ts
= g_malloc0(sizeof(*ts
));
191 ts
->string
= strdup("test string");
195 static void struct_compare(TestStruct
*ts1
, TestStruct
*ts2
)
199 g_assert_cmpint(ts1
->integer
, ==, ts2
->integer
);
200 g_assert(ts1
->boolean
== ts2
->boolean
);
201 g_assert_cmpstr(ts1
->string
, ==, ts2
->string
);
204 static void struct_cleanup(TestStruct
*ts
)
210 static void visit_struct(Visitor
*v
, void **native
, Error
**errp
)
212 visit_type_TestStruct(v
, NULL
, (TestStruct
**)native
, errp
);
215 static UserDefTwo
*nested_struct_create(void)
217 UserDefTwo
*udnp
= g_malloc0(sizeof(*udnp
));
218 udnp
->string0
= strdup("test_string0");
219 udnp
->dict1
= g_malloc0(sizeof(*udnp
->dict1
));
220 udnp
->dict1
->string1
= strdup("test_string1");
221 udnp
->dict1
->dict2
= g_malloc0(sizeof(*udnp
->dict1
->dict2
));
222 udnp
->dict1
->dict2
->userdef
= g_new0(UserDefOne
, 1);
223 udnp
->dict1
->dict2
->userdef
->integer
= 42;
224 udnp
->dict1
->dict2
->userdef
->string
= strdup("test_string");
225 udnp
->dict1
->dict2
->string
= strdup("test_string2");
226 udnp
->dict1
->dict3
= g_malloc0(sizeof(*udnp
->dict1
->dict3
));
227 udnp
->dict1
->has_dict3
= true;
228 udnp
->dict1
->dict3
->userdef
= g_new0(UserDefOne
, 1);
229 udnp
->dict1
->dict3
->userdef
->integer
= 43;
230 udnp
->dict1
->dict3
->userdef
->string
= strdup("test_string");
231 udnp
->dict1
->dict3
->string
= strdup("test_string3");
235 static void nested_struct_compare(UserDefTwo
*udnp1
, UserDefTwo
*udnp2
)
239 g_assert_cmpstr(udnp1
->string0
, ==, udnp2
->string0
);
240 g_assert_cmpstr(udnp1
->dict1
->string1
, ==, udnp2
->dict1
->string1
);
241 g_assert_cmpint(udnp1
->dict1
->dict2
->userdef
->integer
, ==,
242 udnp2
->dict1
->dict2
->userdef
->integer
);
243 g_assert_cmpstr(udnp1
->dict1
->dict2
->userdef
->string
, ==,
244 udnp2
->dict1
->dict2
->userdef
->string
);
245 g_assert_cmpstr(udnp1
->dict1
->dict2
->string
, ==,
246 udnp2
->dict1
->dict2
->string
);
247 g_assert(udnp1
->dict1
->has_dict3
== udnp2
->dict1
->has_dict3
);
248 g_assert_cmpint(udnp1
->dict1
->dict3
->userdef
->integer
, ==,
249 udnp2
->dict1
->dict3
->userdef
->integer
);
250 g_assert_cmpstr(udnp1
->dict1
->dict3
->userdef
->string
, ==,
251 udnp2
->dict1
->dict3
->userdef
->string
);
252 g_assert_cmpstr(udnp1
->dict1
->dict3
->string
, ==,
253 udnp2
->dict1
->dict3
->string
);
256 static void nested_struct_cleanup(UserDefTwo
*udnp
)
258 qapi_free_UserDefTwo(udnp
);
261 static void visit_nested_struct(Visitor
*v
, void **native
, Error
**errp
)
263 visit_type_UserDefTwo(v
, NULL
, (UserDefTwo
**)native
, errp
);
266 static void visit_nested_struct_list(Visitor
*v
, void **native
, Error
**errp
)
268 visit_type_UserDefTwoList(v
, NULL
, (UserDefTwoList
**)native
, errp
);
273 typedef enum VisitorCapabilities
{
277 VCAP_PRIMITIVE_LISTS
= 8,
278 } VisitorCapabilities
;
280 typedef struct SerializeOps
{
281 void (*serialize
)(void *native_in
, void **datap
,
282 VisitorFunc visit
, Error
**errp
);
283 void (*deserialize
)(void **native_out
, void *datap
,
284 VisitorFunc visit
, Error
**errp
);
285 void (*cleanup
)(void *datap
);
287 VisitorCapabilities caps
;
290 typedef struct TestArgs
{
291 const SerializeOps
*ops
;
295 static void test_primitives(gconstpointer opaque
)
297 TestArgs
*args
= (TestArgs
*) opaque
;
298 const SerializeOps
*ops
= args
->ops
;
299 PrimitiveType
*pt
= args
->test_data
;
300 PrimitiveType
*pt_copy
= g_malloc0(sizeof(*pt_copy
));
301 void *serialize_data
;
303 pt_copy
->type
= pt
->type
;
304 ops
->serialize(pt
, &serialize_data
, visit_primitive_type
, &error_abort
);
305 ops
->deserialize((void **)&pt_copy
, serialize_data
, visit_primitive_type
,
308 g_assert(pt_copy
!= NULL
);
311 g_assert_cmpstr(pt
->value
.string
, ==, pt_copy
->value
.string
);
312 g_free((char *)pt_copy
->value
.string
);
315 g_assert_cmpint(pt
->value
.boolean
, ==, pt
->value
.boolean
);
318 g_assert_cmpfloat(pt
->value
.number
, ==, pt_copy
->value
.number
);
321 g_assert_cmpint(pt
->value
.integer
, ==, pt_copy
->value
.integer
);
324 g_assert_cmpuint(pt
->value
.u8
, ==, pt_copy
->value
.u8
);
327 g_assert_cmpuint(pt
->value
.u16
, ==, pt_copy
->value
.u16
);
330 g_assert_cmpuint(pt
->value
.u32
, ==, pt_copy
->value
.u32
);
333 g_assert_cmpuint(pt
->value
.u64
, ==, pt_copy
->value
.u64
);
336 g_assert_cmpint(pt
->value
.s8
, ==, pt_copy
->value
.s8
);
339 g_assert_cmpint(pt
->value
.s16
, ==, pt_copy
->value
.s16
);
342 g_assert_cmpint(pt
->value
.s32
, ==, pt_copy
->value
.s32
);
345 g_assert_cmpint(pt
->value
.s64
, ==, pt_copy
->value
.s64
);
348 g_assert_not_reached();
351 ops
->cleanup(serialize_data
);
356 static void test_primitive_lists(gconstpointer opaque
)
358 TestArgs
*args
= (TestArgs
*) opaque
;
359 const SerializeOps
*ops
= args
->ops
;
360 PrimitiveType
*pt
= args
->test_data
;
361 PrimitiveList pl
= { .value
= { NULL
} };
362 PrimitiveList pl_copy
= { .value
= { NULL
} };
363 PrimitiveList
*pl_copy_ptr
= &pl_copy
;
364 void *serialize_data
;
365 void *cur_head
= NULL
;
368 pl
.type
= pl_copy
.type
= pt
->type
;
370 /* build up our list of primitive types */
371 for (i
= 0; i
< 32; i
++) {
374 QAPI_LIST_PREPEND(pl
.value
.strings
, g_strdup(pt
->value
.string
));
377 case PTYPE_INTEGER
: {
378 QAPI_LIST_PREPEND(pl
.value
.integers
, pt
->value
.integer
);
382 QAPI_LIST_PREPEND(pl
.value
.s8_integers
, pt
->value
.s8
);
386 QAPI_LIST_PREPEND(pl
.value
.s16_integers
, pt
->value
.s16
);
390 QAPI_LIST_PREPEND(pl
.value
.s32_integers
, pt
->value
.s32
);
394 QAPI_LIST_PREPEND(pl
.value
.s64_integers
, pt
->value
.s64
);
398 QAPI_LIST_PREPEND(pl
.value
.u8_integers
, pt
->value
.u8
);
402 QAPI_LIST_PREPEND(pl
.value
.u16_integers
, pt
->value
.u16
);
406 QAPI_LIST_PREPEND(pl
.value
.u32_integers
, pt
->value
.u32
);
410 QAPI_LIST_PREPEND(pl
.value
.u64_integers
, pt
->value
.u64
);
414 QAPI_LIST_PREPEND(pl
.value
.numbers
, pt
->value
.number
);
417 case PTYPE_BOOLEAN
: {
418 QAPI_LIST_PREPEND(pl
.value
.booleans
, pt
->value
.boolean
);
422 g_assert_not_reached();
426 ops
->serialize((void **)&pl
, &serialize_data
, visit_primitive_list
,
428 ops
->deserialize((void **)&pl_copy_ptr
, serialize_data
,
429 visit_primitive_list
, &error_abort
);
433 /* compare our deserialized list of primitives to the original */
435 switch (pl_copy
.type
) {
440 cur_head
= ptr
->next
;
442 cur_head
= ptr
= pl_copy
.value
.strings
;
444 g_assert_cmpstr(pt
->value
.string
, ==, ptr
->value
);
447 case PTYPE_INTEGER
: {
451 cur_head
= ptr
->next
;
453 cur_head
= ptr
= pl_copy
.value
.integers
;
455 g_assert_cmpint(pt
->value
.integer
, ==, ptr
->value
);
462 cur_head
= ptr
->next
;
464 cur_head
= ptr
= pl_copy
.value
.s8_integers
;
466 g_assert_cmpint(pt
->value
.s8
, ==, ptr
->value
);
473 cur_head
= ptr
->next
;
475 cur_head
= ptr
= pl_copy
.value
.s16_integers
;
477 g_assert_cmpint(pt
->value
.s16
, ==, ptr
->value
);
484 cur_head
= ptr
->next
;
486 cur_head
= ptr
= pl_copy
.value
.s32_integers
;
488 g_assert_cmpint(pt
->value
.s32
, ==, ptr
->value
);
495 cur_head
= ptr
->next
;
497 cur_head
= ptr
= pl_copy
.value
.s64_integers
;
499 g_assert_cmpint(pt
->value
.s64
, ==, ptr
->value
);
506 cur_head
= ptr
->next
;
508 cur_head
= ptr
= pl_copy
.value
.u8_integers
;
510 g_assert_cmpint(pt
->value
.u8
, ==, ptr
->value
);
517 cur_head
= ptr
->next
;
519 cur_head
= ptr
= pl_copy
.value
.u16_integers
;
521 g_assert_cmpint(pt
->value
.u16
, ==, ptr
->value
);
528 cur_head
= ptr
->next
;
530 cur_head
= ptr
= pl_copy
.value
.u32_integers
;
532 g_assert_cmpint(pt
->value
.u32
, ==, ptr
->value
);
539 cur_head
= ptr
->next
;
541 cur_head
= ptr
= pl_copy
.value
.u64_integers
;
543 g_assert_cmpint(pt
->value
.u64
, ==, ptr
->value
);
548 GString
*double_expected
= g_string_new("");
549 GString
*double_actual
= g_string_new("");
552 cur_head
= ptr
->next
;
554 cur_head
= ptr
= pl_copy
.value
.numbers
;
556 /* we serialize with %f for our reference visitors, so rather than
557 * fuzzy floating math to test "equality", just compare the
560 g_string_printf(double_expected
, "%.6f", pt
->value
.number
);
561 g_string_printf(double_actual
, "%.6f", ptr
->value
);
562 g_assert_cmpstr(double_actual
->str
, ==, double_expected
->str
);
563 g_string_free(double_expected
, true);
564 g_string_free(double_actual
, true);
567 case PTYPE_BOOLEAN
: {
571 cur_head
= ptr
->next
;
573 cur_head
= ptr
= pl_copy
.value
.booleans
;
575 g_assert_cmpint(!!pt
->value
.boolean
, ==, !!ptr
->value
);
579 g_assert_not_reached();
584 g_assert_cmpint(i
, ==, 33);
586 ops
->cleanup(serialize_data
);
587 dealloc_helper(&pl
, visit_primitive_list
, &error_abort
);
588 dealloc_helper(&pl_copy
, visit_primitive_list
, &error_abort
);
592 static void test_struct(gconstpointer opaque
)
594 TestArgs
*args
= (TestArgs
*) opaque
;
595 const SerializeOps
*ops
= args
->ops
;
596 TestStruct
*ts
= struct_create();
597 TestStruct
*ts_copy
= NULL
;
598 void *serialize_data
;
600 ops
->serialize(ts
, &serialize_data
, visit_struct
, &error_abort
);
601 ops
->deserialize((void **)&ts_copy
, serialize_data
, visit_struct
,
604 struct_compare(ts
, ts_copy
);
607 struct_cleanup(ts_copy
);
609 ops
->cleanup(serialize_data
);
613 static void test_nested_struct(gconstpointer opaque
)
615 TestArgs
*args
= (TestArgs
*) opaque
;
616 const SerializeOps
*ops
= args
->ops
;
617 UserDefTwo
*udnp
= nested_struct_create();
618 UserDefTwo
*udnp_copy
= NULL
;
619 void *serialize_data
;
621 ops
->serialize(udnp
, &serialize_data
, visit_nested_struct
, &error_abort
);
622 ops
->deserialize((void **)&udnp_copy
, serialize_data
, visit_nested_struct
,
625 nested_struct_compare(udnp
, udnp_copy
);
627 nested_struct_cleanup(udnp
);
628 nested_struct_cleanup(udnp_copy
);
630 ops
->cleanup(serialize_data
);
634 static void test_nested_struct_list(gconstpointer opaque
)
636 TestArgs
*args
= (TestArgs
*) opaque
;
637 const SerializeOps
*ops
= args
->ops
;
638 UserDefTwoList
*listp
= NULL
, *tmp
, *tmp_copy
, *listp_copy
= NULL
;
639 void *serialize_data
;
642 for (i
= 0; i
< 8; i
++) {
643 QAPI_LIST_PREPEND(listp
, nested_struct_create());
646 ops
->serialize(listp
, &serialize_data
, visit_nested_struct_list
,
648 ops
->deserialize((void **)&listp_copy
, serialize_data
,
649 visit_nested_struct_list
, &error_abort
);
652 tmp_copy
= listp_copy
;
655 nested_struct_compare(listp
->value
, listp_copy
->value
);
657 listp_copy
= listp_copy
->next
;
660 qapi_free_UserDefTwoList(tmp
);
661 qapi_free_UserDefTwoList(tmp_copy
);
663 ops
->cleanup(serialize_data
);
667 static PrimitiveType pt_values
[] = {
670 .description
= "string_empty",
671 .type
= PTYPE_STRING
,
675 .description
= "string_whitespace",
676 .type
= PTYPE_STRING
,
677 .value
.string
= "a b c\td",
680 .description
= "string_newlines",
681 .type
= PTYPE_STRING
,
682 .value
.string
= "a\nb\n",
685 .description
= "string_commas",
686 .type
= PTYPE_STRING
,
687 .value
.string
= "a,b, c,d",
690 .description
= "string_single_quoted",
691 .type
= PTYPE_STRING
,
692 .value
.string
= "'a b',cd",
695 .description
= "string_double_quoted",
696 .type
= PTYPE_STRING
,
697 .value
.string
= "\"a b\",cd",
701 .description
= "boolean_true1",
702 .type
= PTYPE_BOOLEAN
,
703 .value
.boolean
= true,
706 .description
= "boolean_true2",
707 .type
= PTYPE_BOOLEAN
,
711 .description
= "boolean_true3",
712 .type
= PTYPE_BOOLEAN
,
716 .description
= "boolean_false1",
717 .type
= PTYPE_BOOLEAN
,
718 .value
.boolean
= false,
721 .description
= "boolean_false2",
722 .type
= PTYPE_BOOLEAN
,
725 /* number tests (double) */
727 .description
= "number_sanity1",
728 .type
= PTYPE_NUMBER
,
732 .description
= "number_sanity2",
733 .type
= PTYPE_NUMBER
,
734 .value
.number
= 3.141593,
737 .description
= "number_min",
738 .type
= PTYPE_NUMBER
,
739 .value
.number
= DBL_MIN
,
742 .description
= "number_max",
743 .type
= PTYPE_NUMBER
,
744 .value
.number
= DBL_MAX
,
746 /* integer tests (int64) */
748 .description
= "integer_sanity1",
749 .type
= PTYPE_INTEGER
,
753 .description
= "integer_sanity2",
754 .type
= PTYPE_INTEGER
,
755 .value
.integer
= INT64_MAX
/ 2 + 1,
758 .description
= "integer_min",
759 .type
= PTYPE_INTEGER
,
760 .value
.integer
= INT64_MIN
,
763 .description
= "integer_max",
764 .type
= PTYPE_INTEGER
,
765 .value
.integer
= INT64_MAX
,
769 .description
= "uint8_sanity1",
774 .description
= "uint8_sanity2",
776 .value
.u8
= UINT8_MAX
/ 2 + 1,
779 .description
= "uint8_min",
784 .description
= "uint8_max",
786 .value
.u8
= UINT8_MAX
,
790 .description
= "uint16_sanity1",
795 .description
= "uint16_sanity2",
797 .value
.u16
= UINT16_MAX
/ 2 + 1,
800 .description
= "uint16_min",
805 .description
= "uint16_max",
807 .value
.u16
= UINT16_MAX
,
811 .description
= "uint32_sanity1",
816 .description
= "uint32_sanity2",
818 .value
.u32
= UINT32_MAX
/ 2 + 1,
821 .description
= "uint32_min",
826 .description
= "uint32_max",
828 .value
.u32
= UINT32_MAX
,
832 .description
= "uint64_sanity1",
837 .description
= "uint64_sanity2",
839 .value
.u64
= UINT64_MAX
/ 2 + 1,
842 .description
= "uint64_min",
847 .description
= "uint64_max",
849 .value
.u64
= UINT64_MAX
,
853 .description
= "int8_sanity1",
858 .description
= "int8_sanity2",
860 .value
.s8
= INT8_MAX
/ 2 + 1,
863 .description
= "int8_min",
865 .value
.s8
= INT8_MIN
,
868 .description
= "int8_max",
870 .value
.s8
= INT8_MAX
,
874 .description
= "int16_sanity1",
879 .description
= "int16_sanity2",
881 .value
.s16
= INT16_MAX
/ 2 + 1,
884 .description
= "int16_min",
886 .value
.s16
= INT16_MIN
,
889 .description
= "int16_max",
891 .value
.s16
= INT16_MAX
,
895 .description
= "int32_sanity1",
900 .description
= "int32_sanity2",
902 .value
.s32
= INT32_MAX
/ 2 + 1,
905 .description
= "int32_min",
907 .value
.s32
= INT32_MIN
,
910 .description
= "int32_max",
912 .value
.s32
= INT32_MAX
,
916 .description
= "int64_sanity1",
921 .description
= "int64_sanity2",
923 .value
.s64
= INT64_MAX
/ 2 + 1,
926 .description
= "int64_min",
928 .value
.s64
= INT64_MIN
,
931 .description
= "int64_max",
933 .value
.s64
= INT64_MAX
,
935 { .type
= PTYPE_EOL
}
938 /* visitor-specific op implementations */
940 typedef struct QmpSerializeData
{
946 static void qmp_serialize(void *native_in
, void **datap
,
947 VisitorFunc visit
, Error
**errp
)
949 QmpSerializeData
*d
= g_malloc0(sizeof(*d
));
951 d
->qov
= qobject_output_visitor_new(&d
->obj
);
952 visit(d
->qov
, &native_in
, errp
);
956 static void qmp_deserialize(void **native_out
, void *datap
,
957 VisitorFunc visit
, Error
**errp
)
959 QmpSerializeData
*d
= datap
;
960 GString
*output_json
;
961 QObject
*obj_orig
, *obj
;
963 visit_complete(d
->qov
, &d
->obj
);
965 output_json
= qobject_to_json(obj_orig
);
966 obj
= qobject_from_json(output_json
->str
, &error_abort
);
968 g_string_free(output_json
, true);
969 d
->qiv
= qobject_input_visitor_new(obj
);
970 qobject_unref(obj_orig
);
972 visit(d
->qiv
, native_out
, errp
);
975 static void qmp_cleanup(void *datap
)
977 QmpSerializeData
*d
= datap
;
984 typedef struct StringSerializeData
{
988 } StringSerializeData
;
990 static void string_serialize(void *native_in
, void **datap
,
991 VisitorFunc visit
, Error
**errp
)
993 StringSerializeData
*d
= g_malloc0(sizeof(*d
));
995 d
->sov
= string_output_visitor_new(false, &d
->string
);
996 visit(d
->sov
, &native_in
, errp
);
1000 static void string_deserialize(void **native_out
, void *datap
,
1001 VisitorFunc visit
, Error
**errp
)
1003 StringSerializeData
*d
= datap
;
1005 visit_complete(d
->sov
, &d
->string
);
1006 d
->siv
= string_input_visitor_new(d
->string
);
1007 visit(d
->siv
, native_out
, errp
);
1010 static void string_cleanup(void *datap
)
1012 StringSerializeData
*d
= datap
;
1020 /* visitor registration, test harness */
1022 /* note: to function interchangeably as a serialization mechanism your
1023 * visitor test implementation should pass the test cases for all visitor
1024 * capabilities: primitives, structures, and lists
1026 static const SerializeOps visitors
[] = {
1029 .serialize
= qmp_serialize
,
1030 .deserialize
= qmp_deserialize
,
1031 .cleanup
= qmp_cleanup
,
1032 .caps
= VCAP_PRIMITIVES
| VCAP_STRUCTURES
| VCAP_LISTS
|
1033 VCAP_PRIMITIVE_LISTS
1037 .serialize
= string_serialize
,
1038 .deserialize
= string_deserialize
,
1039 .cleanup
= string_cleanup
,
1040 .caps
= VCAP_PRIMITIVES
1045 static void add_visitor_type(const SerializeOps
*ops
)
1047 char testname_prefix
[32];
1052 sprintf(testname_prefix
, "/visitor/serialization/%s", ops
->type
);
1054 if (ops
->caps
& VCAP_PRIMITIVES
) {
1055 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1056 sprintf(testname
, "%s/primitives/%s", testname_prefix
,
1057 pt_values
[i
].description
);
1058 args
= g_malloc0(sizeof(*args
));
1060 args
->test_data
= &pt_values
[i
];
1061 g_test_add_data_func(testname
, args
, test_primitives
);
1066 if (ops
->caps
& VCAP_STRUCTURES
) {
1067 sprintf(testname
, "%s/struct", testname_prefix
);
1068 args
= g_malloc0(sizeof(*args
));
1070 args
->test_data
= NULL
;
1071 g_test_add_data_func(testname
, args
, test_struct
);
1073 sprintf(testname
, "%s/nested_struct", testname_prefix
);
1074 args
= g_malloc0(sizeof(*args
));
1076 args
->test_data
= NULL
;
1077 g_test_add_data_func(testname
, args
, test_nested_struct
);
1080 if (ops
->caps
& VCAP_LISTS
) {
1081 sprintf(testname
, "%s/nested_struct_list", testname_prefix
);
1082 args
= g_malloc0(sizeof(*args
));
1084 args
->test_data
= NULL
;
1085 g_test_add_data_func(testname
, args
, test_nested_struct_list
);
1088 if (ops
->caps
& VCAP_PRIMITIVE_LISTS
) {
1090 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1091 sprintf(testname
, "%s/primitive_list/%s", testname_prefix
,
1092 pt_values
[i
].description
);
1093 args
= g_malloc0(sizeof(*args
));
1095 args
->test_data
= &pt_values
[i
];
1096 g_test_add_data_func(testname
, args
, test_primitive_lists
);
1102 int main(int argc
, char **argv
)
1106 g_test_init(&argc
, &argv
, NULL
);
1108 while (visitors
[i
].type
!= NULL
) {
1109 add_visitor_type(&visitors
[i
]);