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 "test-qapi-visit.h"
18 #include "qapi/error.h"
19 #include "qapi/qmp/qjson.h"
20 #include "qapi/qmp/qstring.h"
21 #include "qapi/qobject-input-visitor.h"
22 #include "qapi/qobject-output-visitor.h"
23 #include "qapi/string-input-visitor.h"
24 #include "qapi/string-output-visitor.h"
25 #include "qapi/dealloc-visitor.h"
27 enum PrimitiveTypeKind
{
43 typedef struct PrimitiveType
{
58 enum PrimitiveTypeKind type
;
59 const char *description
;
62 typedef struct PrimitiveList
{
68 int8List
*s8_integers
;
69 int16List
*s16_integers
;
70 int32List
*s32_integers
;
71 int64List
*s64_integers
;
72 uint8List
*u8_integers
;
73 uint16List
*u16_integers
;
74 uint32List
*u32_integers
;
75 uint64List
*u64_integers
;
77 enum PrimitiveTypeKind type
;
78 const char *description
;
83 typedef void (*VisitorFunc
)(Visitor
*v
, void **native
, Error
**errp
);
85 static void dealloc_helper(void *native_in
, VisitorFunc visit
, Error
**errp
)
87 Visitor
*v
= qapi_dealloc_visitor_new();
89 visit(v
, &native_in
, errp
);
94 static void visit_primitive_type(Visitor
*v
, void **native
, Error
**errp
)
96 PrimitiveType
*pt
= *native
;
99 visit_type_str(v
, NULL
, (char **)&pt
->value
.string
, errp
);
102 visit_type_bool(v
, NULL
, &pt
->value
.boolean
, errp
);
105 visit_type_number(v
, NULL
, &pt
->value
.number
, errp
);
108 visit_type_int(v
, NULL
, &pt
->value
.integer
, errp
);
111 visit_type_uint8(v
, NULL
, &pt
->value
.u8
, errp
);
114 visit_type_uint16(v
, NULL
, &pt
->value
.u16
, errp
);
117 visit_type_uint32(v
, NULL
, &pt
->value
.u32
, errp
);
120 visit_type_uint64(v
, NULL
, &pt
->value
.u64
, errp
);
123 visit_type_int8(v
, NULL
, &pt
->value
.s8
, errp
);
126 visit_type_int16(v
, NULL
, &pt
->value
.s16
, errp
);
129 visit_type_int32(v
, NULL
, &pt
->value
.s32
, errp
);
132 visit_type_int64(v
, NULL
, &pt
->value
.s64
, errp
);
135 g_assert_not_reached();
139 static void visit_primitive_list(Visitor
*v
, void **native
, Error
**errp
)
141 PrimitiveList
*pl
= *native
;
144 visit_type_strList(v
, NULL
, &pl
->value
.strings
, errp
);
147 visit_type_boolList(v
, NULL
, &pl
->value
.booleans
, errp
);
150 visit_type_numberList(v
, NULL
, &pl
->value
.numbers
, errp
);
153 visit_type_intList(v
, NULL
, &pl
->value
.integers
, errp
);
156 visit_type_int8List(v
, NULL
, &pl
->value
.s8_integers
, errp
);
159 visit_type_int16List(v
, NULL
, &pl
->value
.s16_integers
, errp
);
162 visit_type_int32List(v
, NULL
, &pl
->value
.s32_integers
, errp
);
165 visit_type_int64List(v
, NULL
, &pl
->value
.s64_integers
, errp
);
168 visit_type_uint8List(v
, NULL
, &pl
->value
.u8_integers
, errp
);
171 visit_type_uint16List(v
, NULL
, &pl
->value
.u16_integers
, errp
);
174 visit_type_uint32List(v
, NULL
, &pl
->value
.u32_integers
, errp
);
177 visit_type_uint64List(v
, NULL
, &pl
->value
.u64_integers
, errp
);
180 g_assert_not_reached();
185 static TestStruct
*struct_create(void)
187 TestStruct
*ts
= g_malloc0(sizeof(*ts
));
190 ts
->string
= strdup("test string");
194 static void struct_compare(TestStruct
*ts1
, TestStruct
*ts2
)
198 g_assert_cmpint(ts1
->integer
, ==, ts2
->integer
);
199 g_assert(ts1
->boolean
== ts2
->boolean
);
200 g_assert_cmpstr(ts1
->string
, ==, ts2
->string
);
203 static void struct_cleanup(TestStruct
*ts
)
209 static void visit_struct(Visitor
*v
, void **native
, Error
**errp
)
211 visit_type_TestStruct(v
, NULL
, (TestStruct
**)native
, errp
);
214 static UserDefTwo
*nested_struct_create(void)
216 UserDefTwo
*udnp
= g_malloc0(sizeof(*udnp
));
217 udnp
->string0
= strdup("test_string0");
218 udnp
->dict1
= g_malloc0(sizeof(*udnp
->dict1
));
219 udnp
->dict1
->string1
= strdup("test_string1");
220 udnp
->dict1
->dict2
= g_malloc0(sizeof(*udnp
->dict1
->dict2
));
221 udnp
->dict1
->dict2
->userdef
= g_new0(UserDefOne
, 1);
222 udnp
->dict1
->dict2
->userdef
->integer
= 42;
223 udnp
->dict1
->dict2
->userdef
->string
= strdup("test_string");
224 udnp
->dict1
->dict2
->string
= strdup("test_string2");
225 udnp
->dict1
->dict3
= g_malloc0(sizeof(*udnp
->dict1
->dict3
));
226 udnp
->dict1
->has_dict3
= true;
227 udnp
->dict1
->dict3
->userdef
= g_new0(UserDefOne
, 1);
228 udnp
->dict1
->dict3
->userdef
->integer
= 43;
229 udnp
->dict1
->dict3
->userdef
->string
= strdup("test_string");
230 udnp
->dict1
->dict3
->string
= strdup("test_string3");
234 static void nested_struct_compare(UserDefTwo
*udnp1
, UserDefTwo
*udnp2
)
238 g_assert_cmpstr(udnp1
->string0
, ==, udnp2
->string0
);
239 g_assert_cmpstr(udnp1
->dict1
->string1
, ==, udnp2
->dict1
->string1
);
240 g_assert_cmpint(udnp1
->dict1
->dict2
->userdef
->integer
, ==,
241 udnp2
->dict1
->dict2
->userdef
->integer
);
242 g_assert_cmpstr(udnp1
->dict1
->dict2
->userdef
->string
, ==,
243 udnp2
->dict1
->dict2
->userdef
->string
);
244 g_assert_cmpstr(udnp1
->dict1
->dict2
->string
, ==,
245 udnp2
->dict1
->dict2
->string
);
246 g_assert(udnp1
->dict1
->has_dict3
== udnp2
->dict1
->has_dict3
);
247 g_assert_cmpint(udnp1
->dict1
->dict3
->userdef
->integer
, ==,
248 udnp2
->dict1
->dict3
->userdef
->integer
);
249 g_assert_cmpstr(udnp1
->dict1
->dict3
->userdef
->string
, ==,
250 udnp2
->dict1
->dict3
->userdef
->string
);
251 g_assert_cmpstr(udnp1
->dict1
->dict3
->string
, ==,
252 udnp2
->dict1
->dict3
->string
);
255 static void nested_struct_cleanup(UserDefTwo
*udnp
)
257 qapi_free_UserDefTwo(udnp
);
260 static void visit_nested_struct(Visitor
*v
, void **native
, Error
**errp
)
262 visit_type_UserDefTwo(v
, NULL
, (UserDefTwo
**)native
, errp
);
265 static void visit_nested_struct_list(Visitor
*v
, void **native
, Error
**errp
)
267 visit_type_UserDefTwoList(v
, NULL
, (UserDefTwoList
**)native
, errp
);
272 typedef enum VisitorCapabilities
{
276 VCAP_PRIMITIVE_LISTS
= 8,
277 } VisitorCapabilities
;
279 typedef struct SerializeOps
{
280 void (*serialize
)(void *native_in
, void **datap
,
281 VisitorFunc visit
, Error
**errp
);
282 void (*deserialize
)(void **native_out
, void *datap
,
283 VisitorFunc visit
, Error
**errp
);
284 void (*cleanup
)(void *datap
);
286 VisitorCapabilities caps
;
289 typedef struct TestArgs
{
290 const SerializeOps
*ops
;
294 static void test_primitives(gconstpointer opaque
)
296 TestArgs
*args
= (TestArgs
*) opaque
;
297 const SerializeOps
*ops
= args
->ops
;
298 PrimitiveType
*pt
= args
->test_data
;
299 PrimitiveType
*pt_copy
= g_malloc0(sizeof(*pt_copy
));
300 void *serialize_data
;
302 pt_copy
->type
= pt
->type
;
303 ops
->serialize(pt
, &serialize_data
, visit_primitive_type
, &error_abort
);
304 ops
->deserialize((void **)&pt_copy
, serialize_data
, visit_primitive_type
,
307 g_assert(pt_copy
!= NULL
);
310 g_assert_cmpstr(pt
->value
.string
, ==, pt_copy
->value
.string
);
311 g_free((char *)pt_copy
->value
.string
);
314 g_assert_cmpint(pt
->value
.boolean
, ==, pt
->value
.boolean
);
317 g_assert_cmpfloat(pt
->value
.number
, ==, pt_copy
->value
.number
);
320 g_assert_cmpint(pt
->value
.integer
, ==, pt_copy
->value
.integer
);
323 g_assert_cmpuint(pt
->value
.u8
, ==, pt_copy
->value
.u8
);
326 g_assert_cmpuint(pt
->value
.u16
, ==, pt_copy
->value
.u16
);
329 g_assert_cmpuint(pt
->value
.u32
, ==, pt_copy
->value
.u32
);
332 g_assert_cmpuint(pt
->value
.u64
, ==, pt_copy
->value
.u64
);
335 g_assert_cmpint(pt
->value
.s8
, ==, pt_copy
->value
.s8
);
338 g_assert_cmpint(pt
->value
.s16
, ==, pt_copy
->value
.s16
);
341 g_assert_cmpint(pt
->value
.s32
, ==, pt_copy
->value
.s32
);
344 g_assert_cmpint(pt
->value
.s64
, ==, pt_copy
->value
.s64
);
347 g_assert_not_reached();
350 ops
->cleanup(serialize_data
);
355 static void test_primitive_lists(gconstpointer opaque
)
357 TestArgs
*args
= (TestArgs
*) opaque
;
358 const SerializeOps
*ops
= args
->ops
;
359 PrimitiveType
*pt
= args
->test_data
;
360 PrimitiveList pl
= { .value
= { NULL
} };
361 PrimitiveList pl_copy
= { .value
= { NULL
} };
362 PrimitiveList
*pl_copy_ptr
= &pl_copy
;
363 void *serialize_data
;
364 void *cur_head
= NULL
;
367 pl
.type
= pl_copy
.type
= pt
->type
;
369 /* build up our list of primitive types */
370 for (i
= 0; i
< 32; i
++) {
373 QAPI_LIST_PREPEND(pl
.value
.strings
, g_strdup(pt
->value
.string
));
376 case PTYPE_INTEGER
: {
377 QAPI_LIST_PREPEND(pl
.value
.integers
, pt
->value
.integer
);
381 QAPI_LIST_PREPEND(pl
.value
.s8_integers
, pt
->value
.s8
);
385 QAPI_LIST_PREPEND(pl
.value
.s16_integers
, pt
->value
.s16
);
389 QAPI_LIST_PREPEND(pl
.value
.s32_integers
, pt
->value
.s32
);
393 QAPI_LIST_PREPEND(pl
.value
.s64_integers
, pt
->value
.s64
);
397 QAPI_LIST_PREPEND(pl
.value
.u8_integers
, pt
->value
.u8
);
401 QAPI_LIST_PREPEND(pl
.value
.u16_integers
, pt
->value
.u16
);
405 QAPI_LIST_PREPEND(pl
.value
.u32_integers
, pt
->value
.u32
);
409 QAPI_LIST_PREPEND(pl
.value
.u64_integers
, pt
->value
.u64
);
413 QAPI_LIST_PREPEND(pl
.value
.numbers
, pt
->value
.number
);
416 case PTYPE_BOOLEAN
: {
417 QAPI_LIST_PREPEND(pl
.value
.booleans
, pt
->value
.boolean
);
421 g_assert_not_reached();
425 ops
->serialize((void **)&pl
, &serialize_data
, visit_primitive_list
,
427 ops
->deserialize((void **)&pl_copy_ptr
, serialize_data
,
428 visit_primitive_list
, &error_abort
);
432 /* compare our deserialized list of primitives to the original */
434 switch (pl_copy
.type
) {
439 cur_head
= ptr
->next
;
441 cur_head
= ptr
= pl_copy
.value
.strings
;
443 g_assert_cmpstr(pt
->value
.string
, ==, ptr
->value
);
446 case PTYPE_INTEGER
: {
450 cur_head
= ptr
->next
;
452 cur_head
= ptr
= pl_copy
.value
.integers
;
454 g_assert_cmpint(pt
->value
.integer
, ==, ptr
->value
);
461 cur_head
= ptr
->next
;
463 cur_head
= ptr
= pl_copy
.value
.s8_integers
;
465 g_assert_cmpint(pt
->value
.s8
, ==, ptr
->value
);
472 cur_head
= ptr
->next
;
474 cur_head
= ptr
= pl_copy
.value
.s16_integers
;
476 g_assert_cmpint(pt
->value
.s16
, ==, ptr
->value
);
483 cur_head
= ptr
->next
;
485 cur_head
= ptr
= pl_copy
.value
.s32_integers
;
487 g_assert_cmpint(pt
->value
.s32
, ==, ptr
->value
);
494 cur_head
= ptr
->next
;
496 cur_head
= ptr
= pl_copy
.value
.s64_integers
;
498 g_assert_cmpint(pt
->value
.s64
, ==, ptr
->value
);
505 cur_head
= ptr
->next
;
507 cur_head
= ptr
= pl_copy
.value
.u8_integers
;
509 g_assert_cmpint(pt
->value
.u8
, ==, ptr
->value
);
516 cur_head
= ptr
->next
;
518 cur_head
= ptr
= pl_copy
.value
.u16_integers
;
520 g_assert_cmpint(pt
->value
.u16
, ==, ptr
->value
);
527 cur_head
= ptr
->next
;
529 cur_head
= ptr
= pl_copy
.value
.u32_integers
;
531 g_assert_cmpint(pt
->value
.u32
, ==, ptr
->value
);
538 cur_head
= ptr
->next
;
540 cur_head
= ptr
= pl_copy
.value
.u64_integers
;
542 g_assert_cmpint(pt
->value
.u64
, ==, ptr
->value
);
547 GString
*double_expected
= g_string_new("");
548 GString
*double_actual
= g_string_new("");
551 cur_head
= ptr
->next
;
553 cur_head
= ptr
= pl_copy
.value
.numbers
;
555 /* we serialize with %f for our reference visitors, so rather than
556 * fuzzy floating math to test "equality", just compare the
559 g_string_printf(double_expected
, "%.6f", pt
->value
.number
);
560 g_string_printf(double_actual
, "%.6f", ptr
->value
);
561 g_assert_cmpstr(double_actual
->str
, ==, double_expected
->str
);
562 g_string_free(double_expected
, true);
563 g_string_free(double_actual
, true);
566 case PTYPE_BOOLEAN
: {
570 cur_head
= ptr
->next
;
572 cur_head
= ptr
= pl_copy
.value
.booleans
;
574 g_assert_cmpint(!!pt
->value
.boolean
, ==, !!ptr
->value
);
578 g_assert_not_reached();
583 g_assert_cmpint(i
, ==, 33);
585 ops
->cleanup(serialize_data
);
586 dealloc_helper(&pl
, visit_primitive_list
, &error_abort
);
587 dealloc_helper(&pl_copy
, visit_primitive_list
, &error_abort
);
591 static void test_struct(gconstpointer opaque
)
593 TestArgs
*args
= (TestArgs
*) opaque
;
594 const SerializeOps
*ops
= args
->ops
;
595 TestStruct
*ts
= struct_create();
596 TestStruct
*ts_copy
= NULL
;
597 void *serialize_data
;
599 ops
->serialize(ts
, &serialize_data
, visit_struct
, &error_abort
);
600 ops
->deserialize((void **)&ts_copy
, serialize_data
, visit_struct
,
603 struct_compare(ts
, ts_copy
);
606 struct_cleanup(ts_copy
);
608 ops
->cleanup(serialize_data
);
612 static void test_nested_struct(gconstpointer opaque
)
614 TestArgs
*args
= (TestArgs
*) opaque
;
615 const SerializeOps
*ops
= args
->ops
;
616 UserDefTwo
*udnp
= nested_struct_create();
617 UserDefTwo
*udnp_copy
= NULL
;
618 void *serialize_data
;
620 ops
->serialize(udnp
, &serialize_data
, visit_nested_struct
, &error_abort
);
621 ops
->deserialize((void **)&udnp_copy
, serialize_data
, visit_nested_struct
,
624 nested_struct_compare(udnp
, udnp_copy
);
626 nested_struct_cleanup(udnp
);
627 nested_struct_cleanup(udnp_copy
);
629 ops
->cleanup(serialize_data
);
633 static void test_nested_struct_list(gconstpointer opaque
)
635 TestArgs
*args
= (TestArgs
*) opaque
;
636 const SerializeOps
*ops
= args
->ops
;
637 UserDefTwoList
*listp
= NULL
, *tmp
, *tmp_copy
, *listp_copy
= NULL
;
638 void *serialize_data
;
641 for (i
= 0; i
< 8; i
++) {
642 QAPI_LIST_PREPEND(listp
, nested_struct_create());
645 ops
->serialize(listp
, &serialize_data
, visit_nested_struct_list
,
647 ops
->deserialize((void **)&listp_copy
, serialize_data
,
648 visit_nested_struct_list
, &error_abort
);
651 tmp_copy
= listp_copy
;
654 nested_struct_compare(listp
->value
, listp_copy
->value
);
656 listp_copy
= listp_copy
->next
;
659 qapi_free_UserDefTwoList(tmp
);
660 qapi_free_UserDefTwoList(tmp_copy
);
662 ops
->cleanup(serialize_data
);
666 static PrimitiveType pt_values
[] = {
669 .description
= "string_empty",
670 .type
= PTYPE_STRING
,
674 .description
= "string_whitespace",
675 .type
= PTYPE_STRING
,
676 .value
.string
= "a b c\td",
679 .description
= "string_newlines",
680 .type
= PTYPE_STRING
,
681 .value
.string
= "a\nb\n",
684 .description
= "string_commas",
685 .type
= PTYPE_STRING
,
686 .value
.string
= "a,b, c,d",
689 .description
= "string_single_quoted",
690 .type
= PTYPE_STRING
,
691 .value
.string
= "'a b',cd",
694 .description
= "string_double_quoted",
695 .type
= PTYPE_STRING
,
696 .value
.string
= "\"a b\",cd",
700 .description
= "boolean_true1",
701 .type
= PTYPE_BOOLEAN
,
702 .value
.boolean
= true,
705 .description
= "boolean_true2",
706 .type
= PTYPE_BOOLEAN
,
710 .description
= "boolean_true3",
711 .type
= PTYPE_BOOLEAN
,
715 .description
= "boolean_false1",
716 .type
= PTYPE_BOOLEAN
,
717 .value
.boolean
= false,
720 .description
= "boolean_false2",
721 .type
= PTYPE_BOOLEAN
,
724 /* number tests (double) */
726 .description
= "number_sanity1",
727 .type
= PTYPE_NUMBER
,
731 .description
= "number_sanity2",
732 .type
= PTYPE_NUMBER
,
733 .value
.number
= 3.141593,
736 .description
= "number_min",
737 .type
= PTYPE_NUMBER
,
738 .value
.number
= DBL_MIN
,
741 .description
= "number_max",
742 .type
= PTYPE_NUMBER
,
743 .value
.number
= DBL_MAX
,
745 /* integer tests (int64) */
747 .description
= "integer_sanity1",
748 .type
= PTYPE_INTEGER
,
752 .description
= "integer_sanity2",
753 .type
= PTYPE_INTEGER
,
754 .value
.integer
= INT64_MAX
/ 2 + 1,
757 .description
= "integer_min",
758 .type
= PTYPE_INTEGER
,
759 .value
.integer
= INT64_MIN
,
762 .description
= "integer_max",
763 .type
= PTYPE_INTEGER
,
764 .value
.integer
= INT64_MAX
,
768 .description
= "uint8_sanity1",
773 .description
= "uint8_sanity2",
775 .value
.u8
= UINT8_MAX
/ 2 + 1,
778 .description
= "uint8_min",
783 .description
= "uint8_max",
785 .value
.u8
= UINT8_MAX
,
789 .description
= "uint16_sanity1",
794 .description
= "uint16_sanity2",
796 .value
.u16
= UINT16_MAX
/ 2 + 1,
799 .description
= "uint16_min",
804 .description
= "uint16_max",
806 .value
.u16
= UINT16_MAX
,
810 .description
= "uint32_sanity1",
815 .description
= "uint32_sanity2",
817 .value
.u32
= UINT32_MAX
/ 2 + 1,
820 .description
= "uint32_min",
825 .description
= "uint32_max",
827 .value
.u32
= UINT32_MAX
,
831 .description
= "uint64_sanity1",
836 .description
= "uint64_sanity2",
838 .value
.u64
= UINT64_MAX
/ 2 + 1,
841 .description
= "uint64_min",
846 .description
= "uint64_max",
848 .value
.u64
= UINT64_MAX
,
852 .description
= "int8_sanity1",
857 .description
= "int8_sanity2",
859 .value
.s8
= INT8_MAX
/ 2 + 1,
862 .description
= "int8_min",
864 .value
.s8
= INT8_MIN
,
867 .description
= "int8_max",
869 .value
.s8
= INT8_MAX
,
873 .description
= "int16_sanity1",
878 .description
= "int16_sanity2",
880 .value
.s16
= INT16_MAX
/ 2 + 1,
883 .description
= "int16_min",
885 .value
.s16
= INT16_MIN
,
888 .description
= "int16_max",
890 .value
.s16
= INT16_MAX
,
894 .description
= "int32_sanity1",
899 .description
= "int32_sanity2",
901 .value
.s32
= INT32_MAX
/ 2 + 1,
904 .description
= "int32_min",
906 .value
.s32
= INT32_MIN
,
909 .description
= "int32_max",
911 .value
.s32
= INT32_MAX
,
915 .description
= "int64_sanity1",
920 .description
= "int64_sanity2",
922 .value
.s64
= INT64_MAX
/ 2 + 1,
925 .description
= "int64_min",
927 .value
.s64
= INT64_MIN
,
930 .description
= "int64_max",
932 .value
.s64
= INT64_MAX
,
934 { .type
= PTYPE_EOL
}
937 /* visitor-specific op implementations */
939 typedef struct QmpSerializeData
{
945 static void qmp_serialize(void *native_in
, void **datap
,
946 VisitorFunc visit
, Error
**errp
)
948 QmpSerializeData
*d
= g_malloc0(sizeof(*d
));
950 d
->qov
= qobject_output_visitor_new(&d
->obj
);
951 visit(d
->qov
, &native_in
, errp
);
955 static void qmp_deserialize(void **native_out
, void *datap
,
956 VisitorFunc visit
, Error
**errp
)
958 QmpSerializeData
*d
= datap
;
959 GString
*output_json
;
960 QObject
*obj_orig
, *obj
;
962 visit_complete(d
->qov
, &d
->obj
);
964 output_json
= qobject_to_json(obj_orig
);
965 obj
= qobject_from_json(output_json
->str
, &error_abort
);
967 g_string_free(output_json
, true);
968 d
->qiv
= qobject_input_visitor_new(obj
);
969 qobject_unref(obj_orig
);
971 visit(d
->qiv
, native_out
, errp
);
974 static void qmp_cleanup(void *datap
)
976 QmpSerializeData
*d
= datap
;
983 typedef struct StringSerializeData
{
987 } StringSerializeData
;
989 static void string_serialize(void *native_in
, void **datap
,
990 VisitorFunc visit
, Error
**errp
)
992 StringSerializeData
*d
= g_malloc0(sizeof(*d
));
994 d
->sov
= string_output_visitor_new(false, &d
->string
);
995 visit(d
->sov
, &native_in
, errp
);
999 static void string_deserialize(void **native_out
, void *datap
,
1000 VisitorFunc visit
, Error
**errp
)
1002 StringSerializeData
*d
= datap
;
1004 visit_complete(d
->sov
, &d
->string
);
1005 d
->siv
= string_input_visitor_new(d
->string
);
1006 visit(d
->siv
, native_out
, errp
);
1009 static void string_cleanup(void *datap
)
1011 StringSerializeData
*d
= datap
;
1019 /* visitor registration, test harness */
1021 /* note: to function interchangeably as a serialization mechanism your
1022 * visitor test implementation should pass the test cases for all visitor
1023 * capabilities: primitives, structures, and lists
1025 static const SerializeOps visitors
[] = {
1028 .serialize
= qmp_serialize
,
1029 .deserialize
= qmp_deserialize
,
1030 .cleanup
= qmp_cleanup
,
1031 .caps
= VCAP_PRIMITIVES
| VCAP_STRUCTURES
| VCAP_LISTS
|
1032 VCAP_PRIMITIVE_LISTS
1036 .serialize
= string_serialize
,
1037 .deserialize
= string_deserialize
,
1038 .cleanup
= string_cleanup
,
1039 .caps
= VCAP_PRIMITIVES
1044 static void add_visitor_type(const SerializeOps
*ops
)
1046 char testname_prefix
[32];
1051 sprintf(testname_prefix
, "/visitor/serialization/%s", ops
->type
);
1053 if (ops
->caps
& VCAP_PRIMITIVES
) {
1054 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1055 sprintf(testname
, "%s/primitives/%s", testname_prefix
,
1056 pt_values
[i
].description
);
1057 args
= g_malloc0(sizeof(*args
));
1059 args
->test_data
= &pt_values
[i
];
1060 g_test_add_data_func(testname
, args
, test_primitives
);
1065 if (ops
->caps
& VCAP_STRUCTURES
) {
1066 sprintf(testname
, "%s/struct", testname_prefix
);
1067 args
= g_malloc0(sizeof(*args
));
1069 args
->test_data
= NULL
;
1070 g_test_add_data_func(testname
, args
, test_struct
);
1072 sprintf(testname
, "%s/nested_struct", testname_prefix
);
1073 args
= g_malloc0(sizeof(*args
));
1075 args
->test_data
= NULL
;
1076 g_test_add_data_func(testname
, args
, test_nested_struct
);
1079 if (ops
->caps
& VCAP_LISTS
) {
1080 sprintf(testname
, "%s/nested_struct_list", testname_prefix
);
1081 args
= g_malloc0(sizeof(*args
));
1083 args
->test_data
= NULL
;
1084 g_test_add_data_func(testname
, args
, test_nested_struct_list
);
1087 if (ops
->caps
& VCAP_PRIMITIVE_LISTS
) {
1089 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1090 sprintf(testname
, "%s/primitive_list/%s", testname_prefix
,
1091 pt_values
[i
].description
);
1092 args
= g_malloc0(sizeof(*args
));
1094 args
->test_data
= &pt_values
[i
];
1095 g_test_add_data_func(testname
, args
, test_primitive_lists
);
1101 int main(int argc
, char **argv
)
1105 g_test_init(&argc
, &argv
, NULL
);
1107 while (visitors
[i
].type
!= NULL
) {
1108 add_visitor_type(&visitors
[i
]);