2 #include "qapi/qmp-output-visitor.h"
3 #include "qapi/qmp-input-visitor.h"
4 #include "test-qapi-types.h"
5 #include "test-qapi-visit.h"
6 #include "qemu-objects.h"
7 #include "qapi/qemu-file-output-visitor.h"
8 #include "qapi/qemu-file-input-visitor.h"
10 #include "qemu-common.h"
12 typedef struct TestStruct
18 typedef struct TestStructList
21 struct TestStructList
*next
;
24 static void visit_type_TestStruct(Visitor
*v
, TestStruct
**obj
, const char *name
, Error
**errp
)
26 visit_start_struct(v
, (void **)obj
, "TestStruct", name
, sizeof(TestStruct
), errp
);
27 visit_type_int(v
, &(*obj
)->x
, "x", errp
);
28 visit_type_int(v
, &(*obj
)->y
, "y", errp
);
29 visit_end_struct(v
, errp
);
32 static void visit_type_TestStructList(Visitor
*m
, TestStructList
** obj
, const char *name
, Error
**errp
)
34 GenericList
*i
, **head
= (GenericList
**)obj
;
36 visit_start_list(m
, name
, errp
);
38 for (*head
= i
= visit_next_list(m
, head
, errp
); i
; i
= visit_next_list(m
, &i
, errp
)) {
39 TestStructList
*native_i
= (TestStructList
*)i
;
40 visit_type_TestStruct(m
, &native_i
->value
, NULL
, errp
);
43 visit_end_list(m
, errp
);
46 /* test core visitor methods */
47 static void test_visitor_core(void)
52 TestStruct ts
= { 42, 82 };
53 TestStruct
*pts
= &ts
;
54 TestStructList
*lts
= NULL
;
62 mo
= qmp_output_visitor_new();
63 v
= qmp_output_get_visitor(mo
);
65 visit_type_TestStruct(v
, &pts
, NULL
, &err
);
67 obj
= qmp_output_get_qobject(mo
);
69 str
= qobject_to_json(obj
);
71 printf("%s\n", qstring_get_str(str
));
75 obj
= QOBJECT(qint_from_int(0x42));
77 mi
= qmp_input_visitor_new(obj
);
78 v
= qmp_input_get_visitor(mi
);
80 visit_type_int(v
, &value
, NULL
, &err
);
82 g_error("%s", error_get_pretty(err
));
85 g_assert(value
== 0x42);
89 obj
= qobject_from_json("{'x': 42, 'y': 84}");
90 mi
= qmp_input_visitor_new(obj
);
91 v
= qmp_input_get_visitor(mi
);
95 visit_type_TestStruct(v
, &pts
, NULL
, &err
);
97 g_error("%s", error_get_pretty(err
));
100 g_assert(pts
!= NULL
);
101 g_assert(pts
->x
== 42);
102 g_assert(pts
->y
== 84);
107 /* test list input visitor */
108 obj
= qobject_from_json("[{'x': 42, 'y': 84}, {'x': 12, 'y': 24}]");
109 mi
= qmp_input_visitor_new(obj
);
110 v
= qmp_input_get_visitor(mi
);
112 visit_type_TestStructList(v
, <s
, NULL
, &err
);
114 g_error("%s", error_get_pretty(err
));
117 g_assert(lts
!= NULL
);
118 g_assert(lts
->value
->x
== 42);
119 g_assert(lts
->value
->y
== 84);
121 g_assert(lts
->next
!= NULL
);
122 g_assert(lts
->next
->value
->x
== 12);
123 g_assert(lts
->next
->value
->y
== 24);
124 g_assert(lts
->next
->next
== NULL
);
128 /* test list output visitor */
129 mo
= qmp_output_visitor_new();
130 v
= qmp_output_get_visitor(mo
);
131 visit_type_TestStructList(v
, <s
, NULL
, &err
);
133 g_error("%s", error_get_pretty(err
));
135 obj
= qmp_output_get_qobject(mo
);
136 g_print("obj: %s\n", qstring_get_str(qobject_to_json(obj
)));
138 qlist
= qobject_to_qlist(obj
);
140 obj
= qlist_pop(qlist
);
141 qdict
= qobject_to_qdict(obj
);
143 assert(qdict_get_int(qdict
, "x") == 42);
144 assert(qdict_get_int(qdict
, "y") == 84);
147 obj
= qlist_pop(qlist
);
148 qdict
= qobject_to_qdict(obj
);
150 assert(qdict_get_int(qdict
, "x") == 12);
151 assert(qdict_get_int(qdict
, "y") == 24);
154 qmp_output_visitor_cleanup(mo
);
158 /* test deep nesting with refs to other user-defined types */
159 static void test_nested_structs(void)
161 QmpOutputVisitor
*mo
;
165 UserDefOne
*ud1_p
= &ud1
, *ud1c_p
= NULL
;
167 UserDefTwo
*ud2_p
= &ud2
, *ud2c_p
= NULL
;
173 ud1
.string
= strdup("fourty two");
176 mo
= qmp_output_visitor_new();
177 v
= qmp_output_get_visitor(mo
);
178 visit_type_UserDefOne(v
, &ud1_p
, "o_O", &err
);
180 g_error("%s", error_get_pretty(err
));
182 obj
= qmp_output_get_qobject(mo
);
186 ud2
.string
= strdup("fourty three");
187 ud2
.dict
.string
= strdup("fourty four");
188 ud2
.dict
.dict
.userdef
= ud1_p
;
189 ud2
.dict
.dict
.string
= strdup("fourty five");
190 ud2
.dict
.has_dict2
= true;
191 ud2
.dict
.dict2
.userdef
= ud1_p
;
192 ud2
.dict
.dict2
.string
= strdup("fourty six");
194 /* c type -> qobject */
195 mo
= qmp_output_visitor_new();
196 v
= qmp_output_get_visitor(mo
);
197 visit_type_UserDefTwo(v
, &ud2_p
, "unused", &err
);
199 g_error("%s", error_get_pretty(err
));
201 obj
= qmp_output_get_qobject(mo
);
203 str
= qobject_to_json_pretty(obj
);
204 g_print("%s\n", qstring_get_str(str
));
207 /* qobject -> c type, should match original struct */
208 mi
= qmp_input_visitor_new(obj
);
209 v
= qmp_input_get_visitor(mi
);
210 visit_type_UserDefTwo(v
, &ud2c_p
, NULL
, &err
);
212 g_error("%s", error_get_pretty(err
));
215 g_assert(!g_strcmp0(ud2c_p
->string
, ud2
.string
));
216 g_assert(!g_strcmp0(ud2c_p
->dict
.string
, ud2
.dict
.string
));
218 ud1c_p
= ud2c_p
->dict
.dict
.userdef
;
219 g_assert(ud1c_p
->integer
== ud1_p
->integer
);
220 g_assert(!g_strcmp0(ud1c_p
->string
, ud1_p
->string
));
222 g_assert(!g_strcmp0(ud2c_p
->dict
.dict
.string
, ud2
.dict
.dict
.string
));
224 ud1c_p
= ud2c_p
->dict
.dict2
.userdef
;
225 g_assert(ud1c_p
->integer
== ud1_p
->integer
);
226 g_assert(!g_strcmp0(ud1c_p
->string
, ud1_p
->string
));
228 g_assert(!g_strcmp0(ud2c_p
->dict
.dict2
.string
, ud2
.dict
.dict2
.string
));
231 g_free(ud2
.dict
.string
);
232 g_free(ud2
.dict
.dict
.string
);
233 g_free(ud2
.dict
.dict2
.string
);
235 qapi_free_UserDefTwo(ud2c_p
);
240 /* test enum values */
241 static void test_enums(void)
243 QmpOutputVisitor
*mo
;
246 EnumOne enum1
= ENUM_ONE_VALUE2
, enum1_cpy
= ENUM_ONE_VALUE1
;
251 /* C type -> QObject */
252 mo
= qmp_output_visitor_new();
253 v
= qmp_output_get_visitor(mo
);
254 visit_type_EnumOne(v
, &enum1
, "unused", &err
);
256 g_error("%s", error_get_pretty(err
));
258 obj
= qmp_output_get_qobject(mo
);
260 str
= qobject_to_json_pretty(obj
);
261 g_print("%s\n", qstring_get_str(str
));
263 g_assert(g_strcmp0(qstring_get_str(qobject_to_qstring(obj
)), "value2") == 0);
265 /* QObject -> C type */
266 mi
= qmp_input_visitor_new(obj
);
267 v
= qmp_input_get_visitor(mi
);
268 visit_type_EnumOne(v
, &enum1_cpy
, "unused", &err
);
270 g_error("%s", error_get_pretty(err
));
272 g_debug("enum1_cpy, enum1: %d, %d", enum1_cpy
, enum1
);
273 g_assert(enum1_cpy
== enum1
);
278 /* test enum values nested in schema-defined structs */
279 static void test_nested_enums(void)
281 QmpOutputVisitor
*mo
;
284 NestedEnumsOne
*nested_enums
, *nested_enums_cpy
= NULL
;
289 nested_enums
= g_malloc0(sizeof(NestedEnumsOne
));
290 nested_enums
->enum1
= ENUM_ONE_VALUE1
;
291 nested_enums
->enum2
= ENUM_ONE_VALUE2
;
292 nested_enums
->enum3
= ENUM_ONE_VALUE3
;
293 nested_enums
->enum4
= ENUM_ONE_VALUE3
;
294 nested_enums
->has_enum2
= false;
295 nested_enums
->has_enum4
= true;
297 /* C type -> QObject */
298 mo
= qmp_output_visitor_new();
299 v
= qmp_output_get_visitor(mo
);
300 visit_type_NestedEnumsOne(v
, &nested_enums
, NULL
, &err
);
302 g_error("%s", error_get_pretty(err
));
304 obj
= qmp_output_get_qobject(mo
);
306 str
= qobject_to_json_pretty(obj
);
307 g_print("%s\n", qstring_get_str(str
));
310 /* QObject -> C type */
311 mi
= qmp_input_visitor_new(obj
);
312 v
= qmp_input_get_visitor(mi
);
313 visit_type_NestedEnumsOne(v
, &nested_enums_cpy
, NULL
, &err
);
315 g_error("%s", error_get_pretty(err
));
317 g_assert(nested_enums_cpy
);
318 g_assert(nested_enums_cpy
->enum1
== nested_enums
->enum1
);
319 g_assert(nested_enums_cpy
->enum3
== nested_enums
->enum3
);
320 g_assert(nested_enums_cpy
->enum4
== nested_enums
->enum4
);
321 g_assert(nested_enums_cpy
->has_enum2
== false);
322 g_assert(nested_enums_cpy
->has_enum4
== true);
324 qmp_output_visitor_cleanup(mo
);
325 qmp_input_visitor_cleanup(mi
);
326 qapi_free_NestedEnumsOne(nested_enums
);
327 qapi_free_NestedEnumsOne(nested_enums_cpy
);
330 #define TEST_QEMU_FILE_PATH "/tmp/test_qemu_file_visitors"
332 typedef struct QEMUFileValue
{
374 QEMUFileValue qfvalues
[] = {
375 { .value
.boolean
= true, .type
= QFV_BOOL
},
376 { .value
.boolean
= false, .type
= QFV_BOOL
},
377 { .value
.number
= 3.14159265, .type
= QFV_NUMBER
},
378 { .value
.u8
= 0, .type
= QFV_U8
},
379 { .value
.u8
= 1, .type
= QFV_U8
},
380 { .value
.u8
= 128, .type
= QFV_U8
},
381 { .value
.u8
= 255u, .type
= QFV_U8
},
382 { .value
.u16
= 0, .type
= QFV_U16
},
383 { .value
.u16
= 1, .type
= QFV_U16
},
384 { .value
.u16
= 32768, .type
= QFV_U16
},
385 { .value
.u16
= 65535u, .type
= QFV_U16
},
386 { .value
.u32
= 0, .type
= QFV_U32
},
387 { .value
.u32
= 1, .type
= QFV_U32
},
388 { .value
.u32
= 2147483648, .type
= QFV_U32
},
389 { .value
.u32
= 4294967295u, .type
= QFV_U32
},
390 { .value
.u64
= 0, .type
= QFV_U64
},
391 { .value
.u64
= 1, .type
= QFV_U64
},
392 { .value
.u64
= 9223372036854775808u, .type
= QFV_U64
},
393 { .value
.u64
= 18446744073709551615u, .type
= QFV_U64
},
394 { .value
.s8
= 0, .type
= QFV_S8
},
395 { .value
.s8
= 1, .type
= QFV_S8
},
396 { .value
.s8
= 128, .type
= QFV_S8
},
397 { .value
.s8
= -1, .type
= QFV_S8
},
398 { .value
.s16
= 0, .type
= QFV_S16
},
399 { .value
.s16
= 1, .type
= QFV_S16
},
400 { .value
.s16
= 32768, .type
= QFV_S16
},
401 { .value
.s16
= -1, .type
= QFV_S16
},
402 { .value
.s32
= 0, .type
= QFV_S32
},
403 { .value
.s32
= 1, .type
= QFV_S32
},
404 { .value
.s32
= 2147483648, .type
= QFV_S32
},
405 { .value
.s32
= -1, .type
= QFV_S32
},
406 { .value
.s64
= 0, .type
= QFV_S64
},
407 { .value
.s64
= 1, .type
= QFV_S64
},
408 { .value
.s64
= 9223372036854775808u, .type
= QFV_S64
},
409 { .value
.s64
= -1, .type
= QFV_S64
},
410 { .array
.u8
= { }, .array_len
= 0, .type
= QFV_U8_ARRAY
},
411 { .array
.u8
= { 1, 2, 3, 4 }, .array_len
= 4, .type
= QFV_U8_ARRAY
},
415 static void qfv_process(QEMUFileValue
*qfv
, bool visitor
, bool write
,
424 visit_type_bool(opaque
, &qfv
->value
.boolean
, NULL
, NULL
);
427 qemu_put_byte(opaque
, qfv
->value
.boolean
);
429 qfv
->value
.boolean
= qemu_get_byte(opaque
);
435 visit_type_number(opaque
, &qfv
->value
.number
, NULL
, NULL
);
438 qemu_put_be64s(opaque
, (uint64_t *)&qfv
->value
.number
);
440 qemu_get_be64s(opaque
, (uint64_t *)&qfv
->value
.number
);
446 visit_type_uint8(opaque
, &qfv
->value
.u8
, NULL
, NULL
);
449 qemu_put_byte(opaque
, qfv
->value
.u8
);
451 qfv
->value
.u8
= qemu_get_byte(opaque
);
457 visit_type_uint16(opaque
, &qfv
->value
.u16
, NULL
, NULL
);
460 qemu_put_be16(opaque
, qfv
->value
.u16
);
462 qfv
->value
.u16
= qemu_get_be16(opaque
);
468 visit_type_uint32(opaque
, &qfv
->value
.u32
, NULL
, NULL
);
471 qemu_put_be32(opaque
, qfv
->value
.u32
);
473 qfv
->value
.u32
= qemu_get_be32(opaque
);
479 visit_type_uint64(opaque
, &qfv
->value
.u64
, NULL
, NULL
);
482 qemu_put_be64(opaque
, qfv
->value
.u64
);
484 qfv
->value
.u64
= qemu_get_be64(opaque
);
490 visit_type_int8(opaque
, &qfv
->value
.s8
, NULL
, NULL
);
493 qemu_put_byte(opaque
, qfv
->value
.s8
);
495 qfv
->value
.s8
= qemu_get_byte(opaque
);
501 visit_type_int16(opaque
, &qfv
->value
.s16
, NULL
, NULL
);
504 qemu_put_be16(opaque
, qfv
->value
.s16
);
506 qfv
->value
.s16
= qemu_get_be16(opaque
);
512 visit_type_int32(opaque
, &qfv
->value
.s32
, NULL
, NULL
);
515 qemu_put_be32(opaque
, qfv
->value
.s32
);
517 qfv
->value
.s32
= qemu_get_be32(opaque
);
523 visit_type_int64(opaque
, &qfv
->value
.s64
, NULL
, NULL
);
526 qemu_put_be64(opaque
, qfv
->value
.s64
);
528 qfv
->value
.s64
= qemu_get_be64(opaque
);
535 visit_start_array(opaque
, (void **)&ptr
, NULL
,
536 qfv
->array_len
, sizeof(uint8_t), NULL
);
537 for (i
= 0; i
< qfv
->array_len
; i
++, visit_next_array(opaque
, NULL
)) {
538 visit_type_uint8(opaque
, &((uint8_t *)ptr
)[i
], NULL
, NULL
);
540 visit_end_array(opaque
, NULL
);
542 for (i
= 0; i
< qfv
->array_len
; i
++) {
544 qemu_put_byte(opaque
, qfv
->array
.u8
[i
]);
546 qfv
->array
.u8
[i
] = qemu_get_byte(opaque
);
556 static void qfv_visitor_write(QEMUFileValue
*qfv
, Visitor
*v
)
558 qfv_process(qfv
, true, true, v
);
561 static void qfv_visitor_read(QEMUFileValue
*qfv
, Visitor
*v
)
563 qfv_process(qfv
, true, false, v
);
566 static void qfv_write(QEMUFileValue
*qfv
, QEMUFile
*f
)
568 qfv_process(qfv
, false, true, f
);
571 static void qfv_read(QEMUFileValue
*qfv
, QEMUFile
*f
)
573 qfv_process(qfv
, false, false, f
);
576 static void test_qemu_file_in_visitor(void)
579 QemuFileInputVisitor
*qfi
;
580 QemuFileOutputVisitor
*qfo
;
582 QEMUFileValue qfval1
, qfval2
;
587 /* write our test scalars/arrays */
588 f1
= qemu_fopen(TEST_QEMU_FILE_PATH
, "wb");
590 qfo
= qemu_file_output_visitor_new(f1
);
591 v
= qemu_file_output_get_visitor(qfo
);
592 for (i
= 0; qfvalues
[i
].type
!= QFV_EOL
; i
++) {
593 qfv_write(&qfvalues
[i
], f1
);
595 /* write our test struct/list. qemu_put_* interfaces have
596 * no analogue for this and instead rely on byte arrays,
597 * so we'll write this using a visitor and simply test
598 * visitor input/output compatibility
600 /* write a simple struct */
604 visit_type_TestStruct(v
, &pts
, NULL
, NULL
);
605 /* throw in a linked list as well */
606 lts
= g_malloc0(sizeof(*lts
));
607 lts
->value
= g_malloc0(sizeof(TestStruct
));
610 lts
->next
= g_malloc0(sizeof(*lts
));
611 lts
->next
->value
= g_malloc0(sizeof(TestStruct
));
612 lts
->next
->value
->x
= 46;
613 lts
->next
->value
->y
= 47;
614 visit_type_TestStructList(v
, <s
, NULL
, NULL
);
615 g_free(lts
->next
->value
);
620 qemu_file_output_visitor_cleanup(qfo
);
623 /* make sure qemu_get_be* and input visitor read same/correct input */
624 f1
= qemu_fopen(TEST_QEMU_FILE_PATH
, "rb");
625 f2
= qemu_fopen(TEST_QEMU_FILE_PATH
, "rb");
626 qfi
= qemu_file_input_visitor_new(f2
);
628 v
= qemu_file_input_get_visitor(qfi
);
630 for (i
= 0; qfvalues
[i
].type
!= QFV_EOL
; i
++) {
631 qfval1
.value
.umax
= qfval2
.value
.umax
= 0;
632 memset(qfval1
.array
.umax
, 0, sizeof(qfval1
.array
.umax
));
633 memset(qfval2
.array
.umax
, 0, sizeof(qfval2
.array
.umax
));
634 qfval1
.type
= qfval2
.type
= qfvalues
[i
].type
;
635 qfval1
.array_len
= qfval2
.array_len
= qfvalues
[i
].array_len
;
636 qfv_read(&qfval1
, f1
);
637 qfv_visitor_read(&qfval2
, v
);
638 if (qfvalues
[i
].type
>= QFV_U8_ARRAY
) {
639 for (j
= 0; j
< qfvalues
[i
].array_len
; j
++) {
640 g_assert(qfval1
.array
.u8
[j
] == qfval2
.array
.u8
[j
]);
641 g_assert(qfval2
.array
.u8
[j
] == qfvalues
[i
].array
.u8
[j
]);
644 g_assert(qfval1
.value
.umax
== qfval2
.value
.umax
);
645 g_assert(qfval2
.value
.umax
== qfvalues
[i
].value
.umax
);
648 qemu_file_input_visitor_cleanup(qfi
);
651 unlink(TEST_QEMU_FILE_PATH
);
654 static void test_qemu_file_out_visitor(void)
657 QemuFileOutputVisitor
*qfo
;
659 QEMUFileValue qfval1
;
664 /* write test scalars/arrays using an output visitor */
665 f
= qemu_fopen(TEST_QEMU_FILE_PATH
, "wb");
667 qfo
= qemu_file_output_visitor_new(f
);
669 v
= qemu_file_output_get_visitor(qfo
);
671 for (i
= 0; qfvalues
[i
].type
!= QFV_EOL
; i
++) {
672 qfv_visitor_write(&qfvalues
[i
], v
);
674 /* write a simple struct */
678 visit_type_TestStruct(v
, &pts
, NULL
, NULL
);
679 /* throw in a linked list as well */
680 lts
= g_malloc0(sizeof(*lts
));
681 lts
->value
= g_malloc0(sizeof(TestStruct
));
684 lts
->next
= g_malloc0(sizeof(*lts
));
685 lts
->next
->value
= g_malloc0(sizeof(TestStruct
));
686 lts
->next
->value
->x
= 46;
687 lts
->next
->value
->y
= 47;
688 visit_type_TestStructList(v
, <s
, NULL
, NULL
);
689 g_free(lts
->next
->value
);
694 qemu_file_output_visitor_cleanup(qfo
);
697 /* make sure output visitor wrote the expected values */
698 f
= qemu_fopen(TEST_QEMU_FILE_PATH
, "rb");
700 for (i
= 0; qfvalues
[i
].type
!= QFV_EOL
; i
++) {
701 qfval1
.type
= qfvalues
[i
].type
;
702 qfval1
.value
.umax
= 0;
703 memset(qfval1
.array
.umax
, 0, sizeof(qfval1
.array
.umax
));
704 qfval1
.array_len
= qfvalues
[i
].array_len
;
706 qfv_read(&qfval1
, f
);
707 if (qfvalues
[i
].type
>= QFV_U8_ARRAY
) {
708 for (j
= 0; j
< qfvalues
[i
].array_len
; j
++) {
709 g_assert(qfval1
.array
.u8
[j
] == qfvalues
[i
].array
.u8
[j
]);
712 g_assert(qfval1
.value
.umax
== qfvalues
[i
].value
.umax
);
715 /* test the struct */
716 g_assert(qemu_get_be64(f
) == ts
.x
);
717 g_assert(qemu_get_be64(f
) == ts
.y
);
718 /* test the linked list */
719 g_assert(qemu_get_be64(f
) == 44);
720 g_assert(qemu_get_be64(f
) == 45);
721 g_assert(qemu_get_be64(f
) == 46);
722 g_assert(qemu_get_be64(f
) == 47);
725 unlink(TEST_QEMU_FILE_PATH
);
728 int main(int argc
, char **argv
)
730 g_test_init(&argc
, &argv
, NULL
);
732 g_test_add_func("/0.15/visitor_core", test_visitor_core
);
733 g_test_add_func("/0.15/nested_structs", test_nested_structs
);
734 g_test_add_func("/0.15/enums", test_enums
);
735 g_test_add_func("/0.15/nested_enums", test_nested_enums
);
736 g_test_add_func("/1.0/qemu_file_input_visitor", test_qemu_file_in_visitor
);
737 g_test_add_func("/1.0/qemu_file_output_visitor", test_qemu_file_out_visitor
);