]> git.proxmox.com Git - mirror_qemu.git/blame - tests/unit/test-visitor-serialization.c
Remove qemu-common.h include from most units
[mirror_qemu.git] / tests / unit / test-visitor-serialization.c
CommitLineData
2d496105
MR
1/*
2 * Unit-tests for visitor-based serialization
3 *
6446a592 4 * Copyright (C) 2014-2015 Red Hat, Inc.
2d496105
MR
5 * Copyright IBM, Corp. 2012
6 *
7 * Authors:
8 * Michael Roth <mdroth@linux.vnet.ibm.com>
9 *
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
12 */
13
681c28a3 14#include "qemu/osdep.h"
2d496105 15#include <float.h>
79ee7df8 16
2d496105 17#include "test-qapi-visit.h"
da34e65c 18#include "qapi/error.h"
c7eb39cb 19#include "qapi/qmp/qjson.h"
fc81fa1e 20#include "qapi/qmp/qstring.h"
b3db211f
DB
21#include "qapi/qobject-input-visitor.h"
22#include "qapi/qobject-output-visitor.h"
0d30b0a2
MR
23#include "qapi/string-input-visitor.h"
24#include "qapi/string-output-visitor.h"
8addacdd
MR
25#include "qapi/dealloc-visitor.h"
26
27enum PrimitiveTypeKind {
28 PTYPE_STRING = 0,
29 PTYPE_BOOLEAN,
30 PTYPE_NUMBER,
31 PTYPE_INTEGER,
32 PTYPE_U8,
33 PTYPE_U16,
34 PTYPE_U32,
35 PTYPE_U64,
36 PTYPE_S8,
37 PTYPE_S16,
38 PTYPE_S32,
39 PTYPE_S64,
40 PTYPE_EOL,
41};
2d496105
MR
42
43typedef struct PrimitiveType {
44 union {
45 const char *string;
46 bool boolean;
47 double number;
48 int64_t integer;
49 uint8_t u8;
50 uint16_t u16;
51 uint32_t u32;
52 uint64_t u64;
53 int8_t s8;
54 int16_t s16;
55 int32_t s32;
56 int64_t s64;
2d496105 57 } value;
8addacdd 58 enum PrimitiveTypeKind type;
2d496105
MR
59 const char *description;
60} PrimitiveType;
61
8addacdd
MR
62typedef struct PrimitiveList {
63 union {
64 strList *strings;
65 boolList *booleans;
66 numberList *numbers;
67 intList *integers;
68 int8List *s8_integers;
69 int16List *s16_integers;
70 int32List *s32_integers;
71 int64List *s64_integers;
72 uint8List *u8_integers;
73 uint16List *u16_integers;
74 uint32List *u32_integers;
75 uint64List *u64_integers;
76 } value;
77 enum PrimitiveTypeKind type;
78 const char *description;
79} PrimitiveList;
80
2d496105
MR
81/* test helpers */
82
8addacdd
MR
83typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
84
85static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
86{
2c0ef9f4 87 Visitor *v = qapi_dealloc_visitor_new();
8addacdd 88
2c0ef9f4 89 visit(v, &native_in, errp);
8addacdd 90
2c0ef9f4 91 visit_free(v);
8addacdd
MR
92}
93
2d496105
MR
94static void visit_primitive_type(Visitor *v, void **native, Error **errp)
95{
96 PrimitiveType *pt = *native;
97 switch(pt->type) {
98 case PTYPE_STRING:
51e72bc1 99 visit_type_str(v, NULL, (char **)&pt->value.string, errp);
2d496105
MR
100 break;
101 case PTYPE_BOOLEAN:
51e72bc1 102 visit_type_bool(v, NULL, &pt->value.boolean, errp);
2d496105
MR
103 break;
104 case PTYPE_NUMBER:
51e72bc1 105 visit_type_number(v, NULL, &pt->value.number, errp);
2d496105
MR
106 break;
107 case PTYPE_INTEGER:
51e72bc1 108 visit_type_int(v, NULL, &pt->value.integer, errp);
2d496105
MR
109 break;
110 case PTYPE_U8:
51e72bc1 111 visit_type_uint8(v, NULL, &pt->value.u8, errp);
2d496105
MR
112 break;
113 case PTYPE_U16:
51e72bc1 114 visit_type_uint16(v, NULL, &pt->value.u16, errp);
2d496105
MR
115 break;
116 case PTYPE_U32:
51e72bc1 117 visit_type_uint32(v, NULL, &pt->value.u32, errp);
2d496105
MR
118 break;
119 case PTYPE_U64:
51e72bc1 120 visit_type_uint64(v, NULL, &pt->value.u64, errp);
2d496105
MR
121 break;
122 case PTYPE_S8:
51e72bc1 123 visit_type_int8(v, NULL, &pt->value.s8, errp);
2d496105
MR
124 break;
125 case PTYPE_S16:
51e72bc1 126 visit_type_int16(v, NULL, &pt->value.s16, errp);
2d496105
MR
127 break;
128 case PTYPE_S32:
51e72bc1 129 visit_type_int32(v, NULL, &pt->value.s32, errp);
2d496105
MR
130 break;
131 case PTYPE_S64:
51e72bc1 132 visit_type_int64(v, NULL, &pt->value.s64, errp);
2d496105
MR
133 break;
134 case PTYPE_EOL:
dfc6f865 135 g_assert_not_reached();
2d496105
MR
136 }
137}
138
8addacdd
MR
139static void visit_primitive_list(Visitor *v, void **native, Error **errp)
140{
141 PrimitiveList *pl = *native;
142 switch (pl->type) {
143 case PTYPE_STRING:
51e72bc1 144 visit_type_strList(v, NULL, &pl->value.strings, errp);
8addacdd
MR
145 break;
146 case PTYPE_BOOLEAN:
51e72bc1 147 visit_type_boolList(v, NULL, &pl->value.booleans, errp);
8addacdd
MR
148 break;
149 case PTYPE_NUMBER:
51e72bc1 150 visit_type_numberList(v, NULL, &pl->value.numbers, errp);
8addacdd
MR
151 break;
152 case PTYPE_INTEGER:
51e72bc1 153 visit_type_intList(v, NULL, &pl->value.integers, errp);
8addacdd
MR
154 break;
155 case PTYPE_S8:
51e72bc1 156 visit_type_int8List(v, NULL, &pl->value.s8_integers, errp);
8addacdd
MR
157 break;
158 case PTYPE_S16:
51e72bc1 159 visit_type_int16List(v, NULL, &pl->value.s16_integers, errp);
8addacdd
MR
160 break;
161 case PTYPE_S32:
51e72bc1 162 visit_type_int32List(v, NULL, &pl->value.s32_integers, errp);
8addacdd
MR
163 break;
164 case PTYPE_S64:
51e72bc1 165 visit_type_int64List(v, NULL, &pl->value.s64_integers, errp);
8addacdd
MR
166 break;
167 case PTYPE_U8:
51e72bc1 168 visit_type_uint8List(v, NULL, &pl->value.u8_integers, errp);
8addacdd
MR
169 break;
170 case PTYPE_U16:
51e72bc1 171 visit_type_uint16List(v, NULL, &pl->value.u16_integers, errp);
8addacdd
MR
172 break;
173 case PTYPE_U32:
51e72bc1 174 visit_type_uint32List(v, NULL, &pl->value.u32_integers, errp);
8addacdd
MR
175 break;
176 case PTYPE_U64:
51e72bc1 177 visit_type_uint64List(v, NULL, &pl->value.u64_integers, errp);
8addacdd
MR
178 break;
179 default:
dfc6f865 180 g_assert_not_reached();
8addacdd
MR
181 }
182}
183
2d496105
MR
184
185static TestStruct *struct_create(void)
186{
187 TestStruct *ts = g_malloc0(sizeof(*ts));
188 ts->integer = -42;
189 ts->boolean = true;
190 ts->string = strdup("test string");
191 return ts;
192}
193
194static void struct_compare(TestStruct *ts1, TestStruct *ts2)
195{
196 g_assert(ts1);
197 g_assert(ts2);
198 g_assert_cmpint(ts1->integer, ==, ts2->integer);
199 g_assert(ts1->boolean == ts2->boolean);
200 g_assert_cmpstr(ts1->string, ==, ts2->string);
201}
202
203static void struct_cleanup(TestStruct *ts)
204{
205 g_free(ts->string);
206 g_free(ts);
207}
208
209static void visit_struct(Visitor *v, void **native, Error **errp)
210{
51e72bc1 211 visit_type_TestStruct(v, NULL, (TestStruct **)native, errp);
2d496105
MR
212}
213
b6fcf32d 214static UserDefTwo *nested_struct_create(void)
2d496105 215{
b6fcf32d 216 UserDefTwo *udnp = g_malloc0(sizeof(*udnp));
2d496105 217 udnp->string0 = strdup("test_string0");
6446a592
EB
218 udnp->dict1 = g_malloc0(sizeof(*udnp->dict1));
219 udnp->dict1->string1 = strdup("test_string1");
220 udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2));
221 udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1);
ddf21908 222 udnp->dict1->dict2->userdef->integer = 42;
6446a592
EB
223 udnp->dict1->dict2->userdef->string = strdup("test_string");
224 udnp->dict1->dict2->string = strdup("test_string2");
225 udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3));
226 udnp->dict1->has_dict3 = true;
227 udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1);
ddf21908 228 udnp->dict1->dict3->userdef->integer = 43;
6446a592
EB
229 udnp->dict1->dict3->userdef->string = strdup("test_string");
230 udnp->dict1->dict3->string = strdup("test_string3");
2d496105
MR
231 return udnp;
232}
233
b6fcf32d 234static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2)
2d496105
MR
235{
236 g_assert(udnp1);
237 g_assert(udnp2);
238 g_assert_cmpstr(udnp1->string0, ==, udnp2->string0);
6446a592 239 g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1);
ddf21908
EB
240 g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==,
241 udnp2->dict1->dict2->userdef->integer);
6446a592
EB
242 g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==,
243 udnp2->dict1->dict2->userdef->string);
244 g_assert_cmpstr(udnp1->dict1->dict2->string, ==,
245 udnp2->dict1->dict2->string);
246 g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3);
ddf21908
EB
247 g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==,
248 udnp2->dict1->dict3->userdef->integer);
6446a592
EB
249 g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==,
250 udnp2->dict1->dict3->userdef->string);
251 g_assert_cmpstr(udnp1->dict1->dict3->string, ==,
252 udnp2->dict1->dict3->string);
2d496105
MR
253}
254
b6fcf32d 255static void nested_struct_cleanup(UserDefTwo *udnp)
2d496105 256{
b6fcf32d 257 qapi_free_UserDefTwo(udnp);
2d496105
MR
258}
259
260static void visit_nested_struct(Visitor *v, void **native, Error **errp)
261{
51e72bc1 262 visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp);
2d496105
MR
263}
264
265static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
266{
51e72bc1 267 visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp);
2d496105
MR
268}
269
270/* test cases */
271
2d496105
MR
272typedef enum VisitorCapabilities {
273 VCAP_PRIMITIVES = 1,
274 VCAP_STRUCTURES = 2,
275 VCAP_LISTS = 4,
8addacdd 276 VCAP_PRIMITIVE_LISTS = 8,
2d496105
MR
277} VisitorCapabilities;
278
279typedef struct SerializeOps {
280 void (*serialize)(void *native_in, void **datap,
281 VisitorFunc visit, Error **errp);
282 void (*deserialize)(void **native_out, void *datap,
283 VisitorFunc visit, Error **errp);
284 void (*cleanup)(void *datap);
285 const char *type;
286 VisitorCapabilities caps;
287} SerializeOps;
288
289typedef struct TestArgs {
290 const SerializeOps *ops;
291 void *test_data;
292} TestArgs;
293
2d496105
MR
294static void test_primitives(gconstpointer opaque)
295{
296 TestArgs *args = (TestArgs *) opaque;
297 const SerializeOps *ops = args->ops;
298 PrimitiveType *pt = args->test_data;
299 PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
2d496105 300 void *serialize_data;
2d496105
MR
301
302 pt_copy->type = pt->type;
3f66f764
EB
303 ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort);
304 ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type,
305 &error_abort);
2d496105 306
2d496105 307 g_assert(pt_copy != NULL);
28f1c1f6
MA
308 switch (pt->type) {
309 case PTYPE_STRING:
2d496105 310 g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
2bd01ac1 311 g_free((char *)pt_copy->value.string);
28f1c1f6
MA
312 break;
313 case PTYPE_BOOLEAN:
314 g_assert_cmpint(pt->value.boolean, ==, pt->value.boolean);
315 break;
316 case PTYPE_NUMBER:
2a02c139 317 g_assert_cmpfloat(pt->value.number, ==, pt_copy->value.number);
28f1c1f6
MA
318 break;
319 case PTYPE_INTEGER:
320 g_assert_cmpint(pt->value.integer, ==, pt_copy->value.integer);
321 break;
322 case PTYPE_U8:
323 g_assert_cmpuint(pt->value.u8, ==, pt_copy->value.u8);
324 break;
325 case PTYPE_U16:
326 g_assert_cmpuint(pt->value.u16, ==, pt_copy->value.u16);
327 break;
328 case PTYPE_U32:
329 g_assert_cmpuint(pt->value.u32, ==, pt_copy->value.u32);
330 break;
331 case PTYPE_U64:
332 g_assert_cmpuint(pt->value.u64, ==, pt_copy->value.u64);
333 break;
334 case PTYPE_S8:
335 g_assert_cmpint(pt->value.s8, ==, pt_copy->value.s8);
336 break;
337 case PTYPE_S16:
338 g_assert_cmpint(pt->value.s16, ==, pt_copy->value.s16);
339 break;
340 case PTYPE_S32:
341 g_assert_cmpint(pt->value.s32, ==, pt_copy->value.s32);
342 break;
343 case PTYPE_S64:
344 g_assert_cmpint(pt->value.s64, ==, pt_copy->value.s64);
345 break;
346 case PTYPE_EOL:
347 g_assert_not_reached();
2d496105
MR
348 }
349
350 ops->cleanup(serialize_data);
351 g_free(args);
2bd01ac1 352 g_free(pt_copy);
2d496105
MR
353}
354
8addacdd
MR
355static void test_primitive_lists(gconstpointer opaque)
356{
357 TestArgs *args = (TestArgs *) opaque;
358 const SerializeOps *ops = args->ops;
359 PrimitiveType *pt = args->test_data;
748bfb4e
SW
360 PrimitiveList pl = { .value = { NULL } };
361 PrimitiveList pl_copy = { .value = { NULL } };
8addacdd 362 PrimitiveList *pl_copy_ptr = &pl_copy;
8addacdd
MR
363 void *serialize_data;
364 void *cur_head = NULL;
365 int i;
366
367 pl.type = pl_copy.type = pt->type;
368
369 /* build up our list of primitive types */
370 for (i = 0; i < 32; i++) {
371 switch (pl.type) {
372 case PTYPE_STRING: {
54aa3de7 373 QAPI_LIST_PREPEND(pl.value.strings, g_strdup(pt->value.string));
8addacdd
MR
374 break;
375 }
376 case PTYPE_INTEGER: {
54aa3de7 377 QAPI_LIST_PREPEND(pl.value.integers, pt->value.integer);
8addacdd
MR
378 break;
379 }
380 case PTYPE_S8: {
54aa3de7 381 QAPI_LIST_PREPEND(pl.value.s8_integers, pt->value.s8);
8addacdd
MR
382 break;
383 }
384 case PTYPE_S16: {
54aa3de7 385 QAPI_LIST_PREPEND(pl.value.s16_integers, pt->value.s16);
8addacdd
MR
386 break;
387 }
388 case PTYPE_S32: {
54aa3de7 389 QAPI_LIST_PREPEND(pl.value.s32_integers, pt->value.s32);
8addacdd
MR
390 break;
391 }
392 case PTYPE_S64: {
54aa3de7 393 QAPI_LIST_PREPEND(pl.value.s64_integers, pt->value.s64);
8addacdd
MR
394 break;
395 }
396 case PTYPE_U8: {
54aa3de7 397 QAPI_LIST_PREPEND(pl.value.u8_integers, pt->value.u8);
8addacdd
MR
398 break;
399 }
400 case PTYPE_U16: {
54aa3de7 401 QAPI_LIST_PREPEND(pl.value.u16_integers, pt->value.u16);
8addacdd
MR
402 break;
403 }
404 case PTYPE_U32: {
54aa3de7 405 QAPI_LIST_PREPEND(pl.value.u32_integers, pt->value.u32);
8addacdd
MR
406 break;
407 }
408 case PTYPE_U64: {
54aa3de7 409 QAPI_LIST_PREPEND(pl.value.u64_integers, pt->value.u64);
8addacdd
MR
410 break;
411 }
412 case PTYPE_NUMBER: {
54aa3de7 413 QAPI_LIST_PREPEND(pl.value.numbers, pt->value.number);
8addacdd
MR
414 break;
415 }
416 case PTYPE_BOOLEAN: {
54aa3de7 417 QAPI_LIST_PREPEND(pl.value.booleans, pt->value.boolean);
8addacdd
MR
418 break;
419 }
420 default:
dfc6f865 421 g_assert_not_reached();
8addacdd
MR
422 }
423 }
424
3f66f764
EB
425 ops->serialize((void **)&pl, &serialize_data, visit_primitive_list,
426 &error_abort);
427 ops->deserialize((void **)&pl_copy_ptr, serialize_data,
428 visit_primitive_list, &error_abort);
8addacdd 429
8addacdd
MR
430 i = 0;
431
432 /* compare our deserialized list of primitives to the original */
433 do {
434 switch (pl_copy.type) {
435 case PTYPE_STRING: {
436 strList *ptr;
437 if (cur_head) {
438 ptr = cur_head;
439 cur_head = ptr->next;
440 } else {
441 cur_head = ptr = pl_copy.value.strings;
442 }
443 g_assert_cmpstr(pt->value.string, ==, ptr->value);
444 break;
445 }
446 case PTYPE_INTEGER: {
447 intList *ptr;
448 if (cur_head) {
449 ptr = cur_head;
450 cur_head = ptr->next;
451 } else {
452 cur_head = ptr = pl_copy.value.integers;
453 }
454 g_assert_cmpint(pt->value.integer, ==, ptr->value);
455 break;
456 }
457 case PTYPE_S8: {
458 int8List *ptr;
459 if (cur_head) {
460 ptr = cur_head;
461 cur_head = ptr->next;
462 } else {
463 cur_head = ptr = pl_copy.value.s8_integers;
464 }
465 g_assert_cmpint(pt->value.s8, ==, ptr->value);
466 break;
467 }
468 case PTYPE_S16: {
469 int16List *ptr;
470 if (cur_head) {
471 ptr = cur_head;
472 cur_head = ptr->next;
473 } else {
474 cur_head = ptr = pl_copy.value.s16_integers;
475 }
476 g_assert_cmpint(pt->value.s16, ==, ptr->value);
477 break;
478 }
479 case PTYPE_S32: {
480 int32List *ptr;
481 if (cur_head) {
482 ptr = cur_head;
483 cur_head = ptr->next;
484 } else {
485 cur_head = ptr = pl_copy.value.s32_integers;
486 }
487 g_assert_cmpint(pt->value.s32, ==, ptr->value);
488 break;
489 }
490 case PTYPE_S64: {
491 int64List *ptr;
492 if (cur_head) {
493 ptr = cur_head;
494 cur_head = ptr->next;
495 } else {
496 cur_head = ptr = pl_copy.value.s64_integers;
497 }
498 g_assert_cmpint(pt->value.s64, ==, ptr->value);
499 break;
500 }
501 case PTYPE_U8: {
502 uint8List *ptr;
503 if (cur_head) {
504 ptr = cur_head;
505 cur_head = ptr->next;
506 } else {
507 cur_head = ptr = pl_copy.value.u8_integers;
508 }
509 g_assert_cmpint(pt->value.u8, ==, ptr->value);
510 break;
511 }
512 case PTYPE_U16: {
513 uint16List *ptr;
514 if (cur_head) {
515 ptr = cur_head;
516 cur_head = ptr->next;
517 } else {
518 cur_head = ptr = pl_copy.value.u16_integers;
519 }
520 g_assert_cmpint(pt->value.u16, ==, ptr->value);
521 break;
522 }
523 case PTYPE_U32: {
524 uint32List *ptr;
525 if (cur_head) {
526 ptr = cur_head;
527 cur_head = ptr->next;
528 } else {
529 cur_head = ptr = pl_copy.value.u32_integers;
530 }
531 g_assert_cmpint(pt->value.u32, ==, ptr->value);
532 break;
533 }
534 case PTYPE_U64: {
535 uint64List *ptr;
536 if (cur_head) {
537 ptr = cur_head;
538 cur_head = ptr->next;
539 } else {
540 cur_head = ptr = pl_copy.value.u64_integers;
541 }
542 g_assert_cmpint(pt->value.u64, ==, ptr->value);
543 break;
544 }
545 case PTYPE_NUMBER: {
546 numberList *ptr;
547 GString *double_expected = g_string_new("");
548 GString *double_actual = g_string_new("");
549 if (cur_head) {
550 ptr = cur_head;
551 cur_head = ptr->next;
552 } else {
553 cur_head = ptr = pl_copy.value.numbers;
554 }
555 /* we serialize with %f for our reference visitors, so rather than
556 * fuzzy floating math to test "equality", just compare the
557 * formatted values
558 */
559 g_string_printf(double_expected, "%.6f", pt->value.number);
560 g_string_printf(double_actual, "%.6f", ptr->value);
561 g_assert_cmpstr(double_actual->str, ==, double_expected->str);
562 g_string_free(double_expected, true);
563 g_string_free(double_actual, true);
564 break;
565 }
566 case PTYPE_BOOLEAN: {
567 boolList *ptr;
568 if (cur_head) {
569 ptr = cur_head;
570 cur_head = ptr->next;
571 } else {
572 cur_head = ptr = pl_copy.value.booleans;
573 }
574 g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
575 break;
576 }
577 default:
dfc6f865 578 g_assert_not_reached();
8addacdd
MR
579 }
580 i++;
581 } while (cur_head);
582
583 g_assert_cmpint(i, ==, 33);
584
585 ops->cleanup(serialize_data);
3f66f764
EB
586 dealloc_helper(&pl, visit_primitive_list, &error_abort);
587 dealloc_helper(&pl_copy, visit_primitive_list, &error_abort);
8addacdd
MR
588 g_free(args);
589}
590
2d496105
MR
591static void test_struct(gconstpointer opaque)
592{
593 TestArgs *args = (TestArgs *) opaque;
594 const SerializeOps *ops = args->ops;
595 TestStruct *ts = struct_create();
596 TestStruct *ts_copy = NULL;
2d496105
MR
597 void *serialize_data;
598
3f66f764
EB
599 ops->serialize(ts, &serialize_data, visit_struct, &error_abort);
600 ops->deserialize((void **)&ts_copy, serialize_data, visit_struct,
601 &error_abort);
2d496105 602
2d496105
MR
603 struct_compare(ts, ts_copy);
604
605 struct_cleanup(ts);
606 struct_cleanup(ts_copy);
607
608 ops->cleanup(serialize_data);
609 g_free(args);
610}
611
612static void test_nested_struct(gconstpointer opaque)
613{
614 TestArgs *args = (TestArgs *) opaque;
615 const SerializeOps *ops = args->ops;
b6fcf32d
EB
616 UserDefTwo *udnp = nested_struct_create();
617 UserDefTwo *udnp_copy = NULL;
2d496105 618 void *serialize_data;
b6fcf32d 619
3f66f764 620 ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort);
b6fcf32d 621 ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct,
3f66f764 622 &error_abort);
2d496105 623
2d496105
MR
624 nested_struct_compare(udnp, udnp_copy);
625
626 nested_struct_cleanup(udnp);
627 nested_struct_cleanup(udnp_copy);
628
629 ops->cleanup(serialize_data);
630 g_free(args);
631}
632
633static void test_nested_struct_list(gconstpointer opaque)
634{
635 TestArgs *args = (TestArgs *) opaque;
636 const SerializeOps *ops = args->ops;
b6fcf32d 637 UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL;
2d496105
MR
638 void *serialize_data;
639 int i = 0;
640
641 for (i = 0; i < 8; i++) {
54aa3de7 642 QAPI_LIST_PREPEND(listp, nested_struct_create());
2d496105 643 }
b6fcf32d 644
3f66f764
EB
645 ops->serialize(listp, &serialize_data, visit_nested_struct_list,
646 &error_abort);
2d496105 647 ops->deserialize((void **)&listp_copy, serialize_data,
3f66f764 648 visit_nested_struct_list, &error_abort);
2d496105
MR
649
650 tmp = listp;
651 tmp_copy = listp_copy;
652 while (listp_copy) {
653 g_assert(listp);
654 nested_struct_compare(listp->value, listp_copy->value);
655 listp = listp->next;
656 listp_copy = listp_copy->next;
657 }
658
b6fcf32d
EB
659 qapi_free_UserDefTwoList(tmp);
660 qapi_free_UserDefTwoList(tmp_copy);
2d496105
MR
661
662 ops->cleanup(serialize_data);
663 g_free(args);
664}
665
748bfb4e 666static PrimitiveType pt_values[] = {
2d496105
MR
667 /* string tests */
668 {
669 .description = "string_empty",
670 .type = PTYPE_STRING,
671 .value.string = "",
672 },
673 {
674 .description = "string_whitespace",
675 .type = PTYPE_STRING,
676 .value.string = "a b c\td",
677 },
678 {
679 .description = "string_newlines",
680 .type = PTYPE_STRING,
681 .value.string = "a\nb\n",
682 },
683 {
684 .description = "string_commas",
685 .type = PTYPE_STRING,
686 .value.string = "a,b, c,d",
687 },
688 {
689 .description = "string_single_quoted",
690 .type = PTYPE_STRING,
691 .value.string = "'a b',cd",
692 },
693 {
694 .description = "string_double_quoted",
695 .type = PTYPE_STRING,
696 .value.string = "\"a b\",cd",
697 },
698 /* boolean tests */
699 {
700 .description = "boolean_true1",
701 .type = PTYPE_BOOLEAN,
702 .value.boolean = true,
703 },
704 {
705 .description = "boolean_true2",
706 .type = PTYPE_BOOLEAN,
707 .value.boolean = 8,
708 },
709 {
710 .description = "boolean_true3",
711 .type = PTYPE_BOOLEAN,
712 .value.boolean = -1,
713 },
714 {
715 .description = "boolean_false1",
716 .type = PTYPE_BOOLEAN,
717 .value.boolean = false,
718 },
719 {
720 .description = "boolean_false2",
721 .type = PTYPE_BOOLEAN,
722 .value.boolean = 0,
723 },
724 /* number tests (double) */
2d496105
MR
725 {
726 .description = "number_sanity1",
727 .type = PTYPE_NUMBER,
728 .value.number = -1,
729 },
730 {
731 .description = "number_sanity2",
732 .type = PTYPE_NUMBER,
2a02c139 733 .value.number = 3.141593,
2d496105
MR
734 },
735 {
736 .description = "number_min",
737 .type = PTYPE_NUMBER,
738 .value.number = DBL_MIN,
739 },
740 {
741 .description = "number_max",
742 .type = PTYPE_NUMBER,
743 .value.number = DBL_MAX,
744 },
745 /* integer tests (int64) */
746 {
747 .description = "integer_sanity1",
748 .type = PTYPE_INTEGER,
749 .value.integer = -1,
750 },
751 {
752 .description = "integer_sanity2",
753 .type = PTYPE_INTEGER,
754 .value.integer = INT64_MAX / 2 + 1,
755 },
756 {
757 .description = "integer_min",
758 .type = PTYPE_INTEGER,
759 .value.integer = INT64_MIN,
760 },
761 {
762 .description = "integer_max",
763 .type = PTYPE_INTEGER,
764 .value.integer = INT64_MAX,
765 },
766 /* uint8 tests */
767 {
768 .description = "uint8_sanity1",
769 .type = PTYPE_U8,
770 .value.u8 = 1,
771 },
772 {
773 .description = "uint8_sanity2",
774 .type = PTYPE_U8,
775 .value.u8 = UINT8_MAX / 2 + 1,
776 },
777 {
778 .description = "uint8_min",
779 .type = PTYPE_U8,
780 .value.u8 = 0,
781 },
782 {
783 .description = "uint8_max",
784 .type = PTYPE_U8,
785 .value.u8 = UINT8_MAX,
786 },
787 /* uint16 tests */
788 {
789 .description = "uint16_sanity1",
790 .type = PTYPE_U16,
791 .value.u16 = 1,
792 },
793 {
794 .description = "uint16_sanity2",
795 .type = PTYPE_U16,
796 .value.u16 = UINT16_MAX / 2 + 1,
797 },
798 {
799 .description = "uint16_min",
800 .type = PTYPE_U16,
801 .value.u16 = 0,
802 },
803 {
804 .description = "uint16_max",
805 .type = PTYPE_U16,
806 .value.u16 = UINT16_MAX,
807 },
808 /* uint32 tests */
809 {
810 .description = "uint32_sanity1",
811 .type = PTYPE_U32,
812 .value.u32 = 1,
813 },
814 {
815 .description = "uint32_sanity2",
816 .type = PTYPE_U32,
817 .value.u32 = UINT32_MAX / 2 + 1,
818 },
819 {
820 .description = "uint32_min",
821 .type = PTYPE_U32,
822 .value.u32 = 0,
823 },
824 {
825 .description = "uint32_max",
826 .type = PTYPE_U32,
827 .value.u32 = UINT32_MAX,
828 },
829 /* uint64 tests */
830 {
831 .description = "uint64_sanity1",
832 .type = PTYPE_U64,
833 .value.u64 = 1,
834 },
835 {
836 .description = "uint64_sanity2",
837 .type = PTYPE_U64,
838 .value.u64 = UINT64_MAX / 2 + 1,
839 },
840 {
841 .description = "uint64_min",
842 .type = PTYPE_U64,
843 .value.u64 = 0,
844 },
845 {
846 .description = "uint64_max",
847 .type = PTYPE_U64,
848 .value.u64 = UINT64_MAX,
849 },
850 /* int8 tests */
851 {
852 .description = "int8_sanity1",
853 .type = PTYPE_S8,
854 .value.s8 = -1,
855 },
856 {
857 .description = "int8_sanity2",
858 .type = PTYPE_S8,
859 .value.s8 = INT8_MAX / 2 + 1,
860 },
861 {
862 .description = "int8_min",
863 .type = PTYPE_S8,
864 .value.s8 = INT8_MIN,
865 },
866 {
867 .description = "int8_max",
868 .type = PTYPE_S8,
869 .value.s8 = INT8_MAX,
870 },
871 /* int16 tests */
872 {
873 .description = "int16_sanity1",
874 .type = PTYPE_S16,
875 .value.s16 = -1,
876 },
877 {
878 .description = "int16_sanity2",
879 .type = PTYPE_S16,
880 .value.s16 = INT16_MAX / 2 + 1,
881 },
882 {
883 .description = "int16_min",
884 .type = PTYPE_S16,
885 .value.s16 = INT16_MIN,
886 },
887 {
888 .description = "int16_max",
889 .type = PTYPE_S16,
890 .value.s16 = INT16_MAX,
891 },
892 /* int32 tests */
893 {
894 .description = "int32_sanity1",
895 .type = PTYPE_S32,
896 .value.s32 = -1,
897 },
898 {
899 .description = "int32_sanity2",
900 .type = PTYPE_S32,
901 .value.s32 = INT32_MAX / 2 + 1,
902 },
903 {
904 .description = "int32_min",
905 .type = PTYPE_S32,
906 .value.s32 = INT32_MIN,
907 },
908 {
909 .description = "int32_max",
910 .type = PTYPE_S32,
911 .value.s32 = INT32_MAX,
912 },
913 /* int64 tests */
914 {
915 .description = "int64_sanity1",
916 .type = PTYPE_S64,
917 .value.s64 = -1,
918 },
919 {
920 .description = "int64_sanity2",
921 .type = PTYPE_S64,
922 .value.s64 = INT64_MAX / 2 + 1,
923 },
924 {
925 .description = "int64_min",
926 .type = PTYPE_S64,
927 .value.s64 = INT64_MIN,
928 },
929 {
930 .description = "int64_max",
931 .type = PTYPE_S64,
932 .value.s64 = INT64_MAX,
933 },
934 { .type = PTYPE_EOL }
935};
936
937/* visitor-specific op implementations */
938
939typedef struct QmpSerializeData {
3b098d56
EB
940 Visitor *qov;
941 QObject *obj;
b70ce101 942 Visitor *qiv;
2d496105
MR
943} QmpSerializeData;
944
945static void qmp_serialize(void *native_in, void **datap,
946 VisitorFunc visit, Error **errp)
947{
948 QmpSerializeData *d = g_malloc0(sizeof(*d));
949
7d5e199a 950 d->qov = qobject_output_visitor_new(&d->obj);
3b098d56 951 visit(d->qov, &native_in, errp);
2d496105
MR
952 *datap = d;
953}
954
955static void qmp_deserialize(void **native_out, void *datap,
956 VisitorFunc visit, Error **errp)
957{
958 QmpSerializeData *d = datap;
eab3a467 959 GString *output_json;
ad7f375d
MR
960 QObject *obj_orig, *obj;
961
3b098d56
EB
962 visit_complete(d->qov, &d->obj);
963 obj_orig = d->obj;
ad7f375d 964 output_json = qobject_to_json(obj_orig);
eab3a467 965 obj = qobject_from_json(output_json->str, &error_abort);
2d496105 966
eab3a467 967 g_string_free(output_json, true);
048abb7b 968 d->qiv = qobject_input_visitor_new(obj);
cb3e7f08
MAL
969 qobject_unref(obj_orig);
970 qobject_unref(obj);
b70ce101 971 visit(d->qiv, native_out, errp);
2d496105
MR
972}
973
974static void qmp_cleanup(void *datap)
975{
976 QmpSerializeData *d = datap;
3b098d56 977 visit_free(d->qov);
b70ce101 978 visit_free(d->qiv);
2bd01ac1
SB
979
980 g_free(d);
2d496105
MR
981}
982
0d30b0a2 983typedef struct StringSerializeData {
2bd01ac1 984 char *string;
3b098d56 985 Visitor *sov;
7a0525c7 986 Visitor *siv;
0d30b0a2
MR
987} StringSerializeData;
988
989static void string_serialize(void *native_in, void **datap,
990 VisitorFunc visit, Error **errp)
991{
992 StringSerializeData *d = g_malloc0(sizeof(*d));
993
3b098d56
EB
994 d->sov = string_output_visitor_new(false, &d->string);
995 visit(d->sov, &native_in, errp);
0d30b0a2
MR
996 *datap = d;
997}
998
999static void string_deserialize(void **native_out, void *datap,
1000 VisitorFunc visit, Error **errp)
1001{
1002 StringSerializeData *d = datap;
1003
3b098d56 1004 visit_complete(d->sov, &d->string);
2bd01ac1 1005 d->siv = string_input_visitor_new(d->string);
7a0525c7 1006 visit(d->siv, native_out, errp);
0d30b0a2
MR
1007}
1008
1009static void string_cleanup(void *datap)
1010{
1011 StringSerializeData *d = datap;
2bd01ac1 1012
3b098d56 1013 visit_free(d->sov);
7a0525c7 1014 visit_free(d->siv);
2bd01ac1
SB
1015 g_free(d->string);
1016 g_free(d);
0d30b0a2
MR
1017}
1018
2d496105
MR
1019/* visitor registration, test harness */
1020
1021/* note: to function interchangeably as a serialization mechanism your
1022 * visitor test implementation should pass the test cases for all visitor
1023 * capabilities: primitives, structures, and lists
1024 */
1025static const SerializeOps visitors[] = {
1026 {
1027 .type = "QMP",
1028 .serialize = qmp_serialize,
1029 .deserialize = qmp_deserialize,
1030 .cleanup = qmp_cleanup,
8addacdd
MR
1031 .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
1032 VCAP_PRIMITIVE_LISTS
2d496105 1033 },
0d30b0a2
MR
1034 {
1035 .type = "String",
1036 .serialize = string_serialize,
1037 .deserialize = string_deserialize,
1038 .cleanup = string_cleanup,
1039 .caps = VCAP_PRIMITIVES
1040 },
2d496105
MR
1041 { NULL }
1042};
1043
1044static void add_visitor_type(const SerializeOps *ops)
1045{
fdf235ba 1046 char testname_prefix[32];
2d496105
MR
1047 char testname[128];
1048 TestArgs *args;
1049 int i = 0;
1050
1051 sprintf(testname_prefix, "/visitor/serialization/%s", ops->type);
1052
1053 if (ops->caps & VCAP_PRIMITIVES) {
1054 while (pt_values[i].type != PTYPE_EOL) {
1055 sprintf(testname, "%s/primitives/%s", testname_prefix,
1056 pt_values[i].description);
1057 args = g_malloc0(sizeof(*args));
1058 args->ops = ops;
1059 args->test_data = &pt_values[i];
1060 g_test_add_data_func(testname, args, test_primitives);
1061 i++;
1062 }
1063 }
1064
1065 if (ops->caps & VCAP_STRUCTURES) {
1066 sprintf(testname, "%s/struct", testname_prefix);
1067 args = g_malloc0(sizeof(*args));
1068 args->ops = ops;
1069 args->test_data = NULL;
1070 g_test_add_data_func(testname, args, test_struct);
1071
1072 sprintf(testname, "%s/nested_struct", testname_prefix);
1073 args = g_malloc0(sizeof(*args));
1074 args->ops = ops;
1075 args->test_data = NULL;
1076 g_test_add_data_func(testname, args, test_nested_struct);
1077 }
1078
1079 if (ops->caps & VCAP_LISTS) {
1080 sprintf(testname, "%s/nested_struct_list", testname_prefix);
1081 args = g_malloc0(sizeof(*args));
1082 args->ops = ops;
1083 args->test_data = NULL;
1084 g_test_add_data_func(testname, args, test_nested_struct_list);
1085 }
8addacdd
MR
1086
1087 if (ops->caps & VCAP_PRIMITIVE_LISTS) {
1088 i = 0;
1089 while (pt_values[i].type != PTYPE_EOL) {
1090 sprintf(testname, "%s/primitive_list/%s", testname_prefix,
1091 pt_values[i].description);
1092 args = g_malloc0(sizeof(*args));
1093 args->ops = ops;
1094 args->test_data = &pt_values[i];
1095 g_test_add_data_func(testname, args, test_primitive_lists);
1096 i++;
1097 }
1098 }
2d496105
MR
1099}
1100
1101int main(int argc, char **argv)
1102{
1103 int i = 0;
1104
1105 g_test_init(&argc, &argv, NULL);
1106
1107 while (visitors[i].type != NULL) {
1108 add_visitor_type(&visitors[i]);
1109 i++;
1110 }
1111
1112 g_test_run();
1113
1114 return 0;
1115}