aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmlmetatype
diff options
context:
space:
mode:
authorAndy Shaw <andy.shaw@qt.io>2017-10-27 12:54:57 +0200
committerAndy Shaw <andy.shaw@qt.io>2017-12-01 10:44:08 +0000
commit2cfe1bb09c11432ca5033f9589243e9e62fe9488 (patch)
tree84e8249bd024e476efef6ca63d9d443010d6070f /tests/auto/qml/qqmlmetatype
parent9e7dbbeec0be2ce07c58edf84ce6e03d60946bce (diff)
Add a means to unregister custom qml types
In cases where Qt is used in a plugin it is possible that a plugin will be unloaded while Qt itself is still loaded and as a result there is a chance that there will be conflicting types registered. Therefore, to ensure that plugins correctly clean up after themselves cleanly, we need to add a means to unregister qml types. This is intended to only be used when the user knows what they are doing. Task-number: QTBUG-56521 Task-number: QTBUG-56532 Change-Id: Ie396e522385004e6e9f3841e04f8072ff29cb15b Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'tests/auto/qml/qqmlmetatype')
-rw-r--r--tests/auto/qml/qqmlmetatype/data/testUnregisterCustomSingletonType.qml8
-rw-r--r--tests/auto/qml/qqmlmetatype/data/testUnregisterCustomType.qml8
-rw-r--r--tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp193
3 files changed, 209 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomSingletonType.qml b/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomSingletonType.qml
new file mode 100644
index 0000000000..85b8f5ac8b
--- /dev/null
+++ b/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomSingletonType.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.7
+import mytypes 1.0
+
+Item {
+ id: root
+ property string text: StaticProvider.singletonGetString()
+}
+
diff --git a/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomType.qml b/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomType.qml
new file mode 100644
index 0000000000..f6ee4e9b77
--- /dev/null
+++ b/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomType.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.7
+import mytypes 1.0
+
+Item {
+ id: root
+ Controller { id: controller; objectName: "controller" }
+}
+
diff --git a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
index 798e3fd386..58361b4b12 100644
--- a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
+++ b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
@@ -60,6 +60,8 @@ private slots:
void isList();
void defaultObject();
+ void unregisterCustomType();
+ void unregisterCustomSingletonType();
};
class TestType : public QObject
@@ -330,6 +332,197 @@ void tst_qqmlmetatype::externalEnums()
}
+class Controller1 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString string MEMBER m_string)
+ Q_PROPERTY(Controller1Enum enumVal MEMBER m_enumVal)
+public:
+ enum Controller1Enum {
+ ENUM_VALUE_1 = 1,
+ ENUM_VALUE_2 = 2
+ };
+ Q_ENUMS(Controller1Enum)
+
+ Controller1(QObject *parent = nullptr) : QObject(parent), m_string("Controller #1"),
+ m_enumVal(ENUM_VALUE_1)
+ {}
+private:
+ QString m_string;
+ Controller1Enum m_enumVal;
+};
+
+class Controller2 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString string MEMBER m_string)
+ Q_PROPERTY(Controller2Enum enumVal MEMBER m_enumVal)
+public:
+ enum Controller2Enum {
+ ENUM_VALUE_1 = 111,
+ ENUM_VALUE_2 = 222
+ };
+ Q_ENUMS(Controller2Enum)
+
+ Controller2(QObject *parent = nullptr) : QObject(parent), m_string("Controller #2"),
+ m_enumVal(ENUM_VALUE_1)
+ {}
+private:
+ QString m_string;
+ Controller2Enum m_enumVal;
+};
+
+void tst_qqmlmetatype::unregisterCustomType()
+{
+ int controllerId = 0;
+ {
+ QQmlEngine engine;
+ QQmlType type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(!type.isValid());
+ controllerId = qmlRegisterType<Controller1>("mytypes", 1, 0, "Controller");
+ type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(!type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj);
+ QObject *controller = obj->findChild<QObject *>("controller");
+ QVERIFY(qobject_cast<Controller1 *>(controller));
+ QVariant stringVal = controller->property("string");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("Controller #1"));
+ QVariant enumVal = controller->property("enumVal");
+ QCOMPARE(enumVal.type(), QVariant::Int);
+ QCOMPARE(enumVal.toInt(), 1);
+ }
+ qmlUnregisterType(controllerId);
+ {
+ QQmlEngine engine;
+ QQmlType type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(!type.isValid());
+ controllerId = qmlRegisterType<Controller2>("mytypes", 1, 0, "Controller");
+ type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(!type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj);
+ QObject *controller = obj->findChild<QObject *>("controller");
+ QVERIFY(qobject_cast<Controller2 *>(controller));
+ QVariant stringVal = controller->property("string");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("Controller #2"));
+ QVariant enumVal = controller->property("enumVal");
+ QCOMPARE(enumVal.type(), QVariant::Int);
+ QCOMPARE(enumVal.toInt(), 111);
+ }
+ qmlUnregisterType(controllerId);
+ {
+ QQmlEngine engine;
+ QQmlType type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(!type.isValid());
+ controllerId = qmlRegisterType<Controller1>("mytypes", 1, 0, "Controller");
+ type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(!type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj);
+ QObject *controller = obj->findChild<QObject *>("controller");
+ QVERIFY(qobject_cast<Controller1 *>(controller));
+ QVariant stringVal = controller->property("string");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("Controller #1"));
+ QVariant enumVal = controller->property("enumVal");
+ QCOMPARE(enumVal.type(), QVariant::Int);
+ QCOMPARE(enumVal.toInt(), 1);
+ }
+}
+
+class StaticProvider1 : public QObject
+{
+ Q_OBJECT
+public:
+ StaticProvider1(QObject *parent = nullptr) : QObject(parent) {}
+ Q_INVOKABLE QString singletonGetString() { return "StaticProvider #1"; }
+};
+
+static QObject* createStaticProvider1(QQmlEngine *, QJSEngine *)
+{
+ return new StaticProvider1;
+}
+
+class StaticProvider2 : public QObject
+{
+ Q_OBJECT
+public:
+ StaticProvider2(QObject *parent = nullptr) : QObject(parent) {}
+ Q_INVOKABLE QString singletonGetString() { return "StaticProvider #2"; }
+};
+
+static QObject* createStaticProvider2(QQmlEngine *, QJSEngine *)
+{
+ return new StaticProvider2;
+}
+
+void tst_qqmlmetatype::unregisterCustomSingletonType()
+{
+ int staticProviderId = 0;
+ {
+ QQmlEngine engine;
+ staticProviderId = qmlRegisterSingletonType<StaticProvider1>("mytypes", 1, 0, "StaticProvider", createStaticProvider1);
+ QQmlType type = QQmlMetaType::qmlType(QString("StaticProvider"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomSingletonType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj.data());
+ QVariant stringVal = obj->property("text");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("StaticProvider #1"));
+ }
+ qmlUnregisterType(staticProviderId);
+ {
+ QQmlEngine engine;
+ staticProviderId = qmlRegisterSingletonType<StaticProvider2>("mytypes", 1, 0, "StaticProvider", createStaticProvider2);
+ QQmlType type = QQmlMetaType::qmlType(QString("StaticProvider"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomSingletonType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj.data());
+ QVariant stringVal = obj->property("text");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("StaticProvider #2"));
+ }
+ qmlUnregisterType(staticProviderId);
+ {
+ QQmlEngine engine;
+ staticProviderId = qmlRegisterSingletonType<StaticProvider1>("mytypes", 1, 0, "StaticProvider", createStaticProvider1);
+ QQmlType type = QQmlMetaType::qmlType(QString("StaticProvider"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomSingletonType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj.data());
+ QVariant stringVal = obj->property("text");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("StaticProvider #1"));
+ }
+}
+
QTEST_MAIN(tst_qqmlmetatype)
#include "tst_qqmlmetatype.moc"