]>
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" |
d23b6caa | 11 | #include "qemu/units.h" |
922a01a0 | 12 | #include "qemu/option.h" |
37974a97 | 13 | #include "qemu/option_int.h" |
da34e65c | 14 | #include "qapi/error.h" |
452fcdbc | 15 | #include "qapi/qmp/qdict.h" |
4ba6fabf LD |
16 | #include "qapi/qmp/qstring.h" |
17 | #include "qemu/config-file.h" | |
18 | ||
4ba6fabf LD |
19 | |
20 | static QemuOptsList opts_list_01 = { | |
21 | .name = "opts_list_01", | |
22 | .head = QTAILQ_HEAD_INITIALIZER(opts_list_01.head), | |
23 | .desc = { | |
24 | { | |
25 | .name = "str1", | |
26 | .type = QEMU_OPT_STRING, | |
575ef8bf KW |
27 | .help = "Help texts are preserved in qemu_opts_append", |
28 | .def_value_str = "default", | |
4ba6fabf LD |
29 | },{ |
30 | .name = "str2", | |
31 | .type = QEMU_OPT_STRING, | |
32 | },{ | |
33 | .name = "str3", | |
34 | .type = QEMU_OPT_STRING, | |
35 | },{ | |
36 | .name = "number1", | |
37 | .type = QEMU_OPT_NUMBER, | |
575ef8bf | 38 | .help = "Having help texts only for some options is okay", |
694baf57 MA |
39 | },{ |
40 | .name = "number2", | |
41 | .type = QEMU_OPT_NUMBER, | |
4ba6fabf LD |
42 | }, |
43 | { /* end of list */ } | |
44 | }, | |
45 | }; | |
46 | ||
47 | static QemuOptsList opts_list_02 = { | |
48 | .name = "opts_list_02", | |
49 | .head = QTAILQ_HEAD_INITIALIZER(opts_list_02.head), | |
50 | .desc = { | |
51 | { | |
52 | .name = "str1", | |
53 | .type = QEMU_OPT_STRING, | |
694baf57 MA |
54 | },{ |
55 | .name = "str2", | |
56 | .type = QEMU_OPT_STRING, | |
4ba6fabf LD |
57 | },{ |
58 | .name = "bool1", | |
59 | .type = QEMU_OPT_BOOL, | |
60 | },{ | |
694baf57 MA |
61 | .name = "bool2", |
62 | .type = QEMU_OPT_BOOL, | |
4ba6fabf LD |
63 | },{ |
64 | .name = "size1", | |
65 | .type = QEMU_OPT_SIZE, | |
694baf57 MA |
66 | },{ |
67 | .name = "size2", | |
68 | .type = QEMU_OPT_SIZE, | |
69 | },{ | |
70 | .name = "size3", | |
71 | .type = QEMU_OPT_SIZE, | |
4ba6fabf LD |
72 | }, |
73 | { /* end of list */ } | |
74 | }, | |
75 | }; | |
76 | ||
748bfb4e | 77 | static QemuOptsList opts_list_03 = { |
4ba6fabf | 78 | .name = "opts_list_03", |
694baf57 | 79 | .implied_opt_name = "implied", |
4ba6fabf LD |
80 | .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head), |
81 | .desc = { | |
82 | /* no elements => accept any params */ | |
83 | { /* end of list */ } | |
84 | }, | |
85 | }; | |
86 | ||
87 | static void register_opts(void) | |
88 | { | |
89 | qemu_add_opts(&opts_list_01); | |
90 | qemu_add_opts(&opts_list_02); | |
91 | qemu_add_opts(&opts_list_03); | |
92 | } | |
93 | ||
94 | static void test_find_unknown_opts(void) | |
95 | { | |
96 | QemuOptsList *list; | |
97 | Error *err = NULL; | |
98 | ||
99 | /* should not return anything, we don't have an "unknown" option */ | |
100 | list = qemu_find_opts_err("unknown", &err); | |
101 | g_assert(list == NULL); | |
157db293 | 102 | error_free_or_abort(&err); |
4ba6fabf LD |
103 | } |
104 | ||
105 | static void test_qemu_find_opts(void) | |
106 | { | |
107 | QemuOptsList *list; | |
108 | ||
109 | /* we have an "opts_list_01" option, should return it */ | |
110 | list = qemu_find_opts("opts_list_01"); | |
111 | g_assert(list != NULL); | |
112 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
113 | } | |
114 | ||
115 | static void test_qemu_opts_create(void) | |
116 | { | |
117 | QemuOptsList *list; | |
118 | QemuOpts *opts; | |
119 | ||
120 | list = qemu_find_opts("opts_list_01"); | |
121 | g_assert(list != NULL); | |
122 | g_assert(QTAILQ_EMPTY(&list->head)); | |
123 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
124 | ||
125 | /* should not find anything at this point */ | |
126 | opts = qemu_opts_find(list, NULL); | |
127 | g_assert(opts == NULL); | |
128 | ||
129 | /* create the opts */ | |
130 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
131 | g_assert(opts != NULL); | |
132 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
133 | ||
134 | /* now we've create the opts, must find it */ | |
135 | opts = qemu_opts_find(list, NULL); | |
136 | g_assert(opts != NULL); | |
137 | ||
138 | qemu_opts_del(opts); | |
139 | ||
140 | /* should not find anything at this point */ | |
141 | opts = qemu_opts_find(list, NULL); | |
142 | g_assert(opts == NULL); | |
143 | } | |
144 | ||
145 | static void test_qemu_opt_get(void) | |
146 | { | |
147 | QemuOptsList *list; | |
148 | QemuOpts *opts; | |
149 | const char *opt = NULL; | |
150 | ||
151 | list = qemu_find_opts("opts_list_01"); | |
152 | g_assert(list != NULL); | |
153 | g_assert(QTAILQ_EMPTY(&list->head)); | |
154 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
155 | ||
156 | /* should not find anything at this point */ | |
157 | opts = qemu_opts_find(list, NULL); | |
158 | g_assert(opts == NULL); | |
159 | ||
160 | /* create the opts */ | |
161 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
162 | g_assert(opts != NULL); | |
163 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
164 | ||
165 | /* haven't set anything to str2 yet */ | |
166 | opt = qemu_opt_get(opts, "str2"); | |
167 | g_assert(opt == NULL); | |
168 | ||
f43e47db | 169 | qemu_opt_set(opts, "str2", "value", &error_abort); |
4ba6fabf LD |
170 | |
171 | /* now we have set str2, should know about it */ | |
172 | opt = qemu_opt_get(opts, "str2"); | |
173 | g_assert_cmpstr(opt, ==, "value"); | |
174 | ||
f43e47db | 175 | qemu_opt_set(opts, "str2", "value2", &error_abort); |
4ba6fabf LD |
176 | |
177 | /* having reset the value, the returned should be the reset one */ | |
178 | opt = qemu_opt_get(opts, "str2"); | |
179 | g_assert_cmpstr(opt, ==, "value2"); | |
180 | ||
181 | qemu_opts_del(opts); | |
182 | ||
183 | /* should not find anything at this point */ | |
184 | opts = qemu_opts_find(list, NULL); | |
185 | g_assert(opts == NULL); | |
186 | } | |
187 | ||
188 | static void test_qemu_opt_get_bool(void) | |
189 | { | |
190 | QemuOptsList *list; | |
191 | QemuOpts *opts; | |
192 | bool opt; | |
4ba6fabf LD |
193 | |
194 | list = qemu_find_opts("opts_list_02"); | |
195 | g_assert(list != NULL); | |
196 | g_assert(QTAILQ_EMPTY(&list->head)); | |
197 | g_assert_cmpstr(list->name, ==, "opts_list_02"); | |
198 | ||
199 | /* should not find anything at this point */ | |
200 | opts = qemu_opts_find(list, NULL); | |
201 | g_assert(opts == NULL); | |
202 | ||
203 | /* create the opts */ | |
204 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
205 | g_assert(opts != NULL); | |
206 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
207 | ||
208 | /* haven't set anything to bool1 yet, so defval should be returned */ | |
209 | opt = qemu_opt_get_bool(opts, "bool1", false); | |
210 | g_assert(opt == false); | |
211 | ||
d8da9e71 | 212 | qemu_opt_set_bool(opts, "bool1", true, &error_abort); |
4ba6fabf LD |
213 | |
214 | /* now we have set bool1, should know about it */ | |
215 | opt = qemu_opt_get_bool(opts, "bool1", false); | |
216 | g_assert(opt == true); | |
217 | ||
218 | /* having reset the value, opt should be the reset one not defval */ | |
d8da9e71 | 219 | qemu_opt_set_bool(opts, "bool1", false, &error_abort); |
4ba6fabf LD |
220 | |
221 | opt = qemu_opt_get_bool(opts, "bool1", true); | |
222 | g_assert(opt == false); | |
223 | ||
224 | qemu_opts_del(opts); | |
225 | ||
226 | /* should not find anything at this point */ | |
227 | opts = qemu_opts_find(list, NULL); | |
228 | g_assert(opts == NULL); | |
229 | } | |
230 | ||
231 | static void test_qemu_opt_get_number(void) | |
232 | { | |
233 | QemuOptsList *list; | |
234 | QemuOpts *opts; | |
235 | uint64_t opt; | |
4ba6fabf LD |
236 | |
237 | list = qemu_find_opts("opts_list_01"); | |
238 | g_assert(list != NULL); | |
239 | g_assert(QTAILQ_EMPTY(&list->head)); | |
240 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
241 | ||
242 | /* should not find anything at this point */ | |
243 | opts = qemu_opts_find(list, NULL); | |
244 | g_assert(opts == NULL); | |
245 | ||
246 | /* create the opts */ | |
247 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
248 | g_assert(opts != NULL); | |
249 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
250 | ||
251 | /* haven't set anything to number1 yet, so defval should be returned */ | |
252 | opt = qemu_opt_get_number(opts, "number1", 5); | |
253 | g_assert(opt == 5); | |
254 | ||
d8da9e71 | 255 | qemu_opt_set_number(opts, "number1", 10, &error_abort); |
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 */ | |
d8da9e71 | 262 | qemu_opt_set_number(opts, "number1", 15, &error_abort); |
4ba6fabf LD |
263 | |
264 | opt = qemu_opt_get_number(opts, "number1", 5); | |
265 | g_assert(opt == 15); | |
266 | ||
267 | qemu_opts_del(opts); | |
268 | ||
269 | /* should not find anything at this point */ | |
270 | opts = qemu_opts_find(list, NULL); | |
271 | g_assert(opts == NULL); | |
272 | } | |
273 | ||
274 | static void test_qemu_opt_get_size(void) | |
275 | { | |
276 | QemuOptsList *list; | |
277 | QemuOpts *opts; | |
278 | uint64_t opt; | |
279 | QDict *dict; | |
280 | ||
281 | list = qemu_find_opts("opts_list_02"); | |
282 | g_assert(list != NULL); | |
283 | g_assert(QTAILQ_EMPTY(&list->head)); | |
284 | g_assert_cmpstr(list->name, ==, "opts_list_02"); | |
285 | ||
286 | /* should not find anything at this point */ | |
287 | opts = qemu_opts_find(list, NULL); | |
288 | g_assert(opts == NULL); | |
289 | ||
290 | /* create the opts */ | |
291 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
292 | g_assert(opts != NULL); | |
293 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
294 | ||
295 | /* haven't set anything to size1 yet, so defval should be returned */ | |
296 | opt = qemu_opt_get_size(opts, "size1", 5); | |
297 | g_assert(opt == 5); | |
298 | ||
299 | dict = qdict_new(); | |
300 | g_assert(dict != NULL); | |
301 | ||
46f5ac20 | 302 | qdict_put_str(dict, "size1", "10"); |
4ba6fabf LD |
303 | |
304 | qemu_opts_absorb_qdict(opts, dict, &error_abort); | |
305 | g_assert(error_abort == NULL); | |
306 | ||
307 | /* now we have set size1, should know about it */ | |
308 | opt = qemu_opt_get_size(opts, "size1", 5); | |
309 | g_assert(opt == 10); | |
310 | ||
311 | /* reset value */ | |
46f5ac20 | 312 | qdict_put_str(dict, "size1", "15"); |
4ba6fabf LD |
313 | |
314 | qemu_opts_absorb_qdict(opts, dict, &error_abort); | |
315 | g_assert(error_abort == NULL); | |
316 | ||
317 | /* test the reset value */ | |
318 | opt = qemu_opt_get_size(opts, "size1", 5); | |
319 | g_assert(opt == 15); | |
320 | ||
321 | qdict_del(dict, "size1"); | |
322 | g_free(dict); | |
323 | ||
324 | qemu_opts_del(opts); | |
325 | ||
326 | /* should not find anything at this point */ | |
327 | opts = qemu_opts_find(list, NULL); | |
328 | g_assert(opts == NULL); | |
329 | } | |
330 | ||
331 | static void test_qemu_opt_unset(void) | |
332 | { | |
333 | QemuOpts *opts; | |
334 | const char *value; | |
335 | int ret; | |
336 | ||
337 | /* dynamically initialized (parsed) opts */ | |
70b94331 | 338 | opts = qemu_opts_parse(&opts_list_03, "key=value", false, NULL); |
4ba6fabf LD |
339 | g_assert(opts != NULL); |
340 | ||
341 | /* check default/parsed value */ | |
342 | value = qemu_opt_get(opts, "key"); | |
343 | g_assert_cmpstr(value, ==, "value"); | |
344 | ||
345 | /* reset it to value2 */ | |
f43e47db | 346 | qemu_opt_set(opts, "key", "value2", &error_abort); |
4ba6fabf LD |
347 | |
348 | value = qemu_opt_get(opts, "key"); | |
349 | g_assert_cmpstr(value, ==, "value2"); | |
350 | ||
351 | /* unset, valid only for "accept any" */ | |
352 | ret = qemu_opt_unset(opts, "key"); | |
353 | g_assert(ret == 0); | |
354 | ||
355 | /* after reset the value should be the parsed/default one */ | |
356 | value = qemu_opt_get(opts, "key"); | |
357 | g_assert_cmpstr(value, ==, "value"); | |
358 | ||
359 | qemu_opts_del(opts); | |
360 | } | |
361 | ||
362 | static void test_qemu_opts_reset(void) | |
363 | { | |
364 | QemuOptsList *list; | |
365 | QemuOpts *opts; | |
366 | uint64_t opt; | |
4ba6fabf LD |
367 | |
368 | list = qemu_find_opts("opts_list_01"); | |
369 | g_assert(list != NULL); | |
370 | g_assert(QTAILQ_EMPTY(&list->head)); | |
371 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
372 | ||
373 | /* should not find anything at this point */ | |
374 | opts = qemu_opts_find(list, NULL); | |
375 | g_assert(opts == NULL); | |
376 | ||
377 | /* create the opts */ | |
378 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
379 | g_assert(opts != NULL); | |
380 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
381 | ||
382 | /* haven't set anything to number1 yet, so defval should be returned */ | |
383 | opt = qemu_opt_get_number(opts, "number1", 5); | |
384 | g_assert(opt == 5); | |
385 | ||
d8da9e71 | 386 | qemu_opt_set_number(opts, "number1", 10, &error_abort); |
4ba6fabf LD |
387 | |
388 | /* now we have set number1, should know about it */ | |
389 | opt = qemu_opt_get_number(opts, "number1", 5); | |
390 | g_assert(opt == 10); | |
391 | ||
392 | qemu_opts_reset(list); | |
393 | ||
394 | /* should not find anything at this point */ | |
395 | opts = qemu_opts_find(list, NULL); | |
396 | g_assert(opts == NULL); | |
397 | } | |
398 | ||
399 | static void test_qemu_opts_set(void) | |
400 | { | |
401 | QemuOptsList *list; | |
402 | QemuOpts *opts; | |
4ba6fabf LD |
403 | const char *opt; |
404 | ||
405 | list = qemu_find_opts("opts_list_01"); | |
406 | g_assert(list != NULL); | |
407 | g_assert(QTAILQ_EMPTY(&list->head)); | |
408 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
409 | ||
410 | /* should not find anything at this point */ | |
411 | opts = qemu_opts_find(list, NULL); | |
412 | g_assert(opts == NULL); | |
413 | ||
414 | /* implicitly create opts and set str3 value */ | |
d8da9e71 | 415 | qemu_opts_set(list, NULL, "str3", "value", &error_abort); |
4ba6fabf LD |
416 | g_assert(!QTAILQ_EMPTY(&list->head)); |
417 | ||
418 | /* get the just created opts */ | |
419 | opts = qemu_opts_find(list, NULL); | |
420 | g_assert(opts != NULL); | |
421 | ||
422 | /* check the str3 value */ | |
423 | opt = qemu_opt_get(opts, "str3"); | |
424 | g_assert_cmpstr(opt, ==, "value"); | |
425 | ||
426 | qemu_opts_del(opts); | |
427 | ||
428 | /* should not find anything at this point */ | |
429 | opts = qemu_opts_find(list, NULL); | |
430 | g_assert(opts == NULL); | |
431 | } | |
432 | ||
694baf57 MA |
433 | static int opts_count_iter(void *opaque, const char *name, const char *value, |
434 | Error **errp) | |
435 | { | |
436 | (*(size_t *)opaque)++; | |
437 | return 0; | |
438 | } | |
439 | ||
440 | static size_t opts_count(QemuOpts *opts) | |
441 | { | |
442 | size_t n = 0; | |
443 | ||
444 | qemu_opt_foreach(opts, opts_count_iter, &n, NULL); | |
445 | return n; | |
446 | } | |
447 | ||
448 | static void test_opts_parse(void) | |
449 | { | |
450 | Error *err = NULL; | |
451 | QemuOpts *opts; | |
694baf57 MA |
452 | |
453 | /* Nothing */ | |
454 | opts = qemu_opts_parse(&opts_list_03, "", false, &error_abort); | |
455 | g_assert_cmpuint(opts_count(opts), ==, 0); | |
456 | ||
457 | /* Empty key */ | |
458 | opts = qemu_opts_parse(&opts_list_03, "=val", false, &error_abort); | |
459 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
460 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val"); | |
461 | ||
694baf57 MA |
462 | /* Multiple keys, last one wins */ |
463 | opts = qemu_opts_parse(&opts_list_03, "a=1,b=2,,x,a=3", | |
464 | false, &error_abort); | |
465 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
466 | g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "3"); | |
467 | g_assert_cmpstr(qemu_opt_get(opts, "b"), ==, "2,x"); | |
468 | ||
469 | /* Except when it doesn't */ | |
470 | opts = qemu_opts_parse(&opts_list_03, "id=foo,id=bar", | |
471 | false, &error_abort); | |
472 | g_assert_cmpuint(opts_count(opts), ==, 0); | |
473 | g_assert_cmpstr(qemu_opts_id(opts), ==, "foo"); | |
474 | ||
475 | /* TODO Cover low-level access to repeated keys */ | |
476 | ||
477 | /* Trailing comma is ignored */ | |
478 | opts = qemu_opts_parse(&opts_list_03, "x=y,", false, &error_abort); | |
479 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
480 | g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, "y"); | |
481 | ||
482 | /* Except when it isn't */ | |
483 | opts = qemu_opts_parse(&opts_list_03, ",", false, &error_abort); | |
484 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
485 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "on"); | |
486 | ||
487 | /* Duplicate ID */ | |
488 | opts = qemu_opts_parse(&opts_list_03, "x=y,id=foo", false, &err); | |
489 | error_free_or_abort(&err); | |
490 | g_assert(!opts); | |
491 | /* TODO Cover .merge_lists = true */ | |
492 | ||
933d1527 | 493 | /* Buggy ID recognition (fixed) */ |
694baf57 MA |
494 | opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort); |
495 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
933d1527 | 496 | g_assert(!qemu_opts_id(opts)); |
694baf57 MA |
497 | g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar"); |
498 | ||
499 | /* Anti-social ID */ | |
500 | opts = qemu_opts_parse(&opts_list_01, "id=666", false, &err); | |
501 | error_free_or_abort(&err); | |
502 | g_assert(!opts); | |
503 | ||
504 | /* Implied value */ | |
505 | opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", | |
506 | false, &error_abort); | |
507 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
508 | g_assert_cmpstr(qemu_opt_get(opts, "an"), ==, "on"); | |
509 | g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off"); | |
510 | g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, ""); | |
511 | ||
0e2052b2 MA |
512 | /* Implied value, negated empty key */ |
513 | opts = qemu_opts_parse(&opts_list_03, "no", false, &error_abort); | |
514 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
515 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "off"); | |
516 | ||
694baf57 MA |
517 | /* Implied key */ |
518 | opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", true, | |
519 | &error_abort); | |
520 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
521 | g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "an"); | |
522 | g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off"); | |
523 | g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, ""); | |
524 | ||
525 | /* Implied key with empty value */ | |
526 | opts = qemu_opts_parse(&opts_list_03, ",", true, &error_abort); | |
527 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
528 | g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ""); | |
529 | ||
530 | /* Implied key with comma value */ | |
531 | opts = qemu_opts_parse(&opts_list_03, ",,,a=1", true, &error_abort); | |
532 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
533 | g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ","); | |
534 | g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "1"); | |
535 | ||
536 | /* Empty key is not an implied key */ | |
537 | opts = qemu_opts_parse(&opts_list_03, "=val", true, &error_abort); | |
538 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
539 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val"); | |
540 | ||
541 | /* Unknown key */ | |
542 | opts = qemu_opts_parse(&opts_list_01, "nonexistent=", false, &err); | |
543 | error_free_or_abort(&err); | |
544 | g_assert(!opts); | |
545 | ||
546 | qemu_opts_reset(&opts_list_01); | |
547 | qemu_opts_reset(&opts_list_03); | |
548 | } | |
549 | ||
550 | static void test_opts_parse_bool(void) | |
551 | { | |
552 | Error *err = NULL; | |
553 | QemuOpts *opts; | |
554 | ||
555 | opts = qemu_opts_parse(&opts_list_02, "bool1=on,bool2=off", | |
556 | false, &error_abort); | |
557 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
558 | g_assert(qemu_opt_get_bool(opts, "bool1", false)); | |
559 | g_assert(!qemu_opt_get_bool(opts, "bool2", true)); | |
560 | ||
561 | opts = qemu_opts_parse(&opts_list_02, "bool1=offer", false, &err); | |
562 | error_free_or_abort(&err); | |
563 | g_assert(!opts); | |
564 | ||
565 | qemu_opts_reset(&opts_list_02); | |
566 | } | |
567 | ||
568 | static void test_opts_parse_number(void) | |
569 | { | |
570 | Error *err = NULL; | |
571 | QemuOpts *opts; | |
572 | ||
573 | /* Lower limit zero */ | |
574 | opts = qemu_opts_parse(&opts_list_01, "number1=0", false, &error_abort); | |
575 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
576 | g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0); | |
577 | ||
578 | /* Upper limit 2^64-1 */ | |
579 | opts = qemu_opts_parse(&opts_list_01, | |
580 | "number1=18446744073709551615,number2=-1", | |
581 | false, &error_abort); | |
582 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
583 | g_assert_cmphex(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX); | |
584 | g_assert_cmphex(qemu_opt_get_number(opts, "number2", 0), ==, UINT64_MAX); | |
585 | ||
586 | /* Above upper limit */ | |
587 | opts = qemu_opts_parse(&opts_list_01, "number1=18446744073709551616", | |
3403e5eb MA |
588 | false, &err); |
589 | error_free_or_abort(&err); | |
590 | g_assert(!opts); | |
694baf57 MA |
591 | |
592 | /* Below lower limit */ | |
593 | opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616", | |
3403e5eb MA |
594 | false, &err); |
595 | error_free_or_abort(&err); | |
596 | g_assert(!opts); | |
694baf57 MA |
597 | |
598 | /* Hex and octal */ | |
599 | opts = qemu_opts_parse(&opts_list_01, "number1=0x2a,number2=052", | |
600 | false, &error_abort); | |
601 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
602 | g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42); | |
603 | g_assert_cmpuint(qemu_opt_get_number(opts, "number2", 0), ==, 42); | |
604 | ||
605 | /* Invalid */ | |
606 | opts = qemu_opts_parse(&opts_list_01, "number1=", false, &err); | |
3403e5eb MA |
607 | error_free_or_abort(&err); |
608 | g_assert(!opts); | |
694baf57 MA |
609 | opts = qemu_opts_parse(&opts_list_01, "number1=eins", false, &err); |
610 | error_free_or_abort(&err); | |
611 | g_assert(!opts); | |
612 | ||
613 | /* Leading whitespace */ | |
614 | opts = qemu_opts_parse(&opts_list_01, "number1= \t42", | |
615 | false, &error_abort); | |
616 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
617 | g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42); | |
618 | ||
619 | /* Trailing crap */ | |
620 | opts = qemu_opts_parse(&opts_list_01, "number1=3.14", false, &err); | |
621 | error_free_or_abort(&err); | |
622 | g_assert(!opts); | |
623 | opts = qemu_opts_parse(&opts_list_01, "number1=08", false, &err); | |
624 | error_free_or_abort(&err); | |
625 | g_assert(!opts); | |
626 | opts = qemu_opts_parse(&opts_list_01, "number1=0 ", false, &err); | |
627 | error_free_or_abort(&err); | |
628 | g_assert(!opts); | |
629 | ||
630 | qemu_opts_reset(&opts_list_01); | |
631 | } | |
632 | ||
633 | static void test_opts_parse_size(void) | |
634 | { | |
635 | Error *err = NULL; | |
636 | QemuOpts *opts; | |
637 | ||
638 | /* Lower limit zero */ | |
639 | opts = qemu_opts_parse(&opts_list_02, "size1=0", false, &error_abort); | |
640 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
641 | g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0); | |
642 | ||
643 | /* Note: precision is 53 bits since we're parsing with strtod() */ | |
644 | ||
645 | /* Around limit of precision: 2^53-1, 2^53, 2^54 */ | |
646 | opts = qemu_opts_parse(&opts_list_02, | |
647 | "size1=9007199254740991," | |
648 | "size2=9007199254740992," | |
649 | "size3=9007199254740993", | |
650 | false, &error_abort); | |
651 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
652 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), | |
653 | ==, 0x1fffffffffffff); | |
654 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), | |
655 | ==, 0x20000000000000); | |
656 | g_assert_cmphex(qemu_opt_get_size(opts, "size3", 1), | |
657 | ==, 0x20000000000000); | |
658 | ||
659 | /* Close to signed upper limit 0x7ffffffffffffc00 (53 msbs set) */ | |
660 | opts = qemu_opts_parse(&opts_list_02, | |
661 | "size1=9223372036854774784," /* 7ffffffffffffc00 */ | |
662 | "size2=9223372036854775295", /* 7ffffffffffffdff */ | |
663 | false, &error_abort); | |
664 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
665 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), | |
666 | ==, 0x7ffffffffffffc00); | |
667 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), | |
668 | ==, 0x7ffffffffffffc00); | |
669 | ||
670 | /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */ | |
671 | opts = qemu_opts_parse(&opts_list_02, | |
672 | "size1=18446744073709549568," /* fffffffffffff800 */ | |
673 | "size2=18446744073709550591", /* fffffffffffffbff */ | |
674 | false, &error_abort); | |
675 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
676 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), | |
677 | ==, 0xfffffffffffff800); | |
678 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), | |
679 | ==, 0xfffffffffffff800); | |
680 | ||
681 | /* Beyond limits */ | |
682 | opts = qemu_opts_parse(&opts_list_02, "size1=-1", false, &err); | |
683 | error_free_or_abort(&err); | |
684 | g_assert(!opts); | |
685 | opts = qemu_opts_parse(&opts_list_02, | |
686 | "size1=18446744073709550592", /* fffffffffffffc00 */ | |
75cdcd15 MA |
687 | false, &err); |
688 | error_free_or_abort(&err); | |
689 | g_assert(!opts); | |
694baf57 MA |
690 | |
691 | /* Suffixes */ | |
692 | opts = qemu_opts_parse(&opts_list_02, "size1=8b,size2=1.5k,size3=2M", | |
693 | false, &error_abort); | |
694 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
695 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, 8); | |
696 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 1536); | |
d23b6caa | 697 | g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * MiB); |
694baf57 MA |
698 | opts = qemu_opts_parse(&opts_list_02, "size1=0.1G,size2=16777215T", |
699 | false, &error_abort); | |
700 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
d23b6caa PMD |
701 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, GiB / 10); |
702 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 16777215ULL * TiB); | |
694baf57 MA |
703 | |
704 | /* Beyond limit with suffix */ | |
705 | opts = qemu_opts_parse(&opts_list_02, "size1=16777216T", | |
75cdcd15 MA |
706 | false, &err); |
707 | error_free_or_abort(&err); | |
708 | g_assert(!opts); | |
694baf57 MA |
709 | |
710 | /* Trailing crap */ | |
711 | opts = qemu_opts_parse(&opts_list_02, "size1=16E", false, &err); | |
712 | error_free_or_abort(&err); | |
713 | g_assert(!opts); | |
75cdcd15 MA |
714 | opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &err); |
715 | error_free_or_abort(&err); | |
716 | g_assert(!opts); | |
694baf57 MA |
717 | |
718 | qemu_opts_reset(&opts_list_02); | |
719 | } | |
720 | ||
32c2dcf5 MA |
721 | static void test_has_help_option(void) |
722 | { | |
723 | static const struct { | |
724 | const char *params; | |
32c2dcf5 | 725 | /* expected value of qemu_opt_has_help_opt() with implied=false */ |
59d27ebc | 726 | bool expect; |
32c2dcf5 | 727 | /* expected value of qemu_opt_has_help_opt() with implied=true */ |
59d27ebc | 728 | bool expect_implied; |
32c2dcf5 | 729 | } test[] = { |
59d27ebc MA |
730 | { "help", true, false }, |
731 | { "?", true, false }, | |
732 | { "helpme", false, false }, | |
733 | { "?me", false, false }, | |
734 | { "a,help", true, true }, | |
735 | { "a,?", true, true }, | |
736 | { "a=0,help,b", true, true }, | |
737 | { "a=0,?,b", true, true }, | |
738 | { "help,b=1", true, false }, | |
739 | { "?,b=1", true, false }, | |
740 | { "a,b,,help", true, true }, | |
741 | { "a,b,,?", true, true }, | |
32c2dcf5 MA |
742 | }; |
743 | int i; | |
744 | QemuOpts *opts; | |
745 | ||
746 | for (i = 0; i < ARRAY_SIZE(test); i++) { | |
747 | g_assert_cmpint(has_help_option(test[i].params), | |
59d27ebc | 748 | ==, test[i].expect); |
32c2dcf5 MA |
749 | opts = qemu_opts_parse(&opts_list_03, test[i].params, false, |
750 | &error_abort); | |
751 | g_assert_cmpint(qemu_opt_has_help_opt(opts), | |
59d27ebc | 752 | ==, test[i].expect); |
32c2dcf5 MA |
753 | qemu_opts_del(opts); |
754 | opts = qemu_opts_parse(&opts_list_03, test[i].params, true, | |
755 | &error_abort); | |
756 | g_assert_cmpint(qemu_opt_has_help_opt(opts), | |
59d27ebc | 757 | ==, test[i].expect_implied); |
32c2dcf5 MA |
758 | qemu_opts_del(opts); |
759 | } | |
760 | } | |
761 | ||
575ef8bf KW |
762 | static void append_verify_list_01(QemuOptDesc *desc, bool with_overlapping) |
763 | { | |
764 | int i = 0; | |
765 | ||
766 | if (with_overlapping) { | |
767 | g_assert_cmpstr(desc[i].name, ==, "str1"); | |
768 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING); | |
769 | g_assert_cmpstr(desc[i].help, ==, | |
770 | "Help texts are preserved in qemu_opts_append"); | |
771 | g_assert_cmpstr(desc[i].def_value_str, ==, "default"); | |
772 | i++; | |
773 | ||
774 | g_assert_cmpstr(desc[i].name, ==, "str2"); | |
775 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING); | |
776 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
777 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
778 | i++; | |
779 | } | |
780 | ||
781 | g_assert_cmpstr(desc[i].name, ==, "str3"); | |
782 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING); | |
783 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
784 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
785 | i++; | |
786 | ||
787 | g_assert_cmpstr(desc[i].name, ==, "number1"); | |
788 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER); | |
789 | g_assert_cmpstr(desc[i].help, ==, | |
790 | "Having help texts only for some options is okay"); | |
791 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
792 | i++; | |
793 | ||
794 | g_assert_cmpstr(desc[i].name, ==, "number2"); | |
795 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER); | |
796 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
797 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
798 | i++; | |
799 | ||
800 | g_assert_cmpstr(desc[i].name, ==, NULL); | |
801 | } | |
802 | ||
803 | static void append_verify_list_02(QemuOptDesc *desc) | |
804 | { | |
805 | int i = 0; | |
806 | ||
807 | g_assert_cmpstr(desc[i].name, ==, "str1"); | |
808 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING); | |
809 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
810 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
811 | i++; | |
812 | ||
813 | g_assert_cmpstr(desc[i].name, ==, "str2"); | |
814 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING); | |
815 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
816 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
817 | i++; | |
818 | ||
819 | g_assert_cmpstr(desc[i].name, ==, "bool1"); | |
820 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL); | |
821 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
822 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
823 | i++; | |
824 | ||
825 | g_assert_cmpstr(desc[i].name, ==, "bool2"); | |
826 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL); | |
827 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
828 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
829 | i++; | |
830 | ||
831 | g_assert_cmpstr(desc[i].name, ==, "size1"); | |
832 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE); | |
833 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
834 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
835 | i++; | |
836 | ||
837 | g_assert_cmpstr(desc[i].name, ==, "size2"); | |
838 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE); | |
839 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
840 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
841 | i++; | |
842 | ||
843 | g_assert_cmpstr(desc[i].name, ==, "size3"); | |
844 | g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE); | |
845 | g_assert_cmpstr(desc[i].help, ==, NULL); | |
846 | g_assert_cmpstr(desc[i].def_value_str, ==, NULL); | |
847 | } | |
848 | ||
849 | static void test_opts_append_to_null(void) | |
850 | { | |
851 | QemuOptsList *merged; | |
852 | ||
853 | merged = qemu_opts_append(NULL, &opts_list_01); | |
854 | g_assert(merged != &opts_list_01); | |
855 | ||
856 | g_assert_cmpstr(merged->name, ==, NULL); | |
857 | g_assert_cmpstr(merged->implied_opt_name, ==, NULL); | |
858 | g_assert_false(merged->merge_lists); | |
859 | ||
860 | append_verify_list_01(merged->desc, true); | |
861 | ||
862 | qemu_opts_free(merged); | |
863 | } | |
864 | ||
865 | static void test_opts_append(void) | |
866 | { | |
867 | QemuOptsList *first, *merged; | |
868 | ||
869 | first = qemu_opts_append(NULL, &opts_list_02); | |
870 | merged = qemu_opts_append(first, &opts_list_01); | |
871 | g_assert(first != &opts_list_02); | |
872 | g_assert(merged != &opts_list_01); | |
873 | ||
874 | g_assert_cmpstr(merged->name, ==, NULL); | |
875 | g_assert_cmpstr(merged->implied_opt_name, ==, NULL); | |
876 | g_assert_false(merged->merge_lists); | |
877 | ||
878 | append_verify_list_02(&merged->desc[0]); | |
879 | append_verify_list_01(&merged->desc[7], false); | |
880 | ||
881 | qemu_opts_free(merged); | |
882 | } | |
883 | ||
37974a97 KW |
884 | static void test_opts_to_qdict_basic(void) |
885 | { | |
886 | QemuOpts *opts; | |
887 | QDict *dict; | |
888 | ||
889 | opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42", | |
890 | false, &error_abort); | |
891 | g_assert(opts != NULL); | |
892 | ||
893 | dict = qemu_opts_to_qdict(opts, NULL); | |
894 | g_assert(dict != NULL); | |
895 | ||
896 | g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo"); | |
897 | g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, ""); | |
898 | g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar"); | |
899 | g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42"); | |
900 | g_assert_false(qdict_haskey(dict, "number2")); | |
901 | ||
cb3e7f08 | 902 | qobject_unref(dict); |
37974a97 KW |
903 | qemu_opts_del(opts); |
904 | } | |
905 | ||
906 | static void test_opts_to_qdict_filtered(void) | |
907 | { | |
908 | QemuOptsList *first, *merged; | |
909 | QemuOpts *opts; | |
910 | QDict *dict; | |
911 | ||
912 | first = qemu_opts_append(NULL, &opts_list_02); | |
913 | merged = qemu_opts_append(first, &opts_list_01); | |
914 | ||
915 | opts = qemu_opts_parse(merged, | |
916 | "str1=foo,str2=,str3=bar,bool1=off,number1=42", | |
917 | false, &error_abort); | |
918 | g_assert(opts != NULL); | |
919 | ||
920 | /* Convert to QDict without deleting from opts */ | |
921 | dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, false); | |
922 | g_assert(dict != NULL); | |
923 | g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo"); | |
924 | g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, ""); | |
925 | g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar"); | |
926 | g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42"); | |
927 | g_assert_false(qdict_haskey(dict, "number2")); | |
928 | g_assert_false(qdict_haskey(dict, "bool1")); | |
cb3e7f08 | 929 | qobject_unref(dict); |
37974a97 KW |
930 | |
931 | dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, false); | |
932 | g_assert(dict != NULL); | |
933 | g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo"); | |
934 | g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, ""); | |
935 | g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off"); | |
936 | g_assert_false(qdict_haskey(dict, "str3")); | |
937 | g_assert_false(qdict_haskey(dict, "number1")); | |
938 | g_assert_false(qdict_haskey(dict, "number2")); | |
cb3e7f08 | 939 | qobject_unref(dict); |
37974a97 KW |
940 | |
941 | /* Now delete converted options from opts */ | |
942 | dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, true); | |
943 | g_assert(dict != NULL); | |
944 | g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo"); | |
945 | g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, ""); | |
946 | g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar"); | |
947 | g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42"); | |
948 | g_assert_false(qdict_haskey(dict, "number2")); | |
949 | g_assert_false(qdict_haskey(dict, "bool1")); | |
cb3e7f08 | 950 | qobject_unref(dict); |
37974a97 KW |
951 | |
952 | dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, true); | |
953 | g_assert(dict != NULL); | |
954 | g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off"); | |
955 | g_assert_false(qdict_haskey(dict, "str1")); | |
956 | g_assert_false(qdict_haskey(dict, "str2")); | |
957 | g_assert_false(qdict_haskey(dict, "str3")); | |
958 | g_assert_false(qdict_haskey(dict, "number1")); | |
959 | g_assert_false(qdict_haskey(dict, "number2")); | |
cb3e7f08 | 960 | qobject_unref(dict); |
37974a97 KW |
961 | |
962 | g_assert_true(QTAILQ_EMPTY(&opts->head)); | |
963 | ||
964 | qemu_opts_del(opts); | |
965 | qemu_opts_free(merged); | |
966 | } | |
967 | ||
968 | static void test_opts_to_qdict_duplicates(void) | |
969 | { | |
970 | QemuOpts *opts; | |
971 | QemuOpt *opt; | |
972 | QDict *dict; | |
973 | ||
974 | opts = qemu_opts_parse(&opts_list_03, "foo=a,foo=b", false, &error_abort); | |
975 | g_assert(opts != NULL); | |
976 | ||
977 | /* Verify that opts has two options with the same name */ | |
978 | opt = QTAILQ_FIRST(&opts->head); | |
979 | g_assert_cmpstr(opt->name, ==, "foo"); | |
980 | g_assert_cmpstr(opt->str , ==, "a"); | |
981 | ||
982 | opt = QTAILQ_NEXT(opt, next); | |
983 | g_assert_cmpstr(opt->name, ==, "foo"); | |
984 | g_assert_cmpstr(opt->str , ==, "b"); | |
985 | ||
986 | opt = QTAILQ_NEXT(opt, next); | |
987 | g_assert(opt == NULL); | |
988 | ||
989 | /* In the conversion to QDict, the last one wins */ | |
990 | dict = qemu_opts_to_qdict(opts, NULL); | |
991 | g_assert(dict != NULL); | |
992 | g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b"); | |
cb3e7f08 | 993 | qobject_unref(dict); |
37974a97 KW |
994 | |
995 | /* The last one still wins if entries are deleted, and both are deleted */ | |
996 | dict = qemu_opts_to_qdict_filtered(opts, NULL, NULL, true); | |
997 | g_assert(dict != NULL); | |
998 | g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b"); | |
cb3e7f08 | 999 | qobject_unref(dict); |
37974a97 KW |
1000 | |
1001 | g_assert_true(QTAILQ_EMPTY(&opts->head)); | |
1002 | ||
1003 | qemu_opts_del(opts); | |
1004 | } | |
575ef8bf | 1005 | |
4ba6fabf LD |
1006 | int main(int argc, char *argv[]) |
1007 | { | |
1008 | register_opts(); | |
1009 | g_test_init(&argc, &argv, NULL); | |
1010 | g_test_add_func("/qemu-opts/find_unknown_opts", test_find_unknown_opts); | |
1011 | g_test_add_func("/qemu-opts/find_opts", test_qemu_find_opts); | |
1012 | g_test_add_func("/qemu-opts/opts_create", test_qemu_opts_create); | |
1013 | g_test_add_func("/qemu-opts/opt_get", test_qemu_opt_get); | |
1014 | g_test_add_func("/qemu-opts/opt_get_bool", test_qemu_opt_get_bool); | |
1015 | g_test_add_func("/qemu-opts/opt_get_number", test_qemu_opt_get_number); | |
1016 | g_test_add_func("/qemu-opts/opt_get_size", test_qemu_opt_get_size); | |
1017 | g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset); | |
1018 | g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset); | |
1019 | g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set); | |
694baf57 MA |
1020 | g_test_add_func("/qemu-opts/opts_parse/general", test_opts_parse); |
1021 | g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool); | |
1022 | g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number); | |
1023 | g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size); | |
32c2dcf5 | 1024 | g_test_add_func("/qemu-opts/has_help_option", test_has_help_option); |
575ef8bf KW |
1025 | g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null); |
1026 | g_test_add_func("/qemu-opts/append", test_opts_append); | |
37974a97 KW |
1027 | g_test_add_func("/qemu-opts/to_qdict/basic", test_opts_to_qdict_basic); |
1028 | g_test_add_func("/qemu-opts/to_qdict/filtered", test_opts_to_qdict_filtered); | |
1029 | g_test_add_func("/qemu-opts/to_qdict/duplicates", test_opts_to_qdict_duplicates); | |
4ba6fabf LD |
1030 | g_test_run(); |
1031 | return 0; | |
1032 | } |