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