1 /* 2 * Options Visitor unit-tests. 3 * 4 * Copyright (C) 2013 Red Hat, Inc. 5 * 6 * Authors: 7 * Laszlo Ersek <lersek@redhat.com> (based on test-string-output-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/config-file.h" /* qemu_add_opts() */ 16 #include "qemu/option.h" /* qemu_opts_parse() */ 17 #include "qapi/error.h" 18 #include "qapi/opts-visitor.h" /* opts_visitor_new() */ 19 #include "test-qapi-visit.h" /* visit_type_UserDefOptions() */ 20 21 static QemuOptsList userdef_opts = { 22 .name = "userdef", 23 .head = QTAILQ_HEAD_INITIALIZER(userdef_opts.head), 24 .desc = { { 0 } } /* validated with OptsVisitor */ 25 }; 26 27 /* fixture (= glib test case context) and test case manipulation */ 28 29 typedef struct OptsVisitorFixture { 30 UserDefOptions *userdef; 31 Error *err; 32 } OptsVisitorFixture; 33 34 35 static void 36 setup_fixture(OptsVisitorFixture *f, gconstpointer test_data) 37 { 38 const char *opts_string = test_data; 39 QemuOpts *opts; 40 Visitor *v; 41 42 opts = qemu_opts_parse(qemu_find_opts("userdef"), opts_string, false, 43 NULL); 44 g_assert(opts != NULL); 45 46 v = opts_visitor_new(opts); 47 visit_type_UserDefOptions(v, NULL, &f->userdef, &f->err); 48 visit_free(v); 49 qemu_opts_del(opts); 50 } 51 52 53 static void 54 teardown_fixture(OptsVisitorFixture *f, gconstpointer test_data) 55 { 56 qapi_free_UserDefOptions(f->userdef); 57 error_free(f->err); 58 } 59 60 61 static void 62 add_test(const char *testpath, 63 void (*test_func)(OptsVisitorFixture *f, gconstpointer test_data), 64 gconstpointer test_data) 65 { 66 g_test_add(testpath, OptsVisitorFixture, test_data, setup_fixture, 67 test_func, teardown_fixture); 68 } 69 70 /* test output evaluation */ 71 72 static void 73 expect_ok(OptsVisitorFixture *f, gconstpointer test_data) 74 { 75 g_assert(f->err == NULL); 76 g_assert(f->userdef != NULL); 77 } 78 79 80 static void 81 expect_fail(OptsVisitorFixture *f, gconstpointer test_data) 82 { 83 g_assert(f->err != NULL); 84 85 /* The error message is printed when this test utility is invoked directly 86 * (ie. without gtester) and the --verbose flag is passed: 87 * 88 * tests/test-opts-visitor --verbose 89 */ 90 g_test_message("'%s': %s", (const char *)test_data, 91 error_get_pretty(f->err)); 92 } 93 94 95 static void 96 test_value(OptsVisitorFixture *f, gconstpointer test_data) 97 { 98 uint64_t magic, bitval; 99 intList *i64; 100 uint64List *u64; 101 uint16List *u16; 102 103 expect_ok(f, test_data); 104 105 magic = 0; 106 for (i64 = f->userdef->i64; i64 != NULL; i64 = i64->next) { 107 g_assert(-16 <= i64->value && i64->value < 64-16); 108 bitval = 1ull << (i64->value + 16); 109 g_assert((magic & bitval) == 0); 110 magic |= bitval; 111 } 112 g_assert(magic == 0xDEADBEEF); 113 114 magic = 0; 115 for (u64 = f->userdef->u64; u64 != NULL; u64 = u64->next) { 116 g_assert(u64->value < 64); 117 bitval = 1ull << u64->value; 118 g_assert((magic & bitval) == 0); 119 magic |= bitval; 120 } 121 g_assert(magic == 0xBADC0FFEE0DDF00DULL); 122 123 magic = 0; 124 for (u16 = f->userdef->u16; u16 != NULL; u16 = u16->next) { 125 g_assert(u16->value < 64); 126 bitval = 1ull << u16->value; 127 g_assert((magic & bitval) == 0); 128 magic |= bitval; 129 } 130 g_assert(magic == 0xD15EA5E); 131 } 132 133 134 static void 135 expect_i64_min(OptsVisitorFixture *f, gconstpointer test_data) 136 { 137 expect_ok(f, test_data); 138 g_assert(f->userdef->has_i64); 139 g_assert(f->userdef->i64->next == NULL); 140 g_assert(f->userdef->i64->value == INT64_MIN); 141 } 142 143 144 static void 145 expect_i64_max(OptsVisitorFixture *f, gconstpointer test_data) 146 { 147 expect_ok(f, test_data); 148 g_assert(f->userdef->has_i64); 149 g_assert(f->userdef->i64->next == NULL); 150 g_assert(f->userdef->i64->value == INT64_MAX); 151 } 152 153 154 static void 155 expect_zero(OptsVisitorFixture *f, gconstpointer test_data) 156 { 157 expect_ok(f, test_data); 158 g_assert(f->userdef->has_u64); 159 g_assert(f->userdef->u64->next == NULL); 160 g_assert(f->userdef->u64->value == 0); 161 } 162 163 164 static void 165 expect_u64_max(OptsVisitorFixture *f, gconstpointer test_data) 166 { 167 expect_ok(f, test_data); 168 g_assert(f->userdef->has_u64); 169 g_assert(f->userdef->u64->next == NULL); 170 g_assert(f->userdef->u64->value == UINT64_MAX); 171 } 172 173 /* test cases */ 174 175 static void 176 test_opts_range_unvisited(void) 177 { 178 Error *err = NULL; 179 intList *list = NULL; 180 intList *tail; 181 QemuOpts *opts; 182 Visitor *v; 183 184 opts = qemu_opts_parse(qemu_find_opts("userdef"), "ilist=0-2", false, 185 &error_abort); 186 187 v = opts_visitor_new(opts); 188 189 visit_start_struct(v, NULL, NULL, 0, &error_abort); 190 191 /* Would be simpler if the visitor genuinely supported virtual walks */ 192 visit_start_list(v, "ilist", (GenericList **)&list, sizeof(*list), 193 &error_abort); 194 tail = list; 195 visit_type_int(v, NULL, &tail->value, &error_abort); 196 g_assert_cmpint(tail->value, ==, 0); 197 tail = (intList *)visit_next_list(v, (GenericList *)tail, sizeof(*list)); 198 g_assert(tail); 199 visit_type_int(v, NULL, &tail->value, &error_abort); 200 g_assert_cmpint(tail->value, ==, 1); 201 tail = (intList *)visit_next_list(v, (GenericList *)tail, sizeof(*list)); 202 g_assert(tail); 203 visit_check_list(v, &error_abort); /* unvisited tail ignored until... */ 204 visit_end_list(v, (void **)&list); 205 206 visit_check_struct(v, &err); /* ...here */ 207 error_free_or_abort(&err); 208 visit_end_struct(v, NULL); 209 210 qapi_free_intList(list); 211 visit_free(v); 212 qemu_opts_del(opts); 213 } 214 215 static void 216 test_opts_range_beyond(void) 217 { 218 Error *err = NULL; 219 intList *list = NULL; 220 intList *tail; 221 QemuOpts *opts; 222 Visitor *v; 223 int64_t val; 224 225 opts = qemu_opts_parse(qemu_find_opts("userdef"), "ilist=0", false, 226 &error_abort); 227 228 v = opts_visitor_new(opts); 229 230 visit_start_struct(v, NULL, NULL, 0, &error_abort); 231 232 /* Would be simpler if the visitor genuinely supported virtual walks */ 233 visit_start_list(v, "ilist", (GenericList **)&list, sizeof(*list), 234 &error_abort); 235 tail = list; 236 visit_type_int(v, NULL, &tail->value, &error_abort); 237 g_assert_cmpint(tail->value, ==, 0); 238 tail = (intList *)visit_next_list(v, (GenericList *)tail, sizeof(*tail)); 239 g_assert(!tail); 240 visit_type_int(v, NULL, &val, &err); 241 error_free_or_abort(&err); 242 visit_end_list(v, (void **)&list); 243 244 visit_check_struct(v, &error_abort); 245 visit_end_struct(v, NULL); 246 247 qapi_free_intList(list); 248 visit_free(v); 249 qemu_opts_del(opts); 250 } 251 252 static void 253 test_opts_dict_unvisited(void) 254 { 255 Error *err = NULL; 256 QemuOpts *opts; 257 Visitor *v; 258 UserDefOptions *userdef; 259 260 opts = qemu_opts_parse(qemu_find_opts("userdef"), "i64x=0,bogus=1", false, 261 &error_abort); 262 263 v = opts_visitor_new(opts); 264 visit_type_UserDefOptions(v, NULL, &userdef, &err); 265 error_free_or_abort(&err); 266 visit_free(v); 267 qemu_opts_del(opts); 268 g_assert(!userdef); 269 } 270 271 int 272 main(int argc, char **argv) 273 { 274 g_test_init(&argc, &argv, NULL); 275 276 qemu_add_opts(&userdef_opts); 277 278 /* Three hexadecimal magic numbers, "dead beef", "bad coffee, odd food" and 279 * "disease", from 280 * <http://en.wikipedia.org/wiki/Magic_number_%28programming%29>, were 281 * converted to binary and dissected into bit ranges. Each magic number is 282 * going to be recomposed using the lists called "i64", "u64" and "u16", 283 * respectively. 284 * 285 * (Note that these types pertain to the individual bit shift counts, not 286 * the magic numbers themselves; the intent is to exercise opts_type_int() 287 * and opts_type_uint64().) 288 * 289 * The "i64" shift counts have been decreased by 16 (decimal) in order to 290 * test negative values as well. Finally, the full list of QemuOpt elements 291 * has been permuted with "shuf". 292 * 293 * Both "i64" and "u64" have some (distinct) single-element ranges 294 * represented as both "a" and "a-a". "u16" is a special case of "i64" (see 295 * visit_type_uint16()), so it wouldn't add a separate test in this regard. 296 */ 297 298 add_test("/visitor/opts/flatten/value", &test_value, 299 "i64=-1-0,u64=12-16,u64=2-3,i64=-11--9,u64=57,u16=9,i64=5-5," 300 "u16=1-4,u16=20,u64=63-63,i64=-16--13,u64=50-52,i64=14-15,u16=11," 301 "i64=7,u16=18,i64=2-3,u16=6,u64=54-55,u64=0,u64=18-20,u64=33-43," 302 "i64=9-12,u16=26-27,u64=59-61,u16=13-16,u64=29-31,u64=22-23," 303 "u16=24,i64=-7--3"); 304 305 add_test("/visitor/opts/i64/val1/errno", &expect_fail, 306 "i64=0x8000000000000000"); 307 add_test("/visitor/opts/i64/val1/empty", &expect_fail, "i64="); 308 add_test("/visitor/opts/i64/val1/trailing", &expect_fail, "i64=5z"); 309 add_test("/visitor/opts/i64/nonlist", &expect_fail, "i64x=5-6"); 310 add_test("/visitor/opts/i64/val2/errno", &expect_fail, 311 "i64=0x7fffffffffffffff-0x8000000000000000"); 312 add_test("/visitor/opts/i64/val2/empty", &expect_fail, "i64=5-"); 313 add_test("/visitor/opts/i64/val2/trailing", &expect_fail, "i64=5-6z"); 314 add_test("/visitor/opts/i64/range/empty", &expect_fail, "i64=6-5"); 315 add_test("/visitor/opts/i64/range/minval", &expect_i64_min, 316 "i64=-0x8000000000000000--0x8000000000000000"); 317 add_test("/visitor/opts/i64/range/maxval", &expect_i64_max, 318 "i64=0x7fffffffffffffff-0x7fffffffffffffff"); 319 320 add_test("/visitor/opts/u64/val1/errno", &expect_fail, "u64=-1"); 321 add_test("/visitor/opts/u64/val1/empty", &expect_fail, "u64="); 322 add_test("/visitor/opts/u64/val1/trailing", &expect_fail, "u64=5z"); 323 add_test("/visitor/opts/u64/nonlist", &expect_fail, "u64x=5-6"); 324 add_test("/visitor/opts/u64/val2/errno", &expect_fail, 325 "u64=0xffffffffffffffff-0x10000000000000000"); 326 add_test("/visitor/opts/u64/val2/empty", &expect_fail, "u64=5-"); 327 add_test("/visitor/opts/u64/val2/trailing", &expect_fail, "u64=5-6z"); 328 add_test("/visitor/opts/u64/range/empty", &expect_fail, "u64=6-5"); 329 add_test("/visitor/opts/u64/range/minval", &expect_zero, "u64=0-0"); 330 add_test("/visitor/opts/u64/range/maxval", &expect_u64_max, 331 "u64=0xffffffffffffffff-0xffffffffffffffff"); 332 333 /* Test maximum range sizes. The macro value is open-coded here 334 * *intentionally*; the test case must use concrete values by design. If 335 * OPTS_VISITOR_RANGE_MAX is changed, the following values need to be 336 * recalculated as well. The assert and this comment should help with it. 337 */ 338 g_assert(OPTS_VISITOR_RANGE_MAX == 65536); 339 340 /* The unsigned case is simple, a u64-u64 difference can always be 341 * represented as a u64. 342 */ 343 add_test("/visitor/opts/u64/range/max", &expect_ok, "u64=0-65535"); 344 add_test("/visitor/opts/u64/range/2big", &expect_fail, "u64=0-65536"); 345 346 /* The same cannot be said about an i64-i64 difference. */ 347 add_test("/visitor/opts/i64/range/max/pos/a", &expect_ok, 348 "i64=0x7fffffffffff0000-0x7fffffffffffffff"); 349 add_test("/visitor/opts/i64/range/max/pos/b", &expect_ok, 350 "i64=0x7ffffffffffeffff-0x7ffffffffffffffe"); 351 add_test("/visitor/opts/i64/range/2big/pos", &expect_fail, 352 "i64=0x7ffffffffffeffff-0x7fffffffffffffff"); 353 add_test("/visitor/opts/i64/range/max/neg/a", &expect_ok, 354 "i64=-0x8000000000000000--0x7fffffffffff0001"); 355 add_test("/visitor/opts/i64/range/max/neg/b", &expect_ok, 356 "i64=-0x7fffffffffffffff--0x7fffffffffff0000"); 357 add_test("/visitor/opts/i64/range/2big/neg", &expect_fail, 358 "i64=-0x8000000000000000--0x7fffffffffff0000"); 359 add_test("/visitor/opts/i64/range/2big/full", &expect_fail, 360 "i64=-0x8000000000000000-0x7fffffffffffffff"); 361 362 g_test_add_func("/visitor/opts/range/unvisited", 363 test_opts_range_unvisited); 364 g_test_add_func("/visitor/opts/range/beyond", 365 test_opts_range_beyond); 366 367 g_test_add_func("/visitor/opts/dict/unvisited", test_opts_dict_unvisited); 368 369 g_test_run(); 370 return 0; 371 } 372