Statistics
| Branch: | Revision:

root / tests / test-visitor-serialization.c @ 8addacdd

History | View | Annotate | Download (33.3 kB)

1
/*
2
 * Unit-tests for visitor-based serialization
3
 *
4
 * Copyright IBM, Corp. 2012
5
 *
6
 * Authors:
7
 *  Michael Roth <mdroth@linux.vnet.ibm.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 <stdlib.h>
15
#include <stdint.h>
16
#include <float.h>
17

    
18
#include "qemu-common.h"
19
#include "test-qapi-types.h"
20
#include "test-qapi-visit.h"
21
#include "qapi/qmp/types.h"
22
#include "qapi/qmp-input-visitor.h"
23
#include "qapi/qmp-output-visitor.h"
24
#include "qapi/string-input-visitor.h"
25
#include "qapi/string-output-visitor.h"
26
#include "qapi-types.h"
27
#include "qapi-visit.h"
28
#include "qapi/dealloc-visitor.h"
29

    
30
enum PrimitiveTypeKind {
31
    PTYPE_STRING = 0,
32
    PTYPE_BOOLEAN,
33
    PTYPE_NUMBER,
34
    PTYPE_INTEGER,
35
    PTYPE_U8,
36
    PTYPE_U16,
37
    PTYPE_U32,
38
    PTYPE_U64,
39
    PTYPE_S8,
40
    PTYPE_S16,
41
    PTYPE_S32,
42
    PTYPE_S64,
43
    PTYPE_EOL,
44
};
45

    
46
typedef struct PrimitiveType {
47
    union {
48
        const char *string;
49
        bool boolean;
50
        double number;
51
        int64_t integer;
52
        uint8_t u8;
53
        uint16_t u16;
54
        uint32_t u32;
55
        uint64_t u64;
56
        int8_t s8;
57
        int16_t s16;
58
        int32_t s32;
59
        int64_t s64;
60
        intmax_t max;
61
    } value;
62
    enum PrimitiveTypeKind type;
63
    const char *description;
64
} PrimitiveType;
65

    
66
typedef struct PrimitiveList {
67
    union {
68
        strList *strings;
69
        boolList *booleans;
70
        numberList *numbers;
71
        intList *integers;
72
        int8List *s8_integers;
73
        int16List *s16_integers;
74
        int32List *s32_integers;
75
        int64List *s64_integers;
76
        uint8List *u8_integers;
77
        uint16List *u16_integers;
78
        uint32List *u32_integers;
79
        uint64List *u64_integers;
80
    } value;
81
    enum PrimitiveTypeKind type;
82
    const char *description;
83
} PrimitiveList;
84

    
85
/* test helpers */
86

    
87
typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
88

    
89
static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
90
{
91
    QapiDeallocVisitor *qdv = qapi_dealloc_visitor_new();
92

    
93
    visit(qapi_dealloc_get_visitor(qdv), &native_in, errp);
94

    
95
    qapi_dealloc_visitor_cleanup(qdv);
96
}
97

    
98
static void visit_primitive_type(Visitor *v, void **native, Error **errp)
99
{
100
    PrimitiveType *pt = *native;
101
    switch(pt->type) {
102
    case PTYPE_STRING:
103
        visit_type_str(v, (char **)&pt->value.string, NULL, errp);
104
        break;
105
    case PTYPE_BOOLEAN:
106
        visit_type_bool(v, &pt->value.boolean, NULL, errp);
107
        break;
108
    case PTYPE_NUMBER:
109
        visit_type_number(v, &pt->value.number, NULL, errp);
110
        break;
111
    case PTYPE_INTEGER:
112
        visit_type_int(v, &pt->value.integer, NULL, errp);
113
        break;
114
    case PTYPE_U8:
115
        visit_type_uint8(v, &pt->value.u8, NULL, errp);
116
        break;
117
    case PTYPE_U16:
118
        visit_type_uint16(v, &pt->value.u16, NULL, errp);
119
        break;
120
    case PTYPE_U32:
121
        visit_type_uint32(v, &pt->value.u32, NULL, errp);
122
        break;
123
    case PTYPE_U64:
124
        visit_type_uint64(v, &pt->value.u64, NULL, errp);
125
        break;
126
    case PTYPE_S8:
127
        visit_type_int8(v, &pt->value.s8, NULL, errp);
128
        break;
129
    case PTYPE_S16:
130
        visit_type_int16(v, &pt->value.s16, NULL, errp);
131
        break;
132
    case PTYPE_S32:
133
        visit_type_int32(v, &pt->value.s32, NULL, errp);
134
        break;
135
    case PTYPE_S64:
136
        visit_type_int64(v, &pt->value.s64, NULL, errp);
137
        break;
138
    case PTYPE_EOL:
139
        g_assert(false);
140
    }
141
}
142

    
143
static void visit_primitive_list(Visitor *v, void **native, Error **errp)
144
{
145
    PrimitiveList *pl = *native;
146
    switch (pl->type) {
147
    case PTYPE_STRING:
148
        visit_type_strList(v, &pl->value.strings, NULL, errp);
149
        break;
150
    case PTYPE_BOOLEAN:
151
        visit_type_boolList(v, &pl->value.booleans, NULL, errp);
152
        break;
153
    case PTYPE_NUMBER:
154
        visit_type_numberList(v, &pl->value.numbers, NULL, errp);
155
        break;
156
    case PTYPE_INTEGER:
157
        visit_type_intList(v, &pl->value.integers, NULL, errp);
158
        break;
159
    case PTYPE_S8:
160
        visit_type_int8List(v, &pl->value.s8_integers, NULL, errp);
161
        break;
162
    case PTYPE_S16:
163
        visit_type_int16List(v, &pl->value.s16_integers, NULL, errp);
164
        break;
165
    case PTYPE_S32:
166
        visit_type_int32List(v, &pl->value.s32_integers, NULL, errp);
167
        break;
168
    case PTYPE_S64:
169
        visit_type_int64List(v, &pl->value.s64_integers, NULL, errp);
170
        break;
171
    case PTYPE_U8:
172
        visit_type_uint8List(v, &pl->value.u8_integers, NULL, errp);
173
        break;
174
    case PTYPE_U16:
175
        visit_type_uint16List(v, &pl->value.u16_integers, NULL, errp);
176
        break;
177
    case PTYPE_U32:
178
        visit_type_uint32List(v, &pl->value.u32_integers, NULL, errp);
179
        break;
180
    case PTYPE_U64:
181
        visit_type_uint64List(v, &pl->value.u64_integers, NULL, errp);
182
        break;
183
    default:
184
        g_assert(false);
185
    }
186
}
187

    
188
typedef struct TestStruct
189
{
190
    int64_t integer;
191
    bool boolean;
192
    char *string;
193
} TestStruct;
194

    
195
static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
196
                                  const char *name, Error **errp)
