qemu/tests/unit/test-qobject-input-visitor.c
<<
>>
Prefs
   1/*
   2 * QObject Input Visitor unit-tests.
   3 *
   4 * Copyright (C) 2011-2016 Red Hat Inc.
   5 *
   6 * Authors:
   7 *  Luiz Capitulino <lcapitulino@redhat.com>
   8 *  Paolo Bonzini <pbonzini@redhat.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
  14#include "qemu/osdep.h"
  15
  16#include "qemu-common.h"
  17#include "qapi/error.h"
  18#include "qapi/qapi-visit-introspect.h"
  19#include "qapi/qobject-input-visitor.h"
  20#include "test-qapi-visit.h"
  21#include "qapi/qmp/qbool.h"
  22#include "qapi/qmp/qdict.h"
  23#include "qapi/qmp/qnull.h"
  24#include "qapi/qmp/qnum.h"
  25#include "qapi/qmp/qstring.h"
  26#include "qapi/qmp/qjson.h"
  27#include "test-qapi-introspect.h"
  28#include "qapi/qapi-introspect.h"
  29
  30typedef struct TestInputVisitorData {
  31    QObject *obj;
  32    Visitor *qiv;
  33} TestInputVisitorData;
  34
  35static void visitor_input_teardown(TestInputVisitorData *data,
  36                                   const void *unused)
  37{
  38    qobject_unref(data->obj);
  39    data->obj = NULL;
  40
  41    if (data->qiv) {
  42        visit_free(data->qiv);
  43        data->qiv = NULL;
  44    }
  45}
  46
  47/* The various test_init functions are provided instead of a test setup
  48   function so that the JSON string used by the tests are kept in the test
  49   functions (and not in main()). */
  50
  51static Visitor *test_init_internal(TestInputVisitorData *data, bool keyval,
  52                                   QObject *obj)
  53{
  54    visitor_input_teardown(data, NULL);
  55
  56    data->obj = obj;
  57
  58    if (keyval) {
  59        data->qiv = qobject_input_visitor_new_keyval(data->obj);
  60    } else {
  61        data->qiv = qobject_input_visitor_new(data->obj);
  62    }
  63    g_assert(data->qiv);
  64    return data->qiv;
  65}
  66
  67static GCC_FMT_ATTR(3, 4)
  68Visitor *visitor_input_test_init_full(TestInputVisitorData *data,
  69                                      bool keyval,
  70                                      const char *json_string, ...)
  71{
  72    Visitor *v;
  73    va_list ap;
  74
  75    va_start(ap, json_string);
  76    v = test_init_internal(data, keyval,
  77                           qobject_from_vjsonf_nofail(json_string, ap));
  78    va_end(ap);
  79    return v;
  80}
  81
  82static GCC_FMT_ATTR(2, 3)
  83Visitor *visitor_input_test_init(TestInputVisitorData *data,
  84                                 const char *json_string, ...)
  85{
  86    Visitor *v;
  87    va_list ap;
  88
  89    va_start(ap, json_string);
  90    v = test_init_internal(data, false,
  91                           qobject_from_vjsonf_nofail(json_string, ap));
  92    va_end(ap);
  93    return v;
  94}
  95
  96/* similar to visitor_input_test_init(), but does not expect a string
  97 * literal/format json_string argument and so can be used for
  98 * programatically generated strings (and we can't pass in programatically
  99 * generated strings via %s format parameters since qobject_from_jsonv()
 100 * will wrap those in double-quotes and treat the entire object as a
 101 * string)
 102 */
 103static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data,
 104                                            const char *json_string)
 105{
 106    return test_init_internal(data, false,
 107                              qobject_from_json(json_string, &error_abort));
 108}
 109
 110static void test_visitor_in_int(TestInputVisitorData *data,
 111                                const void *unused)
 112{
 113    int64_t res = 0;
 114    double dbl;
 115    int value = -42;
 116    Visitor *v;
 117
 118    v = visitor_input_test_init(data, "%d", value);
 119
 120    visit_type_int(v, NULL, &res, &error_abort);
 121    g_assert_cmpint(res, ==, value);
 122
 123    visit_type_number(v, NULL, &dbl, &error_abort);
 124    g_assert_cmpfloat(dbl, ==, -42.0);
 125}
 126
 127static void test_visitor_in_uint(TestInputVisitorData *data,
 128                                const void *unused)
 129{
 130    uint64_t res = 0;
 131    int64_t i64;
 132    double dbl;
 133    int value = 42;
 134    Visitor *v;
 135
 136    v = visitor_input_test_init(data, "%d", value);
 137
 138    visit_type_uint64(v, NULL, &res, &error_abort);
 139    g_assert_cmpuint(res, ==, (uint64_t)value);
 140
 141    visit_type_int(v, NULL, &i64, &error_abort);
 142    g_assert_cmpint(i64, ==, value);
 143
 144    visit_type_number(v, NULL, &dbl, &error_abort);
 145    g_assert_cmpfloat(dbl, ==, value);
 146
 147    /* BUG: value between INT64_MIN and -1 accepted modulo 2^64 */
 148    v = visitor_input_test_init(data, "%d", -value);
 149
 150    visit_type_uint64(v, NULL, &res, &error_abort);
 151    g_assert_cmpuint(res, ==, (uint64_t)-value);
 152
 153    v = visitor_input_test_init(data, "18446744073709551574");
 154
 155    visit_type_uint64(v, NULL, &res, &error_abort);
 156    g_assert_cmpuint(res, ==, 18446744073709551574U);
 157
 158    visit_type_number(v, NULL, &dbl, &error_abort);
 159    g_assert_cmpfloat(dbl, ==, 18446744073709552000.0);
 160}
 161
 162static void test_visitor_in_int_overflow(TestInputVisitorData *data,
 163                                         const void *unused)
 164{
 165    int64_t res = 0;
 166    Error *err = NULL;
 167    Visitor *v;
 168
 169    /*
 170     * This will overflow a QNUM_I64, so should be deserialized into a
 171     * QNUM_DOUBLE field instead, leading to an error if we pass it to
 172     * visit_type_int().  Confirm this.
 173     */
 174    v = visitor_input_test_init(data, "%f", DBL_MAX);
 175
 176    visit_type_int(v, NULL, &res, &err);
 177    error_free_or_abort(&err);
 178}
 179
 180static void test_visitor_in_int_keyval(TestInputVisitorData *data,
 181                                       const void *unused)
 182{
 183    int64_t res = 0, value = -42;
 184    Error *err = NULL;
 185    Visitor *v;
 186
 187    v = visitor_input_test_init_full(data, true, "%" PRId64, value);
 188    visit_type_int(v, NULL, &res, &err);
 189    error_free_or_abort(&err);
 190}
 191
 192static void test_visitor_in_int_str_keyval(TestInputVisitorData *data,
 193                                           const void *unused)
 194{
 195    int64_t res = 0, value = -42;
 196    Visitor *v;
 197
 198    v = visitor_input_test_init_full(data, true, "\"-42\"");
 199
 200    visit_type_int(v, NULL, &res, &error_abort);
 201    g_assert_cmpint(res, ==, value);
 202}
 203
 204static void test_visitor_in_int_str_fail(TestInputVisitorData *data,
 205                                         const void *unused)
 206{
 207    int64_t res = 0;
 208    Visitor *v;
 209    Error *err = NULL;
 210
 211    v = visitor_input_test_init(data, "\"-42\"");
 212
 213    visit_type_int(v, NULL, &res, &err);
 214    error_free_or_abort(&err);
 215}
 216
 217static void test_visitor_in_bool(TestInputVisitorData *data,
 218                                 const void *unused)
 219{
 220    bool res = false;
 221    Visitor *v;
 222
 223    v = visitor_input_test_init(data, "true");
 224
 225    visit_type_bool(v, NULL, &res, &error_abort);
 226    g_assert_cmpint(res, ==, true);
 227}
 228
 229static void test_visitor_in_bool_keyval(TestInputVisitorData *data,
 230                                        const void *unused)
 231{
 232    bool res = false;
 233    Error *err = NULL;
 234    Visitor *v;
 235
 236    v = visitor_input_test_init_full(data, true, "true");
 237
 238    visit_type_bool(v, NULL, &res, &err);
 239    error_free_or_abort(&err);
 240}
 241
 242static void test_visitor_in_bool_str_keyval(TestInputVisitorData *data,
 243                                            const void *unused)
 244{
 245    bool res = false;
 246    Visitor *v;
 247
 248    v = visitor_input_test_init_full(data, true, "\"on\"");
 249
 250    visit_type_bool(v, NULL, &res, &error_abort);
 251    g_assert_cmpint(res, ==, true);
 252}
 253
 254static void test_visitor_in_bool_str_fail(TestInputVisitorData *data,
 255                                          const void *unused)
 256{
 257    bool res = false;
 258    Visitor *v;
 259    Error *err = NULL;
 260
 261    v = visitor_input_test_init(data, "\"true\"");
 262
 263    visit_type_bool(v, NULL, &res, &err);
 264    error_free_or_abort(&err);
 265}
 266
 267static void test_visitor_in_number(TestInputVisitorData *data,
 268                                   const void *unused)
 269{
 270    double res = 0, value = 3.14;
 271    Visitor *v;
 272
 273    v = visitor_input_test_init(data, "%f", value);
 274
 275    visit_type_number(v, NULL, &res, &error_abort);
 276    g_assert_cmpfloat(res, ==, value);
 277}
 278
 279static void test_visitor_in_large_number(TestInputVisitorData *data,
 280                                         const void *unused)
 281{
 282    Error *err = NULL;
 283    double res = 0;
 284    int64_t i64;
 285    uint64_t u64;
 286    Visitor *v;
 287
 288    v = visitor_input_test_init(data, "-18446744073709551616"); /* -2^64 */
 289
 290    visit_type_number(v, NULL, &res, &error_abort);
 291    g_assert_cmpfloat(res, ==, -18446744073709552e3);
 292
 293    visit_type_int(v, NULL, &i64, &err);
 294    error_free_or_abort(&err);
 295
 296    visit_type_uint64(v, NULL, &u64, &err);
 297    error_free_or_abort(&err);
 298}
 299
 300static void test_visitor_in_number_keyval(TestInputVisitorData *data,
 301                                          const void *unused)
 302{
 303    double res = 0, value = 3.14;
 304    Error *err = NULL;
 305    Visitor *v;
 306
 307    v = visitor_input_test_init_full(data, true, "%f", value);
 308
 309    visit_type_number(v, NULL, &res, &err);
 310    error_free_or_abort(&err);
 311}
 312
 313static void test_visitor_in_number_str_keyval(TestInputVisitorData *data,
 314                                              const void *unused)
 315{
 316    double res = 0, value = 3.14;
 317    Visitor *v;
 318    Error *err = NULL;
 319
 320    v = visitor_input_test_init_full(data, true, "\"3.14\"");
 321
 322    visit_type_number(v, NULL, &res, &error_abort);
 323    g_assert_cmpfloat(res, ==, value);
 324
 325    v = visitor_input_test_init_full(data, true, "\"inf\"");
 326
 327    visit_type_number(v, NULL, &res, &err);
 328    error_free_or_abort(&err);
 329}
 330
 331static void test_visitor_in_number_str_fail(TestInputVisitorData *data,
 332                                            const void *unused)
 333{
 334    double res = 0;
 335    Visitor *v;
 336    Error *err = NULL;
 337
 338    v = visitor_input_test_init(data, "\"3.14\"");
 339
 340    visit_type_number(v, NULL, &res, &err);
 341    error_free_or_abort(&err);
 342}
 343
 344static void test_visitor_in_size_str_keyval(TestInputVisitorData *data,
 345                                            const void *unused)
 346{
 347    uint64_t res, value = 500 * 1024 * 1024;
 348    Visitor *v;
 349
 350    v = visitor_input_test_init_full(data, true, "\"500M\"");
 351
 352    visit_type_size(v, NULL, &res, &error_abort);
 353    g_assert_cmpfloat(res, ==, value);
 354}
 355
 356static void test_visitor_in_size_str_fail(TestInputVisitorData *data,
 357                                          const void *unused)
 358{
 359    uint64_t res = 0;
 360    Visitor *v;
 361    Error *err = NULL;
 362
 363    v = visitor_input_test_init(data, "\"500M\"");
 364
 365    visit_type_size(v, NULL, &res, &err);
 366    error_free_or_abort(&err);
 367}
 368
 369static void test_visitor_in_string(TestInputVisitorData *data,
 370                                   const void *unused)
 371{
 372    char *res = NULL, *value = (char *) "Q E M U";
 373    Visitor *v;
 374
 375    v = visitor_input_test_init(data, "%s", value);
 376
 377    visit_type_str(v, NULL, &res, &error_abort);
 378    g_assert_cmpstr(res, ==, value);
 379
 380    g_free(res);
 381}
 382
 383static void test_visitor_in_enum(TestInputVisitorData *data,
 384                                 const void *unused)
 385{
 386    Visitor *v;
 387    EnumOne i;
 388
 389    for (i = 0; i < ENUM_ONE__MAX; i++) {
 390        EnumOne res = -1;
 391
 392        v = visitor_input_test_init(data, "%s", EnumOne_str(i));
 393
 394        visit_type_EnumOne(v, NULL, &res, &error_abort);
 395        g_assert_cmpint(i, ==, res);
 396    }
 397}
 398
 399
 400static void test_visitor_in_struct(TestInputVisitorData *data,
 401                                   const void *unused)
 402{
 403    TestStruct *p = NULL;
 404    Visitor *v;
 405
 406    v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
 407
 408    visit_type_TestStruct(v, NULL, &p, &error_abort);
 409    g_assert_cmpint(p->integer, ==, -42);
 410    g_assert(p->boolean == true);
 411    g_assert_cmpstr(p->string, ==, "foo");
 412
 413    g_free(p->string);
 414    g_free(p);
 415}
 416
 417static void test_visitor_in_struct_nested(TestInputVisitorData *data,
 418                                          const void *unused)
 419{
 420    g_autoptr(UserDefTwo) udp = NULL;
 421    Visitor *v;
 422
 423    v = visitor_input_test_init(data, "{ 'string0': 'string0', "
 424                                "'dict1': { 'string1': 'string1', "
 425                                "'dict2': { 'userdef': { 'integer': 42, "
 426                                "'string': 'string' }, 'string': 'string2'}}}");
 427
 428    visit_type_UserDefTwo(v, NULL, &udp, &error_abort);
 429
 430    g_assert_cmpstr(udp->string0, ==, "string0");
 431    g_assert_cmpstr(udp->dict1->string1, ==, "string1");
 432    g_assert_cmpint(udp->dict1->dict2->userdef->integer, ==, 42);
 433    g_assert_cmpstr(udp->dict1->dict2->userdef->string, ==, "string");
 434    g_assert_cmpstr(udp->dict1->dict2->string, ==, "string2");
 435    g_assert(udp->dict1->has_dict3 == false);
 436}
 437
 438static void test_visitor_in_list(TestInputVisitorData *data,
 439                                 const void *unused)
 440{
 441    UserDefOneList *item, *head = NULL;
 442    Visitor *v;
 443    int i;
 444
 445    v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
 446
 447    visit_type_UserDefOneList(v, NULL, &head, &error_abort);
 448    g_assert(head != NULL);
 449
 450    for (i = 0, item = head; item; item = item->next, i++) {
 451        char string[12];
 452
 453        snprintf(string, sizeof(string), "string%d", i);
 454        g_assert_cmpstr(item->value->string, ==, string);
 455        g_assert_cmpint(item->value->integer, ==, 42 + i);
 456    }
 457
 458    qapi_free_UserDefOneList(head);
 459    head = NULL;
 460
 461    /* An empty list is valid */
 462    v = visitor_input_test_init(data, "[]");
 463    visit_type_UserDefOneList(v, NULL, &head, &error_abort);
 464    g_assert(!head);
 465}
 466
 467static void test_visitor_in_list_struct(TestInputVisitorData *data,
 468                                        const void *unused)
 469{
 470    const char *int_member[] = {
 471        "integer", "s8", "s16", "s32", "s64", "u8", "u16", "u32", "u64" };
 472    g_autoptr(GString) json = g_string_new("");
 473    int i, j;
 474    const char *sep;
 475    g_autoptr(ArrayStruct) arrs = NULL;
 476    Visitor *v;
 477    intList *int_list;
 478    int8List *s8_list;
 479    int16List *s16_list;
 480    int32List *s32_list;
 481    int64List *s64_list;
 482    uint8List *u8_list;
 483    uint16List *u16_list;
 484    uint32List *u32_list;
 485    uint64List *u64_list;
 486    numberList *num_list;
 487    boolList *bool_list;
 488    strList *str_list;
 489
 490    g_string_append_printf(json, "{");
 491
 492    for (i = 0; i < G_N_ELEMENTS(int_member); i++) {
 493        g_string_append_printf(json, "'%s': [", int_member[i]);
 494        sep = "";
 495        for (j = 0; j < 32; j++) {
 496            g_string_append_printf(json, "%s%d", sep, j);
 497            sep = ", ";
 498        }
 499        g_string_append_printf(json, "], ");
 500    }
 501
 502    g_string_append_printf(json, "'number': [");
 503    sep = "";
 504    for (i = 0; i < 32; i++) {
 505        g_string_append_printf(json, "%s%f", sep, (double)i / 3);
 506        sep = ", ";
 507    }
 508    g_string_append_printf(json, "], ");
 509
 510    g_string_append_printf(json, "'boolean': [");
 511    sep = "";
 512    for (i = 0; i < 32; i++) {
 513        g_string_append_printf(json, "%s%s",
 514                               sep, i % 3 == 0 ? "true" : "false");
 515        sep = ", ";
 516    }
 517    g_string_append_printf(json, "], ");
 518
 519    g_string_append_printf(json, "'string': [");
 520    sep = "";
 521    for (i = 0; i < 32; i++) {
 522        g_string_append_printf(json, "%s'%d'", sep, i);
 523        sep = ", ";
 524    }
 525    g_string_append_printf(json, "]");
 526
 527    g_string_append_printf(json, "}");
 528
 529    v = visitor_input_test_init_raw(data, json->str);
 530    visit_type_ArrayStruct(v, NULL, &arrs, &error_abort);
 531
 532    i = 0;
 533    for (int_list = arrs->integer; int_list; int_list = int_list->next) {
 534        g_assert_cmpint(int_list->value, ==, i);
 535        i++;
 536    }
 537
 538    i = 0;
 539    for (s8_list = arrs->s8; s8_list; s8_list = s8_list->next) {
 540        g_assert_cmpint(s8_list->value, ==, i);
 541        i++;
 542    }
 543
 544    i = 0;
 545    for (s16_list = arrs->s16; s16_list; s16_list = s16_list->next) {
 546        g_assert_cmpint(s16_list->value, ==, i);
 547        i++;
 548    }
 549
 550    i = 0;
 551    for (s32_list = arrs->s32; s32_list; s32_list = s32_list->next) {
 552        g_assert_cmpint(s32_list->value, ==, i);
 553        i++;
 554    }
 555
 556    i = 0;
 557    for (s64_list = arrs->s64; s64_list; s64_list = s64_list->next) {
 558        g_assert_cmpint(s64_list->value, ==, i);
 559        i++;
 560    }
 561
 562    i = 0;
 563    for (u8_list = arrs->u8; u8_list; u8_list = u8_list->next) {
 564        g_assert_cmpint(u8_list->value, ==, i);
 565        i++;
 566    }
 567
 568    i = 0;
 569    for (u16_list = arrs->u16; u16_list; u16_list = u16_list->next) {
 570        g_assert_cmpint(u16_list->value, ==, i);
 571        i++;
 572    }
 573
 574    i = 0;
 575    for (u32_list = arrs->u32; u32_list; u32_list = u32_list->next) {
 576        g_assert_cmpint(u32_list->value, ==, i);
 577        i++;
 578    }
 579
 580    i = 0;
 581    for (u64_list = arrs->u64; u64_list; u64_list = u64_list->next) {
 582        g_assert_cmpint(u64_list->value, ==, i);
 583        i++;
 584    }
 585
 586    i = 0;
 587    for (num_list = arrs->number; num_list; num_list = num_list->next) {
 588        char expected[32], actual[32];
 589
 590        sprintf(expected, "%.6f", (double)i / 3);
 591        sprintf(actual, "%.6f", num_list->value);
 592        g_assert_cmpstr(expected, ==, actual);
 593        i++;
 594    }
 595
 596    i = 0;
 597    for (bool_list = arrs->boolean; bool_list; bool_list = bool_list->next) {
 598        g_assert_cmpint(bool_list->value, ==, i % 3 == 0);
 599        i++;
 600    }
 601
 602    i = 0;
 603    for (str_list = arrs->string; str_list; str_list = str_list->next) {
 604        char expected[32];
 605
 606        sprintf(expected, "%d", i);
 607        g_assert_cmpstr(str_list->value, ==, expected);
 608        i++;
 609    }
 610}
 611
 612static void test_visitor_in_any(TestInputVisitorData *data,
 613                                const void *unused)
 614{
 615    QObject *res = NULL;
 616    Visitor *v;
 617    QNum *qnum;
 618    QBool *qbool;
 619    QString *qstring;
 620    QDict *qdict;
 621    QObject *qobj;
 622    int64_t val;
 623
 624    v = visitor_input_test_init(data, "-42");
 625    visit_type_any(v, NULL, &res, &error_abort);
 626    qnum = qobject_to(QNum, res);
 627    g_assert(qnum);
 628    g_assert(qnum_get_try_int(qnum, &val));
 629    g_assert_cmpint(val, ==, -42);
 630    qobject_unref(res);
 631
 632    v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
 633    visit_type_any(v, NULL, &res, &error_abort);
 634    qdict = qobject_to(QDict, res);
 635    g_assert(qdict && qdict_size(qdict) == 3);
 636    qobj = qdict_get(qdict, "integer");
 637    g_assert(qobj);
 638    qnum = qobject_to(QNum, qobj);
 639    g_assert(qnum);
 640    g_assert(qnum_get_try_int(qnum, &val));
 641    g_assert_cmpint(val, ==, -42);
 642    qobj = qdict_get(qdict, "boolean");
 643    g_assert(qobj);
 644    qbool = qobject_to(QBool, qobj);
 645    g_assert(qbool);
 646    g_assert(qbool_get_bool(qbool) == true);
 647    qobj = qdict_get(qdict, "string");
 648    g_assert(qobj);
 649    qstring = qobject_to(QString, qobj);
 650    g_assert(qstring);
 651    g_assert_cmpstr(qstring_get_str(qstring), ==, "foo");
 652    qobject_unref(res);
 653}
 654
 655static void test_visitor_in_null(TestInputVisitorData *data,
 656                                 const void *unused)
 657{
 658    Visitor *v;
 659    Error *err = NULL;
 660    QNull *null;
 661    char *tmp;
 662
 663    /*
 664     * FIXME: Since QAPI doesn't know the 'null' type yet, we can't
 665     * test visit_type_null() by reading into a QAPI struct then
 666     * checking that it was populated correctly.  The best we can do
 667     * for now is ensure that we consumed null from the input, proven
 668     * by the fact that we can't re-read the key; and that we detect
 669     * when input is not null.
 670     */
 671
 672    v = visitor_input_test_init_full(data, false,
 673                                     "{ 'a': null, 'b': '' }");
 674    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 675    visit_type_null(v, "a", &null, &error_abort);
 676    g_assert(qobject_type(QOBJECT(null)) == QTYPE_QNULL);
 677    qobject_unref(null);
 678    visit_type_null(v, "b", &null, &err);
 679    error_free_or_abort(&err);
 680    g_assert(!null);
 681    visit_type_str(v, "c", &tmp, &err);
 682    error_free_or_abort(&err);
 683    g_assert(!tmp);
 684    visit_check_struct(v, &error_abort);
 685    visit_end_struct(v, NULL);
 686}
 687
 688static void test_visitor_in_union_flat(TestInputVisitorData *data,
 689                                       const void *unused)
 690{
 691    Visitor *v;
 692    g_autoptr(UserDefFlatUnion) tmp = NULL;
 693    UserDefUnionBase *base;
 694
 695    v = visitor_input_test_init(data,
 696                                "{ 'enum1': 'value1', "
 697                                "'integer': 41, "
 698                                "'string': 'str', "
 699                                "'boolean': true }");
 700
 701    visit_type_UserDefFlatUnion(v, NULL, &tmp, &error_abort);
 702    g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
 703    g_assert_cmpstr(tmp->string, ==, "str");
 704    g_assert_cmpint(tmp->integer, ==, 41);
 705    g_assert_cmpint(tmp->u.value1.boolean, ==, true);
 706
 707    base = qapi_UserDefFlatUnion_base(tmp);
 708    g_assert(&base->enum1 == &tmp->enum1);
 709}
 710
 711static void test_visitor_in_alternate(TestInputVisitorData *data,
 712                                      const void *unused)
 713{
 714    Visitor *v;
 715    UserDefAlternate *tmp;
 716    WrapAlternate *wrap;
 717
 718    v = visitor_input_test_init(data, "42");
 719    visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
 720    g_assert_cmpint(tmp->type, ==, QTYPE_QNUM);
 721    g_assert_cmpint(tmp->u.i, ==, 42);
 722    qapi_free_UserDefAlternate(tmp);
 723
 724    v = visitor_input_test_init(data, "'value1'");
 725    visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
 726    g_assert_cmpint(tmp->type, ==, QTYPE_QSTRING);
 727    g_assert_cmpint(tmp->u.e, ==, ENUM_ONE_VALUE1);
 728    qapi_free_UserDefAlternate(tmp);
 729
 730    v = visitor_input_test_init(data, "null");
 731    visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
 732    g_assert_cmpint(tmp->type, ==, QTYPE_QNULL);
 733    qapi_free_UserDefAlternate(tmp);
 734
 735    v = visitor_input_test_init(data, "{'integer':1, 'string':'str', "
 736                                "'enum1':'value1', 'boolean':true}");
 737    visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
 738    g_assert_cmpint(tmp->type, ==, QTYPE_QDICT);
 739    g_assert_cmpint(tmp->u.udfu.integer, ==, 1);
 740    g_assert_cmpstr(tmp->u.udfu.string, ==, "str");
 741    g_assert_cmpint(tmp->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
 742    g_assert_cmpint(tmp->u.udfu.u.value1.boolean, ==, true);
 743    g_assert_cmpint(tmp->u.udfu.u.value1.has_a_b, ==, false);
 744    qapi_free_UserDefAlternate(tmp);
 745
 746    v = visitor_input_test_init(data, "{ 'alt': 42 }");
 747    visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
 748    g_assert_cmpint(wrap->alt->type, ==, QTYPE_QNUM);
 749    g_assert_cmpint(wrap->alt->u.i, ==, 42);
 750    qapi_free_WrapAlternate(wrap);
 751
 752    v = visitor_input_test_init(data, "{ 'alt': 'value1' }");
 753    visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
 754    g_assert_cmpint(wrap->alt->type, ==, QTYPE_QSTRING);
 755    g_assert_cmpint(wrap->alt->u.e, ==, ENUM_ONE_VALUE1);
 756    qapi_free_WrapAlternate(wrap);
 757
 758    v = visitor_input_test_init(data, "{ 'alt': {'integer':1, 'string':'str', "
 759                                "'enum1':'value1', 'boolean':true} }");
 760    visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
 761    g_assert_cmpint(wrap->alt->type, ==, QTYPE_QDICT);
 762    g_assert_cmpint(wrap->alt->u.udfu.integer, ==, 1);
 763    g_assert_cmpstr(wrap->alt->u.udfu.string, ==, "str");
 764    g_assert_cmpint(wrap->alt->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
 765    g_assert_cmpint(wrap->alt->u.udfu.u.value1.boolean, ==, true);
 766    g_assert_cmpint(wrap->alt->u.udfu.u.value1.has_a_b, ==, false);
 767    qapi_free_WrapAlternate(wrap);
 768}
 769
 770static void test_visitor_in_alternate_number(TestInputVisitorData *data,
 771                                             const void *unused)
 772{
 773    Visitor *v;
 774    Error *err = NULL;
 775    AltEnumBool *aeb;
 776    AltEnumNum *aen;
 777    AltNumEnum *ans;
 778    AltEnumInt *asi;
 779
 780    /* Parsing an int */
 781
 782    v = visitor_input_test_init(data, "42");
 783    visit_type_AltEnumBool(v, NULL, &aeb, &err);
 784    error_free_or_abort(&err);
 785    qapi_free_AltEnumBool(aeb);
 786
 787    v = visitor_input_test_init(data, "42");
 788    visit_type_AltEnumNum(v, NULL, &aen, &error_abort);
 789    g_assert_cmpint(aen->type, ==, QTYPE_QNUM);
 790    g_assert_cmpfloat(aen->u.n, ==, 42);
 791    qapi_free_AltEnumNum(aen);
 792
 793    v = visitor_input_test_init(data, "42");
 794    visit_type_AltNumEnum(v, NULL, &ans, &error_abort);
 795    g_assert_cmpint(ans->type, ==, QTYPE_QNUM);
 796    g_assert_cmpfloat(ans->u.n, ==, 42);
 797    qapi_free_AltNumEnum(ans);
 798
 799    v = visitor_input_test_init(data, "42");
 800    visit_type_AltEnumInt(v, NULL, &asi, &error_abort);
 801    g_assert_cmpint(asi->type, ==, QTYPE_QNUM);
 802    g_assert_cmpint(asi->u.i, ==, 42);
 803    qapi_free_AltEnumInt(asi);
 804
 805    /* Parsing a double */
 806
 807    v = visitor_input_test_init(data, "42.5");
 808    visit_type_AltEnumBool(v, NULL, &aeb, &err);
 809    error_free_or_abort(&err);
 810    qapi_free_AltEnumBool(aeb);
 811
 812    v = visitor_input_test_init(data, "42.5");
 813    visit_type_AltEnumNum(v, NULL, &aen, &error_abort);
 814    g_assert_cmpint(aen->type, ==, QTYPE_QNUM);
 815    g_assert_cmpfloat(aen->u.n, ==, 42.5);
 816    qapi_free_AltEnumNum(aen);
 817
 818    v = visitor_input_test_init(data, "42.5");
 819    visit_type_AltNumEnum(v, NULL, &ans, &error_abort);
 820    g_assert_cmpint(ans->type, ==, QTYPE_QNUM);
 821    g_assert_cmpfloat(ans->u.n, ==, 42.5);
 822    qapi_free_AltNumEnum(ans);
 823
 824    v = visitor_input_test_init(data, "42.5");
 825    visit_type_AltEnumInt(v, NULL, &asi, &err);
 826    error_free_or_abort(&err);
 827    qapi_free_AltEnumInt(asi);
 828}
 829
 830static void input_visitor_test_add(const char *testpath,
 831                                   const void *user_data,
 832                                   void (*test_func)(TestInputVisitorData *data,
 833                                                     const void *user_data))
 834{
 835    g_test_add(testpath, TestInputVisitorData, user_data, NULL, test_func,
 836               visitor_input_teardown);
 837}
 838
 839static void test_visitor_in_errors(TestInputVisitorData *data,
 840                                   const void *unused)
 841{
 842    TestStruct *p = NULL;
 843    Error *err = NULL;
 844    Visitor *v;
 845    strList *q = NULL;
 846    UserDefTwo *r = NULL;
 847    WrapAlternate *s = NULL;
 848
 849    v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', "
 850                                "'string': -42 }");
 851
 852    visit_type_TestStruct(v, NULL, &p, &err);
 853    error_free_or_abort(&err);
 854    g_assert(!p);
 855
 856    v = visitor_input_test_init(data, "[ '1', '2', false, '3' ]");
 857    visit_type_strList(v, NULL, &q, &err);
 858    error_free_or_abort(&err);
 859    assert(!q);
 860
 861    v = visitor_input_test_init(data, "{ 'str':'hi' }");
 862    visit_type_UserDefTwo(v, NULL, &r, &err);
 863    error_free_or_abort(&err);
 864    assert(!r);
 865
 866    v = visitor_input_test_init(data, "{ }");
 867    visit_type_WrapAlternate(v, NULL, &s, &err);
 868    error_free_or_abort(&err);
 869    assert(!s);
 870}
 871
 872static void test_visitor_in_wrong_type(TestInputVisitorData *data,
 873                                       const void *unused)
 874{
 875    TestStruct *p = NULL;
 876    Visitor *v;
 877    strList *q = NULL;
 878    int64_t i;
 879    Error *err = NULL;
 880
 881    /* Make sure arrays and structs cannot be confused */
 882
 883    v = visitor_input_test_init(data, "[]");
 884    visit_type_TestStruct(v, NULL, &p, &err);
 885    error_free_or_abort(&err);
 886    g_assert(!p);
 887
 888    v = visitor_input_test_init(data, "{}");
 889    visit_type_strList(v, NULL, &q, &err);
 890    error_free_or_abort(&err);
 891    assert(!q);
 892
 893    /* Make sure primitives and struct cannot be confused */
 894
 895    v = visitor_input_test_init(data, "1");
 896    visit_type_TestStruct(v, NULL, &p, &err);
 897    error_free_or_abort(&err);
 898    g_assert(!p);
 899
 900    v = visitor_input_test_init(data, "{}");
 901    visit_type_int(v, NULL, &i, &err);
 902    error_free_or_abort(&err);
 903
 904    /* Make sure primitives and arrays cannot be confused */
 905
 906    v = visitor_input_test_init(data, "1");
 907    visit_type_strList(v, NULL, &q, &err);
 908    error_free_or_abort(&err);
 909    assert(!q);
 910
 911    v = visitor_input_test_init(data, "[]");
 912    visit_type_int(v, NULL, &i, &err);
 913    error_free_or_abort(&err);
 914}
 915
 916static void test_visitor_in_fail_struct(TestInputVisitorData *data,
 917                                        const void *unused)
 918{
 919    TestStruct *p = NULL;
 920    Error *err = NULL;
 921    Visitor *v;
 922
 923    v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }");
 924
 925    visit_type_TestStruct(v, NULL, &p, &err);
 926    error_free_or_abort(&err);
 927    g_assert(!p);
 928}
 929
 930static void test_visitor_in_fail_struct_nested(TestInputVisitorData *data,
 931                                               const void *unused)
 932{
 933    UserDefTwo *udp = NULL;
 934    Error *err = NULL;
 935    Visitor *v;
 936
 937    v = visitor_input_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}");
 938
 939    visit_type_UserDefTwo(v, NULL, &udp, &err);
 940    error_free_or_abort(&err);
 941    g_assert(!udp);
 942}
 943
 944static void test_visitor_in_fail_struct_in_list(TestInputVisitorData *data,
 945                                                const void *unused)
 946{
 947    UserDefOneList *head = NULL;
 948    Error *err = NULL;
 949    Visitor *v;
 950
 951    v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]");
 952
 953    visit_type_UserDefOneList(v, NULL, &head, &err);
 954    error_free_or_abort(&err);
 955    g_assert(!head);
 956}
 957
 958static void test_visitor_in_fail_struct_missing(TestInputVisitorData *data,
 959                                                const void *unused)
 960{
 961    Error *err = NULL;
 962    Visitor *v;
 963    QObject *any;
 964    QNull *null;
 965    GenericAlternate *alt;
 966    bool present;
 967    int en;
 968    int64_t i64;
 969    uint32_t u32;
 970    int8_t i8;
 971    char *str;
 972    double dbl;
 973
 974    v = visitor_input_test_init(data, "{ 'sub': [ {} ] }");
 975    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 976    visit_start_struct(v, "struct", NULL, 0, &err);
 977    error_free_or_abort(&err);
 978    visit_start_list(v, "list", NULL, 0, &err);
 979    error_free_or_abort(&err);
 980    visit_start_alternate(v, "alternate", &alt, sizeof(*alt), &err);
 981    error_free_or_abort(&err);
 982    visit_optional(v, "optional", &present);
 983    g_assert(!present);
 984    visit_type_enum(v, "enum", &en, &EnumOne_lookup, &err);
 985    error_free_or_abort(&err);
 986    visit_type_int(v, "i64", &i64, &err);
 987    error_free_or_abort(&err);
 988    visit_type_uint32(v, "u32", &u32, &err);
 989    error_free_or_abort(&err);
 990    visit_type_int8(v, "i8", &i8, &err);
 991    error_free_or_abort(&err);
 992    visit_type_str(v, "i8", &str, &err);
 993    error_free_or_abort(&err);
 994    visit_type_number(v, "dbl", &dbl, &err);
 995    error_free_or_abort(&err);
 996    visit_type_any(v, "any", &any, &err);
 997    error_free_or_abort(&err);
 998    visit_type_null(v, "null", &null, &err);
 999    error_free_or_abort(&err);
1000    visit_start_list(v, "sub", NULL, 0, &error_abort);
1001    visit_start_struct(v, NULL, NULL, 0, &error_abort);
1002    visit_type_int(v, "i64", &i64, &err);
1003    error_free_or_abort(&err);
1004    visit_end_struct(v, NULL);
1005    visit_end_list(v, NULL);
1006    visit_end_struct(v, NULL);
1007}
1008
1009static void test_visitor_in_fail_list(TestInputVisitorData *data,
1010                                      const void *unused)
1011{
1012    int64_t i64 = -1;
1013    Error *err = NULL;
1014    Visitor *v;
1015
1016    /* Unvisited list tail */
1017
1018    v = visitor_input_test_init(data, "[ 1, 2, 3 ]");
1019
1020    visit_start_list(v, NULL, NULL, 0, &error_abort);
1021    visit_type_int(v, NULL, &i64, &error_abort);
1022    g_assert_cmpint(i64, ==, 1);
1023    visit_type_int(v, NULL, &i64, &error_abort);
1024    g_assert_cmpint(i64, ==, 2);
1025    visit_check_list(v, &err);
1026    error_free_or_abort(&err);
1027    visit_end_list(v, NULL);
1028
1029    /* Visit beyond end of list */
1030    v = visitor_input_test_init(data, "[]");
1031
1032    visit_start_list(v, NULL, NULL, 0, &error_abort);
1033    visit_type_int(v, NULL, &i64, &err);
1034    error_free_or_abort(&err);
1035    visit_end_list(v, NULL);
1036}
1037
1038static void test_visitor_in_fail_list_nested(TestInputVisitorData *data,
1039                                             const void *unused)
1040{
1041    int64_t i64 = -1;
1042    Error *err = NULL;
1043    Visitor *v;
1044
1045    /* Unvisited nested list tail */
1046
1047    v = visitor_input_test_init(data, "[ 0, [ 1, 2, 3 ] ]");
1048
1049    visit_start_list(v, NULL, NULL, 0, &error_abort);
1050    visit_type_int(v, NULL, &i64, &error_abort);
1051    g_assert_cmpint(i64, ==, 0);
1052    visit_start_list(v, NULL, NULL, 0, &error_abort);
1053    visit_type_int(v, NULL, &i64, &error_abort);
1054    g_assert_cmpint(i64, ==, 1);
1055    visit_check_list(v, &err);
1056    error_free_or_abort(&err);
1057    visit_end_list(v, NULL);
1058    visit_check_list(v, &error_abort);
1059    visit_end_list(v, NULL);
1060}
1061
1062static void test_visitor_in_fail_union_flat(TestInputVisitorData *data,
1063                                            const void *unused)
1064{
1065    UserDefFlatUnion *tmp = NULL;
1066    Error *err = NULL;
1067    Visitor *v;
1068
1069    v = visitor_input_test_init(data, "{ 'enum1': 'value2', 'string': 'c', 'integer': 41, 'boolean': true }");
1070
1071    visit_type_UserDefFlatUnion(v, NULL, &tmp, &err);
1072    error_free_or_abort(&err);
1073    g_assert(!tmp);
1074}
1075
1076static void test_visitor_in_fail_union_flat_no_discrim(TestInputVisitorData *data,
1077                                                       const void *unused)
1078{
1079    UserDefFlatUnion2 *tmp = NULL;
1080    Error *err = NULL;
1081    Visitor *v;
1082
1083    /* test situation where discriminator field ('enum1' here) is missing */
1084    v = visitor_input_test_init(data, "{ 'integer': 42, 'string': 'c', 'string1': 'd', 'string2': 'e' }");
1085
1086    visit_type_UserDefFlatUnion2(v, NULL, &tmp, &err);
1087    error_free_or_abort(&err);
1088    g_assert(!tmp);
1089}
1090
1091static void test_visitor_in_fail_alternate(TestInputVisitorData *data,
1092                                           const void *unused)
1093{
1094    UserDefAlternate *tmp;
1095    Visitor *v;
1096    Error *err = NULL;
1097
1098    v = visitor_input_test_init(data, "3.14");
1099
1100    visit_type_UserDefAlternate(v, NULL, &tmp, &err);
1101    error_free_or_abort(&err);
1102    g_assert(!tmp);
1103}
1104
1105static void do_test_visitor_in_qmp_introspect(TestInputVisitorData *data,
1106                                              const QLitObject *qlit)
1107{
1108    g_autoptr(SchemaInfoList) schema = NULL;
1109    QObject *obj = qobject_from_qlit(qlit);
1110    Visitor *v;
1111
1112    v = qobject_input_visitor_new(obj);
1113
1114    visit_type_SchemaInfoList(v, NULL, &schema, &error_abort);
1115    g_assert(schema);
1116
1117    qobject_unref(obj);
1118    visit_free(v);
1119}
1120
1121static void test_visitor_in_qmp_introspect(TestInputVisitorData *data,
1122                                           const void *unused)
1123{
1124    do_test_visitor_in_qmp_introspect(data, &test_qmp_schema_qlit);
1125}
1126
1127int main(int argc, char **argv)
1128{
1129    g_test_init(&argc, &argv, NULL);
1130
1131    input_visitor_test_add("/visitor/input/int",
1132                           NULL, test_visitor_in_int);
1133    input_visitor_test_add("/visitor/input/uint",
1134                           NULL, test_visitor_in_uint);
1135    input_visitor_test_add("/visitor/input/int_overflow",
1136                           NULL, test_visitor_in_int_overflow);
1137    input_visitor_test_add("/visitor/input/int_keyval",
1138                           NULL, test_visitor_in_int_keyval);
1139    input_visitor_test_add("/visitor/input/int_str_keyval",
1140                           NULL, test_visitor_in_int_str_keyval);
1141    input_visitor_test_add("/visitor/input/int_str_fail",
1142                           NULL, test_visitor_in_int_str_fail);
1143    input_visitor_test_add("/visitor/input/bool",
1144                           NULL, test_visitor_in_bool);
1145    input_visitor_test_add("/visitor/input/bool_keyval",
1146                           NULL, test_visitor_in_bool_keyval);
1147    input_visitor_test_add("/visitor/input/bool_str_keyval",
1148                           NULL, test_visitor_in_bool_str_keyval);
1149    input_visitor_test_add("/visitor/input/bool_str_fail",
1150                           NULL, test_visitor_in_bool_str_fail);
1151    input_visitor_test_add("/visitor/input/number",
1152                           NULL, test_visitor_in_number);
1153    input_visitor_test_add("/visitor/input/large_number",
1154                           NULL, test_visitor_in_large_number);
1155    input_visitor_test_add("/visitor/input/number_keyval",
1156                           NULL, test_visitor_in_number_keyval);
1157    input_visitor_test_add("/visitor/input/number_str_keyval",
1158                           NULL, test_visitor_in_number_str_keyval);
1159    input_visitor_test_add("/visitor/input/number_str_fail",
1160                           NULL, test_visitor_in_number_str_fail);
1161    input_visitor_test_add("/visitor/input/size_str_keyval",
1162                           NULL, test_visitor_in_size_str_keyval);
1163    input_visitor_test_add("/visitor/input/size_str_fail",
1164                           NULL, test_visitor_in_size_str_fail);
1165    input_visitor_test_add("/visitor/input/string",
1166                           NULL, test_visitor_in_string);
1167    input_visitor_test_add("/visitor/input/enum",
1168                           NULL, test_visitor_in_enum);
1169    input_visitor_test_add("/visitor/input/struct",
1170                           NULL, test_visitor_in_struct);
1171    input_visitor_test_add("/visitor/input/struct-nested",
1172                           NULL, test_visitor_in_struct_nested);
1173    input_visitor_test_add("/visitor/input/list2",
1174                           NULL, test_visitor_in_list_struct);
1175    input_visitor_test_add("/visitor/input/list",
1176                           NULL, test_visitor_in_list);
1177    input_visitor_test_add("/visitor/input/any",
1178                           NULL, test_visitor_in_any);
1179    input_visitor_test_add("/visitor/input/null",
1180                           NULL, test_visitor_in_null);
1181    input_visitor_test_add("/visitor/input/union-flat",
1182                           NULL, test_visitor_in_union_flat);
1183    input_visitor_test_add("/visitor/input/alternate",
1184                           NULL, test_visitor_in_alternate);
1185    input_visitor_test_add("/visitor/input/errors",
1186                           NULL, test_visitor_in_errors);
1187    input_visitor_test_add("/visitor/input/wrong-type",
1188                           NULL, test_visitor_in_wrong_type);
1189    input_visitor_test_add("/visitor/input/alternate-number",
1190                           NULL, test_visitor_in_alternate_number);
1191    input_visitor_test_add("/visitor/input/fail/struct",
1192                           NULL, test_visitor_in_fail_struct);
1193    input_visitor_test_add("/visitor/input/fail/struct-nested",
1194                           NULL, test_visitor_in_fail_struct_nested);
1195    input_visitor_test_add("/visitor/input/fail/struct-in-list",
1196                           NULL, test_visitor_in_fail_struct_in_list);
1197    input_visitor_test_add("/visitor/input/fail/struct-missing",
1198                           NULL, test_visitor_in_fail_struct_missing);
1199    input_visitor_test_add("/visitor/input/fail/list",
1200                           NULL, test_visitor_in_fail_list);
1201    input_visitor_test_add("/visitor/input/fail/list-nested",
1202                           NULL, test_visitor_in_fail_list_nested);
1203    input_visitor_test_add("/visitor/input/fail/union-flat",
1204                           NULL, test_visitor_in_fail_union_flat);
1205    input_visitor_test_add("/visitor/input/fail/union-flat-no-discriminator",
1206                           NULL, test_visitor_in_fail_union_flat_no_discrim);
1207    input_visitor_test_add("/visitor/input/fail/alternate",
1208                           NULL, test_visitor_in_fail_alternate);
1209    input_visitor_test_add("/visitor/input/qapi-introspect",
1210                           NULL, test_visitor_in_qmp_introspect);
1211
1212    g_test_run();
1213
1214    return 0;
1215}
1216