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