root / tests / test-qmp-output-visitor.c @ 4115852b
History | View | Annotate | Download (14.8 kB)
1 |
/*
|
---|---|
2 |
* QMP Output 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 |
|
15 |
#include "qapi/qmp-output-visitor.h" |
16 |
#include "test-qapi-types.h" |
17 |
#include "test-qapi-visit.h" |
18 |
#include "qemu-objects.h" |
19 |
|
20 |
typedef struct TestOutputVisitorData { |
21 |
QmpOutputVisitor *qov; |
22 |
Visitor *ov; |
23 |
} TestOutputVisitorData; |
24 |
|
25 |
static void visitor_output_setup(TestOutputVisitorData *data, |
26 |
const void *unused) |
27 |
{ |
28 |
data->qov = qmp_output_visitor_new(); |
29 |
g_assert(data->qov != NULL);
|
30 |
|
31 |
data->ov = qmp_output_get_visitor(data->qov); |
32 |
g_assert(data->ov != NULL);
|
33 |
} |
34 |
|
35 |
static void visitor_output_teardown(TestOutputVisitorData *data, |
36 |
const void *unused) |
37 |
{ |
38 |
qmp_output_visitor_cleanup(data->qov); |
39 |
data->qov = NULL;
|
40 |
data->ov = NULL;
|
41 |
} |
42 |
|
43 |
static void test_visitor_out_int(TestOutputVisitorData *data, |
44 |
const void *unused) |
45 |
{ |
46 |
int64_t value = -42;
|
47 |
Error *errp = NULL;
|
48 |
QObject *obj; |
49 |
|
50 |
visit_type_int(data->ov, &value, NULL, &errp);
|
51 |
g_assert(error_is_set(&errp) == 0);
|
52 |
|
53 |
obj = qmp_output_get_qobject(data->qov); |
54 |
g_assert(obj != NULL);
|
55 |
g_assert(qobject_type(obj) == QTYPE_QINT); |
56 |
g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, value); |
57 |
|
58 |
qobject_decref(obj); |
59 |
} |
60 |
|
61 |
static void test_visitor_out_bool(TestOutputVisitorData *data, |
62 |
const void *unused) |
63 |
{ |
64 |
Error *errp = NULL;
|
65 |
bool value = true; |
66 |
QObject *obj; |
67 |
|
68 |
visit_type_bool(data->ov, &value, NULL, &errp);
|
69 |
g_assert(error_is_set(&errp) == 0);
|
70 |
|
71 |
obj = qmp_output_get_qobject(data->qov); |
72 |
g_assert(obj != NULL);
|
73 |
g_assert(qobject_type(obj) == QTYPE_QBOOL); |
74 |
g_assert(qbool_get_int(qobject_to_qbool(obj)) == value); |
75 |
|
76 |
qobject_decref(obj); |
77 |
} |
78 |
|
79 |
static void test_visitor_out_number(TestOutputVisitorData *data, |
80 |
const void *unused) |
81 |
{ |
82 |
double value = 3.14; |
83 |
Error *errp = NULL;
|
84 |
QObject *obj; |
85 |
|
86 |
visit_type_number(data->ov, &value, NULL, &errp);
|
87 |
g_assert(error_is_set(&errp) == 0);
|
88 |
|
89 |
obj = qmp_output_get_qobject(data->qov); |
90 |
g_assert(obj != NULL);
|
91 |
g_assert(qobject_type(obj) == QTYPE_QFLOAT); |
92 |
g_assert(qfloat_get_double(qobject_to_qfloat(obj)) == value); |
93 |
|
94 |
qobject_decref(obj); |
95 |
} |
96 |
|
97 |
static void test_visitor_out_string(TestOutputVisitorData *data, |
98 |
const void *unused) |
99 |
{ |
100 |
char *string = (char *) "Q E M U"; |
101 |
Error *errp = NULL;
|
102 |
QObject *obj; |
103 |
|
104 |
visit_type_str(data->ov, &string, NULL, &errp);
|
105 |
g_assert(error_is_set(&errp) == 0);
|
106 |
|
107 |
obj = qmp_output_get_qobject(data->qov); |
108 |
g_assert(obj != NULL);
|
109 |
g_assert(qobject_type(obj) == QTYPE_QSTRING); |
110 |
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, string); |
111 |
|
112 |
qobject_decref(obj); |
113 |
} |
114 |
|
115 |
static void test_visitor_out_no_string(TestOutputVisitorData *data, |
116 |
const void *unused) |
117 |
{ |
118 |
char *string = NULL; |
119 |
Error *errp = NULL;
|
120 |
QObject *obj; |
121 |
|
122 |
/* A null string should return "" */
|
123 |
visit_type_str(data->ov, &string, NULL, &errp);
|
124 |
g_assert(error_is_set(&errp) == 0);
|
125 |
|
126 |
obj = qmp_output_get_qobject(data->qov); |
127 |
g_assert(obj != NULL);
|
128 |
g_assert(qobject_type(obj) == QTYPE_QSTRING); |
129 |
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, "");
|
130 |
|
131 |
qobject_decref(obj); |
132 |
} |
133 |
|
134 |
static void test_visitor_out_enum(TestOutputVisitorData *data, |
135 |
const void *unused) |
136 |
{ |
137 |
Error *errp = NULL;
|
138 |
QObject *obj; |
139 |
EnumOne i; |
140 |
|
141 |
for (i = 0; i < ENUM_ONE_MAX; i++) { |
142 |
visit_type_EnumOne(data->ov, &i, "unused", &errp);
|
143 |
g_assert(!error_is_set(&errp)); |
144 |
|
145 |
obj = qmp_output_get_qobject(data->qov); |
146 |
g_assert(obj != NULL);
|
147 |
g_assert(qobject_type(obj) == QTYPE_QSTRING); |
148 |
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, |
149 |
EnumOne_lookup[i]); |
150 |
qobject_decref(obj); |
151 |
} |
152 |
} |
153 |
|
154 |
static void test_visitor_out_enum_errors(TestOutputVisitorData *data, |
155 |
const void *unused) |
156 |
{ |
157 |
EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
|
158 |
Error *errp; |
159 |
|
160 |
for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { |
161 |
errp = NULL;
|
162 |
visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
|
163 |
g_assert(error_is_set(&errp) == true);
|
164 |
error_free(errp); |
165 |
} |
166 |
} |
167 |
|
168 |
typedef struct TestStruct |
169 |
{ |
170 |
int64_t integer; |
171 |
bool boolean;
|
172 |
char *string;
|
173 |
} TestStruct; |
174 |
|
175 |
static void visit_type_TestStruct(Visitor *v, TestStruct **obj, |
176 |
const char *name, Error **errp) |
177 |
{ |
178 |
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), |
179 |
errp); |
180 |
|
181 |
visit_type_int(v, &(*obj)->integer, "integer", errp);
|
182 |
visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
|
183 |
visit_type_str(v, &(*obj)->string, "string", errp);
|
184 |
|
185 |
visit_end_struct(v, errp); |
186 |
} |
187 |
|
188 |
static void test_visitor_out_struct(TestOutputVisitorData *data, |
189 |
const void *unused) |
190 |
{ |
191 |
TestStruct test_struct = { .integer = 42,
|
192 |
.boolean = false,
|
193 |
.string = (char *) "foo"}; |
194 |
TestStruct *p = &test_struct; |
195 |
Error *errp = NULL;
|
196 |
QObject *obj; |
197 |
QDict *qdict; |
198 |
|
199 |
visit_type_TestStruct(data->ov, &p, NULL, &errp);
|
200 |
g_assert(!error_is_set(&errp)); |
201 |
|
202 |
obj = qmp_output_get_qobject(data->qov); |
203 |
g_assert(obj != NULL);
|
204 |
g_assert(qobject_type(obj) == QTYPE_QDICT); |
205 |
|
206 |
qdict = qobject_to_qdict(obj); |
207 |
g_assert_cmpint(qdict_size(qdict), ==, 3);
|
208 |
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42); |
209 |
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, 0); |
210 |
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "foo"); |
211 |
|
212 |
QDECREF(qdict); |
213 |
} |
214 |
|
215 |
static void test_visitor_out_struct_nested(TestOutputVisitorData *data, |
216 |
const void *unused) |
217 |
{ |
218 |
int64_t value = 42;
|
219 |
Error *errp = NULL;
|
220 |
UserDefNested *ud2; |
221 |
QObject *obj; |
222 |
QDict *qdict, *dict1, *dict2, *dict3, *userdef; |
223 |
const char *string = "user def string"; |
224 |
const char *strings[] = { "forty two", "forty three", "forty four", |
225 |
"forty five" };
|
226 |
|
227 |
ud2 = g_malloc0(sizeof(*ud2));
|
228 |
ud2->string0 = g_strdup(strings[0]);
|
229 |
|
230 |
ud2->dict1.string1 = g_strdup(strings[1]);
|
231 |
ud2->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
|
232 |
ud2->dict1.dict2.userdef1->string = g_strdup(string); |
233 |
ud2->dict1.dict2.userdef1->integer = value; |
234 |
ud2->dict1.dict2.string2 = g_strdup(strings[2]);
|
235 |
|
236 |
ud2->dict1.has_dict3 = true;
|
237 |
ud2->dict1.dict3.userdef2 = g_malloc0(sizeof(UserDefOne));
|
238 |
ud2->dict1.dict3.userdef2->string = g_strdup(string); |
239 |
ud2->dict1.dict3.userdef2->integer = value; |
240 |
ud2->dict1.dict3.string3 = g_strdup(strings[3]);
|
241 |
|
242 |
visit_type_UserDefNested(data->ov, &ud2, "unused", &errp);
|
243 |
g_assert(!error_is_set(&errp)); |
244 |
|
245 |
obj = qmp_output_get_qobject(data->qov); |
246 |
g_assert(obj != NULL);
|
247 |
g_assert(qobject_type(obj) == QTYPE_QDICT); |
248 |
|
249 |
qdict = qobject_to_qdict(obj); |
250 |
g_assert_cmpint(qdict_size(qdict), ==, 2);
|
251 |
g_assert_cmpstr(qdict_get_str(qdict, "string0"), ==, strings[0]); |
252 |
|
253 |
dict1 = qdict_get_qdict(qdict, "dict1");
|
254 |
g_assert_cmpint(qdict_size(dict1), ==, 3);
|
255 |
g_assert_cmpstr(qdict_get_str(dict1, "string1"), ==, strings[1]); |
256 |
|
257 |
dict2 = qdict_get_qdict(dict1, "dict2");
|
258 |
g_assert_cmpint(qdict_size(dict2), ==, 2);
|
259 |
g_assert_cmpstr(qdict_get_str(dict2, "string2"), ==, strings[2]); |
260 |
userdef = qdict_get_qdict(dict2, "userdef1");
|
261 |
g_assert_cmpint(qdict_size(userdef), ==, 2);
|
262 |
g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
|
263 |
g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
|
264 |
|
265 |
dict3 = qdict_get_qdict(dict1, "dict3");
|
266 |
g_assert_cmpint(qdict_size(dict3), ==, 2);
|
267 |
g_assert_cmpstr(qdict_get_str(dict3, "string3"), ==, strings[3]); |
268 |
userdef = qdict_get_qdict(dict3, "userdef2");
|
269 |
g_assert_cmpint(qdict_size(userdef), ==, 2);
|
270 |
g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
|
271 |
g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
|
272 |
|
273 |
QDECREF(qdict); |
274 |
qapi_free_UserDefNested(ud2); |
275 |
} |
276 |
|
277 |
static void test_visitor_out_struct_errors(TestOutputVisitorData *data, |
278 |
const void *unused) |
279 |
{ |
280 |
EnumOne bad_values[] = { ENUM_ONE_MAX, -1 };
|
281 |
UserDefOne u = { 0 }, *pu = &u;
|
282 |
Error *errp; |
283 |
int i;
|
284 |
|
285 |
for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { |
286 |
errp = NULL;
|
287 |
u.has_enum1 = true;
|
288 |
u.enum1 = bad_values[i]; |
289 |
visit_type_UserDefOne(data->ov, &pu, "unused", &errp);
|
290 |
g_assert(error_is_set(&errp) == true);
|
291 |
error_free(errp); |
292 |
} |
293 |
} |
294 |
|
295 |
typedef struct TestStructList |
296 |
{ |
297 |
TestStruct *value; |
298 |
struct TestStructList *next;
|
299 |
} TestStructList; |
300 |
|
301 |
static void visit_type_TestStructList(Visitor *v, TestStructList **obj, |
302 |
const char *name, Error **errp) |
303 |
{ |
304 |
GenericList *i, **head = (GenericList **)obj; |
305 |
|
306 |
visit_start_list(v, name, errp); |
307 |
|
308 |
for (*head = i = visit_next_list(v, head, errp); i; i = visit_next_list(v, &i, errp)) {
|
309 |
TestStructList *native_i = (TestStructList *)i; |
310 |
visit_type_TestStruct(v, &native_i->value, NULL, errp);
|
311 |
} |
312 |
|
313 |
visit_end_list(v, errp); |
314 |
} |
315 |
|
316 |
static void test_visitor_out_list(TestOutputVisitorData *data, |
317 |
const void *unused) |
318 |
{ |
319 |
char *value_str = (char *) "list value"; |
320 |
TestStructList *p, *head = NULL;
|
321 |
const int max_items = 10; |
322 |
bool value_bool = true; |
323 |
int value_int = 10; |
324 |
Error *errp = NULL;
|
325 |
QListEntry *entry; |
326 |
QObject *obj; |
327 |
QList *qlist; |
328 |
int i;
|
329 |
|
330 |
for (i = 0; i < max_items; i++) { |
331 |
p = g_malloc0(sizeof(*p));
|
332 |
p->value = g_malloc0(sizeof(*p->value));
|
333 |
p->value->integer = value_int; |
334 |
p->value->boolean = value_bool; |
335 |
p->value->string = value_str; |
336 |
|
337 |
p->next = head; |
338 |
head = p; |
339 |
} |
340 |
|
341 |
visit_type_TestStructList(data->ov, &head, NULL, &errp);
|
342 |
g_assert(!error_is_set(&errp)); |
343 |
|
344 |
obj = qmp_output_get_qobject(data->qov); |
345 |
g_assert(obj != NULL);
|
346 |
g_assert(qobject_type(obj) == QTYPE_QLIST); |
347 |
|
348 |
qlist = qobject_to_qlist(obj); |
349 |
g_assert(!qlist_empty(qlist)); |
350 |
|
351 |
i = 0;
|
352 |
QLIST_FOREACH_ENTRY(qlist, entry) { |
353 |
QDict *qdict; |
354 |
|
355 |
g_assert(qobject_type(entry->value) == QTYPE_QDICT); |
356 |
qdict = qobject_to_qdict(entry->value); |
357 |
g_assert_cmpint(qdict_size(qdict), ==, 3);
|
358 |
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int);
|
359 |
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool);
|
360 |
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, value_str);
|
361 |
i++; |
362 |
} |
363 |
g_assert_cmpint(i, ==, max_items); |
364 |
|
365 |
QDECREF(qlist); |
366 |
|
367 |
for (p = head; p;) {
|
368 |
TestStructList *tmp = p->next; |
369 |
g_free(p->value); |
370 |
g_free(p); |
371 |
p = tmp; |
372 |
} |
373 |
} |
374 |
|
375 |
static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data, |
376 |
const void *unused) |
377 |
{ |
378 |
UserDefNestedList *p, *head = NULL;
|
379 |
const char string[] = "foo bar"; |
380 |
int i, max_count = 1024; |
381 |
|
382 |
for (i = 0; i < max_count; i++) { |
383 |
p = g_malloc0(sizeof(*p));
|
384 |
p->value = g_malloc0(sizeof(*p->value));
|
385 |
|
386 |
p->value->string0 = g_strdup(string); |
387 |
p->value->dict1.string1 = g_strdup(string); |
388 |
p->value->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
|
389 |
p->value->dict1.dict2.userdef1->string = g_strdup(string); |
390 |
p->value->dict1.dict2.userdef1->integer = 42;
|
391 |
p->value->dict1.dict2.string2 = g_strdup(string); |
392 |
p->value->dict1.has_dict3 = false;
|
393 |
|
394 |
p->next = head; |
395 |
head = p; |
396 |
} |
397 |
|
398 |
qapi_free_UserDefNestedList(head); |
399 |
} |
400 |
|
401 |
static void test_visitor_out_union(TestOutputVisitorData *data, |
402 |
const void *unused) |
403 |
{ |
404 |
QObject *arg, *qvalue; |
405 |
QDict *qdict, *value; |
406 |
|
407 |
Error *err = NULL;
|
408 |
|
409 |
UserDefUnion *tmp = g_malloc0(sizeof(UserDefUnion));
|
410 |
tmp->kind = USER_DEF_UNION_KIND_A; |
411 |
tmp->a = g_malloc0(sizeof(UserDefA));
|
412 |
tmp->a->boolean = true;
|
413 |
|
414 |
visit_type_UserDefUnion(data->ov, &tmp, NULL, &err);
|
415 |
g_assert(err == NULL);
|
416 |
arg = qmp_output_get_qobject(data->qov); |
417 |
|
418 |
g_assert(qobject_type(arg) == QTYPE_QDICT); |
419 |
qdict = qobject_to_qdict(arg); |
420 |
|
421 |
g_assert_cmpstr(qdict_get_str(qdict, "type"), ==, "a"); |
422 |
|
423 |
qvalue = qdict_get(qdict, "data");
|
424 |
g_assert(data != NULL);
|
425 |
g_assert(qobject_type(qvalue) == QTYPE_QDICT); |
426 |
value = qobject_to_qdict(qvalue); |
427 |
g_assert_cmpint(qdict_get_bool(value, "boolean"), ==, true); |
428 |
|
429 |
qapi_free_UserDefUnion(tmp); |
430 |
QDECREF(qdict); |
431 |
} |
432 |
|
433 |
static void output_visitor_test_add(const char *testpath, |
434 |
TestOutputVisitorData *data, |
435 |
void (*test_func)(TestOutputVisitorData *data, const void *user_data)) |
436 |
{ |
437 |
g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup, |
438 |
test_func, visitor_output_teardown); |
439 |
} |
440 |
|
441 |
int main(int argc, char **argv) |
442 |
{ |
443 |
TestOutputVisitorData out_visitor_data; |
444 |
|
445 |
g_test_init(&argc, &argv, NULL);
|
446 |
|
447 |
output_visitor_test_add("/visitor/output/int",
|
448 |
&out_visitor_data, test_visitor_out_int); |
449 |
output_visitor_test_add("/visitor/output/bool",
|
450 |
&out_visitor_data, test_visitor_out_bool); |
451 |
output_visitor_test_add("/visitor/output/number",
|
452 |
&out_visitor_data, test_visitor_out_number); |
453 |
output_visitor_test_add("/visitor/output/string",
|
454 |
&out_visitor_data, test_visitor_out_string); |
455 |
output_visitor_test_add("/visitor/output/no-string",
|
456 |
&out_visitor_data, test_visitor_out_no_string); |
457 |
output_visitor_test_add("/visitor/output/enum",
|
458 |
&out_visitor_data, test_visitor_out_enum); |
459 |
output_visitor_test_add("/visitor/output/enum-errors",
|
460 |
&out_visitor_data, test_visitor_out_enum_errors); |
461 |
output_visitor_test_add("/visitor/output/struct",
|
462 |
&out_visitor_data, test_visitor_out_struct); |
463 |
output_visitor_test_add("/visitor/output/struct-nested",
|
464 |
&out_visitor_data, test_visitor_out_struct_nested); |
465 |
output_visitor_test_add("/visitor/output/struct-errors",
|
466 |
&out_visitor_data, test_visitor_out_struct_errors); |
467 |
output_visitor_test_add("/visitor/output/list",
|
468 |
&out_visitor_data, test_visitor_out_list); |
469 |
output_visitor_test_add("/visitor/output/list-qapi-free",
|
470 |
&out_visitor_data, test_visitor_out_list_qapi_free); |
471 |
output_visitor_test_add("/visitor/output/union",
|
472 |
&out_visitor_data, test_visitor_out_union); |
473 |
|
474 |
g_test_run(); |
475 |
|
476 |
return 0; |
477 |
} |