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