197
{
198
    visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), errp);
199

    
200
    visit_type_int(v, &(*obj)->integer, "integer", errp);
201
    visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
202
    visit_type_str(v, &(*obj)->string, "string", errp);
203

    
204
    visit_end_struct(v, errp);
205
}
206

    
207
static TestStruct *struct_create(void)
208
{
209
    TestStruct *ts = g_malloc0(sizeof(*ts));
210
    ts->integer = -42;
211
    ts->boolean = true;
212
    ts->string = strdup("test string");
213
    return ts;
214
}
215

    
216
static void struct_compare(TestStruct *ts1, TestStruct *ts2)
217
{
218
    g_assert(ts1);
219
    g_assert(ts2);
220
    g_assert_cmpint(ts1->integer, ==, ts2->integer);
221
    g_assert(ts1->boolean == ts2->boolean);
222
    g_assert_cmpstr(ts1->string, ==, ts2->string);
223
}
224

    
225
static void struct_cleanup(TestStruct *ts)
226
{
227
    g_free(ts->string);
228
    g_free(ts);
229
}
230

    
231
static void visit_struct(Visitor *v, void **native, Error **errp)
232
{
233
    visit_type_TestStruct(v, (TestStruct **)native, NULL, errp);
234
}
235

    
236
static UserDefNested *nested_struct_create(void)
237
{
238
    UserDefNested *udnp = g_malloc0(sizeof(*udnp));
239
    udnp->string0 = strdup("test_string0");
240
    udnp->dict1.string1 = strdup("test_string1");
241
    udnp->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
242
    udnp->dict1.dict2.userdef1->integer = 42;
243
    udnp->dict1.dict2.userdef1->string = strdup("test_string");
244
    udnp->dict1.dict2.string2 = strdup("test_string2");
245
    udnp->dict1.has_dict3 = true;
246
    udnp->dict1.dict3.userdef2 = g_malloc0(sizeof(UserDefOne));
247
    udnp->dict1.dict3.userdef2->integer = 43;
248
    udnp->dict1.dict3.userdef2->string = strdup("test_string");
249
    udnp->dict1.dict3.string3 = strdup("test_string3");
250
    return udnp;
251
}
252

    
253
static void nested_struct_compare(UserDefNested *udnp1, UserDefNested *udnp2)
254
{
255
    g_assert(udnp1);
256
    g_assert(udnp2);
257
    g_assert_cmpstr(udnp1->string0, ==, udnp2->string0);
258
    g_assert_cmpstr(udnp1->dict1.string1, ==, udnp2->dict1.string1);
259
    g_assert_cmpint(udnp1->dict1.dict2.userdef1->integer, ==,
260
                    udnp2->dict1.dict2.userdef1->integer);
261
    g_assert_cmpstr(udnp1->dict1.dict2.userdef1->string, ==,
262
                    udnp2->dict1.dict2.userdef1->string);
263
    g_assert_cmpstr(udnp1->dict1.dict2.string2, ==, udnp2->dict1.dict2.string2);
264
    g_assert(udnp1->dict1.has_dict3 == udnp2->dict1.has_dict3);
265
    g_assert_cmpint(udnp1->dict1.dict3.userdef2->integer, ==,
266
                    udnp2->dict1.dict3.userdef2->integer);
267
    g_assert_cmpstr(udnp1->dict1.dict3.userdef2->string, ==,
268
                    udnp2->dict1.dict3.userdef2->string);
269
    g_assert_cmpstr(udnp1->dict1.dict3.string3, ==, udnp2->dict1.dict3.string3);
270
}
271

    
272
static void nested_struct_cleanup(UserDefNested *udnp)
273
{
274
    qapi_free_UserDefNested(udnp);
275
}
276

    
277
static void visit_nested_struct(Visitor *v, void **native, Error **errp)
278
{
279
    visit_type_UserDefNested(v, (UserDefNested **)native, NULL, errp);
280
}
281

    
282
static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
283
{
284
    visit_type_UserDefNestedList(v, (UserDefNestedList **)native, NULL, errp);
285
}
286

    
287
/* test cases */
288

    
289
typedef enum VisitorCapabilities {
290
    VCAP_PRIMITIVES = 1,
291
    VCAP_STRUCTURES = 2,
292
    VCAP_LISTS = 4,
293
    VCAP_PRIMITIVE_LISTS = 8,
294
} VisitorCapabilities;
295

    
296
typedef struct SerializeOps {
297
    void (*serialize)(void *native_in, void **datap,
298
                      VisitorFunc visit, Error **errp);
299
    void (*deserialize)(void **native_out, void *datap,
300
                            VisitorFunc visit, Error **errp);
301
    void (*cleanup)(void *datap);
302
    const char *type;
303
    VisitorCapabilities caps;
304
} SerializeOps;
305

    
306
typedef struct TestArgs {
307
    const SerializeOps *ops;
308
    void *test_data;
309
} TestArgs;
310

    
311
static void test_primitives(gconstpointer opaque)
312
{
313
    TestArgs *args = (TestArgs *) opaque;
314
    const SerializeOps *ops = args->ops;
315
    PrimitiveType *pt = args->test_data;
316
    PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
317
    Error *err = NULL;
318
    void *serialize_data;
319

    
320
    pt_copy->type = pt->type;
321
    ops->serialize(pt, &serialize_data, visit_primitive_type, &err);
322
    ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type, &err);
