]>
Commit | Line | Data |
---|---|---|
4ba6fabf LD |
1 | /* |
2 | * QemuOpts unit-tests. | |
3 | * | |
4 | * Copyright (C) 2014 Leandro Dorileo <l@dorileo.org> | |
5 | * | |
6 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
7 | * See the COPYING.LIB file in the top-level directory. | |
8 | */ | |
9 | ||
681c28a3 | 10 | #include "qemu/osdep.h" |
694baf57 | 11 | #include "qemu/cutils.h" |
da34e65c | 12 | #include "qapi/error.h" |
4ba6fabf LD |
13 | #include "qapi/qmp/qstring.h" |
14 | #include "qemu/config-file.h" | |
15 | ||
4ba6fabf LD |
16 | |
17 | static QemuOptsList opts_list_01 = { | |
18 | .name = "opts_list_01", | |
19 | .head = QTAILQ_HEAD_INITIALIZER(opts_list_01.head), | |
20 | .desc = { | |
21 | { | |
22 | .name = "str1", | |
23 | .type = QEMU_OPT_STRING, | |
24 | },{ | |
25 | .name = "str2", | |
26 | .type = QEMU_OPT_STRING, | |
27 | },{ | |
28 | .name = "str3", | |
29 | .type = QEMU_OPT_STRING, | |
30 | },{ | |
31 | .name = "number1", | |
32 | .type = QEMU_OPT_NUMBER, | |
694baf57 MA |
33 | },{ |
34 | .name = "number2", | |
35 | .type = QEMU_OPT_NUMBER, | |
4ba6fabf LD |
36 | }, |
37 | { /* end of list */ } | |
38 | }, | |
39 | }; | |
40 | ||
41 | static QemuOptsList opts_list_02 = { | |
42 | .name = "opts_list_02", | |
43 | .head = QTAILQ_HEAD_INITIALIZER(opts_list_02.head), | |
44 | .desc = { | |
45 | { | |
46 | .name = "str1", | |
47 | .type = QEMU_OPT_STRING, | |
694baf57 MA |
48 | },{ |
49 | .name = "str2", | |
50 | .type = QEMU_OPT_STRING, | |
4ba6fabf LD |
51 | },{ |
52 | .name = "bool1", | |
53 | .type = QEMU_OPT_BOOL, | |
54 | },{ | |
694baf57 MA |
55 | .name = "bool2", |
56 | .type = QEMU_OPT_BOOL, | |
4ba6fabf LD |
57 | },{ |
58 | .name = "size1", | |
59 | .type = QEMU_OPT_SIZE, | |
694baf57 MA |
60 | },{ |
61 | .name = "size2", | |
62 | .type = QEMU_OPT_SIZE, | |
63 | },{ | |
64 | .name = "size3", | |
65 | .type = QEMU_OPT_SIZE, | |
4ba6fabf LD |
66 | }, |
67 | { /* end of list */ } | |
68 | }, | |
69 | }; | |
70 | ||
748bfb4e | 71 | static QemuOptsList opts_list_03 = { |
4ba6fabf | 72 | .name = "opts_list_03", |
694baf57 | 73 | .implied_opt_name = "implied", |
4ba6fabf LD |
74 | .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head), |
75 | .desc = { | |
76 | /* no elements => accept any params */ | |
77 | { /* end of list */ } | |
78 | }, | |
79 | }; | |
80 | ||
81 | static void register_opts(void) | |
82 | { | |
83 | qemu_add_opts(&opts_list_01); | |
84 | qemu_add_opts(&opts_list_02); | |
85 | qemu_add_opts(&opts_list_03); | |
86 | } | |
87 | ||
88 | static void test_find_unknown_opts(void) | |
89 | { | |
90 | QemuOptsList *list; | |
91 | Error *err = NULL; | |
92 | ||
93 | /* should not return anything, we don't have an "unknown" option */ | |
94 | list = qemu_find_opts_err("unknown", &err); | |
95 | g_assert(list == NULL); | |
96 | g_assert(err); | |
97 | error_free(err); | |
98 | } | |
99 | ||
100 | static void test_qemu_find_opts(void) | |
101 | { | |
102 | QemuOptsList *list; | |
103 | ||
104 | /* we have an "opts_list_01" option, should return it */ | |
105 | list = qemu_find_opts("opts_list_01"); | |
106 | g_assert(list != NULL); | |
107 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
108 | } | |
109 | ||
110 | static void test_qemu_opts_create(void) | |
111 | { | |
112 | QemuOptsList *list; | |
113 | QemuOpts *opts; | |
114 | ||
115 | list = qemu_find_opts("opts_list_01"); | |
116 | g_assert(list != NULL); | |
117 | g_assert(QTAILQ_EMPTY(&list->head)); | |
118 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
119 | ||
120 | /* should not find anything at this point */ | |
121 | opts = qemu_opts_find(list, NULL); | |
122 | g_assert(opts == NULL); | |
123 | ||
124 | /* create the opts */ | |
125 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
126 | g_assert(opts != NULL); | |
127 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
128 | ||
129 | /* now we've create the opts, must find it */ | |
130 | opts = qemu_opts_find(list, NULL); | |
131 | g_assert(opts != NULL); | |
132 | ||
133 | qemu_opts_del(opts); | |
134 | ||
135 | /* should not find anything at this point */ | |
136 | opts = qemu_opts_find(list, NULL); | |
137 | g_assert(opts == NULL); | |
138 | } | |
139 | ||
140 | static void test_qemu_opt_get(void) | |
141 | { | |
142 | QemuOptsList *list; | |
143 | QemuOpts *opts; | |
144 | const char *opt = NULL; | |
145 | ||
146 | list = qemu_find_opts("opts_list_01"); | |
147 | g_assert(list != NULL); | |
148 | g_assert(QTAILQ_EMPTY(&list->head)); | |
149 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
150 | ||
151 | /* should not find anything at this point */ | |
152 | opts = qemu_opts_find(list, NULL); | |
153 | g_assert(opts == NULL); | |
154 | ||
155 | /* create the opts */ | |
156 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
157 | g_assert(opts != NULL); | |
158 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
159 | ||
160 | /* haven't set anything to str2 yet */ | |
161 | opt = qemu_opt_get(opts, "str2"); | |
162 | g_assert(opt == NULL); | |
163 | ||
f43e47db | 164 | qemu_opt_set(opts, "str2", "value", &error_abort); |
4ba6fabf LD |
165 | |
166 | /* now we have set str2, should know about it */ | |
167 | opt = qemu_opt_get(opts, "str2"); | |
168 | g_assert_cmpstr(opt, ==, "value"); | |
169 | ||
f43e47db | 170 | qemu_opt_set(opts, "str2", "value2", &error_abort); |
4ba6fabf LD |
171 | |
172 | /* having reset the value, the returned should be the reset one */ | |
173 | opt = qemu_opt_get(opts, "str2"); | |
174 | g_assert_cmpstr(opt, ==, "value2"); | |
175 | ||
176 | qemu_opts_del(opts); | |
177 | ||
178 | /* should not find anything at this point */ | |
179 | opts = qemu_opts_find(list, NULL); | |
180 | g_assert(opts == NULL); | |
181 | } | |
182 | ||
183 | static void test_qemu_opt_get_bool(void) | |
184 | { | |
cccb7967 | 185 | Error *err = NULL; |
4ba6fabf LD |
186 | QemuOptsList *list; |
187 | QemuOpts *opts; | |
188 | bool opt; | |
4ba6fabf LD |
189 | |
190 | list = qemu_find_opts("opts_list_02"); | |
191 | g_assert(list != NULL); | |
192 | g_assert(QTAILQ_EMPTY(&list->head)); | |
193 | g_assert_cmpstr(list->name, ==, "opts_list_02"); | |
194 | ||
195 | /* should not find anything at this point */ | |
196 | opts = qemu_opts_find(list, NULL); | |
197 | g_assert(opts == NULL); | |
198 | ||
199 | /* create the opts */ | |
200 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
201 | g_assert(opts != NULL); | |
202 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
203 | ||
204 | /* haven't set anything to bool1 yet, so defval should be returned */ | |
205 | opt = qemu_opt_get_bool(opts, "bool1", false); | |
206 | g_assert(opt == false); | |
207 | ||
cccb7967 MA |
208 | qemu_opt_set_bool(opts, "bool1", true, &err); |
209 | g_assert(!err); | |
4ba6fabf LD |
210 | |
211 | /* now we have set bool1, should know about it */ | |
212 | opt = qemu_opt_get_bool(opts, "bool1", false); | |
213 | g_assert(opt == true); | |
214 | ||
215 | /* having reset the value, opt should be the reset one not defval */ | |
cccb7967 MA |
216 | qemu_opt_set_bool(opts, "bool1", false, &err); |
217 | g_assert(!err); | |
4ba6fabf LD |
218 | |
219 | opt = qemu_opt_get_bool(opts, "bool1", true); | |
220 | g_assert(opt == false); | |
221 | ||
222 | qemu_opts_del(opts); | |
223 | ||
224 | /* should not find anything at this point */ | |
225 | opts = qemu_opts_find(list, NULL); | |
226 | g_assert(opts == NULL); | |
227 | } | |
228 | ||
229 | static void test_qemu_opt_get_number(void) | |
230 | { | |
39101f25 | 231 | Error *err = NULL; |
4ba6fabf LD |
232 | QemuOptsList *list; |
233 | QemuOpts *opts; | |
234 | uint64_t opt; | |
4ba6fabf LD |
235 | |
236 | list = qemu_find_opts("opts_list_01"); | |
237 | g_assert(list != NULL); | |
238 | g_assert(QTAILQ_EMPTY(&list->head)); | |
239 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
240 | ||
241 | /* should not find anything at this point */ | |
242 | opts = qemu_opts_find(list, NULL); | |
243 | g_assert(opts == NULL); | |
244 | ||
245 | /* create the opts */ | |
246 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
247 | g_assert(opts != NULL); | |
248 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
249 | ||
250 | /* haven't set anything to number1 yet, so defval should be returned */ | |
251 | opt = qemu_opt_get_number(opts, "number1", 5); | |
252 | g_assert(opt == 5); | |
253 | ||
39101f25 MA |
254 | qemu_opt_set_number(opts, "number1", 10, &err); |
255 | g_assert(!err); | |
4ba6fabf LD |
256 | |
257 | /* now we have set number1, should know about it */ | |
258 | opt = qemu_opt_get_number(opts, "number1", 5); | |
259 | g_assert(opt == 10); | |
260 | ||
261 | /* having reset it, the returned should be the reset one not defval */ | |
39101f25 MA |
262 | qemu_opt_set_number(opts, "number1", 15, &err); |
263 | g_assert(!err); | |
4ba6fabf LD |
264 | |
265 | opt = qemu_opt_get_number(opts, "number1", 5); | |
266 | g_assert(opt == 15); | |
267 | ||
268 | qemu_opts_del(opts); | |
269 | ||
270 | /* should not find anything at this point */ | |
271 | opts = qemu_opts_find(list, NULL); | |
272 | g_assert(opts == NULL); | |
273 | } | |
274 | ||
275 | static void test_qemu_opt_get_size(void) | |
276 | { | |
277 | QemuOptsList *list; | |
278 | QemuOpts *opts; | |
279 | uint64_t opt; | |
280 | QDict *dict; | |
281 | ||
282 | list = qemu_find_opts("opts_list_02"); | |
283 | g_assert(list != NULL); | |
284 | g_assert(QTAILQ_EMPTY(&list->head)); | |
285 | g_assert_cmpstr(list->name, ==, "opts_list_02"); | |
286 | ||
287 | /* should not find anything at this point */ | |
288 | opts = qemu_opts_find(list, NULL); | |
289 | g_assert(opts == NULL); | |
290 | ||
291 | /* create the opts */ | |
292 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
293 | g_assert(opts != NULL); | |
294 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
295 | ||
296 | /* haven't set anything to size1 yet, so defval should be returned */ | |
297 | opt = qemu_opt_get_size(opts, "size1", 5); | |
298 | g_assert(opt == 5); | |
299 | ||
300 | dict = qdict_new(); | |
301 | g_assert(dict != NULL); | |
302 | ||
303 | qdict_put(dict, "size1", qstring_from_str("10")); | |
304 | ||
305 | qemu_opts_absorb_qdict(opts, dict, &error_abort); | |
306 | g_assert(error_abort == NULL); | |
307 | ||
308 | /* now we have set size1, should know about it */ | |
309 | opt = qemu_opt_get_size(opts, "size1", 5); | |
310 | g_assert(opt == 10); | |
311 | ||
312 | /* reset value */ | |
313 | qdict_put(dict, "size1", qstring_from_str("15")); | |
314 | ||
315 | qemu_opts_absorb_qdict(opts, dict, &error_abort); | |
316 | g_assert(error_abort == NULL); | |
317 | ||
318 | /* test the reset value */ | |
319 | opt = qemu_opt_get_size(opts, "size1", 5); | |
320 | g_assert(opt == 15); | |
321 | ||
322 | qdict_del(dict, "size1"); | |
323 | g_free(dict); | |
324 | ||
325 | qemu_opts_del(opts); | |
326 | ||
327 | /* should not find anything at this point */ | |
328 | opts = qemu_opts_find(list, NULL); | |
329 | g_assert(opts == NULL); | |
330 | } | |
331 | ||
332 | static void test_qemu_opt_unset(void) | |
333 | { | |
334 | QemuOpts *opts; | |
335 | const char *value; | |
336 | int ret; | |
337 | ||
338 | /* dynamically initialized (parsed) opts */ | |
70b94331 | 339 | opts = qemu_opts_parse(&opts_list_03, "key=value", false, NULL); |
4ba6fabf LD |
340 | g_assert(opts != NULL); |
341 | ||
342 | /* check default/parsed value */ | |
343 | value = qemu_opt_get(opts, "key"); | |
344 | g_assert_cmpstr(value, ==, "value"); | |
345 | ||
346 | /* reset it to value2 */ | |
f43e47db | 347 | qemu_opt_set(opts, "key", "value2", &error_abort); |
4ba6fabf LD |
348 | |
349 | value = qemu_opt_get(opts, "key"); | |
350 | g_assert_cmpstr(value, ==, "value2"); | |
351 | ||
352 | /* unset, valid only for "accept any" */ | |
353 | ret = qemu_opt_unset(opts, "key"); | |
354 | g_assert(ret == 0); | |
355 | ||
356 | /* after reset the value should be the parsed/default one */ | |
357 | value = qemu_opt_get(opts, "key"); | |
358 | g_assert_cmpstr(value, ==, "value"); | |
359 | ||
360 | qemu_opts_del(opts); | |
361 | } | |
362 | ||
363 | static void test_qemu_opts_reset(void) | |
364 | { | |
39101f25 | 365 | Error *err = NULL; |
4ba6fabf LD |
366 | QemuOptsList *list; |
367 | QemuOpts *opts; | |
368 | uint64_t opt; | |
4ba6fabf LD |
369 | |
370 | list = qemu_find_opts("opts_list_01"); | |
371 | g_assert(list != NULL); | |
372 | g_assert(QTAILQ_EMPTY(&list->head)); | |
373 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
374 | ||
375 | /* should not find anything at this point */ | |
376 | opts = qemu_opts_find(list, NULL); | |
377 | g_assert(opts == NULL); | |
378 | ||
379 | /* create the opts */ | |
380 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
381 | g_assert(opts != NULL); | |
382 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
383 | ||
384 | /* haven't set anything to number1 yet, so defval should be returned */ | |
385 | opt = qemu_opt_get_number(opts, "number1", 5); | |
386 | g_assert(opt == 5); | |
387 | ||
39101f25 MA |
388 | qemu_opt_set_number(opts, "number1", 10, &err); |
389 | g_assert(!err); | |
4ba6fabf LD |
390 | |
391 | /* now we have set number1, should know about it */ | |
392 | opt = qemu_opt_get_number(opts, "number1", 5); | |
393 | g_assert(opt == 10); | |
394 | ||
395 | qemu_opts_reset(list); | |
396 | ||
397 | /* should not find anything at this point */ | |
398 | opts = qemu_opts_find(list, NULL); | |
399 | g_assert(opts == NULL); | |
400 | } | |
401 | ||
402 | static void test_qemu_opts_set(void) | |
403 | { | |
79087c78 | 404 | Error *err = NULL; |
4ba6fabf LD |
405 | QemuOptsList *list; |
406 | QemuOpts *opts; | |
4ba6fabf LD |
407 | const char *opt; |
408 | ||
409 | list = qemu_find_opts("opts_list_01"); | |
410 | g_assert(list != NULL); | |
411 | g_assert(QTAILQ_EMPTY(&list->head)); | |
412 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
413 | ||
414 | /* should not find anything at this point */ | |
415 | opts = qemu_opts_find(list, NULL); | |
416 | g_assert(opts == NULL); | |
417 | ||
418 | /* implicitly create opts and set str3 value */ | |
79087c78 MA |
419 | qemu_opts_set(list, NULL, "str3", "value", &err); |
420 | g_assert(!err); | |
4ba6fabf LD |
421 | g_assert(!QTAILQ_EMPTY(&list->head)); |
422 | ||
423 | /* get the just created opts */ | |
424 | opts = qemu_opts_find(list, NULL); | |
425 | g_assert(opts != NULL); | |
426 | ||
427 | /* check the str3 value */ | |
428 | opt = qemu_opt_get(opts, "str3"); | |
429 | g_assert_cmpstr(opt, ==, "value"); | |
430 | ||
431 | qemu_opts_del(opts); | |
432 | ||
433 | /* should not find anything at this point */ | |
434 | opts = qemu_opts_find(list, NULL); | |
435 | g_assert(opts == NULL); | |
436 | } | |
437 | ||
694baf57 MA |
438 | static int opts_count_iter(void *opaque, const char *name, const char *value, |
439 | Error **errp) | |
440 | { | |
441 | (*(size_t *)opaque)++; | |
442 | return 0; | |
443 | } | |
444 | ||
445 | static size_t opts_count(QemuOpts *opts) | |
446 | { | |
447 | size_t n = 0; | |
448 | ||
449 | qemu_opt_foreach(opts, opts_count_iter, &n, NULL); | |
450 | return n; | |
451 | } | |
452 | ||
453 | static void test_opts_parse(void) | |
454 | { | |
455 | Error *err = NULL; | |
456 | QemuOpts *opts; | |
457 | char long_key[129]; | |
458 | char *params; | |
459 | ||
460 | /* Nothing */ | |
461 | opts = qemu_opts_parse(&opts_list_03, "", false, &error_abort); | |
462 | g_assert_cmpuint(opts_count(opts), ==, 0); | |
463 | ||
464 | /* Empty key */ | |
465 | opts = qemu_opts_parse(&opts_list_03, "=val", false, &error_abort); | |
466 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
467 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val"); | |
468 | ||
469 | /* Long key */ | |
470 | memset(long_key, 'a', 127); | |
471 | long_key[127] = 'z'; | |
472 | long_key[128] = 0; | |
473 | params = g_strdup_printf("%s=v", long_key); | |
474 | opts = qemu_opts_parse(&opts_list_03, params + 1, NULL, &error_abort); | |
475 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
476 | g_assert_cmpstr(qemu_opt_get(opts, long_key + 1), ==, "v"); | |
477 | ||
478 | /* Overlong key gets truncated */ | |
479 | opts = qemu_opts_parse(&opts_list_03, params, NULL, &error_abort); | |
480 | g_assert(opts_count(opts) == 1); | |
481 | long_key[127] = 0; | |
482 | g_assert_cmpstr(qemu_opt_get(opts, long_key), ==, "v"); | |
483 | g_free(params); | |
484 | ||
485 | /* Multiple keys, last one wins */ | |
486 | opts = qemu_opts_parse(&opts_list_03, "a=1,b=2,,x,a=3", | |
487 | false, &error_abort); | |
488 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
489 | g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "3"); | |
490 | g_assert_cmpstr(qemu_opt_get(opts, "b"), ==, "2,x"); | |
491 | ||
492 | /* Except when it doesn't */ | |
493 | opts = qemu_opts_parse(&opts_list_03, "id=foo,id=bar", | |
494 | false, &error_abort); | |
495 | g_assert_cmpuint(opts_count(opts), ==, 0); | |
496 | g_assert_cmpstr(qemu_opts_id(opts), ==, "foo"); | |
497 | ||
498 | /* TODO Cover low-level access to repeated keys */ | |
499 | ||
500 | /* Trailing comma is ignored */ | |
501 | opts = qemu_opts_parse(&opts_list_03, "x=y,", false, &error_abort); | |
502 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
503 | g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, "y"); | |
504 | ||
505 | /* Except when it isn't */ | |
506 | opts = qemu_opts_parse(&opts_list_03, ",", false, &error_abort); | |
507 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
508 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "on"); | |
509 | ||
510 | /* Duplicate ID */ | |
511 | opts = qemu_opts_parse(&opts_list_03, "x=y,id=foo", false, &err); | |
512 | error_free_or_abort(&err); | |
513 | g_assert(!opts); | |
514 | /* TODO Cover .merge_lists = true */ | |
515 | ||
516 | /* Buggy ID recognition */ | |
517 | opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort); | |
518 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
519 | g_assert_cmpstr(qemu_opts_id(opts), ==, "bar"); /* BUG */ | |
520 | g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar"); | |
521 | ||
522 | /* Anti-social ID */ | |
523 | opts = qemu_opts_parse(&opts_list_01, "id=666", false, &err); | |
524 | error_free_or_abort(&err); | |
525 | g_assert(!opts); | |
526 | ||
527 | /* Implied value */ | |
528 | opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", | |
529 | false, &error_abort); | |
530 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
531 | g_assert_cmpstr(qemu_opt_get(opts, "an"), ==, "on"); | |
532 | g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off"); | |
533 | g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, ""); | |
534 | ||
535 | /* Implied key */ | |
536 | opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", true, | |
537 | &error_abort); | |
538 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
539 | g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "an"); | |
540 | g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off"); | |
541 | g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, ""); | |
542 | ||
543 | /* Implied key with empty value */ | |
544 | opts = qemu_opts_parse(&opts_list_03, ",", true, &error_abort); | |
545 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
546 | g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ""); | |
547 | ||
548 | /* Implied key with comma value */ | |
549 | opts = qemu_opts_parse(&opts_list_03, ",,,a=1", true, &error_abort); | |
550 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
551 | g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ","); | |
552 | g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "1"); | |
553 | ||
554 | /* Empty key is not an implied key */ | |
555 | opts = qemu_opts_parse(&opts_list_03, "=val", true, &error_abort); | |
556 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
557 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val"); | |
558 | ||
559 | /* Unknown key */ | |
560 | opts = qemu_opts_parse(&opts_list_01, "nonexistent=", false, &err); | |
561 | error_free_or_abort(&err); | |
562 | g_assert(!opts); | |
563 | ||
564 | qemu_opts_reset(&opts_list_01); | |
565 | qemu_opts_reset(&opts_list_03); | |
566 | } | |
567 | ||
568 | static void test_opts_parse_bool(void) | |
569 | { | |
570 | Error *err = NULL; | |
571 | QemuOpts *opts; | |
572 | ||
573 | opts = qemu_opts_parse(&opts_list_02, "bool1=on,bool2=off", | |
574 | false, &error_abort); | |
575 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
576 | g_assert(qemu_opt_get_bool(opts, "bool1", false)); | |
577 | g_assert(!qemu_opt_get_bool(opts, "bool2", true)); | |
578 | ||
579 | opts = qemu_opts_parse(&opts_list_02, "bool1=offer", false, &err); | |
580 | error_free_or_abort(&err); | |
581 | g_assert(!opts); | |
582 | ||
583 | qemu_opts_reset(&opts_list_02); | |
584 | } | |
585 | ||
586 | static void test_opts_parse_number(void) | |
587 | { | |
588 | Error *err = NULL; | |
589 | QemuOpts *opts; | |
590 | ||
591 | /* Lower limit zero */ | |
592 | opts = qemu_opts_parse(&opts_list_01, "number1=0", false, &error_abort); | |
593 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
594 | g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0); | |
595 | ||
596 | /* Upper limit 2^64-1 */ | |
597 | opts = qemu_opts_parse(&opts_list_01, | |
598 | "number1=18446744073709551615,number2=-1", | |
599 | false, &error_abort); | |
600 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
601 | g_assert_cmphex(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX); | |
602 | g_assert_cmphex(qemu_opt_get_number(opts, "number2", 0), ==, UINT64_MAX); | |
603 | ||
604 | /* Above upper limit */ | |
605 | opts = qemu_opts_parse(&opts_list_01, "number1=18446744073709551616", | |
3403e5eb MA |
606 | false, &err); |
607 | error_free_or_abort(&err); | |
608 | g_assert(!opts); | |
694baf57 MA |
609 | |
610 | /* Below lower limit */ | |
611 | opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616", | |
3403e5eb MA |
612 | false, &err); |
613 | error_free_or_abort(&err); | |
614 | g_assert(!opts); | |
694baf57 MA |
615 | |
616 | /* Hex and octal */ | |
617 | opts = qemu_opts_parse(&opts_list_01, "number1=0x2a,number2=052", | |
618 | false, &error_abort); | |
619 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
620 | g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42); | |
621 | g_assert_cmpuint(qemu_opt_get_number(opts, "number2", 0), ==, 42); | |
622 | ||
623 | /* Invalid */ | |
624 | opts = qemu_opts_parse(&opts_list_01, "number1=", false, &err); | |
3403e5eb MA |
625 | error_free_or_abort(&err); |
626 | g_assert(!opts); | |
694baf57 MA |
627 | opts = qemu_opts_parse(&opts_list_01, "number1=eins", false, &err); |
628 | error_free_or_abort(&err); | |
629 | g_assert(!opts); | |
630 | ||
631 | /* Leading whitespace */ | |
632 | opts = qemu_opts_parse(&opts_list_01, "number1= \t42", | |
633 | false, &error_abort); | |
634 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
635 | g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42); | |
636 | ||
637 | /* Trailing crap */ | |
638 | opts = qemu_opts_parse(&opts_list_01, "number1=3.14", false, &err); | |
639 | error_free_or_abort(&err); | |
640 | g_assert(!opts); | |
641 | opts = qemu_opts_parse(&opts_list_01, "number1=08", false, &err); | |
642 | error_free_or_abort(&err); | |
643 | g_assert(!opts); | |
644 | opts = qemu_opts_parse(&opts_list_01, "number1=0 ", false, &err); | |
645 | error_free_or_abort(&err); | |
646 | g_assert(!opts); | |
647 | ||
648 | qemu_opts_reset(&opts_list_01); | |
649 | } | |
650 | ||
651 | static void test_opts_parse_size(void) | |
652 | { | |
653 | Error *err = NULL; | |
654 | QemuOpts *opts; | |
655 | ||
656 | /* Lower limit zero */ | |
657 | opts = qemu_opts_parse(&opts_list_02, "size1=0", false, &error_abort); | |
658 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
659 | g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0); | |
660 | ||
661 | /* Note: precision is 53 bits since we're parsing with strtod() */ | |
662 | ||
663 | /* Around limit of precision: 2^53-1, 2^53, 2^54 */ | |
664 | opts = qemu_opts_parse(&opts_list_02, | |
665 | "size1=9007199254740991," | |
666 | "size2=9007199254740992," | |
667 | "size3=9007199254740993", | |
668 | false, &error_abort); | |
669 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
670 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), | |
671 | ==, 0x1fffffffffffff); | |
672 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), | |
673 | ==, 0x20000000000000); | |
674 | g_assert_cmphex(qemu_opt_get_size(opts, "size3", 1), | |
675 | ==, 0x20000000000000); | |
676 | ||
677 | /* Close to signed upper limit 0x7ffffffffffffc00 (53 msbs set) */ | |
678 | opts = qemu_opts_parse(&opts_list_02, | |
679 | "size1=9223372036854774784," /* 7ffffffffffffc00 */ | |
680 | "size2=9223372036854775295", /* 7ffffffffffffdff */ | |
681 | false, &error_abort); | |
682 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
683 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), | |
684 | ==, 0x7ffffffffffffc00); | |
685 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), | |
686 | ==, 0x7ffffffffffffc00); | |
687 | ||
688 | /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */ | |
689 | opts = qemu_opts_parse(&opts_list_02, | |
690 | "size1=18446744073709549568," /* fffffffffffff800 */ | |
691 | "size2=18446744073709550591", /* fffffffffffffbff */ | |
692 | false, &error_abort); | |
693 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
694 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), | |
695 | ==, 0xfffffffffffff800); | |
696 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), | |
697 | ==, 0xfffffffffffff800); | |
698 | ||
699 | /* Beyond limits */ | |
700 | opts = qemu_opts_parse(&opts_list_02, "size1=-1", false, &err); | |
701 | error_free_or_abort(&err); | |
702 | g_assert(!opts); | |
703 | opts = qemu_opts_parse(&opts_list_02, | |
704 | "size1=18446744073709550592", /* fffffffffffffc00 */ | |
75cdcd15 MA |
705 | false, &err); |
706 | error_free_or_abort(&err); | |
707 | g_assert(!opts); | |
694baf57 MA |
708 | |
709 | /* Suffixes */ | |
710 | opts = qemu_opts_parse(&opts_list_02, "size1=8b,size2=1.5k,size3=2M", | |
711 | false, &error_abort); | |
712 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
713 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, 8); | |
714 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 1536); | |
715 | g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * M_BYTE); | |
716 | opts = qemu_opts_parse(&opts_list_02, "size1=0.1G,size2=16777215T", | |
717 | false, &error_abort); | |
718 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
719 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, G_BYTE / 10); | |
720 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), | |
721 | ==, 16777215 * T_BYTE); | |
722 | ||
723 | /* Beyond limit with suffix */ | |
724 | opts = qemu_opts_parse(&opts_list_02, "size1=16777216T", | |
75cdcd15 MA |
725 | false, &err); |
726 | error_free_or_abort(&err); | |
727 | g_assert(!opts); | |
694baf57 MA |
728 | |
729 | /* Trailing crap */ | |
730 | opts = qemu_opts_parse(&opts_list_02, "size1=16E", false, &err); | |
731 | error_free_or_abort(&err); | |
732 | g_assert(!opts); | |
75cdcd15 MA |
733 | opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &err); |
734 | error_free_or_abort(&err); | |
735 | g_assert(!opts); | |
694baf57 MA |
736 | |
737 | qemu_opts_reset(&opts_list_02); | |
738 | } | |
739 | ||
4ba6fabf LD |
740 | int main(int argc, char *argv[]) |
741 | { | |
742 | register_opts(); | |
743 | g_test_init(&argc, &argv, NULL); | |
744 | g_test_add_func("/qemu-opts/find_unknown_opts", test_find_unknown_opts); | |
745 | g_test_add_func("/qemu-opts/find_opts", test_qemu_find_opts); | |
746 | g_test_add_func("/qemu-opts/opts_create", test_qemu_opts_create); | |
747 | g_test_add_func("/qemu-opts/opt_get", test_qemu_opt_get); | |
748 | g_test_add_func("/qemu-opts/opt_get_bool", test_qemu_opt_get_bool); | |
749 | g_test_add_func("/qemu-opts/opt_get_number", test_qemu_opt_get_number); | |
750 | g_test_add_func("/qemu-opts/opt_get_size", test_qemu_opt_get_size); | |
751 | g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset); | |
752 | g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset); | |
753 | g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set); | |
694baf57 MA |
754 | g_test_add_func("/qemu-opts/opts_parse/general", test_opts_parse); |
755 | g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool); | |
756 | g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number); | |
757 | g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size); | |
4ba6fabf LD |
758 | g_test_run(); |
759 | return 0; | |
760 | } |