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"
18 #include "qemu-common.h"
19 #include "test-qapi-types.h"
20 #include "test-qapi-visit.h"
21 #include "qapi/qmp/types.h"
22 #include "qapi/qmp-input-visitor.h"
23 #include "qapi/qmp-output-visitor.h"
24 #include "qapi/string-input-visitor.h"
25 #include "qapi/string-output-visitor.h"
26 #include "qapi-types.h"
27 #include "qapi-visit.h"
28 #include "qapi/dealloc-visitor.h"
30 enum PrimitiveTypeKind
{
46 typedef struct PrimitiveType
{
62 enum PrimitiveTypeKind type
;
63 const char *description
;
66 typedef struct PrimitiveList
{
72 int8List
*s8_integers
;
73 int16List
*s16_integers
;
74 int32List
*s32_integers
;
75 int64List
*s64_integers
;
76 uint8List
*u8_integers
;
77 uint16List
*u16_integers
;
78 uint32List
*u32_integers
;
79 uint64List
*u64_integers
;
81 enum PrimitiveTypeKind type
;
82 const char *description
;
87 typedef void (*VisitorFunc
)(Visitor
*v
, void **native
, Error
**errp
);
89 static void dealloc_helper(void *native_in
, VisitorFunc visit
, Error
**errp
)
91 QapiDeallocVisitor
*qdv
= qapi_dealloc_visitor_new();
93 visit(qapi_dealloc_get_visitor(qdv
), &native_in
, errp
);
95 qapi_dealloc_visitor_cleanup(qdv
);
98 static void visit_primitive_type(Visitor
*v
, void **native
, Error
**errp
)
100 PrimitiveType
*pt
= *native
;
103 visit_type_str(v
, NULL
, (char **)&pt
->value
.string
, errp
);
106 visit_type_bool(v
, NULL
, &pt
->value
.boolean
, errp
);
109 visit_type_number(v
, NULL
, &pt
->value
.number
, errp
);
112 visit_type_int(v
, NULL
, &pt
->value
.integer
, errp
);
115 visit_type_uint8(v
, NULL
, &pt
->value
.u8
, errp
);
118 visit_type_uint16(v
, NULL
, &pt
->value
.u16
, errp
);
121 visit_type_uint32(v
, NULL
, &pt
->value
.u32
, errp
);
124 visit_type_uint64(v
, NULL
, &pt
->value
.u64
, errp
);
127 visit_type_int8(v
, NULL
, &pt
->value
.s8
, errp
);
130 visit_type_int16(v
, NULL
, &pt
->value
.s16
, errp
);
133 visit_type_int32(v
, NULL
, &pt
->value
.s32
, errp
);
136 visit_type_int64(v
, NULL
, &pt
->value
.s64
, errp
);
139 g_assert_not_reached();
143 static void visit_primitive_list(Visitor
*v
, void **native
, Error
**errp
)
145 PrimitiveList
*pl
= *native
;
148 visit_type_strList(v
, NULL
, &pl
->value
.strings
, errp
);
151 visit_type_boolList(v
, NULL
, &pl
->value
.booleans
, errp
);
154 visit_type_numberList(v
, NULL
, &pl
->value
.numbers
, errp
);
157 visit_type_intList(v
, NULL
, &pl
->value
.integers
, errp
);
160 visit_type_int8List(v
, NULL
, &pl
->value
.s8_integers
, errp
);
163 visit_type_int16List(v
, NULL
, &pl
->value
.s16_integers
, errp
);
166 visit_type_int32List(v
, NULL
, &pl
->value
.s32_integers
, errp
);
169 visit_type_int64List(v
, NULL
, &pl
->value
.s64_integers
, errp
);
172 visit_type_uint8List(v
, NULL
, &pl
->value
.u8_integers
, errp
);
175 visit_type_uint16List(v
, NULL
, &pl
->value
.u16_integers
, errp
);
178 visit_type_uint32List(v
, NULL
, &pl
->value
.u32_integers
, errp
);
181 visit_type_uint64List(v
, NULL
, &pl
->value
.u64_integers
, errp
);
184 g_assert_not_reached();
189 static TestStruct
*struct_create(void)
191 TestStruct
*ts
= g_malloc0(sizeof(*ts
));
194 ts
->string
= strdup("test string");
198 static void struct_compare(TestStruct
*ts1
, TestStruct
*ts2
)
202 g_assert_cmpint(ts1
->integer
, ==, ts2
->integer
);
203 g_assert(ts1
->boolean
== ts2
->boolean
);
204 g_assert_cmpstr(ts1
->string
, ==, ts2
->string
);
207 static void struct_cleanup(TestStruct
*ts
)
213 static void visit_struct(Visitor
*v
, void **native
, Error
**errp
)
215 visit_type_TestStruct(v
, NULL
, (TestStruct
**)native
, errp
);
218 static UserDefTwo
*nested_struct_create(void)
220 UserDefTwo
*udnp
= g_malloc0(sizeof(*udnp
));
221 udnp
->string0
= strdup("test_string0");
222 udnp
->dict1
= g_malloc0(sizeof(*udnp
->dict1
));
223 udnp
->dict1
->string1
= strdup("test_string1");
224 udnp
->dict1
->dict2
= g_malloc0(sizeof(*udnp
->dict1
->dict2
));
225 udnp
->dict1
->dict2
->userdef
= g_new0(UserDefOne
, 1);
226 udnp
->dict1
->dict2
->userdef
->integer
= 42;
227 udnp
->dict1
->dict2
->userdef
->string
= strdup("test_string");
228 udnp
->dict1
->dict2
->string
= strdup("test_string2");
229 udnp
->dict1
->dict3
= g_malloc0(sizeof(*udnp
->dict1
->dict3
));
230 udnp
->dict1
->has_dict3
= true;
231 udnp
->dict1
->dict3
->userdef
= g_new0(UserDefOne
, 1);
232 udnp
->dict1
->dict3
->userdef
->integer
= 43;
233 udnp
->dict1
->dict3
->userdef
->string
= strdup("test_string");
234 udnp
->dict1
->dict3
->string
= strdup("test_string3");
238 static void nested_struct_compare(UserDefTwo
*udnp1
, UserDefTwo
*udnp2
)
242 g_assert_cmpstr(udnp1
->string0
, ==, udnp2
->string0
);
243 g_assert_cmpstr(udnp1
->dict1
->string1
, ==, udnp2
->dict1
->string1
);
244 g_assert_cmpint(udnp1
->dict1
->dict2
->userdef
->integer
, ==,
245 udnp2
->dict1
->dict2
->userdef
->integer
);
246 g_assert_cmpstr(udnp1
->dict1
->dict2
->userdef
->string
, ==,
247 udnp2
->dict1
->dict2
->userdef
->string
);
248 g_assert_cmpstr(udnp1
->dict1
->dict2
->string
, ==,
249 udnp2
->dict1
->dict2
->string
);
250 g_assert(udnp1
->dict1
->has_dict3
== udnp2
->dict1
->has_dict3
);
251 g_assert_cmpint(udnp1
->dict1
->dict3
->userdef
->integer
, ==,
252 udnp2
->dict1
->dict3
->userdef
->integer
);
253 g_assert_cmpstr(udnp1
->dict1
->dict3
->userdef
->string
, ==,
254 udnp2
->dict1
->dict3
->userdef
->string
);
255 g_assert_cmpstr(udnp1
->dict1
->dict3
->string
, ==,
256 udnp2
->dict1
->dict3
->string
);
259 static void nested_struct_cleanup(UserDefTwo
*udnp
)
261 qapi_free_UserDefTwo(udnp
);
264 static void visit_nested_struct(Visitor
*v
, void **native
, Error
**errp
)
266 visit_type_UserDefTwo(v
, NULL
, (UserDefTwo
**)native
, errp
);
269 static void visit_nested_struct_list(Visitor
*v
, void **native
, Error
**errp
)
271 visit_type_UserDefTwoList(v
, NULL
, (UserDefTwoList
**)native
, errp
);
276 typedef enum VisitorCapabilities
{
280 VCAP_PRIMITIVE_LISTS
= 8,
281 } VisitorCapabilities
;
283 typedef struct SerializeOps
{
284 void (*serialize
)(void *native_in
, void **datap
,
285 VisitorFunc visit
, Error
**errp
);
286 void (*deserialize
)(void **native_out
, void *datap
,
287 VisitorFunc visit
, Error
**errp
);
288 void (*cleanup
)(void *datap
);
290 VisitorCapabilities caps
;
293 typedef struct TestArgs
{
294 const SerializeOps
*ops
;
298 static void test_primitives(gconstpointer opaque
)
300 TestArgs
*args
= (TestArgs
*) opaque
;
301 const SerializeOps
*ops
= args
->ops
;
302 PrimitiveType
*pt
= args
->test_data
;
303 PrimitiveType
*pt_copy
= g_malloc0(sizeof(*pt_copy
));
304 void *serialize_data
;
306 pt_copy
->type
= pt
->type
;
307 ops
->serialize(pt
, &serialize_data
, visit_primitive_type
, &error_abort
);
308 ops
->deserialize((void **)&pt_copy
, serialize_data
, visit_primitive_type
,
311 g_assert(pt_copy
!= NULL
);
312 if (pt
->type
== PTYPE_STRING
) {
313 g_assert_cmpstr(pt
->value
.string
, ==, pt_copy
->value
.string
);
314 g_free((char *)pt_copy
->value
.string
);
315 } else if (pt
->type
== PTYPE_NUMBER
) {
316 GString
*double_expected
= g_string_new("");
317 GString
*double_actual
= g_string_new("");
318 /* we serialize with %f for our reference visitors, so rather than fuzzy
319 * floating math to test "equality", just compare the formatted values
321 g_string_printf(double_expected
, "%.6f", pt
->value
.number
);
322 g_string_printf(double_actual
, "%.6f", pt_copy
->value
.number
);
323 g_assert_cmpstr(double_actual
->str
, ==, double_expected
->str
);
325 g_string_free(double_expected
, true);
326 g_string_free(double_actual
, true);
327 } else if (pt
->type
== PTYPE_BOOLEAN
) {
328 g_assert_cmpint(!!pt
->value
.max
, ==, !!pt
->value
.max
);
330 g_assert_cmpint(pt
->value
.max
, ==, pt_copy
->value
.max
);
333 ops
->cleanup(serialize_data
);
338 static void test_primitive_lists(gconstpointer opaque
)
340 TestArgs
*args
= (TestArgs
*) opaque
;
341 const SerializeOps
*ops
= args
->ops
;
342 PrimitiveType
*pt
= args
->test_data
;
343 PrimitiveList pl
= { .value
= { NULL
} };
344 PrimitiveList pl_copy
= { .value
= { NULL
} };
345 PrimitiveList
*pl_copy_ptr
= &pl_copy
;
346 void *serialize_data
;
347 void *cur_head
= NULL
;
350 pl
.type
= pl_copy
.type
= pt
->type
;
352 /* build up our list of primitive types */
353 for (i
= 0; i
< 32; i
++) {
356 strList
*tmp
= g_new0(strList
, 1);
357 tmp
->value
= g_strdup(pt
->value
.string
);
358 if (pl
.value
.strings
== NULL
) {
359 pl
.value
.strings
= tmp
;
361 tmp
->next
= pl
.value
.strings
;
362 pl
.value
.strings
= tmp
;
366 case PTYPE_INTEGER
: {
367 intList
*tmp
= g_new0(intList
, 1);
368 tmp
->value
= pt
->value
.integer
;
369 if (pl
.value
.integers
== NULL
) {
370 pl
.value
.integers
= tmp
;
372 tmp
->next
= pl
.value
.integers
;
373 pl
.value
.integers
= tmp
;
378 int8List
*tmp
= g_new0(int8List
, 1);
379 tmp
->value
= pt
->value
.s8
;
380 if (pl
.value
.s8_integers
== NULL
) {
381 pl
.value
.s8_integers
= tmp
;
383 tmp
->next
= pl
.value
.s8_integers
;
384 pl
.value
.s8_integers
= tmp
;
389 int16List
*tmp
= g_new0(int16List
, 1);
390 tmp
->value
= pt
->value
.s16
;
391 if (pl
.value
.s16_integers
== NULL
) {
392 pl
.value
.s16_integers
= tmp
;
394 tmp
->next
= pl
.value
.s16_integers
;
395 pl
.value
.s16_integers
= tmp
;
400 int32List
*tmp
= g_new0(int32List
, 1);
401 tmp
->value
= pt
->value
.s32
;
402 if (pl
.value
.s32_integers
== NULL
) {
403 pl
.value
.s32_integers
= tmp
;
405 tmp
->next
= pl
.value
.s32_integers
;
406 pl
.value
.s32_integers
= tmp
;
411 int64List
*tmp
= g_new0(int64List
, 1);
412 tmp
->value
= pt
->value
.s64
;
413 if (pl
.value
.s64_integers
== NULL
) {
414 pl
.value
.s64_integers
= tmp
;
416 tmp
->next
= pl
.value
.s64_integers
;
417 pl
.value
.s64_integers
= tmp
;
422 uint8List
*tmp
= g_new0(uint8List
, 1);
423 tmp
->value
= pt
->value
.u8
;
424 if (pl
.value
.u8_integers
== NULL
) {
425 pl
.value
.u8_integers
= tmp
;
427 tmp
->next
= pl
.value
.u8_integers
;
428 pl
.value
.u8_integers
= tmp
;
433 uint16List
*tmp
= g_new0(uint16List
, 1);
434 tmp
->value
= pt
->value
.u16
;
435 if (pl
.value
.u16_integers
== NULL
) {
436 pl
.value
.u16_integers
= tmp
;
438 tmp
->next
= pl
.value
.u16_integers
;
439 pl
.value
.u16_integers
= tmp
;
444 uint32List
*tmp
= g_new0(uint32List
, 1);
445 tmp
->value
= pt
->value
.u32
;
446 if (pl
.value
.u32_integers
== NULL
) {
447 pl
.value
.u32_integers
= tmp
;
449 tmp
->next
= pl
.value
.u32_integers
;
450 pl
.value
.u32_integers
= tmp
;
455 uint64List
*tmp
= g_new0(uint64List
, 1);
456 tmp
->value
= pt
->value
.u64
;
457 if (pl
.value
.u64_integers
== NULL
) {
458 pl
.value
.u64_integers
= tmp
;
460 tmp
->next
= pl
.value
.u64_integers
;
461 pl
.value
.u64_integers
= tmp
;
466 numberList
*tmp
= g_new0(numberList
, 1);
467 tmp
->value
= pt
->value
.number
;
468 if (pl
.value
.numbers
== NULL
) {
469 pl
.value
.numbers
= tmp
;
471 tmp
->next
= pl
.value
.numbers
;
472 pl
.value
.numbers
= tmp
;
476 case PTYPE_BOOLEAN
: {
477 boolList
*tmp
= g_new0(boolList
, 1);
478 tmp
->value
= pt
->value
.boolean
;
479 if (pl
.value
.booleans
== NULL
) {
480 pl
.value
.booleans
= tmp
;
482 tmp
->next
= pl
.value
.booleans
;
483 pl
.value
.booleans
= tmp
;
488 g_assert_not_reached();
492 ops
->serialize((void **)&pl
, &serialize_data
, visit_primitive_list
,
494 ops
->deserialize((void **)&pl_copy_ptr
, serialize_data
,
495 visit_primitive_list
, &error_abort
);
499 /* compare our deserialized list of primitives to the original */
501 switch (pl_copy
.type
) {
506 cur_head
= ptr
->next
;
508 cur_head
= ptr
= pl_copy
.value
.strings
;
510 g_assert_cmpstr(pt
->value
.string
, ==, ptr
->value
);
513 case PTYPE_INTEGER
: {
517 cur_head
= ptr
->next
;
519 cur_head
= ptr
= pl_copy
.value
.integers
;
521 g_assert_cmpint(pt
->value
.integer
, ==, ptr
->value
);
528 cur_head
= ptr
->next
;
530 cur_head
= ptr
= pl_copy
.value
.s8_integers
;
532 g_assert_cmpint(pt
->value
.s8
, ==, ptr
->value
);
539 cur_head
= ptr
->next
;
541 cur_head
= ptr
= pl_copy
.value
.s16_integers
;
543 g_assert_cmpint(pt
->value
.s16
, ==, ptr
->value
);
550 cur_head
= ptr
->next
;
552 cur_head
= ptr
= pl_copy
.value
.s32_integers
;
554 g_assert_cmpint(pt
->value
.s32
, ==, ptr
->value
);
561 cur_head
= ptr
->next
;
563 cur_head
= ptr
= pl_copy
.value
.s64_integers
;
565 g_assert_cmpint(pt
->value
.s64
, ==, ptr
->value
);
572 cur_head
= ptr
->next
;
574 cur_head
= ptr
= pl_copy
.value
.u8_integers
;
576 g_assert_cmpint(pt
->value
.u8
, ==, ptr
->value
);
583 cur_head
= ptr
->next
;
585 cur_head
= ptr
= pl_copy
.value
.u16_integers
;
587 g_assert_cmpint(pt
->value
.u16
, ==, ptr
->value
);
594 cur_head
= ptr
->next
;
596 cur_head
= ptr
= pl_copy
.value
.u32_integers
;
598 g_assert_cmpint(pt
->value
.u32
, ==, ptr
->value
);
605 cur_head
= ptr
->next
;
607 cur_head
= ptr
= pl_copy
.value
.u64_integers
;
609 g_assert_cmpint(pt
->value
.u64
, ==, ptr
->value
);
614 GString
*double_expected
= g_string_new("");
615 GString
*double_actual
= g_string_new("");
618 cur_head
= ptr
->next
;
620 cur_head
= ptr
= pl_copy
.value
.numbers
;
622 /* we serialize with %f for our reference visitors, so rather than
623 * fuzzy floating math to test "equality", just compare the
626 g_string_printf(double_expected
, "%.6f", pt
->value
.number
);
627 g_string_printf(double_actual
, "%.6f", ptr
->value
);
628 g_assert_cmpstr(double_actual
->str
, ==, double_expected
->str
);
629 g_string_free(double_expected
, true);
630 g_string_free(double_actual
, true);
633 case PTYPE_BOOLEAN
: {
637 cur_head
= ptr
->next
;
639 cur_head
= ptr
= pl_copy
.value
.booleans
;
641 g_assert_cmpint(!!pt
->value
.boolean
, ==, !!ptr
->value
);
645 g_assert_not_reached();
650 g_assert_cmpint(i
, ==, 33);
652 ops
->cleanup(serialize_data
);
653 dealloc_helper(&pl
, visit_primitive_list
, &error_abort
);
654 dealloc_helper(&pl_copy
, visit_primitive_list
, &error_abort
);
658 static void test_struct(gconstpointer opaque
)
660 TestArgs
*args
= (TestArgs
*) opaque
;
661 const SerializeOps
*ops
= args
->ops
;
662 TestStruct
*ts
= struct_create();
663 TestStruct
*ts_copy
= NULL
;
664 void *serialize_data
;
666 ops
->serialize(ts
, &serialize_data
, visit_struct
, &error_abort
);
667 ops
->deserialize((void **)&ts_copy
, serialize_data
, visit_struct
,
670 struct_compare(ts
, ts_copy
);
673 struct_cleanup(ts_copy
);
675 ops
->cleanup(serialize_data
);
679 static void test_nested_struct(gconstpointer opaque
)
681 TestArgs
*args
= (TestArgs
*) opaque
;
682 const SerializeOps
*ops
= args
->ops
;
683 UserDefTwo
*udnp
= nested_struct_create();
684 UserDefTwo
*udnp_copy
= NULL
;
685 void *serialize_data
;
687 ops
->serialize(udnp
, &serialize_data
, visit_nested_struct
, &error_abort
);
688 ops
->deserialize((void **)&udnp_copy
, serialize_data
, visit_nested_struct
,
691 nested_struct_compare(udnp
, udnp_copy
);
693 nested_struct_cleanup(udnp
);
694 nested_struct_cleanup(udnp_copy
);
696 ops
->cleanup(serialize_data
);
700 static void test_nested_struct_list(gconstpointer opaque
)
702 TestArgs
*args
= (TestArgs
*) opaque
;
703 const SerializeOps
*ops
= args
->ops
;
704 UserDefTwoList
*listp
= NULL
, *tmp
, *tmp_copy
, *listp_copy
= NULL
;
705 void *serialize_data
;
708 for (i
= 0; i
< 8; i
++) {
709 tmp
= g_new0(UserDefTwoList
, 1);
710 tmp
->value
= nested_struct_create();
715 ops
->serialize(listp
, &serialize_data
, visit_nested_struct_list
,
717 ops
->deserialize((void **)&listp_copy
, serialize_data
,
718 visit_nested_struct_list
, &error_abort
);
721 tmp_copy
= listp_copy
;
724 nested_struct_compare(listp
->value
, listp_copy
->value
);
726 listp_copy
= listp_copy
->next
;
729 qapi_free_UserDefTwoList(tmp
);
730 qapi_free_UserDefTwoList(tmp_copy
);
732 ops
->cleanup(serialize_data
);
736 static PrimitiveType pt_values
[] = {
739 .description
= "string_empty",
740 .type
= PTYPE_STRING
,
744 .description
= "string_whitespace",
745 .type
= PTYPE_STRING
,
746 .value
.string
= "a b c\td",
749 .description
= "string_newlines",
750 .type
= PTYPE_STRING
,
751 .value
.string
= "a\nb\n",
754 .description
= "string_commas",
755 .type
= PTYPE_STRING
,
756 .value
.string
= "a,b, c,d",
759 .description
= "string_single_quoted",
760 .type
= PTYPE_STRING
,
761 .value
.string
= "'a b',cd",
764 .description
= "string_double_quoted",
765 .type
= PTYPE_STRING
,
766 .value
.string
= "\"a b\",cd",
770 .description
= "boolean_true1",
771 .type
= PTYPE_BOOLEAN
,
772 .value
.boolean
= true,
775 .description
= "boolean_true2",
776 .type
= PTYPE_BOOLEAN
,
780 .description
= "boolean_true3",
781 .type
= PTYPE_BOOLEAN
,
785 .description
= "boolean_false1",
786 .type
= PTYPE_BOOLEAN
,
787 .value
.boolean
= false,
790 .description
= "boolean_false2",
791 .type
= PTYPE_BOOLEAN
,
794 /* number tests (double) */
795 /* note: we format these to %.6f before comparing, since that's how
796 * we serialize them and it doesn't make sense to check precision
800 .description
= "number_sanity1",
801 .type
= PTYPE_NUMBER
,
805 .description
= "number_sanity2",
806 .type
= PTYPE_NUMBER
,
807 .value
.number
= 3.14159265,
810 .description
= "number_min",
811 .type
= PTYPE_NUMBER
,
812 .value
.number
= DBL_MIN
,
815 .description
= "number_max",
816 .type
= PTYPE_NUMBER
,
817 .value
.number
= DBL_MAX
,
819 /* integer tests (int64) */
821 .description
= "integer_sanity1",
822 .type
= PTYPE_INTEGER
,
826 .description
= "integer_sanity2",
827 .type
= PTYPE_INTEGER
,
828 .value
.integer
= INT64_MAX
/ 2 + 1,
831 .description
= "integer_min",
832 .type
= PTYPE_INTEGER
,
833 .value
.integer
= INT64_MIN
,
836 .description
= "integer_max",
837 .type
= PTYPE_INTEGER
,
838 .value
.integer
= INT64_MAX
,
842 .description
= "uint8_sanity1",
847 .description
= "uint8_sanity2",
849 .value
.u8
= UINT8_MAX
/ 2 + 1,
852 .description
= "uint8_min",
857 .description
= "uint8_max",
859 .value
.u8
= UINT8_MAX
,
863 .description
= "uint16_sanity1",
868 .description
= "uint16_sanity2",
870 .value
.u16
= UINT16_MAX
/ 2 + 1,
873 .description
= "uint16_min",
878 .description
= "uint16_max",
880 .value
.u16
= UINT16_MAX
,
884 .description
= "uint32_sanity1",
889 .description
= "uint32_sanity2",
891 .value
.u32
= UINT32_MAX
/ 2 + 1,
894 .description
= "uint32_min",
899 .description
= "uint32_max",
901 .value
.u32
= UINT32_MAX
,
905 .description
= "uint64_sanity1",
910 .description
= "uint64_sanity2",
912 .value
.u64
= UINT64_MAX
/ 2 + 1,
915 .description
= "uint64_min",
920 .description
= "uint64_max",
922 .value
.u64
= UINT64_MAX
,
926 .description
= "int8_sanity1",
931 .description
= "int8_sanity2",
933 .value
.s8
= INT8_MAX
/ 2 + 1,
936 .description
= "int8_min",
938 .value
.s8
= INT8_MIN
,
941 .description
= "int8_max",
943 .value
.s8
= INT8_MAX
,
947 .description
= "int16_sanity1",
952 .description
= "int16_sanity2",
954 .value
.s16
= INT16_MAX
/ 2 + 1,
957 .description
= "int16_min",
959 .value
.s16
= INT16_MIN
,
962 .description
= "int16_max",
964 .value
.s16
= INT16_MAX
,
968 .description
= "int32_sanity1",
973 .description
= "int32_sanity2",
975 .value
.s32
= INT32_MAX
/ 2 + 1,
978 .description
= "int32_min",
980 .value
.s32
= INT32_MIN
,
983 .description
= "int32_max",
985 .value
.s32
= INT32_MAX
,
989 .description
= "int64_sanity1",
994 .description
= "int64_sanity2",
996 .value
.s64
= INT64_MAX
/ 2 + 1,
999 .description
= "int64_min",
1001 .value
.s64
= INT64_MIN
,
1004 .description
= "int64_max",
1006 .value
.s64
= INT64_MAX
,
1008 { .type
= PTYPE_EOL
}
1011 /* visitor-specific op implementations */
1013 typedef struct QmpSerializeData
{
1014 QmpOutputVisitor
*qov
;
1015 QmpInputVisitor
*qiv
;
1018 static void qmp_serialize(void *native_in
, void **datap
,
1019 VisitorFunc visit
, Error
**errp
)
1021 QmpSerializeData
*d
= g_malloc0(sizeof(*d
));
1023 d
->qov
= qmp_output_visitor_new();
1024 visit(qmp_output_get_visitor(d
->qov
), &native_in
, errp
);
1028 static void qmp_deserialize(void **native_out
, void *datap
,
1029 VisitorFunc visit
, Error
**errp
)
1031 QmpSerializeData
*d
= datap
;
1032 QString
*output_json
;
1033 QObject
*obj_orig
, *obj
;
1035 obj_orig
= qmp_output_get_qobject(d
->qov
);
1036 output_json
= qobject_to_json(obj_orig
);
1037 obj
= qobject_from_json(qstring_get_str(output_json
));
1039 QDECREF(output_json
);
1040 d
->qiv
= qmp_input_visitor_new(obj
);
1041 qobject_decref(obj_orig
);
1042 qobject_decref(obj
);
1043 visit(qmp_input_get_visitor(d
->qiv
), native_out
, errp
);
1046 static void qmp_cleanup(void *datap
)
1048 QmpSerializeData
*d
= datap
;
1049 qmp_output_visitor_cleanup(d
->qov
);
1050 qmp_input_visitor_cleanup(d
->qiv
);
1055 typedef struct StringSerializeData
{
1057 StringOutputVisitor
*sov
;
1058 StringInputVisitor
*siv
;
1059 } StringSerializeData
;
1061 static void string_serialize(void *native_in
, void **datap
,
1062 VisitorFunc visit
, Error
**errp
)
1064 StringSerializeData
*d
= g_malloc0(sizeof(*d
));
1066 d
->sov
= string_output_visitor_new(false);
1067 visit(string_output_get_visitor(d
->sov
), &native_in
, errp
);
1071 static void string_deserialize(void **native_out
, void *datap
,
1072 VisitorFunc visit
, Error
**errp
)
1074 StringSerializeData
*d
= datap
;
1076 d
->string
= string_output_get_string(d
->sov
);
1077 d
->siv
= string_input_visitor_new(d
->string
);
1078 visit(string_input_get_visitor(d
->siv
), native_out
, errp
);
1081 static void string_cleanup(void *datap
)
1083 StringSerializeData
*d
= datap
;
1085 string_output_visitor_cleanup(d
->sov
);
1086 string_input_visitor_cleanup(d
->siv
);
1091 /* visitor registration, test harness */
1093 /* note: to function interchangeably as a serialization mechanism your
1094 * visitor test implementation should pass the test cases for all visitor
1095 * capabilities: primitives, structures, and lists
1097 static const SerializeOps visitors
[] = {
1100 .serialize
= qmp_serialize
,
1101 .deserialize
= qmp_deserialize
,
1102 .cleanup
= qmp_cleanup
,
1103 .caps
= VCAP_PRIMITIVES
| VCAP_STRUCTURES
| VCAP_LISTS
|
1104 VCAP_PRIMITIVE_LISTS
1108 .serialize
= string_serialize
,
1109 .deserialize
= string_deserialize
,
1110 .cleanup
= string_cleanup
,
1111 .caps
= VCAP_PRIMITIVES
1116 static void add_visitor_type(const SerializeOps
*ops
)
1118 char testname_prefix
[128];
1123 sprintf(testname_prefix
, "/visitor/serialization/%s", ops
->type
);
1125 if (ops
->caps
& VCAP_PRIMITIVES
) {
1126 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1127 sprintf(testname
, "%s/primitives/%s", testname_prefix
,
1128 pt_values
[i
].description
);
1129 args
= g_malloc0(sizeof(*args
));
1131 args
->test_data
= &pt_values
[i
];
1132 g_test_add_data_func(testname
, args
, test_primitives
);
1137 if (ops
->caps
& VCAP_STRUCTURES
) {
1138 sprintf(testname
, "%s/struct", testname_prefix
);
1139 args
= g_malloc0(sizeof(*args
));
1141 args
->test_data
= NULL
;
1142 g_test_add_data_func(testname
, args
, test_struct
);
1144 sprintf(testname
, "%s/nested_struct", testname_prefix
);
1145 args
= g_malloc0(sizeof(*args
));
1147 args
->test_data
= NULL
;
1148 g_test_add_data_func(testname
, args
, test_nested_struct
);
1151 if (ops
->caps
& VCAP_LISTS
) {
1152 sprintf(testname
, "%s/nested_struct_list", testname_prefix
);
1153 args
= g_malloc0(sizeof(*args
));
1155 args
->test_data
= NULL
;
1156 g_test_add_data_func(testname
, args
, test_nested_struct_list
);
1159 if (ops
->caps
& VCAP_PRIMITIVE_LISTS
) {
1161 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1162 sprintf(testname
, "%s/primitive_list/%s", testname_prefix
,
1163 pt_values
[i
].description
);
1164 args
= g_malloc0(sizeof(*args
));
1166 args
->test_data
= &pt_values
[i
];
1167 g_test_add_data_func(testname
, args
, test_primitive_lists
);
1173 int main(int argc
, char **argv
)
1177 g_test_init(&argc
, &argv
, NULL
);
1179 while (visitors
[i
].type
!= NULL
) {
1180 add_visitor_type(&visitors
[i
]);