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-types.h"
19 #include "test-qapi-visit.h"
20 #include "qapi/error.h"
21 #include "qapi/qmp/types.h"
22 #include "qapi/qmp/qjson.h"
23 #include "qapi/qobject-input-visitor.h"
24 #include "qapi/qobject-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 Visitor
*v
= qapi_dealloc_visitor_new();
94 visit(v
, &native_in
, errp
);
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
{
1020 static void qmp_serialize(void *native_in
, void **datap
,
1021 VisitorFunc visit
, Error
**errp
)
1023 QmpSerializeData
*d
= g_malloc0(sizeof(*d
));
1025 d
->qov
= qobject_output_visitor_new(&d
->obj
);
1026 visit(d
->qov
, &native_in
, errp
);
1030 static void qmp_deserialize(void **native_out
, void *datap
,
1031 VisitorFunc visit
, Error
**errp
)
1033 QmpSerializeData
*d
= datap
;
1034 QString
*output_json
;
1035 QObject
*obj_orig
, *obj
;
1037 visit_complete(d
->qov
, &d
->obj
);
1039 output_json
= qobject_to_json(obj_orig
);
1040 obj
= qobject_from_json(qstring_get_str(output_json
));
1042 QDECREF(output_json
);
1043 d
->qiv
= qobject_input_visitor_new(obj
, true);
1044 qobject_decref(obj_orig
);
1045 qobject_decref(obj
);
1046 visit(d
->qiv
, native_out
, errp
);
1049 static void qmp_cleanup(void *datap
)
1051 QmpSerializeData
*d
= datap
;
1058 typedef struct StringSerializeData
{
1062 } StringSerializeData
;
1064 static void string_serialize(void *native_in
, void **datap
,
1065 VisitorFunc visit
, Error
**errp
)
1067 StringSerializeData
*d
= g_malloc0(sizeof(*d
));
1069 d
->sov
= string_output_visitor_new(false, &d
->string
);
1070 visit(d
->sov
, &native_in
, errp
);
1074 static void string_deserialize(void **native_out
, void *datap
,
1075 VisitorFunc visit
, Error
**errp
)
1077 StringSerializeData
*d
= datap
;
1079 visit_complete(d
->sov
, &d
->string
);
1080 d
->siv
= string_input_visitor_new(d
->string
);
1081 visit(d
->siv
, native_out
, errp
);
1084 static void string_cleanup(void *datap
)
1086 StringSerializeData
*d
= datap
;
1094 /* visitor registration, test harness */
1096 /* note: to function interchangeably as a serialization mechanism your
1097 * visitor test implementation should pass the test cases for all visitor
1098 * capabilities: primitives, structures, and lists
1100 static const SerializeOps visitors
[] = {
1103 .serialize
= qmp_serialize
,
1104 .deserialize
= qmp_deserialize
,
1105 .cleanup
= qmp_cleanup
,
1106 .caps
= VCAP_PRIMITIVES
| VCAP_STRUCTURES
| VCAP_LISTS
|
1107 VCAP_PRIMITIVE_LISTS
1111 .serialize
= string_serialize
,
1112 .deserialize
= string_deserialize
,
1113 .cleanup
= string_cleanup
,
1114 .caps
= VCAP_PRIMITIVES
1119 static void add_visitor_type(const SerializeOps
*ops
)
1121 char testname_prefix
[128];
1126 sprintf(testname_prefix
, "/visitor/serialization/%s", ops
->type
);
1128 if (ops
->caps
& VCAP_PRIMITIVES
) {
1129 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1130 sprintf(testname
, "%s/primitives/%s", testname_prefix
,
1131 pt_values
[i
].description
);
1132 args
= g_malloc0(sizeof(*args
));
1134 args
->test_data
= &pt_values
[i
];
1135 g_test_add_data_func(testname
, args
, test_primitives
);
1140 if (ops
->caps
& VCAP_STRUCTURES
) {
1141 sprintf(testname
, "%s/struct", testname_prefix
);
1142 args
= g_malloc0(sizeof(*args
));
1144 args
->test_data
= NULL
;
1145 g_test_add_data_func(testname
, args
, test_struct
);
1147 sprintf(testname
, "%s/nested_struct", testname_prefix
);
1148 args
= g_malloc0(sizeof(*args
));
1150 args
->test_data
= NULL
;
1151 g_test_add_data_func(testname
, args
, test_nested_struct
);
1154 if (ops
->caps
& VCAP_LISTS
) {
1155 sprintf(testname
, "%s/nested_struct_list", testname_prefix
);
1156 args
= g_malloc0(sizeof(*args
));
1158 args
->test_data
= NULL
;
1159 g_test_add_data_func(testname
, args
, test_nested_struct_list
);
1162 if (ops
->caps
& VCAP_PRIMITIVE_LISTS
) {
1164 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1165 sprintf(testname
, "%s/primitive_list/%s", testname_prefix
,
1166 pt_values
[i
].description
);
1167 args
= g_malloc0(sizeof(*args
));
1169 args
->test_data
= &pt_values
[i
];
1170 g_test_add_data_func(testname
, args
, test_primitive_lists
);
1176 int main(int argc
, char **argv
)
1180 g_test_init(&argc
, &argv
, NULL
);
1182 while (visitors
[i
].type
!= NULL
) {
1183 add_visitor_type(&visitors
[i
]);