]> git.proxmox.com Git - mirror_qemu.git/blobdiff - tests/device-introspect-test.c
Merge remote-tracking branch 'remotes/ehabkost/tags/machine-next-pull-request' into...
[mirror_qemu.git] / tests / device-introspect-test.c
index c5637cc406963320ef9ad16772ca93ba1aac305a..0b4f221c29de9ed7f7ea46e9044b761c5439390e 100644 (file)
@@ -20,8 +20,8 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 #include "qapi/qmp/qstring.h"
-#include "qapi/qmp/qbool.h"
 #include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
 #include "libqtest.h"
 
 const char common_args[] = "-nodefaults -machine none";
@@ -32,19 +32,69 @@ static QList *qom_list_types(const char *implements, bool abstract)
     QList *ret;
     QDict *args = qdict_new();
 
-    qdict_put(args, "abstract", qbool_from_bool(abstract));
+    qdict_put_bool(args, "abstract", abstract);
     if (implements) {
-        qdict_put(args, "implements", qstring_from_str(implements));
+        qdict_put_str(args, "implements", implements);
     }
     resp = qmp("{'execute': 'qom-list-types',"
                " 'arguments': %p }", args);
     g_assert(qdict_haskey(resp, "return"));
     ret = qdict_get_qlist(resp, "return");
-    QINCREF(ret);
-    QDECREF(resp);
+    qobject_ref(ret);
+    qobject_unref(resp);
     return ret;
 }
 
+/* Build a name -> ObjectTypeInfo index from a ObjectTypeInfo list */
+static QDict *qom_type_index(QList *types)
+{
+    QDict *index = qdict_new();
+    QListEntry *e;
+
+    QLIST_FOREACH_ENTRY(types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *name = qdict_get_str(d, "name");
+        qobject_ref(d);
+        qdict_put(index, name, d);
+    }
+    return index;
+}
+
+/* Check if @parent is present in the parent chain of @type */
+static bool qom_has_parent(QDict *index, const char *type, const char *parent)
+{
+    while (type) {
+        QDict *d = qdict_get_qdict(index, type);
+        const char *p = d && qdict_haskey(d, "parent") ?
+                        qdict_get_str(d, "parent") :
+                        NULL;
+
+        if (!strcmp(type, parent)) {
+            return true;
+        }
+
+        type = p;
+    }
+
+    return false;
+}
+
+/* Find an entry on a list returned by qom-list-types */
+static QDict *type_list_find(QList *types, const char *name)
+{
+    QListEntry *e;
+
+    QLIST_FOREACH_ENTRY(types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *ename = qdict_get_str(d, "name");
+        if (!strcmp(ename, name)) {
+            return d;
+        }
+    }
+
+    return NULL;
+}
+
 static QList *device_type_list(bool abstract)
 {
     return qom_list_types("device", abstract);
@@ -58,7 +108,7 @@ static void test_one_device(const char *type)
     resp = qmp("{'execute': 'device-list-properties',"
                " 'arguments': {'typename': %s}}",
                type);
-    QDECREF(resp);
+    qobject_unref(resp);
 
     help = hmp("device_add \"%s,help\"", type);
     g_free(help);
@@ -79,7 +129,7 @@ static void test_device_intro_list(void)
     qtest_start(common_args);
 
     types = device_type_list(true);
-    QDECREF(types);
+    qobject_unref(types);
 
     help = hmp("device_add help");
     g_free(help);
@@ -87,6 +137,61 @@ static void test_device_intro_list(void)
     qtest_end();
 }
 