323

    
324
    g_assert(err == NULL);
325
    g_assert(pt_copy != NULL);
326
    if (pt->type == PTYPE_STRING) {
327
        g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
328
        g_free((char *)pt_copy->value.string);
329
    } else if (pt->type == PTYPE_NUMBER) {
330
        GString *double_expected = g_string_new("");
331
        GString *double_actual = g_string_new("");
332
        /* we serialize with %f for our reference visitors, so rather than fuzzy
333
         * floating math to test "equality", just compare the formatted values
334
         */
335
        g_string_printf(double_expected, "%.6f", pt->value.number);
336
        g_string_printf(double_actual, "%.6f", pt_copy->value.number);
337
        g_assert_cmpstr(double_actual->str, ==, double_expected->str);
338

    
339
        g_string_free(double_expected, true);
340
        g_string_free(double_actual, true);
341
    } else if (pt->type == PTYPE_BOOLEAN) {
342
        g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max);
343
    } else {
344
        g_assert_cmpint(pt->value.max, ==, pt_copy->value.max);
345
    }
346

    
347
    ops->cleanup(serialize_data);
348
    g_free(args);
349
    g_free(pt_copy);
350
}
351

    
352
static void test_primitive_lists(gconstpointer opaque)
353
{
354
    TestArgs *args = (TestArgs *) opaque;
355
    const SerializeOps *ops = args->ops;
356
    PrimitiveType *pt = args->test_data;
357
    PrimitiveList pl = { .value = { 0 } };
358
    PrimitiveList pl_copy = { .value = { 0 } };
359
    PrimitiveList *pl_copy_ptr = &pl_copy;
360
    Error *err = NULL;
361
    void *serialize_data;
362
    void *cur_head = NULL;
363
    int i;
364

    
365
    pl.type = pl_copy.type = pt->type;
366

    
367
    /* build up our list of primitive types */
368
    for (i = 0; i < 32; i++) {
369
        switch (pl.type) {
370
        case PTYPE_STRING: {
371
            strList *tmp = g_new0(strList, 1);
372
            tmp->value = g_strdup(pt->value.string);
373
            if (pl.value.strings == NULL) {
374
                pl.value.strings = tmp;
375
            } else {
376
                tmp->next = pl.value.strings;
377
                pl.value.strings = tmp;
378
            }
379
            break;
380
        }
381
        case PTYPE_INTEGER: {
382
            intList *tmp = g_new0(intList, 1);
383
            tmp->value = pt->value.integer;
384
            if (pl.value.integers == NULL) {
385
                pl.value.integers = tmp;
386
            } else {
387
                tmp->next = pl.value.integers;
388
                pl.value.integers = tmp;
389
            }
390
            break;
391
        }
392
        case PTYPE_S8: {
393
            int8List *tmp = g_new0(int8List, 1);
394
            tmp->value = pt->value.s8;
395
            if (pl.value.s8_integers == NULL) {
396
                pl.value.s8_integers = tmp;
397
            } else {
398
                tmp->next = pl.value.s8_integers;
399
                pl.value.s8_integers = tmp;
400
            }
401
            break;
402
        }
403
        case PTYPE_S16: {
404
            int16List *tmp = g_new0(int16List, 1);
405
            tmp->value = pt->value.s16;
406
            if (pl.value.s16_integers == NULL) {
407
                pl.value.s16_integers = tmp;
408
            } else {
409
                tmp->next = pl.value.s16_integers;
410
                pl.value.s16_integers = tmp;
411
            }
412
            break;
413
        }
414
        case PTYPE_S32: {
415
            int32List *tmp = g_new0(int32List, 1);
416
            tmp->value = pt->value.s32;
417
            if (pl.value.s32_integers == NULL) {
418
                pl.value.s32_integers = tmp;
419
            } else {
420
                tmp->next = pl.value.s32_integers;
421
                pl.value.s32_integers = tmp;
422
            }
423
            break;
424
        }
425
        case PTYPE_S64: {
426
            int64List *tmp = g_new0(int64List, 1);
427
            tmp->value = pt->value.s64;
428
            if (pl.value.s64_integers == NULL) {
429
                pl.value.s64_integers = tmp;
430
            } else {
431
                tmp->next = pl.value.s64_integers;
432
                pl.value.s64_integers = tmp;
433
            }
434
            break;
435
        }
436
        case PTYPE_U8: {
437
            uint8List *tmp = g_new0(uint8List, 1);
438
            tmp->value = pt->value.u8;
439
            if (pl.value.u8_integers == NULL) {
440
                pl.value.u8_integers = tmp;
441
            } else {
442
                tmp->next = pl.value.u8_integers;
443
                pl.value.u8_integers = tmp;
444
            }
445
            break;
446
        }
447
        case PTYPE_U16: {
448
            uint16List *tmp = g_new0(uint16List, 1);
449
            tmp->value = pt->value.u16;
450
            if (pl.value.u16_integers == NULL) {
451
                pl.value.u16_integers = tmp;
452
            } else {
453
                tmp->next = pl.value.u16_integers;
454
                pl.value.u16_integers = tmp;
455
            }
456
            break;
457
        }
458
        case PTYPE_U32: {
459
            uint32List *tmp = g_new0(uint32List, 1);
460
            tmp->value = pt->value.u32;
461
            if (pl.value.u32_integers == NULL) {
462
                pl.value.u32_integers = tmp;
463
            } else {
464
                tmp->next = pl.value.u32_integers;
465
                pl.value.u32_integers = tmp;
466
            }
467
            break;
468
        }
469
        case PTYPE_U64: {
470
            uint64List *tmp = g_new0(uint64List, 1);
471
            tmp->value = pt->value.u64;
472
            if (pl.value.u64_integers == NULL) {
473
                pl.value.u64_integers = tmp;
474
            } else {
475
                tmp->next = pl.value.u64_integers;
476
                pl.value.u64_integers = tmp;
477
            }
478
            break;
479
        }
480
        case PTYPE_NUMBER: {
481
            numberList *tmp = g_new0(numberList, 1);
482
            tmp->value = pt->value.number;
483
            if (pl.value.numbers == NULL) {
484
                pl.value.numbers = tmp;
485
            } else {
486
                tmp->next = pl.value.numbers;
487
                pl.value.numbers = tmp;
488
            }
489
            break;
490
        }
491
        case PTYPE_BOOLEAN: {
492
            boolList *tmp = g_new0(boolList, 1);
493
            tmp->value = pt->value.boolean;
494
            if (pl.value.booleans == NULL) {
495
                pl.value.booleans = tmp;
496
            } else {
497
                tmp->next = pl.value.booleans;
498
                pl.value.booleans = tmp;
499
            }
500
            break;
501
        }
502
        default:
503
            g_assert(0);
504
        }
505
    }
506

    
507
    ops->serialize((void **)&pl, &serialize_data, visit_primitive_list, &err);
508
    ops->deserialize((void **)&pl_copy_ptr, serialize_data, visit_primitive_list, &err);
509

    
510
    g_assert(err == NULL);
511
    i = 0;
512

    
513
    /* compare our deserialized list of primitives to the original */
514
    do {
515
        switch (pl_copy.type) {
516
        case PTYPE_STRING: {
517
            strList *ptr;
518
            if (cur_head) {
519
                ptr = cur_head;
520
                cur_head = ptr->next;
521
            } else {
522
                cur_head = ptr = pl_copy.value.strings;
523
            }
524
            g_assert_cmpstr(pt->value.string, ==, ptr->value);
525
            break;
526
        }
527
        case PTYPE_INTEGER: {
528
            intList *ptr;
529
            if (cur_head) {
530
                ptr = cur_head;
531
                cur_head = ptr->next;
532
            } else {
533
                cur_head = ptr = pl_copy.value.integers;
534
            }
535
            g_assert_cmpint(pt->value.integer, ==, ptr->value);
536
            break;
537
        }
538
        case PTYPE_S8: {
539
            int8List *ptr;
540
            if (cur_head) {
541
                ptr = cur_head;
542
                cur_head = ptr->next;
543
            } else {
544
                cur_head = ptr = pl_copy.value.s8_integers;
545
            }
546
            g_assert_cmpint(pt->value.s8, ==, ptr->value);
547
            break;
548
        }
549
        case PTYPE_S16: {
550
            int16List *ptr;
551
            if (cur_head) {
552
                ptr = cur_head;
553
                cur_head = ptr->next;
554
            } else {
555
                cur_head = ptr = pl_copy.value.s16_integers;
556
            }
557
            g_assert_cmpint(pt->value.s16, ==, ptr->value);
558
            break;
559
        }
560
        case PTYPE_S32: {
561
            int32List *ptr;
562
            if (cur_head) {
563
                ptr = cur_head;
564
                cur_head = ptr->next;
565
            } else {
566
                cur_head = ptr = pl_copy.value.s32_integers;
567
            }
568
            g_assert_cmpint(pt->value.s32, ==, ptr->value);
569
            break;
570
        }
571
        case PTYPE_S64: {
572
            int64List *ptr;
573
            if (cur_head) {
574
                ptr = cur_head;
575
                cur_head = ptr->next;
576
            } else {
577
                cur_head = ptr = pl_copy.value.s64_integers;
578
            }
579
            g_assert_cmpint(pt->value.s64, ==, ptr->value);
580
            break;
581
        }
582
        case PTYPE_U8: {
583
            uint8List *ptr;
584
            if (cur_head) {
585
                ptr = cur_head;
586
                cur_head = ptr->next;
587
            } else {
588
                cur_head = ptr = pl_copy.value.u8_integers;
589
            }
590
            g_assert_cmpint(pt->value.u8, ==, ptr->value);
591
            break;
592
        }
593
        case PTYPE_U16: {
594
            uint16List *ptr;
595
            if (cur_head) {
596
                ptr = cur_head;
597
                cur_head = ptr->next;
598
            } else {
599
                cur_head = ptr = pl_copy.value.u16_integers;
600
            }
601
            g_assert_cmpint(pt->value.u16, ==, ptr->value);
602
            break;
603
        }
604
        case PTYPE_U32: {
605
            uint32List *ptr;
606
            if (cur_head) {
607
                ptr = cur_head;
608
                cur_head = ptr->next;
609
            } else {
610
                cur_head = ptr = pl_copy.value.u32_integers;
611
            }
612
            g_assert_cmpint(pt->value.u32, ==, ptr->value);
613
            break;
614
        }
615
        case PTYPE_U64: {
616
            uint64List *ptr;
617
            if (cur_head) {
618
                ptr = cur_head;
619
                cur_head = ptr->next;
620
            } else {
621
                cur_head = ptr = pl_copy.value.u64_integers;
622
            }
623
            g_assert_cmpint(pt->value.u64, ==, ptr->value);
624
            break;
625
        }
626
        case PTYPE_NUMBER: {
627
            numberList *ptr;
628
            GString *double_expected = g_string_new("");
629
            GString *double_actual = g_string_new("");
630
            if (cur_head) {
631
                ptr = cur_head;
632
                cur_head = ptr->next;
633
            } else {
634
                cur_head = ptr = pl_copy.value.numbers;
635
            }
636
            /* we serialize with %f for our reference visitors, so rather than
637
             * fuzzy floating math to test "equality", just compare the
638
             * formatted values
639
             */
640
            g_string_printf(double_expected, "%.6f", pt->value.number);
641
            g_string_printf(double_actual, "%.6f", ptr->value);
642
            g_assert_cmpstr(double_actual->str, ==, double_expected->str);
643
            g_string_free(double_expected, true);
644
            g_string_free(double_actual, true);
645
            break;
646
        }
647
        case PTYPE_BOOLEAN: {
648
            boolList *ptr;
649
            if (cur_head) {
650
                ptr = cur_head;
651
                cur_head = ptr->next;
652
            } else {
653
                cur_head = ptr = pl_copy.value.booleans;
654
            }
655
            g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
656
            break;
657
        }
658
        default:
659
            g_assert(0);
660
        }
661
        i++;
662
    } while (cur_head);
663

    
664
    g_assert_cmpint(i, ==, 33);
665

    
666
    ops->cleanup(serialize_data);
667
    dealloc_helper(&pl, visit_primitive_list, &err);
668
    g_assert(!err);
669
    dealloc_helper(&pl_copy, visit_primitive_list, &err);
670
    g_assert(!err);
671
    g_free(args);
672
}
673

    
674
static void test_struct(gconstpointer opaque)
675
{
676
    TestArgs *args = (TestArgs *) opaque;
677
    const SerializeOps *ops = args->ops;
678
    TestStruct *ts = struct_create();
679
    TestStruct *ts_copy = NULL;
680
    Error *err = NULL;
681
    void *serialize_data;
682

    
683
    ops->serialize(ts, &serialize_data, visit_struct, &err);
684
    ops->deserialize((void **)&ts_copy, serialize_data, visit_struct, &err); 
685

    
686
    g_assert(err == NULL);
687
    struct_compare(ts, ts_copy);
688

    
689
    struct_cleanup(ts);
690
    struct_cleanup(ts_copy);
691

    
692
    ops->cleanup(serialize_data);
693
    g_free(args);
694
}
695

    
696
static void test_nested_struct(gconstpointer opaque)
697
{
698
    TestArgs *args = (TestArgs *) opaque;
699
    const SerializeOps *ops = args->ops;
700
    UserDefNested *udnp = nested_struct_create();
701
    UserDefNested *udnp_copy = NULL;
702
    Error *err = NULL;
703
    void *serialize_data;
704
    
705
    ops->serialize(udnp, &serialize_data, visit_nested_struct, &err);
706
    ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct, &err); 
