]> git.proxmox.com Git - mirror_qemu.git/blobdiff - tests/test-qemu-opts.c
minikconf: do not include variables from MINIKCONF_ARGS in config-all-devices.mak
[mirror_qemu.git] / tests / test-qemu-opts.c
index 0ad74b464f2b6c50c6a377c777e1c01936237f6f..ef96e84aedb70d3761e486856084c8ea3904d6ec 100644 (file)
@@ -8,8 +8,11 @@
  */
 
 #include "qemu/osdep.h"
-#include "qemu/cutils.h"
+#include "qemu/units.h"
+#include "qemu/option.h"
+#include "qemu/option_int.h"
 #include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qstring.h"
 #include "qemu/config-file.h"
 
@@ -21,6 +24,8 @@ static QemuOptsList opts_list_01 = {
         {
             .name = "str1",
             .type = QEMU_OPT_STRING,
+            .help = "Help texts are preserved in qemu_opts_append",
+            .def_value_str = "default",
         },{
             .name = "str2",
             .type = QEMU_OPT_STRING,
@@ -30,6 +35,7 @@ static QemuOptsList opts_list_01 = {
         },{
             .name = "number1",
             .type = QEMU_OPT_NUMBER,
+            .help = "Having help texts only for some options is okay",
         },{
             .name = "number2",
             .type = QEMU_OPT_NUMBER,
@@ -299,7 +305,7 @@ static void test_qemu_opt_get_size(void)
     dict = qdict_new();
     g_assert(dict != NULL);
 
-    qdict_put(dict, "size1", qstring_from_str("10"));
+    qdict_put_str(dict, "size1", "10");
 
     qemu_opts_absorb_qdict(opts, dict, &error_abort);
     g_assert(error_abort == NULL);
@@ -309,7 +315,7 @@ static void test_qemu_opt_get_size(void)
     g_assert(opt == 10);
 
     /* reset value */
-    qdict_put(dict, "size1", qstring_from_str("15"));
+    qdict_put_str(dict, "size1", "15");
 
     qemu_opts_absorb_qdict(opts, dict, &error_abort);
     g_assert(error_abort == NULL);
@@ -453,8 +459,6 @@ static void test_opts_parse(void)
 {
     Error *err = NULL;
     QemuOpts *opts;
-    char long_key[129];
-    char *params;
 
     /* Nothing */
     opts = qemu_opts_parse(&opts_list_03, "", false, &error_abort);
@@ -465,22 +469,6 @@ static void test_opts_parse(void)
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val");
 
-    /* Long key */
-    memset(long_key, 'a', 127);
-    long_key[127] = 'z';
-    long_key[128] = 0;
-    params = g_strdup_printf("%s=v", long_key);
-    opts = qemu_opts_parse(&opts_list_03, params + 1, NULL, &error_abort);
-    g_assert_cmpuint(opts_count(opts), ==, 1);
-    g_assert_cmpstr(qemu_opt_get(opts, long_key + 1), ==, "v");
-
-    /* Overlong key gets truncated */
-    opts = qemu_opts_parse(&opts_list_03, params, NULL, &error_abort);
-    g_assert(opts_count(opts) == 1);
-    long_key[127] = 0;
-    g_assert_cmpstr(qemu_opt_get(opts, long_key), ==, "v");
-    g_free(params);
-
     /* Multiple keys, last one wins */
     opts = qemu_opts_parse(&opts_list_03, "a=1,b=2,,x,a=3",
                            false, &error_abort);
@@ -716,13 +704,12 @@ static void test_opts_parse_size(void)
     g_assert_cmpuint(opts_count(opts), ==, 3);
     g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, 8);
     g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 1536);
-    g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * M_BYTE);
+    g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * MiB);
     opts = qemu_opts_parse(&opts_list_02, "size1=0.1G,size2=16777215T",
                            false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 2);
-    g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, G_BYTE / 10);
-    g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0),
-                     ==, 16777215 * T_BYTE);
+    g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, GiB / 10);
+    g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 16777215ULL * TiB);
 
     /* Beyond limit with suffix */
     opts = qemu_opts_parse(&opts_list_02, "size1=16777216T",
@@ -741,6 +728,250 @@ static void test_opts_parse_size(void)
     qemu_opts_reset(&opts_list_02);
 }
 
