2 * Unit-tests for visitor-based serialization
4 * Copyright IBM, Corp. 2012
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
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
, (char **)&pt
->value
.string
, NULL
, errp
);
106 visit_type_bool(v
, &pt
->value
.boolean
, NULL
, errp
);
109 visit_type_number(v
, &pt
->value
.number
, NULL
, errp
);
112 visit_type_int(v
, &pt
->value
.integer
, NULL
, errp
);
115 visit_type_uint8(v
, &pt
->value
.u8
, NULL
, errp
);
118 visit_type_uint16(v
, &pt
->value
.u16
, NULL
, errp
);
121 visit_type_uint32(v
, &pt
->value
.u32
, NULL
, errp
);
124 visit_type_uint64(v
, &pt
->value
.u64
, NULL
, errp
);
127 visit_type_int8(v
, &pt
->value
.s8
, NULL
, errp
);
130 visit_type_int16(v
, &pt
->value
.s16
, NULL
, errp
);
133 visit_type_int32(v
, &pt
->value
.s32
, NULL
, errp
);
136 visit_type_int64(v
, &pt
->value
.s64
, NULL
, errp
);
143 static void visit_primitive_list(Visitor
*v
, void **native
, Error
**errp
)
145 PrimitiveList
*pl
= *native
;
148 visit_type_strList(v
, &pl
->value
.strings
, NULL
, errp
);
151 visit_type_boolList(v
, &pl
->value
.booleans
, NULL
, errp
);
154 visit_type_numberList(v
, &pl
->value
.numbers
, NULL
, errp
);
157 visit_type_intList(v
, &pl
->value
.integers
, NULL
, errp
);
160 visit_type_int8List(v
, &pl
->value
.s8_integers
, NULL
, errp
);
163 visit_type_int16List(v
, &pl
->value
.s16_integers
, NULL
, errp
);
166 visit_type_int32List(v
, &pl
->value
.s32_integers
, NULL
, errp
);
169 visit_type_int64List(v
, &pl
->value
.s64_integers
, NULL
, errp
);
172 visit_type_uint8List(v
, &pl
->value
.u8_integers
, NULL
, errp
);
175 visit_type_uint16List(v
, &pl
->value
.u16_integers
, NULL
, errp
);
178 visit_type_uint32List(v
, &pl
->value
.u32_integers
, NULL
, errp
);
181 visit_type_uint64List(v
, &pl
->value
.u64_integers
, NULL
, errp
);
188 typedef struct TestStruct
195 static void visit_type_TestStruct(Visitor
*v
, TestStruct
**obj
,
196 const char *name
, Error
**errp
)
198 visit_start_struct(v
, (void **)obj
, NULL
, name
, sizeof(TestStruct
), errp
);
200 visit_type_int(v
, &(*obj
)->integer
, "integer", errp
);
201 visit_type_bool(v
, &(*obj
)->boolean
, "boolean", errp
);
202 visit_type_str(v
, &(*obj
)->string
, "string", errp
);
204 visit_end_struct(v
, errp
);
207 static TestStruct
*struct_create(void)
209 TestStruct
*ts
= g_malloc0(sizeof(*ts
));
212 ts
->string
= strdup("test string");
216 static void struct_compare(TestStruct
*ts1
, TestStruct
*ts2
)
220 g_assert_cmpint(ts1
->integer
, ==, ts2
->integer
);
221 g_assert(ts1
->boolean
== ts2
->boolean
);
222 g_assert_cmpstr(ts1
->string
, ==, ts2
->string
);
225 static void struct_cleanup(TestStruct
*ts
)
231 static void visit_struct(Visitor
*v
, void **native
, Error
**errp
)
233 visit_type_TestStruct(v
, (TestStruct
**)native
, NULL
, errp
);
236 static UserDefNested
*nested_struct_create(void)
238 UserDefNested
*udnp
= g_malloc0(sizeof(*udnp
));
239 udnp
->string0
= strdup("test_string0");
240 udnp
->dict1
.string1
= strdup("test_string1");
241 udnp
->dict1
.dict2
.userdef1
= g_malloc0(sizeof(UserDefOne
));
242 udnp
->dict1
.dict2
.userdef1
->integer
= 42;
243 udnp
->dict1
.dict2
.userdef1
->string
= strdup("test_string");
244 udnp
->dict1
.dict2
.string2
= strdup("test_string2");
245 udnp
->dict1
.has_dict3
= true;
246 udnp
->dict1
.dict3
.userdef2
= g_malloc0(sizeof(UserDefOne
));
247 udnp
->dict1
.dict3
.userdef2
->integer
= 43;
248 udnp
->dict1
.dict3
.userdef2
->string
= strdup("test_string");
249 udnp
->dict1
.dict3
.string3
= strdup("test_string3");
253 static void nested_struct_compare(UserDefNested
*udnp1
, UserDefNested
*udnp2
)
257 g_assert_cmpstr(udnp1
->string0
, ==, udnp2
->string0
);
258 g_assert_cmpstr(udnp1
->dict1
.string1
, ==, udnp2
->dict1
.string1
);
259 g_assert_cmpint(udnp1
->dict1
.dict2
.userdef1
->integer
, ==,
260 udnp2
->dict1
.dict2
.userdef1
->integer
);
261 g_assert_cmpstr(udnp1
->dict1
.dict2
.userdef1
->string
, ==,
262 udnp2
->dict1
.dict2
.userdef1
->string
);
263 g_assert_cmpstr(udnp1
->dict1
.dict2
.string2
, ==, udnp2
->dict1
.dict2
.string2
);
264 g_assert(udnp1
->dict1
.has_dict3
== udnp2
->dict1
.has_dict3
);
265 g_assert_cmpint(udnp1
->dict1
.dict3
.userdef2
->integer
, ==,
266 udnp2
->dict1
.dict3
.userdef2
->integer
);
267 g_assert_cmpstr(udnp1
->dict1
.dict3
.userdef2
->string
, ==,
268 udnp2
->dict1
.dict3
.userdef2
->string
);
269 g_assert_cmpstr(udnp1
->dict1
.dict3
.string3
, ==, udnp2
->dict1
.dict3
.string3
);
272 static void nested_struct_cleanup(UserDefNested
*udnp
)
274 qapi_free_UserDefNested(udnp
);
277 static void visit_nested_struct(Visitor
*v
, void **native
, Error
**errp
)
279 visit_type_UserDefNested(v
, (UserDefNested
**)native
, NULL
, errp
);
282 static void visit_nested_struct_list(Visitor
*v
, void **native
, Error
**errp
)
284 visit_type_UserDefNestedList(v
, (UserDefNestedList
**)native
, NULL
, errp
);
289 typedef enum VisitorCapabilities
{
293 VCAP_PRIMITIVE_LISTS
= 8,
294 } VisitorCapabilities
;
296 typedef struct SerializeOps
{
297 void (*serialize
)(void *native_in
, void **datap
,
298 VisitorFunc visit
, Error
**errp
);
299 void (*deserialize
)(void **native_out
, void *datap
,
300 VisitorFunc visit
, Error
**errp
);
301 void (*cleanup
)(void *datap
);
303 VisitorCapabilities caps
;
306 typedef struct TestArgs
{
307 const SerializeOps
*ops
;
311 static void test_primitives(gconstpointer opaque
)
313 TestArgs
*args
= (TestArgs
*) opaque
;
314 const SerializeOps
*ops
= args
->ops
;
315 PrimitiveType
*pt
= args
->test_data
;
316 PrimitiveType
*pt_copy
= g_malloc0(sizeof(*pt_copy
));
318 void *serialize_data
;
320 pt_copy
->type
= pt
->type
;
321 ops
->serialize(pt
, &serialize_data
, visit_primitive_type
, &err
);
322 ops
->deserialize((void **)&pt_copy
, serialize_data
, visit_primitive_type
, &err
);
324 g_assert(err
== NULL
);
325 g_assert(pt_copy
!= NULL
);
326 if (pt
->type
== PTYPE_STRING
) {
327 g_assert_cmpstr(pt
->value
.string
, ==, pt_copy
->value
.string
);
328 g_free((char *)pt_copy
->value
.string
);
329 } else if (pt
->type
== PTYPE_NUMBER
) {
330 GString
*double_expected
= g_string_new("");
331 GString
*double_actual
= g_string_new("");
332 /* we serialize with %f for our reference visitors, so rather than fuzzy
333 * floating math to test "equality", just compare the formatted values
335 g_string_printf(double_expected
, "%.6f", pt
->value
.number
);
336 g_string_printf(double_actual
, "%.6f", pt_copy
->value
.number
);
337 g_assert_cmpstr(double_actual
->str
, ==, double_expected
->str
);
339 g_string_free(double_expected
, true);
340 g_string_free(double_actual
, true);
341 } else if (pt
->type
== PTYPE_BOOLEAN
) {
342 g_assert_cmpint(!!pt
->value
.max
, ==, !!pt
->value
.max
);
344 g_assert_cmpint(pt
->value
.max
, ==, pt_copy
->value
.max
);
347 ops
->cleanup(serialize_data
);
352 static void test_primitive_lists(gconstpointer opaque
)
354 TestArgs
*args
= (TestArgs
*) opaque
;
355 const SerializeOps
*ops
= args
->ops
;
356 PrimitiveType
*pt
= args
->test_data
;
357 PrimitiveList pl
= { .value
= { 0 } };
358 PrimitiveList pl_copy
= { .value
= { 0 } };
359 PrimitiveList
*pl_copy_ptr
= &pl_copy
;
361 void *serialize_data
;
362 void *cur_head
= NULL
;
365 pl
.type
= pl_copy
.type
= pt
->type
;
367 /* build up our list of primitive types */
368 for (i
= 0; i
< 32; i
++) {
371 strList
*tmp
= g_new0(strList
, 1);
372 tmp
->value
= g_strdup(pt
->value
.string
);
373 if (pl
.value
.strings
== NULL
) {
374 pl
.value
.strings
= tmp
;
376 tmp
->next
= pl
.value
.strings
;
377 pl
.value
.strings
= tmp
;
381 case PTYPE_INTEGER
: {
382 intList
*tmp
= g_new0(intList
, 1);
383 tmp
->value
= pt
->value
.integer
;
384 if (pl
.value
.integers
== NULL
) {
385 pl
.value
.integers
= tmp
;
387 tmp
->next
= pl
.value
.integers
;
388 pl
.value
.integers
= tmp
;
393 int8List
*tmp
= g_new0(int8List
, 1);
394 tmp
->value
= pt
->value
.s8
;
395 if (pl
.value
.s8_integers
== NULL
) {
396 pl
.value
.s8_integers
= tmp
;
398 tmp
->next
= pl
.value
.s8_integers
;
399 pl
.value
.s8_integers
= tmp
;
404 int16List
*tmp
= g_new0(int16List
, 1);
405 tmp
->value
= pt
->value
.s16
;
406 if (pl
.value
.s16_integers
== NULL
) {
407 pl
.value
.s16_integers
= tmp
;
409 tmp
->next
= pl
.value
.s16_integers
;
410 pl
.value
.s16_integers
= tmp
;
415 int32List
*tmp
= g_new0(int32List
, 1);
416 tmp
->value
= pt
->value
.s32
;
417 if (pl
.value
.s32_integers
== NULL
) {
418 pl
.value
.s32_integers
= tmp
;
420 tmp
->next
= pl
.value
.s32_integers
;
421 pl
.value
.s32_integers
= tmp
;
426 int64List
*tmp
= g_new0(int64List
, 1);
427 tmp
->value
= pt
->value
.s64
;
428 if (pl
.value
.s64_integers
== NULL
) {
429 pl
.value
.s64_integers
= tmp
;
431 tmp
->next
= pl
.value
.s64_integers
;
432 pl
.value
.s64_integers
= tmp
;
437 uint8List
*tmp
= g_new0(uint8List
, 1);
438 tmp
->value
= pt
->value
.u8
;
439 if (pl
.value
.u8_integers
== NULL
) {
440 pl
.value
.u8_integers
= tmp
;
442 tmp
->next
= pl
.value
.u8_integers
;
443 pl
.value
.u8_integers
= tmp
;
448 uint16List
*tmp
= g_new0(uint16List
, 1);
449 tmp
->value
= pt
->value
.u16
;
450 if (pl
.value
.u16_integers
== NULL
) {
451 pl
.value
.u16_integers
= tmp
;
453 tmp
->next
= pl
.value
.u16_integers
;
454 pl
.value
.u16_integers
= tmp
;
459 uint32List
*tmp
= g_new0(uint32List
, 1);
460 tmp
->value
= pt
->value
.u32
;
461 if (pl
.value
.u32_integers
== NULL
) {
462 pl
.value
.u32_integers
= tmp
;
464 tmp
->next
= pl
.value
.u32_integers
;
465 pl
.value
.u32_integers
= tmp
;
470 uint64List
*tmp
= g_new0(uint64List
, 1);
471 tmp
->value
= pt
->value
.u64
;
472 if (pl
.value
.u64_integers
== NULL
) {
473 pl
.value
.u64_integers
= tmp
;
475 tmp
->next
= pl
.value
.u64_integers
;
476 pl
.value
.u64_integers
= tmp
;
481 numberList
*tmp
= g_new0(numberList
, 1);
482 tmp
->value
= pt
->value
.number
;
483 if (pl
.value
.numbers
== NULL
) {
484 pl
.value
.numbers
= tmp
;
486 tmp
->next
= pl
.value
.numbers
;
487 pl
.value
.numbers
= tmp
;
491 case PTYPE_BOOLEAN
: {
492 boolList
*tmp
= g_new0(boolList
, 1);
493 tmp
->value
= pt
->value
.boolean
;
494 if (pl
.value
.booleans
== NULL
) {
495 pl
.value
.booleans
= tmp
;
497 tmp
->next
= pl
.value
.booleans
;
498 pl
.value
.booleans
= tmp
;
507 ops
->serialize((void **)&pl
, &serialize_data
, visit_primitive_list
, &err
);
508 ops
->deserialize((void **)&pl_copy_ptr
, serialize_data
, visit_primitive_list
, &err
);
510 g_assert(err
== NULL
);
513 /* compare our deserialized list of primitives to the original */
515 switch (pl_copy
.type
) {
520 cur_head
= ptr
->next
;
522 cur_head
= ptr
= pl_copy
.value
.strings
;
524 g_assert_cmpstr(pt
->value
.string
, ==, ptr
->value
);
527 case PTYPE_INTEGER
: {
531 cur_head
= ptr
->next
;
533 cur_head
= ptr
= pl_copy
.value
.integers
;
535 g_assert_cmpint(pt
->value
.integer
, ==, ptr
->value
);
542 cur_head
= ptr
->next
;
544 cur_head
= ptr
= pl_copy
.value
.s8_integers
;
546 g_assert_cmpint(pt
->value
.s8
, ==, ptr
->value
);
553 cur_head
= ptr
->next
;
555 cur_head
= ptr
= pl_copy
.value
.s16_integers
;
557 g_assert_cmpint(pt
->value
.s16
, ==, ptr
->value
);
564 cur_head
= ptr
->next
;
566 cur_head
= ptr
= pl_copy
.value
.s32_integers
;
568 g_assert_cmpint(pt
->value
.s32
, ==, ptr
->value
);
575 cur_head
= ptr
->next
;
577 cur_head
= ptr
= pl_copy
.value
.s64_integers
;
579 g_assert_cmpint(pt
->value
.s64
, ==, ptr
->value
);
586 cur_head
= ptr
->next
;
588 cur_head
= ptr
= pl_copy
.value
.u8_integers
;
590 g_assert_cmpint(pt
->value
.u8
, ==, ptr
->value
);
597 cur_head
= ptr
->next
;
599 cur_head
= ptr
= pl_copy
.value
.u16_integers
;
601 g_assert_cmpint(pt
->value
.u16
, ==, ptr
->value
);
608 cur_head
= ptr
->next
;
610 cur_head
= ptr
= pl_copy
.value
.u32_integers
;
612 g_assert_cmpint(pt
->value
.u32
, ==, ptr
->value
);
619 cur_head
= ptr
->next
;
621 cur_head
= ptr
= pl_copy
.value
.u64_integers
;
623 g_assert_cmpint(pt
->value
.u64
, ==, ptr
->value
);
628 GString
*double_expected
= g_string_new("");
629 GString
*double_actual
= g_string_new("");
632 cur_head
= ptr
->next
;
634 cur_head
= ptr
= pl_copy
.value
.numbers
;
636 /* we serialize with %f for our reference visitors, so rather than
637 * fuzzy floating math to test "equality", just compare the
640 g_string_printf(double_expected
, "%.6f", pt
->value
.number
);
641 g_string_printf(double_actual
, "%.6f", ptr
->value
);
642 g_assert_cmpstr(double_actual
->str
, ==, double_expected
->str
);
643 g_string_free(double_expected
, true);
644 g_string_free(double_actual
, true);
647 case PTYPE_BOOLEAN
: {
651 cur_head
= ptr
->next
;
653 cur_head
= ptr
= pl_copy
.value
.booleans
;
655 g_assert_cmpint(!!pt
->value
.boolean
, ==, !!ptr
->value
);
664 g_assert_cmpint(i
, ==, 33);
666 ops
->cleanup(serialize_data
);
667 dealloc_helper(&pl
, visit_primitive_list
, &err
);
669 dealloc_helper(&pl_copy
, visit_primitive_list
, &err
);
674 static void test_struct(gconstpointer opaque
)
676 TestArgs
*args
= (TestArgs
*) opaque
;
677 const SerializeOps
*ops
= args
->ops
;
678 TestStruct
*ts
= struct_create();
679 TestStruct
*ts_copy
= NULL
;
681 void *serialize_data
;
683 ops
->serialize(ts
, &serialize_data
, visit_struct
, &err
);
684 ops
->deserialize((void **)&ts_copy
, serialize_data
, visit_struct
, &err
);
686 g_assert(err
== NULL
);
687 struct_compare(ts
, ts_copy
);
690 struct_cleanup(ts_copy
);
692 ops
->cleanup(serialize_data
);
696 static void test_nested_struct(gconstpointer opaque
)
698 TestArgs
*args
= (TestArgs
*) opaque
;
699 const SerializeOps
*ops
= args
->ops
;
700 UserDefNested
*udnp
= nested_struct_create();
701 UserDefNested
*udnp_copy
= NULL
;
703 void *serialize_data
;
705 ops
->serialize(udnp
, &serialize_data
, visit_nested_struct
, &err
);
706 ops
->deserialize((void **)&udnp_copy
, serialize_data
, visit_nested_struct
, &err
);
708 g_assert(err
== NULL
);
709 nested_struct_compare(udnp
, udnp_copy
);
711 nested_struct_cleanup(udnp
);
712 nested_struct_cleanup(udnp_copy
);
714 ops
->cleanup(serialize_data
);
718 static void test_nested_struct_list(gconstpointer opaque
)
720 TestArgs
*args
= (TestArgs
*) opaque
;
721 const SerializeOps
*ops
= args
->ops
;
722 UserDefNestedList
*listp
= NULL
, *tmp
, *tmp_copy
, *listp_copy
= NULL
;
724 void *serialize_data
;
727 for (i
= 0; i
< 8; i
++) {
728 tmp
= g_malloc0(sizeof(UserDefNestedList
));
729 tmp
->value
= nested_struct_create();
734 ops
->serialize(listp
, &serialize_data
, visit_nested_struct_list
, &err
);
735 ops
->deserialize((void **)&listp_copy
, serialize_data
,
736 visit_nested_struct_list
, &err
);
738 g_assert(err
== NULL
);
741 tmp_copy
= listp_copy
;
744 nested_struct_compare(listp
->value
, listp_copy
->value
);
746 listp_copy
= listp_copy
->next
;
749 qapi_free_UserDefNestedList(tmp
);
750 qapi_free_UserDefNestedList(tmp_copy
);
752 ops
->cleanup(serialize_data
);
756 PrimitiveType pt_values
[] = {
759 .description
= "string_empty",
760 .type
= PTYPE_STRING
,
764 .description
= "string_whitespace",
765 .type
= PTYPE_STRING
,
766 .value
.string
= "a b c\td",
769 .description
= "string_newlines",
770 .type
= PTYPE_STRING
,
771 .value
.string
= "a\nb\n",
774 .description
= "string_commas",
775 .type
= PTYPE_STRING
,
776 .value
.string
= "a,b, c,d",
779 .description
= "string_single_quoted",
780 .type
= PTYPE_STRING
,
781 .value
.string
= "'a b',cd",
784 .description
= "string_double_quoted",
785 .type
= PTYPE_STRING
,
786 .value
.string
= "\"a b\",cd",
790 .description
= "boolean_true1",
791 .type
= PTYPE_BOOLEAN
,
792 .value
.boolean
= true,
795 .description
= "boolean_true2",
796 .type
= PTYPE_BOOLEAN
,
800 .description
= "boolean_true3",
801 .type
= PTYPE_BOOLEAN
,
805 .description
= "boolean_false1",
806 .type
= PTYPE_BOOLEAN
,
807 .value
.boolean
= false,
810 .description
= "boolean_false2",
811 .type
= PTYPE_BOOLEAN
,
814 /* number tests (double) */
815 /* note: we format these to %.6f before comparing, since that's how
816 * we serialize them and it doesn't make sense to check precision
820 .description
= "number_sanity1",
821 .type
= PTYPE_NUMBER
,
825 .description
= "number_sanity2",
826 .type
= PTYPE_NUMBER
,
827 .value
.number
= 3.14159265,
830 .description
= "number_min",
831 .type
= PTYPE_NUMBER
,
832 .value
.number
= DBL_MIN
,
835 .description
= "number_max",
836 .type
= PTYPE_NUMBER
,
837 .value
.number
= DBL_MAX
,
839 /* integer tests (int64) */
841 .description
= "integer_sanity1",
842 .type
= PTYPE_INTEGER
,
846 .description
= "integer_sanity2",
847 .type
= PTYPE_INTEGER
,
848 .value
.integer
= INT64_MAX
/ 2 + 1,
851 .description
= "integer_min",
852 .type
= PTYPE_INTEGER
,
853 .value
.integer
= INT64_MIN
,
856 .description
= "integer_max",
857 .type
= PTYPE_INTEGER
,
858 .value
.integer
= INT64_MAX
,
862 .description
= "uint8_sanity1",
867 .description
= "uint8_sanity2",
869 .value
.u8
= UINT8_MAX
/ 2 + 1,
872 .description
= "uint8_min",
877 .description
= "uint8_max",
879 .value
.u8
= UINT8_MAX
,
883 .description
= "uint16_sanity1",
888 .description
= "uint16_sanity2",
890 .value
.u16
= UINT16_MAX
/ 2 + 1,
893 .description
= "uint16_min",
898 .description
= "uint16_max",
900 .value
.u16
= UINT16_MAX
,
904 .description
= "uint32_sanity1",
909 .description
= "uint32_sanity2",
911 .value
.u32
= UINT32_MAX
/ 2 + 1,
914 .description
= "uint32_min",
919 .description
= "uint32_max",
921 .value
.u32
= UINT32_MAX
,
925 .description
= "uint64_sanity1",
930 .description
= "uint64_sanity2",
932 .value
.u64
= UINT64_MAX
/ 2 + 1,
935 .description
= "uint64_min",
940 .description
= "uint64_max",
942 .value
.u64
= UINT64_MAX
,
946 .description
= "int8_sanity1",
951 .description
= "int8_sanity2",
953 .value
.s8
= INT8_MAX
/ 2 + 1,
956 .description
= "int8_min",
958 .value
.s8
= INT8_MIN
,
961 .description
= "int8_max",
963 .value
.s8
= INT8_MAX
,
967 .description
= "int16_sanity1",
972 .description
= "int16_sanity2",
974 .value
.s16
= INT16_MAX
/ 2 + 1,
977 .description
= "int16_min",
979 .value
.s16
= INT16_MIN
,
982 .description
= "int16_max",
984 .value
.s16
= INT16_MAX
,
988 .description
= "int32_sanity1",
993 .description
= "int32_sanity2",
995 .value
.s32
= INT32_MAX
/ 2 + 1,
998 .description
= "int32_min",
1000 .value
.s32
= INT32_MIN
,
1003 .description
= "int32_max",
1005 .value
.s32
= INT32_MAX
,
1009 .description
= "int64_sanity1",
1014 .description
= "int64_sanity2",
1016 .value
.s64
= INT64_MAX
/ 2 + 1,
1019 .description
= "int64_min",
1021 .value
.s64
= INT64_MIN
,
1024 .description
= "int64_max",
1026 .value
.s64
= INT64_MAX
,
1028 { .type
= PTYPE_EOL
}
1031 /* visitor-specific op implementations */
1033 typedef struct QmpSerializeData
{
1034 QmpOutputVisitor
*qov
;
1035 QmpInputVisitor
*qiv
;
1038 static void qmp_serialize(void *native_in
, void **datap
,
1039 VisitorFunc visit
, Error
**errp
)
1041 QmpSerializeData
*d
= g_malloc0(sizeof(*d
));
1043 d
->qov
= qmp_output_visitor_new();
1044 visit(qmp_output_get_visitor(d
->qov
), &native_in
, errp
);
1048 static void qmp_deserialize(void **native_out
, void *datap
,
1049 VisitorFunc visit
, Error
**errp
)
1051 QmpSerializeData
*d
= datap
;
1052 QString
*output_json
;
1053 QObject
*obj_orig
, *obj
;
1055 obj_orig
= qmp_output_get_qobject(d
->qov
);
1056 output_json
= qobject_to_json(obj_orig
);
1057 obj
= qobject_from_json(qstring_get_str(output_json
));
1059 QDECREF(output_json
);
1060 d
->qiv
= qmp_input_visitor_new(obj
);
1061 qobject_decref(obj_orig
);
1062 qobject_decref(obj
);
1063 visit(qmp_input_get_visitor(d
->qiv
), native_out
, errp
);
1066 static void qmp_cleanup(void *datap
)
1068 QmpSerializeData
*d
= datap
;
1069 qmp_output_visitor_cleanup(d
->qov
);
1070 qmp_input_visitor_cleanup(d
->qiv
);
1075 typedef struct StringSerializeData
{
1077 StringOutputVisitor
*sov
;
1078 StringInputVisitor
*siv
;
1079 } StringSerializeData
;
1081 static void string_serialize(void *native_in
, void **datap
,
1082 VisitorFunc visit
, Error
**errp
)
1084 StringSerializeData
*d
= g_malloc0(sizeof(*d
));
1086 d
->sov
= string_output_visitor_new();
1087 visit(string_output_get_visitor(d
->sov
), &native_in
, errp
);
1091 static void string_deserialize(void **native_out
, void *datap
,
1092 VisitorFunc visit
, Error
**errp
)
1094 StringSerializeData
*d
= datap
;
1096 d
->string
= string_output_get_string(d
->sov
);
1097 d
->siv
= string_input_visitor_new(d
->string
);
1098 visit(string_input_get_visitor(d
->siv
), native_out
, errp
);
1101 static void string_cleanup(void *datap
)
1103 StringSerializeData
*d
= datap
;
1105 string_output_visitor_cleanup(d
->sov
);
1106 string_input_visitor_cleanup(d
->siv
);
1111 /* visitor registration, test harness */
1113 /* note: to function interchangeably as a serialization mechanism your
1114 * visitor test implementation should pass the test cases for all visitor
1115 * capabilities: primitives, structures, and lists
1117 static const SerializeOps visitors
[] = {
1120 .serialize
= qmp_serialize
,
1121 .deserialize
= qmp_deserialize
,
1122 .cleanup
= qmp_cleanup
,
1123 .caps
= VCAP_PRIMITIVES
| VCAP_STRUCTURES
| VCAP_LISTS
|
1124 VCAP_PRIMITIVE_LISTS
1128 .serialize
= string_serialize
,
1129 .deserialize
= string_deserialize
,
1130 .cleanup
= string_cleanup
,
1131 .caps
= VCAP_PRIMITIVES
1136 static void add_visitor_type(const SerializeOps
*ops
)
1138 char testname_prefix
[128];
1143 sprintf(testname_prefix
, "/visitor/serialization/%s", ops
->type
);
1145 if (ops
->caps
& VCAP_PRIMITIVES
) {
1146 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1147 sprintf(testname
, "%s/primitives/%s", testname_prefix
,
1148 pt_values
[i
].description
);
1149 args
= g_malloc0(sizeof(*args
));
1151 args
->test_data
= &pt_values
[i
];
1152 g_test_add_data_func(testname
, args
, test_primitives
);
1157 if (ops
->caps
& VCAP_STRUCTURES
) {
1158 sprintf(testname
, "%s/struct", testname_prefix
);
1159 args
= g_malloc0(sizeof(*args
));
1161 args
->test_data
= NULL
;
1162 g_test_add_data_func(testname
, args
, test_struct
);
1164 sprintf(testname
, "%s/nested_struct", testname_prefix
);
1165 args
= g_malloc0(sizeof(*args
));
1167 args
->test_data
= NULL
;
1168 g_test_add_data_func(testname
, args
, test_nested_struct
);
1171 if (ops
->caps
& VCAP_LISTS
) {
1172 sprintf(testname
, "%s/nested_struct_list", testname_prefix
);
1173 args
= g_malloc0(sizeof(*args
));
1175 args
->test_data
= NULL
;
1176 g_test_add_data_func(testname
, args
, test_nested_struct_list
);
1179 if (ops
->caps
& VCAP_PRIMITIVE_LISTS
) {
1181 while (pt_values
[i
].type
!= PTYPE_EOL
) {
1182 sprintf(testname
, "%s/primitive_list/%s", testname_prefix
,
1183 pt_values
[i
].description
);
1184 args
= g_malloc0(sizeof(*args
));
1186 args
->test_data
= &pt_values
[i
];
1187 g_test_add_data_func(testname
, args
, test_primitive_lists
);
1193 int main(int argc
, char **argv
)
1197 g_test_init(&argc
, &argv
, NULL
);
1199 while (visitors
[i
].type
!= NULL
) {
1200 add_visitor_type(&visitors
[i
]);