707

    
708
    g_assert(err == NULL);
709
    nested_struct_compare(udnp, udnp_copy);
710

    
711
    nested_struct_cleanup(udnp);
712
    nested_struct_cleanup(udnp_copy);
713

    
714
    ops->cleanup(serialize_data);
715
    g_free(args);
716
}
717

    
718
static void test_nested_struct_list(gconstpointer opaque)
719
{
720
    TestArgs *args = (TestArgs *) opaque;
721
    const SerializeOps *ops = args->ops;
722
    UserDefNestedList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL;
723
    Error *err = NULL;
724
    void *serialize_data;
725
    int i = 0;
726

    
727
    for (i = 0; i < 8; i++) {
728
        tmp = g_malloc0(sizeof(UserDefNestedList));
729
        tmp->value = nested_struct_create();
730
        tmp->next = listp;
731
        listp = tmp;
732
    }
733
    
734
    ops->serialize(listp, &serialize_data, visit_nested_struct_list, &err);
735
    ops->deserialize((void **)&listp_copy, serialize_data,
736
                     visit_nested_struct_list, &err); 
737

    
738
    g_assert(err == NULL);
739

    
740
    tmp = listp;
741
    tmp_copy = listp_copy;
742
    while (listp_copy) {
743
        g_assert(listp);
744
        nested_struct_compare(listp->value, listp_copy->value);
745
        listp = listp->next;
746
        listp_copy = listp_copy->next;
747
    }
748

    
749
    qapi_free_UserDefNestedList(tmp);
750
    qapi_free_UserDefNestedList(tmp_copy);
751

    
752
    ops->cleanup(serialize_data);
753
    g_free(args);
754
}
755

    
756
PrimitiveType pt_values[] = {
757
    /* string tests */
758
    {
759
        .description = "string_empty",
760
        .type = PTYPE_STRING,
761
        .value.string = "",
762
    },
763
    {
764
        .description = "string_whitespace",
765
        .type = PTYPE_STRING,
766
        .value.string = "a b  c\td",
767
    },
768
    {
769
        .description = "string_newlines",
770
        .type = PTYPE_STRING,
771
        .value.string = "a\nb\n",
772
    },
773
    {
774
        .description = "string_commas",
775
        .type = PTYPE_STRING,
776
        .value.string = "a,b, c,d",
777
    },
778
    {
779
        .description = "string_single_quoted",
780
        .type = PTYPE_STRING,
781
        .value.string = "'a b',cd",
782
    },
783
    {
784
        .description = "string_double_quoted",
785
        .type = PTYPE_STRING,
786
        .value.string = "\"a b\",cd",
787
    },
788
    /* boolean tests */
789
    {
790
        .description = "boolean_true1",
791
        .type = PTYPE_BOOLEAN,
792
        .value.boolean = true,
793
    },
794
    {
795
        .description = "boolean_true2",
796
        .type = PTYPE_BOOLEAN,
797
        .value.boolean = 8,
798
    },
799
    {
800
        .description = "boolean_true3",
801
        .type = PTYPE_BOOLEAN,
802
        .value.boolean = -1,
803
    },
804
    {
805
        .description = "boolean_false1",
806
        .type = PTYPE_BOOLEAN,
807
        .value.boolean = false,
808
    },
809
    {
810
        .description = "boolean_false2",
811
        .type = PTYPE_BOOLEAN,
812
        .value.boolean = 0,
813
    },
814
    /* number tests (double) */
815
    /* note: we format these to %.6f before comparing, since that's how
816
     * we serialize them and it doesn't make sense to check precision
817
     * beyond that.
818
     */
819
    {
820
        .description = "number_sanity1",
821
        .type = PTYPE_NUMBER,
822
        .value.number = -1,
823
    },
824
    {
825
        .description = "number_sanity2",
826
        .type = PTYPE_NUMBER,
827
        .value.number = 3.14159265,
828
    },
829
    {
830
        .description = "number_min",
831
        .type = PTYPE_NUMBER,
832
        .value.number = DBL_MIN,
833
    },
834
    {
835
        .description = "number_max",
836
        .type = PTYPE_NUMBER,
837
        .value.number = DBL_MAX,
838
    },
839
    /* integer tests (int64) */
840
    {
841
        .description = "integer_sanity1",
842
        .type = PTYPE_INTEGER,
843
        .value.integer = -1,
844
    },
845
    {
846
        .description = "integer_sanity2",
847
        .type = PTYPE_INTEGER,
848
        .value.integer = INT64_MAX / 2 + 1,
849
    },
850
    {
851
        .description = "integer_min",
852
        .type = PTYPE_INTEGER,
853
        .value.integer = INT64_MIN,
854
    },
855
    {
856
        .description = "integer_max",
857
        .type = PTYPE_INTEGER,
858
        .value.integer = INT64_MAX,
859
    },
860
    /* uint8 tests */
861
    {
862
        .description = "uint8_sanity1",
863
        .type = PTYPE_U8,
864
        .value.u8 = 1,
865
    },
866
    {
867
        .description = "uint8_sanity2",
868
        .type = PTYPE_U8,
869
        .value.u8 = UINT8_MAX / 2 + 1,
870
    },
871
    {
872
        .description = "uint8_min",
873
        .type = PTYPE_U8,
874
        .value.u8 = 0,
875
    },
876
    {
877
        .description = "uint8_max",
878
        .type = PTYPE_U8,
879
        .value.u8 = UINT8_MAX,
880
    },
881
    /* uint16 tests */
882
    {
883
        .description = "uint16_sanity1",
884
        .type = PTYPE_U16,
885
        .value.u16 = 1,
886
    },
887
    {
888
        .description = "uint16_sanity2",
889
        .type = PTYPE_U16,
890
        .value.u16 = UINT16_MAX / 2 + 1,
891
    },
892
    {
893
        .description = "uint16_min",
894
        .type = PTYPE_U16,
895
        .value.u16 = 0,
896
    },
897
    {
898
        .description = "uint16_max",
899
        .type = PTYPE_U16,
900
        .value.u16 = UINT16_MAX,
901
    },
902
    /* uint32 tests */
903
    {
904
        .description = "uint32_sanity1",
905
        .type = PTYPE_U32,
906
        .value.u32 = 1,
907
    },
908
    {
909
        .description = "uint32_sanity2",
910
        .type = PTYPE_U32,
911
        .value.u32 = UINT32_MAX / 2 + 1,
912
    },
913
    {
914
        .description = "uint32_min",
915
        .type = PTYPE_U32,
916
        .value.u32 = 0,
917
    },
918
    {
919
        .description = "uint32_max",
920
        .type = PTYPE_U32,
921
        .value.u32 = UINT32_MAX,
922
    },
923
    /* uint64 tests */
924
    {
925
        .description = "uint64_sanity1",
926
        .type = PTYPE_U64,
927
        .value.u64 = 1,
928
    },
929
    {
930
        .description = "uint64_sanity2",
931
        .type = PTYPE_U64,
932
        .value.u64 = UINT64_MAX / 2 + 1,
933
    },
934
    {
935
        .description = "uint64_min",
936
        .type = PTYPE_U64,
937
        .value.u64 = 0,
938
    },
939
    {
940
        .description = "uint64_max",
941
        .type = PTYPE_U64,
942
        .value.u64 = UINT64_MAX,
943
    },
944
    /* int8 tests */
945
    {
946
        .description = "int8_sanity1",
947
        .type = PTYPE_S8,
948
        .value.s8 = -1,
949
    },
950
    {
951
        .description = "int8_sanity2",
952
        .type = PTYPE_S8,
953
        .value.s8 = INT8_MAX / 2 + 1,
954
    },
955
    {
956
        .description = "int8_min",
957
        .type = PTYPE_S8,
958
        .value.s8 = INT8_MIN,
959
    },
960
    {
961
        .description = "int8_max",
962
        .type = PTYPE_S8,
963
        .value.s8 = INT8_MAX,
964
    },
965
    /* int16 tests */
966
    {
967
        .description = "int16_sanity1",
968
        .type = PTYPE_S16,
969
        .value.s16 = -1,
970
    },
971
    {
972
        .description = "int16_sanity2",
973
        .type = PTYPE_S16,
974
        .value.s16 = INT16_MAX / 2 + 1,
975
    },
976
    {
977
        .description = "int16_min",
978
        .type = PTYPE_S16,
979
        .value.s16 = INT16_MIN,
980
    },
981
    {
982
        .description = "int16_max",
983
        .type = PTYPE_S16,
984
        .value.s16 = INT16_MAX,
985
    },
986
    /* int32 tests */
987
    {
988
        .description = "int32_sanity1",
989
        .type = PTYPE_S32,
990
        .value.s32 = -1,
991
    },
992
    {
993
        .description = "int32_sanity2",
994
        .type = PTYPE_S32,
995
        .value.s32 = INT32_MAX / 2 + 1,
996
    },
997
    {
998
        .description = "int32_min",
999
        .type = PTYPE_S32,
1000
        .value.s32 = INT32_MIN,
1001
    },
1002
    {
1003
        .description = "int32_max",
1004
        .type = PTYPE_S32,
1005
        .value.s32 = INT32_MAX,
1006
    },
1007
    /* int64 tests */
1008
    {
1009
        .description = "int64_sanity1",
1010
        .type = PTYPE_S64,
1011
        .value.s64 = -1,
1012
    },
1013
    {
1014
        .description = "int64_sanity2",
1015
        .type = PTYPE_S64,
1016
        .value.s64 = INT64_MAX / 2 + 1,
1017
    },
1018
    {
1019
        .description = "int64_min",
1020
        .type = PTYPE_S64,
1021
        .value.s64 = INT64_MIN,
1022
    },
1023
    {
1024
        .description = "int64_max",
1025
        .type = PTYPE_S64,
1026
        .value.s64 = INT64_MAX,
1027
    },
1028
    { .type = PTYPE_EOL }
1029
};
1030

    
1031
/* visitor-specific op implementations */
1032

    
1033
typedef struct QmpSerializeData {
1034
    QmpOutputVisitor *qov;
1035
    QmpInputVisitor *qiv;
1036
} QmpSerializeData;
1037

    
1038
static void qmp_serialize(void *native_in, void **datap,
1039
                          VisitorFunc visit, Error **errp)