+static void append_verify_list_01(QemuOptDesc *desc, bool with_overlapping)
+{
+    int i = 0;
+
+    if (with_overlapping) {
+        g_assert_cmpstr(desc[i].name, ==, "str1");
+        g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+        g_assert_cmpstr(desc[i].help, ==,
+                        "Help texts are preserved in qemu_opts_append");
+        g_assert_cmpstr(desc[i].def_value_str, ==, "default");
+        i++;
+
+        g_assert_cmpstr(desc[i].name, ==, "str2");
+        g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+        g_assert_cmpstr(desc[i].help, ==, NULL);
+        g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+        i++;
+    }
+
+    g_assert_cmpstr(desc[i].name, ==, "str3");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "number1");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
+    g_assert_cmpstr(desc[i].help, ==,
+                    "Having help texts only for some options is okay");
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "number2");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, NULL);
+}
+
+static void append_verify_list_02(QemuOptDesc *desc)
+{
+    int i = 0;
+
+    g_assert_cmpstr(desc[i].name, ==, "str1");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "str2");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "bool1");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "bool2");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "size1");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "size2");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "size3");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+}
+
+static void test_opts_append_to_null(void)
+{
+    QemuOptsList *merged;
+
+    merged = qemu_opts_append(NULL, &opts_list_01);
+    g_assert(merged != &opts_list_01);
+
+    g_assert_cmpstr(merged->name, ==, NULL);
+    g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
+    g_assert_false(merged->merge_lists);
+
+    append_verify_list_01(merged->desc, true);
+
+    qemu_opts_free(merged);
+}
+
+static void test_opts_append(void)
+{
+    QemuOptsList *first, *merged;
+
+    first = qemu_opts_append(NULL, &opts_list_02);
+    merged = qemu_opts_append(first, &opts_list_01);
+    g_assert(first != &opts_list_02);
+    g_assert(merged != &opts_list_01);
+
+    g_assert_cmpstr(merged->name, ==, NULL);
+    g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
+    g_assert_false(merged->merge_lists);
+
+    append_verify_list_02(&merged->desc[0]);
+    append_verify_list_01(&merged->desc[7], false);
+
+    qemu_opts_free(merged);
+}
+
+static void test_opts_to_qdict_basic(void)
+{
+    QemuOpts *opts;
+    QDict *dict;
+
+    opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42",
+                           false, &error_abort);
+    g_assert(opts != NULL);
+
+    dict = qemu_opts_to_qdict(opts, NULL);
+    g_assert(dict != NULL);
+
+    g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
+    g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
+    g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
+    g_assert_false(qdict_haskey(dict, "number2"));
+
+    qobject_unref(dict);
+    qemu_opts_del(opts);
+}
+
+static void test_opts_to_qdict_filtered(void)
+{
+    QemuOptsList *first, *merged;
+    QemuOpts *opts;
+    QDict *dict;
+
+    first = qemu_opts_append(NULL, &opts_list_02);
+    merged = qemu_opts_append(first, &opts_list_01);
+
+    opts = qemu_opts_parse(merged,
+                           "str1=foo,str2=,str3=bar,bool1=off,number1=42",
+                           false, &error_abort);
+    g_assert(opts != NULL);
+
+    /* Convert to QDict without deleting from opts */
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, false);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
+    g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
+    g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
+    g_assert_false(qdict_haskey(dict, "number2"));
+    g_assert_false(qdict_haskey(dict, "bool1"));
+    qobject_unref(dict);
+
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, false);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
+    g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
+    g_assert_false(qdict_haskey(dict, "str3"));
+    g_assert_false(qdict_haskey(dict, "number1"));
+    g_assert_false(qdict_haskey(dict, "number2"));
+    qobject_unref(dict);
+
+    /* Now delete converted options from opts */
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, true);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
+    g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
+    g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
+    g_assert_false(qdict_haskey(dict, "number2"));
+    g_assert_false(qdict_haskey(dict, "bool1"));
+    qobject_unref(dict);
+
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, true);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
+    g_assert_false(qdict_haskey(dict, "str1"));
+    g_assert_false(qdict_haskey(dict, "str2"));
+    g_assert_false(qdict_haskey(dict, "str3"));
+    g_assert_false(qdict_haskey(dict, "number1"));
+    g_assert_false(qdict_haskey(dict, "number2"));
+    qobject_unref(dict);
+
+    g_assert_true(QTAILQ_EMPTY(&opts->head));
+
+    qemu_opts_del(opts);
+    qemu_opts_free(merged);
+}
+
+static void test_opts_to_qdict_duplicates(void)
+{
+    QemuOpts *opts;
+    QemuOpt *opt;
+    QDict *dict;
+
+    opts = qemu_opts_parse(&opts_list_03, "foo=a,foo=b", false, &error_abort);
+    g_assert(opts != NULL);
+
+    /* Verify that opts has two options with the same name */
+    opt = QTAILQ_FIRST(&opts->head);
+    g_assert_cmpstr(opt->name, ==, "foo");
+    g_assert_cmpstr(opt->str , ==, "a");
+
+    opt = QTAILQ_NEXT(opt, next);
+    g_assert_cmpstr(opt->name, ==, "foo");
+    g_assert_cmpstr(opt->str , ==, "b");
+
+    opt = QTAILQ_NEXT(opt, next);
+    g_assert(opt == NULL);
+
+    /* In the conversion to QDict, the last one wins */
+    dict = qemu_opts_to_qdict(opts, NULL);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
+    qobject_unref(dict);
+
+    /* The last one still wins if entries are deleted, and both are deleted */
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, NULL, true);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
+    qobject_unref(dict);
+
+    g_assert_true(QTAILQ_EMPTY(&opts->head));
+
+    qemu_opts_del(opts);
+}
+
 int main(int argc, char *argv[])
 {
     register_opts();
@@ -759,6 +990,11 @@ int main(int argc, char *argv[])
     g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool);
     g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number);
     g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
+    g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null);
+    g_test_add_func("/qemu-opts/append", test_opts_append);
+    g_test_add_func("/qemu-opts/to_qdict/basic", test_opts_to_qdict_basic);
+    g_test_add_func("/qemu-opts/to_qdict/filtered", test_opts_to_qdict_filtered);
+    g_test_add_func("/qemu-opts/to_qdict/duplicates", test_opts_to_qdict_duplicates);
     g_test_run();
     return 0;
 }