qemu/tests/test-string-input-visitor.c
<<
>>
Prefs
   1/*
   2 * String Input Visitor unit-tests.
   3 *
   4 * Copyright (C) 2012 Red Hat Inc.
   5 *
   6 * Authors:
   7 *  Paolo Bonzini <pbonzini@redhat.com> (based on test-qobject-input-visitor)
   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 "qemu/osdep.h"
  14
  15#include "qemu-common.h"
  16#include "qapi/error.h"
  17#include "qapi/string-input-visitor.h"
  18#include "test-qapi-visit.h"
  19
  20typedef struct TestInputVisitorData {
  21    Visitor *v;
  22} TestInputVisitorData;
  23
  24static void visitor_input_teardown(TestInputVisitorData *data,
  25                                   const void *unused)
  26{
  27    if (data->v) {
  28        visit_free(data->v);
  29        data->v = NULL;
  30    }
  31}
  32
  33/* This is provided instead of a test setup function so that the JSON
  34   string used by the tests are kept in the test functions (and not
  35   int main()) */
  36static
  37Visitor *visitor_input_test_init(TestInputVisitorData *data,
  38                                 const char *string)
  39{
  40    visitor_input_teardown(data, NULL);
  41
  42    data->v = string_input_visitor_new(string);
  43    g_assert(data->v);
  44    return data->v;
  45}
  46
  47static void test_visitor_in_int(TestInputVisitorData *data,
  48                                const void *unused)
  49{
  50    int64_t res = 0, value = -42;
  51    Error *err = NULL;
  52    Visitor *v;
  53
  54    v = visitor_input_test_init(data, "-42");
  55
  56    visit_type_int(v, NULL, &res, &err);
  57    g_assert(!err);
  58    g_assert_cmpint(res, ==, value);
  59
  60    v = visitor_input_test_init(data, "not an int");
  61
  62    visit_type_int(v, NULL, &res, &err);
  63    error_free_or_abort(&err);
  64
  65    v = visitor_input_test_init(data, "");
  66
  67    visit_type_int(v, NULL, &res, &err);
  68    error_free_or_abort(&err);
  69}
  70
  71static void check_ilist(Visitor *v, int64_t *expected, size_t n)
  72{
  73    int64List *res = NULL;
  74    int64List *tail;
  75    int i;
  76
  77    visit_type_int64List(v, NULL, &res, &error_abort);
  78    tail = res;
  79    for (i = 0; i < n; i++) {
  80        g_assert(tail);
  81        g_assert_cmpint(tail->value, ==, expected[i]);
  82        tail = tail->next;
  83    }
  84    g_assert(!tail);
  85
  86    qapi_free_int64List(res);
  87}
  88
  89static void check_ulist(Visitor *v, uint64_t *expected, size_t n)
  90{
  91    uint64List *res = NULL;
  92    uint64List *tail;
  93    int i;
  94
  95    /* BUG: unsigned numbers above INT64_MAX don't work */
  96    for (i = 0; i < n; i++) {
  97        if (expected[i] > INT64_MAX) {
  98            Error *err = NULL;
  99            visit_type_uint64List(v, NULL, &res, &err);
 100            error_free_or_abort(&err);
 101            return;
 102        }
 103    }
 104
 105    visit_type_uint64List(v, NULL, &res, &error_abort);
 106    tail = res;
 107    for (i = 0; i < n; i++) {
 108        g_assert(tail);
 109        g_assert_cmpuint(tail->value, ==, expected[i]);
 110        tail = tail->next;
 111    }
 112    g_assert(!tail);
 113
 114    qapi_free_uint64List(res);
 115}
 116
 117static void test_visitor_in_intList(TestInputVisitorData *data,
 118                                    const void *unused)
 119{
 120    /* Note: the visitor *sorts* ranges *unsigned* */
 121    int64_t expect1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20 };
 122    int64_t expect2[] = { 32767, -32768, -32767 };
 123    int64_t expect3[] = { INT64_MAX, INT64_MIN };
 124    uint64_t expect4[] = { UINT64_MAX };
 125    Error *err = NULL;
 126    int64List *res = NULL;
 127    int64List *tail;
 128    Visitor *v;
 129    int64_t val;
 130
 131    /* Valid lists */
 132
 133    v = visitor_input_test_init(data, "1,2,0,2-4,20,5-9,1-8");
 134    check_ilist(v, expect1, ARRAY_SIZE(expect1));
 135
 136    v = visitor_input_test_init(data, "32767,-32768--32767");
 137    check_ilist(v, expect2, ARRAY_SIZE(expect2));
 138
 139    v = visitor_input_test_init(data,
 140                                "-9223372036854775808,9223372036854775807");
 141    check_ilist(v, expect3, ARRAY_SIZE(expect3));
 142
 143    v = visitor_input_test_init(data, "18446744073709551615");
 144    check_ulist(v, expect4, ARRAY_SIZE(expect4));
 145
 146    /* Empty list */
 147
 148    v = visitor_input_test_init(data, "");
 149    visit_type_int64List(v, NULL, &res, &error_abort);
 150    g_assert(!res);
 151
 152    /* Not a list */
 153
 154    v = visitor_input_test_init(data, "not an int list");
 155
 156    visit_type_int64List(v, NULL, &res, &err);
 157    error_free_or_abort(&err);
 158    g_assert(!res);
 159
 160    /* Unvisited list tail */
 161
 162    v = visitor_input_test_init(data, "0,2-3");
 163
 164    /* Would be simpler if the visitor genuinely supported virtual walks */
 165    visit_start_list(v, NULL, (GenericList **)&res, sizeof(*res),
 166                     &error_abort);
 167    tail = res;
 168    visit_type_int64(v, NULL, &tail->value, &error_abort);
 169    g_assert_cmpint(tail->value, ==, 0);
 170    tail = (int64List *)visit_next_list(v, (GenericList *)tail, sizeof(*res));
 171    g_assert(tail);
 172    visit_type_int64(v, NULL, &tail->value, &error_abort);
 173    g_assert_cmpint(tail->value, ==, 2);
 174    tail = (int64List *)visit_next_list(v, (GenericList *)tail, sizeof(*res));
 175    g_assert(tail);
 176
 177    visit_check_list(v, &err);
 178    error_free_or_abort(&err);
 179    visit_end_list(v, (void **)&res);
 180
 181    qapi_free_int64List(res);
 182
 183    /* Visit beyond end of list */
 184    v = visitor_input_test_init(data, "0");
 185
 186    visit_start_list(v, NULL, (GenericList **)&res, sizeof(*res),
 187                     &error_abort);
 188    tail = res;
 189    visit_type_int64(v, NULL, &tail->value, &err);
 190    g_assert_cmpint(tail->value, ==, 0);
 191    visit_type_int64(v, NULL, &val, &err);
 192    g_assert_cmpint(val, ==, 1); /* BUG */
 193    visit_check_list(v, &error_abort);
 194    visit_end_list(v, (void **)&res);
 195
 196    qapi_free_int64List(res);
 197}
 198
 199static void test_visitor_in_bool(TestInputVisitorData *data,
 200                                 const void *unused)
 201{
 202    Error *err = NULL;
 203    bool res = false;
 204    Visitor *v;
 205
 206    v = visitor_input_test_init(data, "true");
 207
 208    visit_type_bool(v, NULL, &res, &err);
 209    g_assert(!err);
 210    g_assert_cmpint(res, ==, true);
 211
 212    v = visitor_input_test_init(data, "yes");
 213
 214    visit_type_bool(v, NULL, &res, &err);
 215    g_assert(!err);
 216    g_assert_cmpint(res, ==, true);
 217
 218    v = visitor_input_test_init(data, "on");
 219
 220    visit_type_bool(v, NULL, &res, &err);
 221    g_assert(!err);
 222    g_assert_cmpint(res, ==, true);
 223
 224    v = visitor_input_test_init(data, "false");
 225
 226    visit_type_bool(v, NULL, &res, &err);
 227    g_assert(!err);
 228    g_assert_cmpint(res, ==, false);
 229
 230    v = visitor_input_test_init(data, "no");
 231
 232    visit_type_bool(v, NULL, &res, &err);
 233    g_assert(!err);
 234    g_assert_cmpint(res, ==, false);
 235
 236    v = visitor_input_test_init(data, "off");
 237
 238    visit_type_bool(v, NULL, &res, &err);
 239    g_assert(!err);
 240    g_assert_cmpint(res, ==, false);
 241}
 242
 243static void test_visitor_in_number(TestInputVisitorData *data,
 244                                   const void *unused)
 245{
 246    double res = 0, value = 3.14;
 247    Error *err = NULL;
 248    Visitor *v;
 249
 250    v = visitor_input_test_init(data, "3.14");
 251
 252    visit_type_number(v, NULL, &res, &err);
 253    g_assert(!err);
 254    g_assert_cmpfloat(res, ==, value);
 255}
 256
 257static void test_visitor_in_string(TestInputVisitorData *data,
 258                                   const void *unused)
 259{
 260    char *res = NULL, *value = (char *) "Q E M U";
 261    Error *err = NULL;
 262    Visitor *v;
 263
 264    v = visitor_input_test_init(data, value);
 265
 266    visit_type_str(v, NULL, &res, &err);
 267    g_assert(!err);
 268    g_assert_cmpstr(res, ==, value);
 269
 270    g_free(res);
 271}
 272
 273static void test_visitor_in_enum(TestInputVisitorData *data,
 274                                 const void *unused)
 275{
 276    Error *err = NULL;
 277    Visitor *v;
 278    EnumOne i;
 279
 280    for (i = 0; i < ENUM_ONE__MAX; i++) {
 281        EnumOne res = -1;
 282
 283        v = visitor_input_test_init(data, EnumOne_str(i));
 284
 285        visit_type_EnumOne(v, NULL, &res, &err);
 286        g_assert(!err);
 287        g_assert_cmpint(i, ==, res);
 288    }
 289}
 290
 291/* Try to crash the visitors */
 292static void test_visitor_in_fuzz(TestInputVisitorData *data,
 293                                 const void *unused)
 294{
 295    int64_t ires;
 296    intList *ilres;
 297    bool bres;
 298    double nres;
 299    char *sres;
 300    EnumOne eres;
 301    Visitor *v;
 302    unsigned int i;
 303    char buf[10000];
 304
 305    for (i = 0; i < 100; i++) {
 306        unsigned int j;
 307
 308        j = g_test_rand_int_range(0, sizeof(buf) - 1);
 309
 310        buf[j] = '\0';
 311
 312        if (j != 0) {
 313            for (j--; j != 0; j--) {
 314                buf[j - 1] = (char)g_test_rand_int_range(0, 256);
 315            }
 316        }
 317
 318        v = visitor_input_test_init(data, buf);
 319        visit_type_int(v, NULL, &ires, NULL);
 320
 321        v = visitor_input_test_init(data, buf);
 322        visit_type_intList(v, NULL, &ilres, NULL);
 323        qapi_free_intList(ilres);
 324
 325        v = visitor_input_test_init(data, buf);
 326        visit_type_bool(v, NULL, &bres, NULL);
 327
 328        v = visitor_input_test_init(data, buf);
 329        visit_type_number(v, NULL, &nres, NULL);
 330
 331        v = visitor_input_test_init(data, buf);
 332        sres = NULL;
 333        visit_type_str(v, NULL, &sres, NULL);
 334        g_free(sres);
 335
 336        v = visitor_input_test_init(data, buf);
 337        visit_type_EnumOne(v, NULL, &eres, NULL);
 338    }
 339}
 340
 341static void input_visitor_test_add(const char *testpath,
 342                                   TestInputVisitorData *data,
 343                                   void (*test_func)(TestInputVisitorData *data, const void *user_data))
 344{
 345    g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
 346               visitor_input_teardown);
 347}
 348
 349int main(int argc, char **argv)
 350{
 351    TestInputVisitorData in_visitor_data;
 352
 353    g_test_init(&argc, &argv, NULL);
 354
 355    input_visitor_test_add("/string-visitor/input/int",
 356                           &in_visitor_data, test_visitor_in_int);
 357    input_visitor_test_add("/string-visitor/input/intList",
 358                           &in_visitor_data, test_visitor_in_intList);
 359    input_visitor_test_add("/string-visitor/input/bool",
 360                           &in_visitor_data, test_visitor_in_bool);
 361    input_visitor_test_add("/string-visitor/input/number",
 362                           &in_visitor_data, test_visitor_in_number);
 363    input_visitor_test_add("/string-visitor/input/string",
 364                            &in_visitor_data, test_visitor_in_string);
 365    input_visitor_test_add("/string-visitor/input/enum",
 366                            &in_visitor_data, test_visitor_in_enum);
 367    input_visitor_test_add("/string-visitor/input/fuzz",
 368                            &in_visitor_data, test_visitor_in_fuzz);
 369
 370    g_test_run();
 371
 372    return 0;
 373}
 374