]>
Commit | Line | Data |
---|---|---|
18fa3ebc PB |
1 | /* |
2 | * QAPI Forwarding Visitor unit-tests. | |
3 | * | |
4 | * Copyright (C) 2021 Red Hat Inc. | |
5 | * | |
6 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
7 | * See the COPYING file in the top-level directory. | |
8 | */ | |
9 | ||
10 | #include "qemu/osdep.h" | |
11 | ||
12 | #include "qemu-common.h" | |
13 | #include "qapi/forward-visitor.h" | |
14 | #include "qapi/qobject-input-visitor.h" | |
15 | #include "qapi/error.h" | |
16 | #include "qapi/qmp/qobject.h" | |
17 | #include "qapi/qmp/qdict.h" | |
18 | #include "test-qapi-visit.h" | |
19 | #include "qemu/option.h" | |
20 | ||
21 | typedef bool GenericVisitor (Visitor *, const char *, void **, Error **); | |
22 | #define CAST_VISIT_TYPE(fn) ((GenericVisitor *)(fn)) | |
23 | ||
24 | /* | |
25 | * Parse @srcstr and wrap it with a ForwardFieldVisitor converting "src" to | |
26 | * "dst". Check that visiting the result with "src" name fails, and return | |
27 | * the result of visiting "dst". | |
28 | */ | |
29 | static void *visit_with_forward(const char *srcstr, GenericVisitor *fn) | |
30 | { | |
31 | bool help = false; | |
32 | QDict *src = keyval_parse(srcstr, NULL, &help, &error_abort); | |
33 | Visitor *v, *alias_v; | |
34 | Error *err = NULL; | |
35 | void *result = NULL; | |
36 | ||
37 | v = qobject_input_visitor_new_keyval(QOBJECT(src)); | |
38 | visit_start_struct(v, NULL, NULL, 0, &error_abort); | |
39 | ||
40 | alias_v = visitor_forward_field(v, "dst", "src"); | |
41 | fn(alias_v, "src", &result, &err); | |
42 | error_free_or_abort(&err); | |
43 | assert(!result); | |
44 | fn(alias_v, "dst", &result, &err); | |
45 | assert(err == NULL); | |
46 | visit_free(alias_v); | |
47 | ||
48 | visit_end_struct(v, NULL); | |
49 | visit_free(v); | |
50 | qobject_unref(QOBJECT(src)); | |
51 | return result; | |
52 | } | |
53 | ||
54 | static void test_forward_any(void) | |
55 | { | |
56 | QObject *src = visit_with_forward("src.integer=42,src.string=Hello,src.enum1=value2", | |
57 | CAST_VISIT_TYPE(visit_type_any)); | |
58 | Visitor *v = qobject_input_visitor_new_keyval(src); | |
59 | Error *err = NULL; | |
60 | UserDefOne *dst; | |
61 | ||
62 | visit_type_UserDefOne(v, NULL, &dst, &err); | |
63 | assert(err == NULL); | |
64 | visit_free(v); | |
65 | ||
66 | g_assert_cmpint(dst->integer, ==, 42); | |
67 | g_assert_cmpstr(dst->string, ==, "Hello"); | |
68 | g_assert_cmpint(dst->has_enum1, ==, true); | |
69 | g_assert_cmpint(dst->enum1, ==, ENUM_ONE_VALUE2); | |
70 | qapi_free_UserDefOne(dst); | |
71 | qobject_unref(QOBJECT(src)); | |
72 | } | |
73 | ||
74 | static void test_forward_size(void) | |
75 | { | |
76 | /* | |
77 | * visit_type_size does not return a pointer, so visit_with_forward | |
78 | * cannot be used. | |
79 | */ | |
80 | bool help = false; | |
81 | QDict *src = keyval_parse("src=1.5M", NULL, &help, &error_abort); | |
82 | Visitor *v, *alias_v; | |
83 | Error *err = NULL; | |
84 | uint64_t result = 0; | |
85 | ||
86 | v = qobject_input_visitor_new_keyval(QOBJECT(src)); | |
87 | visit_start_struct(v, NULL, NULL, 0, &error_abort); | |
88 | ||
89 | alias_v = visitor_forward_field(v, "dst", "src"); | |
90 | visit_type_size(alias_v, "src", &result, &err); | |
91 | error_free_or_abort(&err); | |
92 | visit_type_size(alias_v, "dst", &result, &err); | |
93 | assert(result == 3 << 19); | |
94 | assert(err == NULL); | |
95 | visit_free(alias_v); | |
96 | ||
97 | visit_end_struct(v, NULL); | |
98 | visit_free(v); | |
99 | qobject_unref(QOBJECT(src)); | |
100 | } | |
101 | ||
102 | static void test_forward_number(void) | |
103 | { | |
104 | /* | |
105 | * visit_type_number does not return a pointer, so visit_with_forward | |
106 | * cannot be used. | |
107 | */ | |
108 | bool help = false; | |
109 | QDict *src = keyval_parse("src=1.5", NULL, &help, &error_abort); | |
110 | Visitor *v, *alias_v; | |
111 | Error *err = NULL; | |
112 | double result = 0.0; | |
113 | ||
114 | v = qobject_input_visitor_new_keyval(QOBJECT(src)); | |
115 | visit_start_struct(v, NULL, NULL, 0, &error_abort); | |
116 | ||
117 | alias_v = visitor_forward_field(v, "dst", "src"); | |
118 | visit_type_number(alias_v, "src", &result, &err); | |
119 | error_free_or_abort(&err); | |
120 | visit_type_number(alias_v, "dst", &result, &err); | |
121 | assert(result == 1.5); | |
122 | assert(err == NULL); | |
123 | visit_free(alias_v); | |
124 | ||
125 | visit_end_struct(v, NULL); | |
126 | visit_free(v); | |
127 | qobject_unref(QOBJECT(src)); | |
128 | } | |
129 | ||
130 | static void test_forward_string(void) | |
131 | { | |
132 | char *dst = visit_with_forward("src=Hello", | |
133 | CAST_VISIT_TYPE(visit_type_str)); | |
134 | ||
135 | g_assert_cmpstr(dst, ==, "Hello"); | |
136 | g_free(dst); | |
137 | } | |
138 | ||
139 | static void test_forward_struct(void) | |
140 | { | |
141 | UserDefOne *dst = visit_with_forward("src.integer=42,src.string=Hello", | |
142 | CAST_VISIT_TYPE(visit_type_UserDefOne)); | |
143 | ||
144 | g_assert_cmpint(dst->integer, ==, 42); | |
145 | g_assert_cmpstr(dst->string, ==, "Hello"); | |
146 | g_assert_cmpint(dst->has_enum1, ==, false); | |
147 | qapi_free_UserDefOne(dst); | |
148 | } | |
149 | ||
150 | static void test_forward_alternate(void) | |
151 | { | |
152 | AltStrObj *s_dst = visit_with_forward("src=hello", | |
153 | CAST_VISIT_TYPE(visit_type_AltStrObj)); | |
154 | AltStrObj *o_dst = visit_with_forward("src.integer=42,src.boolean=true,src.string=world", | |
155 | CAST_VISIT_TYPE(visit_type_AltStrObj)); | |
156 | ||
157 | g_assert_cmpint(s_dst->type, ==, QTYPE_QSTRING); | |
158 | g_assert_cmpstr(s_dst->u.s, ==, "hello"); | |
159 | g_assert_cmpint(o_dst->type, ==, QTYPE_QDICT); | |
160 | g_assert_cmpint(o_dst->u.o.integer, ==, 42); | |
161 | g_assert_cmpint(o_dst->u.o.boolean, ==, true); | |
162 | g_assert_cmpstr(o_dst->u.o.string, ==, "world"); | |
163 | ||
164 | qapi_free_AltStrObj(s_dst); | |
165 | qapi_free_AltStrObj(o_dst); | |
166 | } | |
167 | ||
168 | static void test_forward_list(void) | |
169 | { | |
170 | uint8List *dst = visit_with_forward("src.0=1,src.1=2,src.2=3,src.3=4", | |
171 | CAST_VISIT_TYPE(visit_type_uint8List)); | |
172 | uint8List *tmp; | |
173 | int i; | |
174 | ||
175 | for (tmp = dst, i = 1; i <= 4; i++) { | |
176 | g_assert(tmp); | |
177 | g_assert_cmpint(tmp->value, ==, i); | |
178 | tmp = tmp->next; | |
179 | } | |
180 | g_assert(!tmp); | |
181 | qapi_free_uint8List(dst); | |
182 | } | |
183 | ||
184 | int main(int argc, char **argv) | |
185 | { | |
186 | g_test_init(&argc, &argv, NULL); | |
187 | ||
188 | g_test_add_func("/visitor/forward/struct", test_forward_struct); | |
189 | g_test_add_func("/visitor/forward/alternate", test_forward_alternate); | |
190 | g_test_add_func("/visitor/forward/string", test_forward_string); | |
191 | g_test_add_func("/visitor/forward/size", test_forward_size); | |
192 | g_test_add_func("/visitor/forward/number", test_forward_number); | |
193 | g_test_add_func("/visitor/forward/any", test_forward_any); | |
194 | g_test_add_func("/visitor/forward/list", test_forward_list); | |
195 | ||
196 | return g_test_run(); | |
197 | } |