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-visit.h"
27 #include "qapi/dealloc-visitor.h"
29 enum PrimitiveTypeKind
{
45 typedef struct PrimitiveType
{
61 enum PrimitiveTypeKind type
;
62 const char *description
;
65 typedef struct PrimitiveList
{
71 int8List
*s8_integers
;
72 int16List
*s16_integers
;
73 int32List
*s32_integers
;
74 int64List
*s64_integers
;
75 uint8List
*u8_integers
;
76 uint16List
*u16_integers
;
77 uint32List
*u32_integers
;
78 uint64List
*u64_integers
;
80 enum PrimitiveTypeKind type
;
81 const char *description
;
86 typedef void (*VisitorFunc
)(Visitor
*v
, void **native
, Error
**errp
);
88 static void dealloc_helper(void *native_in
, VisitorFunc visit
, Error
**errp
)
90 Visitor
*v
= qapi_dealloc_visitor_new();
92 visit(v
, &native_in
, errp
);
97 static void visit_primitive_type(Visitor
*v
, void **native
, Error
**errp
)
99 PrimitiveType
*pt
= *native
;
102 visit_type_str(v
, NULL
, (char **)&pt
->value
.string
, errp
);
105 visit_type_bool(v
, NULL
, &pt
->value
.boolean
, errp
);
108 visit_type_number(v
, NULL
, &pt
->value
.number
, errp
);
111 visit_type_int(v
, NULL
, &pt
->value
.integer
, errp
);
114 visit_type_uint8(v
, NULL
, &pt
->value
.u8
, errp
);
117 visit_type_uint16(v
, NULL
, &pt
->value
.u16
, errp
);
120 visit_type_uint32(v
, NULL
, &pt
->value
.u32
, errp
);
123 visit_type_uint64(v
, NULL
, &pt
->value
.u64
, errp
);
126 visit_type_int8(v
, NULL
, &pt
->value
.s8
, errp
);
129 visit_type_int16(v
, NULL
, &pt
->value
.s16
, errp
);
132 visit_type_int32(v
, NULL
, &pt
->value
.s32
, errp
);
135 visit_type_int64(v
, NULL
, &pt
->value
.s64
, errp
);
138 g_assert_not_reached();
142 static void visit_primitive_list(Visitor
*v
, void **native
, Error
**errp
)
144 PrimitiveList
*pl
= *native
;
147 visit_type_strList(v
, NULL
, &pl
->value
.strings
, errp
);
150 visit_type_boolList(v
, NULL
, &pl
->value
.booleans
, errp
);
153 visit_type_numberList(v
, NULL
, &pl
->value
.numbers
, errp
);
156 visit_type_intList(v
, NULL
, &pl
->value
.integers
, errp
);
159 visit_type_int8List(v
, NULL
, &pl
->value
.s8_integers
, errp
);
162 visit_type_int16List(v
, NULL
, &pl
->value
.s16_integers
, errp
);
165 visit_type_int32List(v
, NULL
, &pl
->value
.s32_integers
, errp
);
168 visit_type_int64List(v
, NULL
, &pl
->value
.s64_integers
, errp
);
171 visit_type_uint8List(v
, NULL
, &pl
->value
.u8_integers
, errp
);
174 visit_type_uint16List(v
, NULL
, &pl
->value
.u16_integers
, errp
);
177 visit_type_uint32List(v
, NULL
, &pl
->value
.u32_integers
, errp
);
180 visit_type_uint64List(v
, NULL
, &pl
->value
.u64_integers
, errp
);
183 g_assert_not_reached();
188 static TestStruct
*struct_create(void)
190 TestStruct
*ts
= g_malloc0(sizeof(*ts
));
193 ts
->string
= strdup("test string");
197 static void struct_compare(TestStruct
*ts1
, TestStruct
*ts2
)
201 g_assert_cmpint(ts1
->integer
, ==, ts2
->integer
);
202 g_assert(ts1
->boolean
== ts2
->boolean
);
203 g_assert_cmpstr(ts1
->string
, ==, ts2
->string
);
206 static void struct_cleanup(TestStruct
*ts
)
212 static void visit_struct(Visitor
*v
, void **native
, Error
**errp
)
214 visit_type_TestStruct(v
, NULL
, (TestStruct
**)native
, errp
);
217 static UserDefTwo
*nested_struct_create(void)
219 UserDefTwo
*udnp
= g_malloc0(sizeof(*udnp
));
220 udnp
->string0
= strdup("test_string0");
221 udnp
->dict1
= g_malloc0(sizeof(*udnp
->dict1
));
222 udnp
->dict1
->string1
= strdup("test_string1");
223 udnp
->dict1
->dict2
= g_malloc0(sizeof(*udnp
->dict1
->dict2
));
224 udnp
->dict1
->dict2
->userdef
= g_new0(UserDefOne
, 1);
225 udnp
->dict1
->dict2
->userdef
->integer
= 42;
226 udnp
->dict1
->dict2
->userdef
->string
= strdup("test_string");
227 udnp
->dict1
->dict2
->string
= strdup("test_string2");
228 udnp
->dict1
->dict3
= g_malloc0(sizeof(*udnp
->dict1
->dict3
));
229 udnp
->dict1
->has_dict3
= true;
230 udnp
->dict1
->dict3
->userdef
= g_new0(UserDefOne
, 1);
231 udnp
->dict1
->dict3
->userdef
->integer
= 43;
232 udnp
->dict1
->dict3
->userdef
->string
= strdup("test_string");
233 udnp
->dict1
->dict3
->string
= strdup("test_string3");
237 static void nested_struct_compare(UserDefTwo
*udnp1
, UserDefTwo
*udnp2
)
241 g_assert_cmpstr(udnp1
->string0
, ==, udnp2
->string0
);
242 g_assert_cmpstr(udnp1
->dict1
->string1
, ==, udnp2
->dict1
->string1
);
243 g_assert_cmpint(udnp1
->dict1
->dict2
->userdef
->integer
, ==,
244 udnp2
->dict1
->dict2
->userdef
->integer
);
245 g_assert_cmpstr(udnp1
->dict1
->dict2
->userdef
->string
, ==,
246 udnp2
->dict1
->dict2
->userdef
->string
);
247 g_assert_cmpstr(udnp1
->dict1
->dict2
->string
, ==,
248 udnp2
->dict1
->dict2
->string
);
249 g_assert(udnp1
->dict1
->has_dict3
== udnp2
->dict1
->has_dict3
);
250 g_assert_cmpint(udnp1
->dict1
->dict3
->userdef
->integer
, ==,
251 udnp2
->dict1
->dict3
->userdef
->integer
);
252 g_assert_cmpstr(udnp1
->dict1
->dict3
->userdef
->string
, ==,
253 udnp2
->dict1
->dict3
->userdef
->string
);
254 g_assert_cmpstr(udnp1
->dict1
->dict3
->string
, ==,
255 udnp2
->dict1
->dict3
->string
);
258 static void nested_struct_cleanup(UserDefTwo
*udnp
)
260 qapi_free_UserDefTwo(udnp
);
263 static void visit_nested_struct(Visitor
*v
, void **native
, Error
**errp
)
265 visit_type_UserDefTwo(v
, NULL
, (UserDefTwo
**)native
, errp
);
268 static void visit_nested_struct_list(Visitor
*v
, void **native
, Error
**errp
)
270 visit_type_UserDefTwoList(v
, NULL
, (UserDefTwoList
**)native
, errp
);
275 typedef enum VisitorCapabilities
{
279 VCAP_PRIMITIVE_LISTS
= 8,
280 } VisitorCapabilities
;
282 typedef struct SerializeOps
{
283 void (*serialize
)(void *native_in
, void **datap
,
284 VisitorFunc visit
, Error
**errp
);
285 void (*deserialize
)(void **native_out
, void *datap
,
286 VisitorFunc visit
, Error
**errp
);
287 void (*cleanup
)(void *datap
);
289 VisitorCapabilities caps
;
292 typedef struct TestArgs
{
293 const SerializeOps
*ops
;
297 static void test_primitives(gconstpointer opaque
)
299 TestArgs
*args
= (TestArgs
*) opaque
;
300 const SerializeOps
*ops
= args
->ops
;
301 PrimitiveType
*pt
= args
->test_data
;
302 PrimitiveType
*pt_copy
= g_malloc0(sizeof(*pt_copy
));
303 void *serialize_data
;
305 pt_copy
->type
= pt
->type
;
306 ops
->serialize(pt
, &serialize_data
, visit_primitive_type
, &error_abort
);
307 ops
->deserialize((void **)&pt_copy
, serialize_data
, visit_primitive_type
,
310 g_assert(pt_copy
!= NULL
);
311 if (pt
->type
== PTYPE_STRING
) {
312 g_assert_cmpstr(pt
->value
.string
, ==, pt_copy
->value
.string
);
313 g_free((char *)pt_copy
->value
.string
);
314 } else if (pt
->type
== PTYPE_NUMBER
) {
315 GString
*double_expected
= g_string_new("");
316 GString
*double_actual
= g_string_new("");
317 /* we serialize with %f for our reference visitors, so rather than fuzzy
318 * floating math to test "equality", just compare the formatted values
320 g_string_printf(double_expected
, "%.6f", pt
->value
.number
);
321 g_string_printf(double_actual
, "%.6f", pt_copy
->value
.number
);
322 g_assert_cmpstr(double_actual
->str
, ==, double_expected
->str
);
324 g_string_free(double_expected
, true);
325 g_string_free(double_actual
, true);
326 } else if (pt
->type
== PTYPE_BOOLEAN
) {
327 g_assert_cmpint(!!pt
->value
.max
, ==, !!pt
->value
.max
);
329 g_assert_cmpint(pt
->value
.max
, ==, pt_copy
->value
.max
);
332 ops
->cleanup(serialize_data
);
337 static void test_primitive_lists(gconstpointer opaque
)
339 TestArgs
*args
= (TestArgs
*) opaque
;
340 const SerializeOps
*ops
= args
->ops
;
341 PrimitiveType
*pt
= args
->test_data
;
342 PrimitiveList pl
= { .value
= { NULL
} };
343 PrimitiveList pl_copy
= { .value
= { NULL
} };
344 PrimitiveList
*pl_copy_ptr
= &pl_copy
;
345 void *serialize_data
;
346 void *cur_head
= NULL
;
349 pl
.type
= pl_copy
.type
= pt
->type
;
351 /* build up our list of primitive types */
352 for (i
= 0; i
< 32; i
++) {
355 strList
*tmp
= g_new0(strList
, 1);
356 tmp
->value
= g_strdup(pt
->value
.string
);
357 if (pl
.value
.strings
== NULL
) {
358 pl
.value
.strings
= tmp
;
360 tmp
->next
= pl
.value
.strings
;
361 pl
.value
.strings
= tmp
;
365 case PTYPE_INTEGER
: {
366 intList
*tmp
= g_new0(intList
, 1);
367 tmp
->value
= pt
->value
.integer
;
368 if (pl
.value
.integers
== NULL
) {
369 pl
.value
.integers
= tmp
;
371 tmp
->next
= pl
.value
.integers
;
372 pl
.value
.integers
= tmp
;
377 int8List
*tmp
= g_new0(int8List
, 1);
378 tmp
->value
= pt
->value
.s8
;
379 if (pl
.value
.s8_integers
== NULL
) {
380 pl
.value
.s8_integers
= tmp
;
382 tmp
->next
= pl
.value
.s8_integers
;
383 pl
.value
.s8_integers
= tmp
;
388 int16List
*tmp
= g_new0(int16List
, 1);
389 tmp
->value
= pt
->value
.s16
;
390 if (pl
.value
.s16_integers
== NULL
) {
391 pl
.value
.s16_integers
= tmp
;
393 tmp
->next
= pl
.value
.s16_integers
;
394 pl
.value
.s16_integers
= tmp
;
399 int32List
*tmp
= g_new0(int32List
, 1);
400 tmp
->value
= pt
->value
.s32
;
401 if (pl
.value
.s32_integers
== NULL
) {
402 pl
.value
.s32_integers
= tmp
;
404 tmp
->next
= pl
.value
.s32_integers
;
405 pl
.value
.s32_integers
= tmp
;
410 int64List
*tmp
= g_new0(int64List
, 1);
411 tmp
->value
= pt
->value
.s64
;
412 if (pl
.value
.s64_integers
== NULL
) {
413 pl
.value
.s64_integers
= tmp
;
415 tmp
->next
= pl
.value
.s64_integers
;
416 pl
.value
.s64_integers
= tmp
;
421 uint8List
*tmp
= g_new0(uint8List
, 1);
422 tmp
->value
= pt
->value
.u8
;
423 if (pl
.value
.u8_integers
== NULL
) {
424 pl
.value
.u8_integers
= tmp
;
426 tmp
->next
= pl
.value
.u8_integers
;
427 pl
.value
.u8_integers
= tmp
;
432 uint16List
*tmp
= g_new0(uint16List
, 1);
433 tmp
->value
= pt
->value
.u16
;
434 if (pl
.value
.u16_integers
== NULL
) {
435 pl
.value
.u16_integers
= tmp
;
437 tmp
->next
= pl
.value
.u16_integers
;
438 pl
.value
.u16_integers
= tmp
;
443 uint32List
*tmp
= g_new0(uint32List
, 1);
444 tmp
->value
= pt
->value
.u32
;
445 if (pl
.value
.u32_integers
== NULL
) {
446 pl
.value
.u32_integers
= tmp
;
448 tmp
->next
= pl
.value
.u32_integers
;
449 pl
.value
.u32_integers
= tmp
;
454 uint64List
*tmp
= g_new0(uint64List
, 1);
455 tmp
->value
= pt
->value
.u64
;
456 if (pl
.value
.u64_integers
== NULL
) {
457 pl
.value
.u64_integers
= tmp
;
459 tmp
->next
= pl
.value
.u64_integers
;
460 pl
.value
.u64_integers
= tmp
;
465 numberList
*tmp
= g_new0(numberList
, 1);
466 tmp
->value
= pt
->value
.number
;
467 if (pl
.value
.numbers
== NULL
) {
468 pl
.value
.numbers
= tmp
;
470 tmp
->next
= pl
.value
.numbers
;
471 pl
.value
.numbers
= tmp
;
475 case PTYPE_BOOLEAN
: {
476 boolList
*tmp
= g_new0(boolList
, 1);
477 tmp
->value
= pt
->value
.boolean
;
478 if (pl
.value
.booleans
== NULL
) {
479 pl
.value
.booleans
= tmp
;
481 tmp
->next
= pl
.value
.booleans
;
482 pl
.value
.booleans
= tmp
;
487 g_assert_not_reached();
491 ops
->serialize((void **)&pl
, &serialize_data
, visit_primitive_list
,
493 ops
->deserialize((void **)&pl_copy_ptr
, serialize_data
,
494 visit_primitive_list
, &error_abort
);
498 /* compare our deserialized list of primitives to the original */
500 switch (pl_copy
.type
) {
505 cur_head
= ptr
->next
;
507 cur_head
= ptr
= pl_copy
.value
.strings
;
509 g_assert_cmpstr(pt
->value
.string
, ==, ptr
->value
);
512 case PTYPE_INTEGER
: {
516 cur_head
= ptr
->next
;
518 cur_head
= ptr
= pl_copy
.value
.integers
;
520 g_assert_cmpint(pt
->value
.integer
, ==, ptr
->value
);
527 cur_head
= ptr
->next
;
529 cur_head
= ptr
= pl_copy
.value
.s8_integers
;
531 g_assert_cmpint(pt
->value
.s8
, ==, ptr
->value
);
538 cur_head
= ptr
->next
;
540 cur_head
= ptr
= pl_copy
.value
.s16_integers
;
542 g_assert_cmpint(pt
->value
.s16
, ==, ptr
->value
);
549 cur_head
= ptr
->next
;
551 cur_head
= ptr
= pl_copy
.value
.s32_integers
;
553 g_assert_cmpint(pt
->value
.s32
, ==, ptr
->value
);
560 cur_head
= ptr
->next
;
562 cur_head
= ptr
= pl_copy
.value
.s64_integers
;
564 g_assert_cmpint(pt
->value
.s64
, ==, ptr
->value
);
571 cur_head
= ptr
->next
;
573 cur_head
= ptr
= pl_copy
.value
.u8_integers
;
575 g_assert_cmpint(pt
->value
.u8
, ==, ptr
->value
);
582 cur_head
= ptr
->next
;
584 cur_head
= ptr
= pl_copy
.value
.u16_integers
;
586 g_assert_cmpint(pt
->value
.u16
, ==, ptr
->value
);
593 cur_head
= ptr
->next
;
595 cur_head
= ptr
= pl_copy
.value
.u32_integers
;
597 g_assert_cmpint(pt
->value
.u32
, ==, ptr
->value
);
604 cur_head
= ptr
->next
;
606 cur_head
= ptr
= pl_copy
.value
.u64_integers
;
608 g_assert_cmpint(pt
->value
.u64
, ==, ptr
->value
);
613 GString
*double_expected
= g_string_new("");
614 GString
*double_actual
= g_string_new("");
617 cur_head
= ptr
->next
;
619 cur_head
= ptr
= pl_copy
.value
.numbers
;
621 /* we serialize with %f for our reference visitors, so rather than
622 * fuzzy floating math to test "equality", just compare the
625 g_string_printf(double_expected
, "%.6f", pt
->value
.number
);
626 g_string_printf(double_actual
, "%.6f", ptr
->value
);
627 g_assert_cmpstr(double_actual
->str
, ==, double_expected
->str
);
628 g_string_free(double_expected
, true);
629 g_string_free(double_actual
, true);
632 case PTYPE_BOOLEAN
: {
636 cur_head
= ptr
->next
;
638 cur_head
= ptr
= pl_copy
.value
.booleans
;
640 g_assert_cmpint(!!pt
->value
.boolean
, ==, !!ptr
->value
);
644 g_assert_not_reached();
649 g_assert_cmpint(i
, ==, 33);
651 ops
->cleanup(serialize_data
);
652 dealloc_helper(&pl
, visit_primitive_list
, &error_abort
);
653 dealloc_helper(&pl_copy
, visit_primitive_list
, &error_abort
);
657 static void test_struct(gconstpointer opaque
)
659 TestArgs
*args
= (TestArgs
*) opaque
;
660 const SerializeOps
*ops
= args
->ops
;
661 TestStruct
*ts
= struct_create();
662 TestStruct
*ts_copy
= NULL
;
663 void *serialize_data
;
665 ops
->serialize(ts
, &serialize_data
, visit_struct
, &error_abort
);
666 ops
->deserialize((void **)&ts_copy
, serialize_data
, visit_struct
,
669 struct_compare(ts
, ts_copy
);
672 struct_cleanup(ts_copy
);
674 ops
->cleanup(serialize_data
);
678 static void test_nested_struct(gconstpointer opaque
)
680 TestArgs
*args
= (TestArgs
*) opaque
;
681 const SerializeOps
*ops
= args
->ops
;
682 UserDefTwo
*udnp
= nested_struct_create();
683 UserDefTwo
*udnp_copy
= NULL
;
684 void *serialize_data
;
686 ops
->serialize(udnp
, &serialize_data
, visit_nested_struct
, &error_abort
);
687 ops
->deserialize((void **)&udnp_copy
, serialize_data
, visit_nested_struct
,
690 nested_struct_compare(udnp
, udnp_copy
);
692 nested_struct_cleanup(udnp
);
693 nested_struct_cleanup(udnp_copy
);
695 ops
->cleanup(serialize_data
);
699 static void test_nested_struct_list(gconstpointer opaque
)
701 TestArgs
*args
= (TestArgs
*) opaque
;
702 const SerializeOps
*ops
= args
->ops
;
703 UserDefTwoList
*listp
= NULL
, *tmp
, *tmp_copy
, *listp_copy
= NULL
;
704 void *serialize_data
;
707 for (i
= 0; i
< 8; i
++) {
708 tmp
= g_new0(UserDefTwoList
, 1);
709 tmp
->value
= nested_struct_create();
714 ops
->serialize(listp
, &serialize_data
, visit_nested_struct_list
,
716 ops
->deserialize((void **)&listp_copy
, serialize_data
,
717 visit_nested_struct_list
, &error_abort
);
720 tmp_copy
= listp_copy
;
723 nested_struct_compare(listp
->value
, listp_copy
->value
);
725 listp_copy
= listp_copy
->next
;
728 qapi_free_UserDefTwoList(tmp
);
729 qapi_free_UserDefTwoList(tmp_copy
);
731 ops
->cleanup(serialize_data
);
735 static PrimitiveType pt_values
[] = {
738 .description
= "string_empty",
739 .type
= PTYPE_STRING
,
743 .description
= "string_whitespace",
744 .type
= PTYPE_STRING
,
745 .value
.string
= "a b c\td",
748 .description
= "string_newlines",
749 .type
= PTYPE_STRING
,
750 .value
.string
= "a\nb\n",
753 .description
= "string_commas",
754 .type
= PTYPE_STRING
,
755 .value
.string
= "a,b, c,d",
758 .description
= "string_single_quoted",
759 .type
= PTYPE_STRING
,
760 .value
.string
= "'a b',cd",
763 .description
= "string_double_quoted",
764 .type
= PTYPE_STRING
,
765 .value
.string
= "\"a b\",cd",
769 .description
= "boolean_true1",
770 .type
= PTYPE_BOOLEAN
,
771 .value
.boolean
= true,
774 .description
= "boolean_true2",
775 .type
= PTYPE_BOOLEAN
,
779 .description
= "boolean_true3",
780 .type
= PTYPE_BOOLEAN
,
784 .description
= "boolean_false1",
785 .type
= PTYPE_BOOLEAN
,
786 .value
.boolean
= false,
789 .description
= "boolean_false2",
790 .type
= PTYPE_BOOLEAN
,
793 /* number tests (double) */
794 /* note: we format these to %.6f before comparing, since that's how
795 * we serialize them and it doesn't make sense to check precision
799 .description
= "number_sanity1",
800 .type
= PTYPE_NUMBER
,
804 .description
= "number_sanity2",
805 .type
= PTYPE_NUMBER
,
806 .value
.number
= 3.14159265,
809 .description
= "number_min",
810 .type
= PTYPE_NUMBER
,
811 .value
.number
= DBL_MIN
,
814 .description
= "number_max",
815 .type
= PTYPE_NUMBER
,
816 .value
.number
= DBL_MAX
,
818 /* integer tests (int64) */
820 .description
= "integer_sanity1",
821 .type
= PTYPE_INTEGER
,
825 .description
= "integer_sanity2",
826 .type
= PTYPE_INTEGER
,
827 .value
.integer
= INT64_MAX
/ 2 + 1,
830 .description
= "integer_min",
831 .type
= PTYPE_INTEGER
,
832 .value
.integer
= INT64_MIN
,
835 .description
= "integer_max",
836 .type
= PTYPE_INTEGER
,
837 .value
.integer
= INT64_MAX
,
841 .description
= "uint8_sanity1",
846 .description
= "uint8_sanity2",
848 .value
.u8
= UINT8_MAX
/ 2 + 1,
851 .description
= "uint8_min",
856 .description
= "uint8_max",
858 .value
.u8
= UINT8_MAX
,
862 .description
= "uint16_sanity1",
867 .description
= "uint16_sanity2",
869 .value
.u16
= UINT16_MAX
/ 2 + 1,
872 .description
= "uint16_min",
877 .description
= "uint16_max",
879 .value
.u16
= UINT16_MAX
,
883 .description
= "uint32_sanity1",
888 .description
= "uint32_sanity2",
890 .value
.u32
= UINT32_MAX
/ 2 + 1,
893 .description
= "uint32_min",
898 .description
= "uint32_max",
900 .value
.u32
= UINT32_MAX
,
904 .description
= "uint64_sanity1",
909 .description
= "uint64_sanity2",
911 .value
.u64
= UINT64_MAX
/ 2 + 1,
914 .description
= "uint64_min",
919 .description
= "uint64_max",
921 .value
.u64
= UINT64_MAX
,
925 .description
= "int8_sanity1",
930 .description
= "int8_sanity2",
932 .value
.s8
= INT8_MAX
/ 2 + 1,
935 .description
= "int8_min",
937 .value
.s8
= INT8_MIN
,
940 .description
= "int8_max",
942 .value
.s8
= INT8_MAX
,
946 .description
= "int16_sanity1",
951 .description
= "int16_sanity2",
953 .value
.s16
= INT16_MAX
/ 2 + 1,
956 .description
= "int16_min",
958 .value
.s16
= INT16_MIN
,
961 .description
= "int16_max",
963 .value
.s16
= INT16_MAX
,
967 .description
= "int32_sanity1",
972 .description
= "int32_sanity2",
974 .value
.s32
= INT32_MAX
/ 2 + 1,
977 .description
= "int32_min",
979 .value
.s32
= INT32_MIN
,
982 .description
= "int32_max",
984 .value
.s32
= INT32_MAX
,
988 .description
= "int64_sanity1",
993 .description
= "int64_sanity2",
995 .value
.s64
= INT64_MAX
/ 2 + 1,
998 .description
= "int64_min",
1000 .value
.s64
= INT64_MIN
,
1003 .description
= "int64_max",
1005 .value
.s64
= INT64_MAX
,
1007 { .type
= PTYPE_EOL
}
1010 /* visitor-specific op implementations */
1012 typedef struct QmpSerializeData
{
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
= qobject_output_visitor_new(&d
->obj
);
1024 visit(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 visit_complete(d
->qov
, &d
->obj
);
1037 output_json
= qobject_to_json(obj_orig
);
1038 obj
= qobject_from_json(qstring_get_str(output_json
), &error_abort
);
1040 QDECREF(output_json
);
1041 d
->qiv
= qobject_input_visitor_new(obj
);
1042 qobject_decref(obj_orig
);
1043 qobject_decref(obj
);
1044 visit(d
->qiv
, native_out
, errp
);
1047 static void qmp_cleanup(void *datap
)
1049 QmpSerializeData
*d
= datap
;
1056 typedef struct StringSerializeData
{
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, &d
->string
);
1068 visit(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 visit_complete(d
->sov
, &d
->string
);
1078 d
->siv
= string_input_visitor_new(d
->string
);
1079 visit(d
->siv
, native_out
, errp
);
1082 static void string_cleanup(void *datap
)
1084 StringSerializeData
*d
= datap
;
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
]);