root / tests / test-qmp-input-visitor.c @ e92cfa0d
History | View | Annotate | Download (9.8 kB)
1 |
/*
|
---|---|
2 |
* QMP Input Visitor unit-tests.
|
3 |
*
|
4 |
* Copyright (C) 2011 Red Hat Inc.
|
5 |
*
|
6 |
* Authors:
|
7 |
* Luiz Capitulino <lcapitulino@redhat.com>
|
8 |
*
|
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.
|
11 |
*/
|
12 |
|
13 |
#include <glib.h> |
14 |
#include <stdarg.h> |
15 |
|
16 |
#include "qemu-common.h" |
17 |
#include "qapi/qmp-input-visitor.h" |
18 |
#include "test-qapi-types.h" |
19 |
#include "test-qapi-visit.h" |
20 |
#include "qapi/qmp/types.h" |
21 |
|
22 |
typedef struct TestInputVisitorData { |
23 |
QObject *obj; |
24 |
QmpInputVisitor *qiv; |
25 |
} TestInputVisitorData; |
26 |
|
27 |
static void visitor_input_teardown(TestInputVisitorData *data, |
28 |
const void *unused) |
29 |
{ |
30 |
qobject_decref(data->obj); |
31 |
data->obj = NULL;
|
32 |
|
33 |
if (data->qiv) {
|
34 |
qmp_input_visitor_cleanup(data->qiv); |
35 |
data->qiv = NULL;
|
36 |
} |
37 |
} |
38 |
|
39 |
/* This is provided instead of a test setup function so that the JSON
|
40 |
string used by the tests are kept in the test functions (and not
|
41 |
int main()) */
|
42 |
static GCC_FMT_ATTR(2, 3) |
43 |
Visitor *visitor_input_test_init(TestInputVisitorData *data, |
44 |
const char *json_string, ...) |
45 |
{ |
46 |
Visitor *v; |
47 |
va_list ap; |
48 |
|
49 |
va_start(ap, json_string); |
50 |
data->obj = qobject_from_jsonv(json_string, &ap); |
51 |
va_end(ap); |
52 |
|
53 |
g_assert(data->obj != NULL);
|
54 |
|
55 |
data->qiv = qmp_input_visitor_new(data->obj); |
56 |
g_assert(data->qiv != NULL);
|
57 |
|
58 |
v = qmp_input_get_visitor(data->qiv); |
59 |
g_assert(v != NULL);
|
60 |
|
61 |
return v;
|
62 |
} |
63 |
|
64 |
static void test_visitor_in_int(TestInputVisitorData *data, |
65 |
const void *unused) |
66 |
{ |
67 |
int64_t res = 0, value = -42; |
68 |
Error *errp = NULL;
|
69 |
Visitor *v; |
70 |
|
71 |
v = visitor_input_test_init(data, "%" PRId64, value);
|
72 |
|
73 |
visit_type_int(v, &res, NULL, &errp);
|
74 |
g_assert(!error_is_set(&errp)); |
75 |
g_assert_cmpint(res, ==, value); |
76 |
} |
77 |
|
78 |
static void test_visitor_in_int_overflow(TestInputVisitorData *data, |
79 |
const void *unused) |
80 |
{ |
81 |
int64_t res = 0;
|
82 |
Error *errp = NULL;
|
83 |
Visitor *v; |
84 |
|
85 |
/* this will overflow a Qint/int64, so should be deserialized into
|
86 |
* a QFloat/double field instead, leading to an error if we pass it
|
87 |
* to visit_type_int. confirm this.
|
88 |
*/
|
89 |
v = visitor_input_test_init(data, "%f", DBL_MAX);
|
90 |
|
91 |
visit_type_int(v, &res, NULL, &errp);
|
92 |
g_assert(error_is_set(&errp)); |
93 |
error_free(errp); |
94 |
} |
95 |
|
96 |
static void test_visitor_in_bool(TestInputVisitorData *data, |
97 |
const void *unused) |
98 |
{ |
99 |
Error *errp = NULL;
|
100 |
bool res = false; |
101 |
Visitor *v; |
102 |
|
103 |
v = visitor_input_test_init(data, "true");
|
104 |
|
105 |
visit_type_bool(v, &res, NULL, &errp);
|
106 |
g_assert(!error_is_set(&errp)); |
107 |
g_assert_cmpint(res, ==, true);
|
108 |
} |
109 |
|
110 |
static void test_visitor_in_number(TestInputVisitorData *data, |
111 |
const void *unused) |
112 |
{ |
113 |
double res = 0, value = 3.14; |
114 |
Error *errp = NULL;
|
115 |
Visitor *v; |
116 |
|
117 |
v = visitor_input_test_init(data, "%f", value);
|
118 |
|
119 |
visit_type_number(v, &res, NULL, &errp);
|
120 |
g_assert(!error_is_set(&errp)); |
121 |
g_assert_cmpfloat(res, ==, value); |
122 |
} |
123 |
|
124 |
static void test_visitor_in_string(TestInputVisitorData *data, |
125 |
const void *unused) |
126 |
{ |
127 |
char *res = NULL, *value = (char *) "Q E M U"; |
128 |
Error *errp = NULL;
|
129 |
Visitor *v; |
130 |
|
131 |
v = visitor_input_test_init(data, "%s", value);
|
132 |
|
133 |
visit_type_str(v, &res, NULL, &errp);
|
134 |
g_assert(!error_is_set(&errp)); |
135 |
g_assert_cmpstr(res, ==, value); |
136 |
|
137 |
g_free(res); |
138 |
} |
139 |
|
140 |
static void test_visitor_in_enum(TestInputVisitorData *data, |
141 |
const void *unused) |
142 |
{ |
143 |
Error *errp = NULL;
|
144 |
Visitor *v; |
145 |
EnumOne i; |
146 |
|
147 |
for (i = 0; EnumOne_lookup[i]; i++) { |
148 |
EnumOne res = -1;
|
149 |
|
150 |
v = visitor_input_test_init(data, "%s", EnumOne_lookup[i]);
|
151 |
|
152 |
visit_type_EnumOne(v, &res, NULL, &errp);
|
153 |
g_assert(!error_is_set(&errp)); |
154 |
g_assert_cmpint(i, ==, res); |
155 |
|
156 |
visitor_input_teardown(data, NULL);
|
157 |
} |
158 |
|
159 |
data->obj = NULL;
|
160 |
data->qiv = NULL;
|
161 |
} |
162 |
|
163 |
typedef struct TestStruct |
164 |
{ |
165 |
int64_t integer; |
166 |
bool boolean;
|
167 |
char *string;
|
168 |
} TestStruct; |
169 |
|
170 |
static void visit_type_TestStruct(Visitor *v, TestStruct **obj, |
171 |
const char *name, Error **errp) |
172 |
{ |
173 |
Error *err = NULL;
|
174 |
if (!error_is_set(errp)) {
|
175 |
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), |
176 |
&err); |
177 |
if (!err) {
|
178 |
visit_type_int(v, &(*obj)->integer, "integer", &err);
|
179 |
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
|
180 |
visit_type_str(v, &(*obj)->string, "string", &err);
|
181 |
|
182 |
/* Always call end_struct if start_struct succeeded. */
|
183 |
error_propagate(errp, err); |
184 |
err = NULL;
|
185 |
visit_end_struct(v, &err); |
186 |
} |
187 |
error_propagate(errp, err); |
188 |
} |
189 |
} |
190 |
|
191 |
static void test_visitor_in_struct(TestInputVisitorData *data, |
192 |
const void *unused) |
193 |
{ |
194 |
TestStruct *p = NULL;
|
195 |
Error *errp = NULL;
|
196 |
Visitor *v; |
197 |
|
198 |
v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
|
199 |
|
200 |
visit_type_TestStruct(v, &p, NULL, &errp);
|
201 |
g_assert(!error_is_set(&errp)); |
202 |
g_assert_cmpint(p->integer, ==, -42);
|
203 |
g_assert(p->boolean == true);
|
204 |
g_assert_cmpstr(p->string, ==, "foo");
|
205 |
|
206 |
g_free(p->string); |
207 |
g_free(p); |
208 |
} |
209 |
|
210 |
static void check_and_free_str(char *str, const char *cmp) |
211 |
{ |
212 |
g_assert_cmpstr(str, ==, cmp); |
213 |
g_free(str); |
214 |
} |
215 |
|
216 |
static void test_visitor_in_struct_nested(TestInputVisitorData *data, |
217 |
const void *unused) |
218 |
{ |
219 |
UserDefNested *udp = NULL;
|
220 |
Error *errp = NULL;
|
221 |
Visitor *v; |
222 |
|
223 |
v = visitor_input_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
|
224 |
|
225 |
visit_type_UserDefNested(v, &udp, NULL, &errp);
|
226 |
g_assert(!error_is_set(&errp)); |
227 |
|
228 |
check_and_free_str(udp->string0, "string0");
|
229 |
check_and_free_str(udp->dict1.string1, "string1");
|
230 |
g_assert_cmpint(udp->dict1.dict2.userdef1->integer, ==, 42);
|
231 |
check_and_free_str(udp->dict1.dict2.userdef1->string, "string");
|
232 |
check_and_free_str(udp->dict1.dict2.string2, "string2");
|
233 |
g_assert(udp->dict1.has_dict3 == false);
|
234 |
|
235 |
g_free(udp->dict1.dict2.userdef1); |
236 |
g_free(udp); |
237 |
} |
238 |
|
239 |
static void test_visitor_in_list(TestInputVisitorData *data, |
240 |
const void *unused) |
241 |
{ |
242 |
UserDefOneList *item, *head = NULL;
|
243 |
Error *errp = NULL;
|
244 |
Visitor *v; |
245 |
int i;
|
246 |
|
247 |
v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
|
248 |
|
249 |
visit_type_UserDefOneList(v, &head, NULL, &errp);
|
250 |
g_assert(!error_is_set(&errp)); |
251 |
g_assert(head != NULL);
|
252 |
|
253 |
for (i = 0, item = head; item; item = item->next, i++) { |
254 |
char string[12]; |
255 |
|
256 |
snprintf(string, sizeof(string), "string%d", i); |
257 |
g_assert_cmpstr(item->value->string, ==, string); |
258 |
g_assert_cmpint(item->value->integer, ==, 42 + i);
|
259 |
} |
260 |
|
261 |
qapi_free_UserDefOneList(head); |
262 |
} |
263 |
|
264 |
static void test_visitor_in_union(TestInputVisitorData *data, |
265 |
const void *unused) |
266 |
{ |
267 |
Visitor *v; |
268 |
Error *err = NULL;
|
269 |
UserDefUnion *tmp; |
270 |
|
271 |
v = visitor_input_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }");
|
272 |
|
273 |
visit_type_UserDefUnion(v, &tmp, NULL, &err);
|
274 |
g_assert(err == NULL);
|
275 |
g_assert_cmpint(tmp->kind, ==, USER_DEF_UNION_KIND_B); |
276 |
g_assert_cmpint(tmp->b->integer, ==, 42);
|
277 |
qapi_free_UserDefUnion(tmp); |
278 |
} |
279 |
|
280 |
static void input_visitor_test_add(const char *testpath, |
281 |
TestInputVisitorData *data, |
282 |
void (*test_func)(TestInputVisitorData *data, const void *user_data)) |
283 |
{ |
284 |
g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
|
285 |
visitor_input_teardown); |
286 |
} |
287 |
|
288 |
static void test_visitor_in_errors(TestInputVisitorData *data, |
289 |
const void *unused) |
290 |
{ |
291 |
TestStruct *p = NULL;
|
292 |
Error *errp = NULL;
|
293 |
Visitor *v; |
294 |
|
295 |
v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }");
|
296 |
|
297 |
visit_type_TestStruct(v, &p, NULL, &errp);
|
298 |
g_assert(error_is_set(&errp)); |
299 |
g_assert(p->string == NULL);
|
300 |
|
301 |
g_free(p->string); |
302 |
g_free(p); |
303 |
} |
304 |
|
305 |
int main(int argc, char **argv) |
306 |
{ |
307 |
TestInputVisitorData in_visitor_data; |
308 |
|
309 |
g_test_init(&argc, &argv, NULL);
|
310 |
|
311 |
input_visitor_test_add("/visitor/input/int",
|
312 |
&in_visitor_data, test_visitor_in_int); |
313 |
input_visitor_test_add("/visitor/input/int_overflow",
|
314 |
&in_visitor_data, test_visitor_in_int_overflow); |
315 |
input_visitor_test_add("/visitor/input/bool",
|
316 |
&in_visitor_data, test_visitor_in_bool); |
317 |
input_visitor_test_add("/visitor/input/number",
|
318 |
&in_visitor_data, test_visitor_in_number); |
319 |
input_visitor_test_add("/visitor/input/string",
|
320 |
&in_visitor_data, test_visitor_in_string); |
321 |
input_visitor_test_add("/visitor/input/enum",
|
322 |
&in_visitor_data, test_visitor_in_enum); |
323 |
input_visitor_test_add("/visitor/input/struct",
|
324 |
&in_visitor_data, test_visitor_in_struct); |
325 |
input_visitor_test_add("/visitor/input/struct-nested",
|
326 |
&in_visitor_data, test_visitor_in_struct_nested); |
327 |
input_visitor_test_add("/visitor/input/list",
|
328 |
&in_visitor_data, test_visitor_in_list); |
329 |
input_visitor_test_add("/visitor/input/union",
|
330 |
&in_visitor_data, test_visitor_in_union); |
331 |
input_visitor_test_add("/visitor/input/errors",
|
332 |
&in_visitor_data, test_visitor_in_errors); |
333 |
|
334 |
g_test_run(); |
335 |
|
336 |
return 0; |
337 |
} |