xref: /qemu/tests/unit/test-qemu-opts.c (revision d8da9e71b6c79c2899c08bb168cd0ae88da70596)
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     QemuOptsList *list;
191     QemuOpts *opts;
192     bool opt;
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 
212     qemu_opt_set_bool(opts, "bool1", true, &error_abort);
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 */
219     qemu_opt_set_bool(opts, "bool1", false, &error_abort);
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;
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 
255     qemu_opt_set_number(opts, "number1", 10, &error_abort);
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 */
262     qemu_opt_set_number(opts, "number1", 15, &error_abort);
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 
302     qdict_put_str(dict, "size1", "10");
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 */
312     qdict_put_str(dict, "size1", "15");
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 */
338     opts = qemu_opts_parse(&opts_list_03, "key=value", false, NULL);
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 */
346     qemu_opt_set(opts, "key", "value2", &error_abort);
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;
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 
386     qemu_opt_set_number(opts, "number1", 10, &error_abort);
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;
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 */
415     qemu_opts_set(list, NULL, "str3", "value", &error_abort);
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 
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;
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 
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 
493     /* Buggy ID recognition (fixed) */
494     opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort);
495     g_assert_cmpuint(opts_count(opts), ==, 1);
496     g_assert(!qemu_opts_id(opts));
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 
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 
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",
588                            false, &err);
589     error_free_or_abort(&err);
590     g_assert(!opts);
591 
592     /* Below lower limit */
593     opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616",
594                            false, &err);
595     error_free_or_abort(&err);
596     g_assert(!opts);
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);
607     error_free_or_abort(&err);
608     g_assert(!opts);
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 */
687                            false, &err);
688     error_free_or_abort(&err);
689     g_assert(!opts);
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);
697     g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * MiB);
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);
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);
703 
704     /* Beyond limit with suffix */
705     opts = qemu_opts_parse(&opts_list_02, "size1=16777216T",
706                            false, &err);
707     error_free_or_abort(&err);
708     g_assert(!opts);
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);
714     opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &err);
715     error_free_or_abort(&err);
716     g_assert(!opts);
717 
718     qemu_opts_reset(&opts_list_02);
719 }
720 
721 static void test_has_help_option(void)
722 {
723     static const struct {
724         const char *params;
725         /* expected value of qemu_opt_has_help_opt() with implied=false */
726         bool expect;
727         /* expected value of qemu_opt_has_help_opt() with implied=true */
728         bool expect_implied;
729     } test[] = {
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 },
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),
748                         ==, test[i].expect);
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),
752                         ==, test[i].expect);
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),
757                         ==, test[i].expect_implied);
758         qemu_opts_del(opts);
759     }
760 }
761 
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 
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 
902     qobject_unref(dict);
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"));
929     qobject_unref(dict);
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"));
939     qobject_unref(dict);
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"));
950     qobject_unref(dict);
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"));
960     qobject_unref(dict);
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");
993     qobject_unref(dict);
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");
999     qobject_unref(dict);
1000 
1001     g_assert_true(QTAILQ_EMPTY(&opts->head));
1002 
1003     qemu_opts_del(opts);
1004 }
1005 
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);
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);
1024     g_test_add_func("/qemu-opts/has_help_option", test_has_help_option);
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);
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);
1030     g_test_run();
1031     return 0;
1032 }
1033