1040
{
1041
    QmpSerializeData *d = g_malloc0(sizeof(*d));
1042

    
1043
    d->qov = qmp_output_visitor_new();
1044
    visit(qmp_output_get_visitor(d->qov), &native_in, errp);
1045
    *datap = d;
1046
}
1047

    
1048
static void qmp_deserialize(void **native_out, void *datap,
1049
                            VisitorFunc visit, Error **errp)
1050
{
1051
    QmpSerializeData *d = datap;
1052
    QString *output_json;
1053
    QObject *obj_orig, *obj;
1054

    
1055
    obj_orig = qmp_output_get_qobject(d->qov);
1056
    output_json = qobject_to_json(obj_orig);
1057
    obj = qobject_from_json(qstring_get_str(output_json));
1058

    
1059
    QDECREF(output_json);
1060
    d->qiv = qmp_input_visitor_new(obj);
1061
    qobject_decref(obj_orig);
1062
    qobject_decref(obj);
1063
    visit(qmp_input_get_visitor(d->qiv), native_out, errp);
1064
}
1065

    
1066
static void qmp_cleanup(void *datap)
1067
{
1068
    QmpSerializeData *d = datap;
1069
    qmp_output_visitor_cleanup(d->qov);
1070
    qmp_input_visitor_cleanup(d->qiv);
1071

    
1072
    g_free(d);
1073
}
1074

    
1075
typedef struct StringSerializeData {
1076
    char *string;
1077
    StringOutputVisitor *sov;
1078
    StringInputVisitor *siv;
1079
} StringSerializeData;
1080

    
1081
static void string_serialize(void *native_in, void **datap,
1082
                             VisitorFunc visit, Error **errp)