+/*
+ * Ensure all entries returned by qom-list-types implements=<parent>
+ * have <parent> as a parent.
+ */
+static void test_qom_list_parents(const char *parent)
+{
+    QList *types;
+    QListEntry *e;
+    QDict *index;
+
+    types = qom_list_types(parent, true);
+    index = qom_type_index(types);
+
+    QLIST_FOREACH_ENTRY(types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *name = qdict_get_str(d, "name");
+
+        g_assert(qom_has_parent(index, name, parent));
+    }
+
+    qobject_unref(types);
+    qobject_unref(index);
+}
+
+static void test_qom_list_fields(void)
+{
+    QList *all_types;
+    QList *non_abstract;
+    QListEntry *e;
+
+    qtest_start(common_args);
+
+    all_types = qom_list_types(NULL, true);
+    non_abstract = qom_list_types(NULL, false);
+
+    QLIST_FOREACH_ENTRY(all_types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *name = qdict_get_str(d, "name");
+        bool abstract = qdict_haskey(d, "abstract") ?
+                        qdict_get_bool(d, "abstract") :
+                        false;
+        bool expected_abstract = !type_list_find(non_abstract, name);
+
+        g_assert(abstract == expected_abstract);
+    }
+
+    test_qom_list_parents("object");
+    test_qom_list_parents("device");
+    test_qom_list_parents("sys-bus-device");
+
+    qobject_unref(all_types);
+    qobject_unref(non_abstract);
+    qtest_end();
+}
+
 static void test_device_intro_none(void)
 {
     qtest_start(common_args);
@@ -111,55 +216,47 @@ static void test_device_intro_concrete(void)
     types = device_type_list(false);
 
     QLIST_FOREACH_ENTRY(types, entry) {
-        type = qdict_get_try_str(qobject_to_qdict(qlist_entry_obj(entry)),
-                                "name");
+        type = qdict_get_try_str(qobject_to(QDict, qlist_entry_obj(entry)),
+                                 "name");
         g_assert(type);
         test_one_device(type);
     }
 
-    QDECREF(types);
+    qobject_unref(types);
     qtest_end();
 }
 
 static void test_abstract_interfaces(void)
 {
     QList *all_types;
-    QList *obj_types;
-    QListEntry *ae;
+    QListEntry *e;
+    QDict *index;
 
     qtest_start(common_args);
-    /* qom-list-types implements=interface would return any type
-     * that implements _any_ interface (not just interface types),
-     * so use a trick to find the interface type names:
-     * - list all object types
-     * - list all types, and look for items that are not
-     *   on the first list
-     */
-    all_types = qom_list_types(NULL, false);
-    obj_types = qom_list_types("object", false);
-
-    QLIST_FOREACH_ENTRY(all_types, ae) {
-        QDict *at = qobject_to_qdict(qlist_entry_obj(ae));
-        const char *aname = qdict_get_str(at, "name");
-        QListEntry *oe;
-        const char *found = NULL;
-
-        QLIST_FOREACH_ENTRY(obj_types, oe) {
-            QDict *ot = qobject_to_qdict(qlist_entry_obj(oe));
-            const char *oname = qdict_get_str(ot, "name");
-            if (!strcmp(aname, oname)) {
-                found = oname;
-                break;
-            }
+
+    all_types = qom_list_types("interface", true);
+    index = qom_type_index(all_types);
+
+    QLIST_FOREACH_ENTRY(all_types, e) {
+        QDict *d = qobject_to(QDict, qlist_entry_obj(e));
+        const char *name = qdict_get_str(d, "name");
+
+        /*
+         * qom-list-types implements=interface returns all types
+         * that implement _any_ interface (not just interface
+         * types), so skip the ones that don't have "interface"
+         * on the parent type chain.
+         */
+        if (!qom_has_parent(index, name, "interface")) {
+            /* Not an interface type */
+            continue;
         }
 
-        /* Using g_assert_cmpstr() will give more useful failure
-         * messages than g_assert(found) */
-        g_assert_cmpstr(aname, ==, found);
+        g_assert(qdict_haskey(d, "abstract") && qdict_get_bool(d, "abstract"));
     }
 
-    QDECREF(all_types);
-    QDECREF(obj_types);
+    qobject_unref(all_types);
+    qobject_unref(index);
     qtest_end();
 }
 
@@ -168,6 +265,7 @@ int main(int argc, char **argv)
     g_test_init(&argc, &argv, NULL);
 
     qtest_add_func("device/introspect/list", test_device_intro_list);
+    qtest_add_func("device/introspect/list-fields", test_qom_list_fields);
     qtest_add_func("device/introspect/none", test_device_intro_none);
     qtest_add_func("device/introspect/abstract", test_device_intro_abstract);
     qtest_add_func("device/introspect/concrete", test_device_intro_concrete);