qemu/tests/test-qmp-input-strict.c
<<
>>
Prefs
   1/*
   2 * QMP Input Visitor unit-tests (strict mode).
   3 *
   4 * Copyright (C) 2011-2012, 2015 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#include <glib.h>
  16
  17#include "qemu-common.h"
  18#include "qapi/error.h"
  19#include "qapi/qmp-input-visitor.h"
  20#include "test-qapi-types.h"
  21#include "test-qapi-visit.h"
  22#include "qapi/qmp/types.h"
  23#include "test-qmp-introspect.h"
  24#include "qmp-introspect.h"
  25#include "qapi-visit.h"
  26
  27typedef struct TestInputVisitorData {
  28    QObject *obj;
  29    QmpInputVisitor *qiv;
  30} TestInputVisitorData;
  31
  32static void validate_teardown(TestInputVisitorData *data,
  33                               const void *unused)
  34{
  35    qobject_decref(data->obj);
  36    data->obj = NULL;
  37
  38    if (data->qiv) {
  39        qmp_input_visitor_cleanup(data->qiv);
  40        data->qiv = NULL;
  41    }
  42}
  43
  44/* The various test_init functions are provided instead of a test setup
  45   function so that the JSON string used by the tests are kept in the test
  46   functions (and not in main()). */
  47static Visitor *validate_test_init_internal(TestInputVisitorData *data,
  48                                            const char *json_string,
  49                                            va_list *ap)
  50{
  51    Visitor *v;
  52
  53    validate_teardown(data, NULL);
  54
  55    data->obj = qobject_from_jsonv(json_string, ap);
  56    g_assert(data->obj);
  57
  58    data->qiv = qmp_input_visitor_new_strict(data->obj);
  59    g_assert(data->qiv);
  60
  61    v = qmp_input_get_visitor(data->qiv);
  62    g_assert(v);
  63
  64    return v;
  65}
  66
  67static GCC_FMT_ATTR(2, 3)
  68Visitor *validate_test_init(TestInputVisitorData *data,
  69                             const char *json_string, ...)
  70{
  71    Visitor *v;
  72    va_list ap;
  73
  74    va_start(ap, json_string);
  75    v = validate_test_init_internal(data, json_string, &ap);
  76    va_end(ap);
  77    return v;
  78}
  79
  80/* similar to validate_test_init(), but does not expect a string
  81 * literal/format json_string argument and so can be used for
  82 * programatically generated strings (and we can't pass in programatically
  83 * generated strings via %s format parameters since qobject_from_jsonv()
  84 * will wrap those in double-quotes and treat the entire object as a
  85 * string)
  86 */
  87static Visitor *validate_test_init_raw(TestInputVisitorData *data,
  88                                       const char *json_string)
  89{
  90    return validate_test_init_internal(data, json_string, NULL);
  91}
  92
  93
  94static void test_validate_struct(TestInputVisitorData *data,
  95                                  const void *unused)
  96{
  97    TestStruct *p = NULL;
  98    Visitor *v;
  99
 100    v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
 101
 102    visit_type_TestStruct(v, NULL, &p, &error_abort);
 103    g_free(p->string);
 104    g_free(p);
 105}
 106
 107static void test_validate_struct_nested(TestInputVisitorData *data,
 108                                         const void *unused)
 109{
 110    UserDefTwo *udp = NULL;
 111    Visitor *v;
 112
 113    v = validate_test_init(data, "{ 'string0': 'string0', "
 114                           "'dict1': { 'string1': 'string1', "
 115                           "'dict2': { 'userdef': { 'integer': 42, "
 116                           "'string': 'string' }, 'string': 'string2'}}}");
 117
 118    visit_type_UserDefTwo(v, NULL, &udp, &error_abort);
 119    qapi_free_UserDefTwo(udp);
 120}
 121
 122static void test_validate_list(TestInputVisitorData *data,
 123                                const void *unused)
 124{
 125    UserDefOneList *head = NULL;
 126    Visitor *v;
 127
 128    v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
 129
 130    visit_type_UserDefOneList(v, NULL, &head, &error_abort);
 131    qapi_free_UserDefOneList(head);
 132}
 133
 134static void test_validate_union_native_list(TestInputVisitorData *data,
 135                                            const void *unused)
 136{
 137    UserDefNativeListUnion *tmp = NULL;
 138    Visitor *v;
 139
 140    v = validate_test_init(data, "{ 'type': 'integer', 'data' : [ 1, 2 ] }");
 141
 142    visit_type_UserDefNativeListUnion(v, NULL, &tmp, &error_abort);
 143    qapi_free_UserDefNativeListUnion(tmp);
 144}
 145
 146static void test_validate_union_flat(TestInputVisitorData *data,
 147                                     const void *unused)
 148{
 149    UserDefFlatUnion *tmp = NULL;
 150    Visitor *v;
 151
 152    v = validate_test_init(data,
 153                           "{ 'enum1': 'value1', "
 154                           "'integer': 41, "
 155                           "'string': 'str', "
 156                           "'boolean': true }");
 157
 158    visit_type_UserDefFlatUnion(v, NULL, &tmp, &error_abort);
 159    qapi_free_UserDefFlatUnion(tmp);
 160}
 161
 162static void test_validate_alternate(TestInputVisitorData *data,
 163                                    const void *unused)
 164{
 165    UserDefAlternate *tmp = NULL;
 166    Visitor *v;
 167
 168    v = validate_test_init(data, "42");
 169
 170    visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
 171    qapi_free_UserDefAlternate(tmp);
 172}
 173
 174static void test_validate_fail_struct(TestInputVisitorData *data,
 175                                       const void *unused)
 176{
 177    TestStruct *p = NULL;
 178    Error *err = NULL;
 179    Visitor *v;
 180
 181    v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }");
 182
 183    visit_type_TestStruct(v, NULL, &p, &err);
 184    error_free_or_abort(&err);
 185    if (p) {
 186        g_free(p->string);
 187    }
 188    g_free(p);
 189}
 190
 191static void test_validate_fail_struct_nested(TestInputVisitorData *data,
 192                                              const void *unused)
 193{
 194    UserDefTwo *udp = NULL;
 195    Error *err = NULL;
 196    Visitor *v;
 197
 198    v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}");
 199
 200    visit_type_UserDefTwo(v, NULL, &udp, &err);
 201    error_free_or_abort(&err);
 202    qapi_free_UserDefTwo(udp);
 203}
 204
 205static void test_validate_fail_list(TestInputVisitorData *data,
 206                                     const void *unused)
 207{
 208    UserDefOneList *head = NULL;
 209    Error *err = NULL;
 210    Visitor *v;
 211
 212    v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]");
 213
 214    visit_type_UserDefOneList(v, NULL, &head, &err);
 215    error_free_or_abort(&err);
 216    qapi_free_UserDefOneList(head);
 217}
 218
 219static void test_validate_fail_union_native_list(TestInputVisitorData *data,
 220                                                 const void *unused)
 221{
 222    UserDefNativeListUnion *tmp = NULL;
 223    Error *err = NULL;
 224    Visitor *v;
 225
 226    v = validate_test_init(data,
 227                           "{ 'type': 'integer', 'data' : [ 'string' ] }");
 228
 229    visit_type_UserDefNativeListUnion(v, NULL, &tmp, &err);
 230    error_free_or_abort(&err);
 231    qapi_free_UserDefNativeListUnion(tmp);
 232}
 233
 234static void test_validate_fail_union_flat(TestInputVisitorData *data,
 235                                          const void *unused)
 236{
 237    UserDefFlatUnion *tmp = NULL;
 238    Error *err = NULL;
 239    Visitor *v;
 240
 241    v = validate_test_init(data, "{ 'string': 'c', 'integer': 41, 'boolean': true }");
 242
 243    visit_type_UserDefFlatUnion(v, NULL, &tmp, &err);
 244    error_free_or_abort(&err);
 245    qapi_free_UserDefFlatUnion(tmp);
 246}
 247
 248static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data,
 249                                                     const void *unused)
 250{
 251    UserDefFlatUnion2 *tmp = NULL;
 252    Error *err = NULL;
 253    Visitor *v;
 254
 255    /* test situation where discriminator field ('enum1' here) is missing */
 256    v = validate_test_init(data, "{ 'integer': 42, 'string': 'c', 'string1': 'd', 'string2': 'e' }");
 257
 258    visit_type_UserDefFlatUnion2(v, NULL, &tmp, &err);
 259    error_free_or_abort(&err);
 260    qapi_free_UserDefFlatUnion2(tmp);
 261}
 262
 263static void test_validate_fail_alternate(TestInputVisitorData *data,
 264                                         const void *unused)
 265{
 266    UserDefAlternate *tmp = NULL;
 267    Visitor *v;
 268    Error *err = NULL;
 269
 270    v = validate_test_init(data, "3.14");
 271
 272    visit_type_UserDefAlternate(v, NULL, &tmp, &err);
 273    error_free_or_abort(&err);
 274    qapi_free_UserDefAlternate(tmp);
 275}
 276
 277static void do_test_validate_qmp_introspect(TestInputVisitorData *data,
 278                                            const char *schema_json)
 279{
 280    SchemaInfoList *schema = NULL;
 281    Visitor *v;
 282
 283    v = validate_test_init_raw(data, schema_json);
 284
 285    visit_type_SchemaInfoList(v, NULL, &schema, &error_abort);
 286    g_assert(schema);
 287
 288    qapi_free_SchemaInfoList(schema);
 289}
 290
 291static void test_validate_qmp_introspect(TestInputVisitorData *data,
 292                                           const void *unused)
 293{
 294    do_test_validate_qmp_introspect(data, test_qmp_schema_json);
 295    do_test_validate_qmp_introspect(data, qmp_schema_json);
 296}
 297
 298static void validate_test_add(const char *testpath,
 299                               TestInputVisitorData *data,
 300                               void (*test_func)(TestInputVisitorData *data, const void *user_data))
 301{
 302    g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
 303               validate_teardown);
 304}
 305
 306int main(int argc, char **argv)
 307{
 308    TestInputVisitorData testdata;
 309
 310    g_test_init(&argc, &argv, NULL);
 311
 312    validate_test_add("/visitor/input-strict/pass/struct",
 313                      &testdata, test_validate_struct);
 314    validate_test_add("/visitor/input-strict/pass/struct-nested",
 315                      &testdata, test_validate_struct_nested);
 316    validate_test_add("/visitor/input-strict/pass/list",
 317                      &testdata, test_validate_list);
 318    validate_test_add("/visitor/input-strict/pass/union-flat",
 319                      &testdata, test_validate_union_flat);
 320    validate_test_add("/visitor/input-strict/pass/alternate",
 321                      &testdata, test_validate_alternate);
 322    validate_test_add("/visitor/input-strict/pass/union-native-list",
 323                      &testdata, test_validate_union_native_list);
 324    validate_test_add("/visitor/input-strict/fail/struct",
 325                      &testdata, test_validate_fail_struct);
 326    validate_test_add("/visitor/input-strict/fail/struct-nested",
 327                      &testdata, test_validate_fail_struct_nested);
 328    validate_test_add("/visitor/input-strict/fail/list",
 329                      &testdata, test_validate_fail_list);
 330    validate_test_add("/visitor/input-strict/fail/union-flat",
 331                      &testdata, test_validate_fail_union_flat);
 332    validate_test_add("/visitor/input-strict/fail/union-flat-no-discriminator",
 333                      &testdata, test_validate_fail_union_flat_no_discrim);
 334    validate_test_add("/visitor/input-strict/fail/alternate",
 335                      &testdata, test_validate_fail_alternate);
 336    validate_test_add("/visitor/input-strict/fail/union-native-list",
 337                      &testdata, test_validate_fail_union_native_list);
 338    validate_test_add("/visitor/input-strict/pass/qmp-introspect",
 339                      &testdata, test_validate_qmp_introspect);
 340
 341    g_test_run();
 342
 343    return 0;
 344}
 345