1083
{
1084
    StringSerializeData *d = g_malloc0(sizeof(*d));
1085

    
1086
    d->sov = string_output_visitor_new();
1087
    visit(string_output_get_visitor(d->sov), &native_in, errp);
1088
    *datap = d;
1089
}
1090

    
1091
static void string_deserialize(void **native_out, void *datap,
1092
                               VisitorFunc visit, Error **errp)
1093
{
1094
    StringSerializeData *d = datap;
1095

    
1096
    d->string = string_output_get_string(d->sov);
1097
    d->siv = string_input_visitor_new(d->string);
1098
    visit(string_input_get_visitor(d->siv), native_out, errp);
1099
}
1100

    
1101
static void string_cleanup(void *datap)
1102
{
1103
    StringSerializeData *d = datap;
1104

    
1105
    string_output_visitor_cleanup(d->sov);
1106
    string_input_visitor_cleanup(d->siv);
1107
    g_free(d->string);
1108
    g_free(d);
1109
}
1110

    
1111
/* visitor registration, test harness */
1112

    
1113
/* note: to function interchangeably as a serialization mechanism your
1114
 * visitor test implementation should pass the test cases for all visitor
1115
 * capabilities: primitives, structures, and lists
1116
 */
1117
static const SerializeOps visitors[] = {
1118
    {
1119
        .type = "QMP",
1120
        .serialize = qmp_serialize,
1121
        .deserialize = qmp_deserialize,
1122
        .cleanup = qmp_cleanup,
1123
        .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
1124
                VCAP_PRIMITIVE_LISTS
1125
    },
1126
    {
1127
        .type = "String",
1128
        .serialize = string_serialize,
1129
        .deserialize = string_deserialize,
1130
        .cleanup = string_cleanup,
1131
        .caps = VCAP_PRIMITIVES
1132
    },
1133
    { NULL }
1134
};
1135

    
1136
static void add_visitor_type(const SerializeOps *ops)
1137
{
1138
    char testname_prefix[128];
1139
    char testname[128];
1140
    TestArgs *args;
1141
    int i = 0;
1142

    
1143
    sprintf(testname_prefix, "/visitor/serialization/%s", ops->type);
1144

    
1145
    if (ops->caps & VCAP_PRIMITIVES) {
1146
        while (pt_values[i].type != PTYPE_EOL) {
1147
            sprintf(testname, "%s/primitives/%s", testname_prefix,
1148
                    pt_values[i].description);
1149
            args = g_malloc0(sizeof(*args));
1150
            args->ops = ops;
1151
            args->test_data = &pt_values[i];
1152
            g_test_add_data_func(testname, args, test_primitives);
1153
            i++;
1154
        }
1155
    }
1156

    
1157
    if (ops->caps & VCAP_STRUCTURES) {
1158
        sprintf(testname, "%s/struct", testname_prefix);
1159
        args = g_malloc0(sizeof(*args));
1160
        args->ops = ops;
1161
        args->test_data = NULL;
1162
        g_test_add_data_func(testname, args, test_struct);
1163

    
1164
        sprintf(testname, "%s/nested_struct", testname_prefix);
1165
        args = g_malloc0(sizeof(*args));
1166
        args->ops = ops;
1167
        args->test_data = NULL;
1168
        g_test_add_data_func(testname, args, test_nested_struct);
1169
    }
1170

    
1171
    if (ops->caps & VCAP_LISTS) {
1172
        sprintf(testname, "%s/nested_struct_list", testname_prefix);
1173
        args = g_malloc0(sizeof(*args));
1174
        args->ops = ops;
1175
        args->test_data = NULL;
1176
        g_test_add_data_func(testname, args, test_nested_struct_list);
1177
    }
1178

    
1179
    if (ops->caps & VCAP_PRIMITIVE_LISTS) {
1180
        i = 0;
1181
        while (pt_values[i].type != PTYPE_EOL) {
1182
            sprintf(testname, "%s/primitive_list/%s", testname_prefix,
1183
                    pt_values[i].description);
1184
            args = g_malloc0(sizeof(*args));
1185
            args->ops = ops;
1186
            args->test_data = &pt_values[i];
1187
            g_test_add_data_func(testname, args, test_primitive_lists);
1188
            i++;
1189
        }
1190
    }
1191
}
1192

    
1193
int main(int argc, char **argv)
1194
{
1195
    int i = 0;
1196

    
1197
    g_test_init(&argc, &argv, NULL);
1198

    
1199
    while (visitors[i].type != NULL) {
1200
        add_visitor_type(&visitors[i]);
1201
        i++;
1202
    }
1203

    
1204
    g_test_run();
1205

    
1206
    return 0;
1207
}