diff options
author | Andy Shaw <andy.shaw@qt.io> | 2017-10-27 12:54:57 +0200 |
---|---|---|
committer | Andy Shaw <andy.shaw@qt.io> | 2017-12-01 10:44:08 +0000 |
commit | 2cfe1bb09c11432ca5033f9589243e9e62fe9488 (patch) | |
tree | 84e8249bd024e476efef6ca63d9d443010d6070f /tests | |
parent | 9e7dbbeec0be2ce07c58edf84ce6e03d60946bce (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')
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" |