From 2b52a997ce3679ac4c94b7c117b0ea11c1523b60 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 6 Nov 2018 13:49:57 +0100 Subject: QML TypeLoader: Sort composite singletons before recursing into them When recursingly loading further types for composite singletons before sorting them, the order in which the recursively referenced types are loaded is random because the composite singletons are kept in an (unordered) hash. Any sorting after loading the child components doesn't help as the recursive references may depend on the types already loaded at that point. Sorting the composite singletons before starting the recursion does help because it eliminates the source of randomness in the system. Fixes: QTBUG-66976 Change-Id: I0fa1f50b36eba8c73eb8d56b4d5118485ab05f35 Reviewed-by: Michael Brasser Reviewed-by: Lars Knoll --- .../data/CppRegisteredSingleton1.qml | 6 +++ .../data/CppRegisteredSingleton2.qml | 7 +++ tests/auto/qml/qqmltypeloader/data/Singleton.qml | 7 +++ .../imports/multisingletonmodule/Singleton1.qml | 7 +++ .../imports/multisingletonmodule/Singleton2.qml | 7 +++ .../data/imports/multisingletonmodule/qmldir | 2 + .../qml/qqmltypeloader/data/multisingletonuser.qml | 7 +++ .../auto/qml/qqmltypeloader/data/singletonuser.qml | 6 +++ .../auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp | 56 ++++++++++++++++++++++ 9 files changed, 105 insertions(+) create mode 100644 tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml create mode 100644 tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml create mode 100644 tests/auto/qml/qqmltypeloader/data/Singleton.qml create mode 100644 tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml create mode 100644 tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml create mode 100644 tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir create mode 100644 tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml create mode 100644 tests/auto/qml/qqmltypeloader/data/singletonuser.qml (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml new file mode 100644 index 0000000000..f4ad5e5f7a --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml @@ -0,0 +1,6 @@ +pragma Singleton +import QtQuick 2.0 + +Item { + property bool ok: true +} diff --git a/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml new file mode 100644 index 0000000000..55dd57517f --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml @@ -0,0 +1,7 @@ +pragma Singleton +import QtQuick 2.0 +import cppsingletonmodule 1.0 + +Item { + property bool ok: CppRegisteredSingleton1.ok +} diff --git a/tests/auto/qml/qqmltypeloader/data/Singleton.qml b/tests/auto/qml/qqmltypeloader/data/Singleton.qml new file mode 100644 index 0000000000..3a1b1c1493 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/Singleton.qml @@ -0,0 +1,7 @@ +pragma Singleton +import QtQml 2.0 +import modulewithsingleton 1.0 + +QtObject { + property bool ok: true +} diff --git a/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml new file mode 100644 index 0000000000..34eca59f86 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml @@ -0,0 +1,7 @@ +pragma Singleton +import QtQuick 2.0 +import "." + +Item { + property bool ok: true +} diff --git a/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml new file mode 100644 index 0000000000..607d85d7fb --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml @@ -0,0 +1,7 @@ +pragma Singleton +import QtQuick 2.0 +import "." + +Item { + property bool ok: Singleton1.ok +} diff --git a/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir new file mode 100644 index 0000000000..71b889a12d --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir @@ -0,0 +1,2 @@ +singleton Singleton1 1.0 Singleton1.qml +singleton Singleton2 1.0 Singleton2.qml diff --git a/tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml b/tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml new file mode 100644 index 0000000000..b80e2c5223 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml @@ -0,0 +1,7 @@ +import QtQml 2.0 +import multisingletonmodule 1.0 +import cppsingletonmodule 1.0 + +QtObject { + property bool ok: Singleton2.ok && CppRegisteredSingleton2.ok +} diff --git a/tests/auto/qml/qqmltypeloader/data/singletonuser.qml b/tests/auto/qml/qqmltypeloader/data/singletonuser.qml new file mode 100644 index 0000000000..79ca47e12f --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/singletonuser.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +import modulewithsingleton 1.0 + +QtObject { + property bool ok: Singleton.ok +} diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index cf3bc8b050..3745fad470 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -31,6 +31,9 @@ #include #include #include +#if QT_CONFIG(process) +#include +#endif #include #include #include "../../shared/testhttpserver.h" @@ -50,6 +53,8 @@ private slots: void keepRegistrations(); void intercept(); void redirect(); + void qmlSingletonWithinModule(); + void multiSingletonModule(); }; void tst_QQMLTypeLoader::testLoadComplete() @@ -428,6 +433,57 @@ void tst_QQMLTypeLoader::redirect() QTRY_COMPARE(object->property("xy").toInt(), 323232); } +void tst_QQMLTypeLoader::qmlSingletonWithinModule() +{ + qmlClearTypeRegistrations(); + QQmlEngine engine; + qmlRegisterSingletonType(testFileUrl("Singleton.qml"), "modulewithsingleton", 1, 0, "Singleton"); + + QQmlComponent component(&engine, testFileUrl("singletonuser.qml")); + QCOMPARE(component.status(), QQmlComponent::Ready); + QScopedPointer obj(component.create()); + QVERIFY(!obj.isNull()); + QVERIFY(obj->property("ok").toBool()); +} + +void tst_QQMLTypeLoader::multiSingletonModule() +{ + qmlClearTypeRegistrations(); + QQmlEngine engine; + engine.addImportPath(testFile("imports")); + + qmlRegisterSingletonType(testFileUrl("CppRegisteredSingleton1.qml"), "cppsingletonmodule", + 1, 0, "CppRegisteredSingleton1"); + qmlRegisterSingletonType(testFileUrl("CppRegisteredSingleton2.qml"), "cppsingletonmodule", + 1, 0, "CppRegisteredSingleton2"); + + QQmlComponent component(&engine, testFileUrl("multisingletonuser.qml")); + QCOMPARE(component.status(), QQmlComponent::Ready); + QScopedPointer obj(component.create()); + QVERIFY(!obj.isNull()); + QVERIFY(obj->property("ok").toBool()); + +#if QT_CONFIG(process) + const char *skipKey = "QT_TST_QQMLTYPELOADER_SKIP_MISMATCH"; + if (qEnvironmentVariableIsSet(skipKey)) + return; + for (int i = 0; i < 5; ++i) { + QProcess child; + child.setProgram(QCoreApplication::applicationFilePath()); + child.setArguments(QStringList(QLatin1String("multiSingletonModule"))); + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert(QLatin1String("QT_LOGGING_RULES"), QLatin1String("qt.qml.diskcache.debug=true")); + env.insert(QLatin1String(skipKey), QLatin1String("1")); + child.setProcessEnvironment(env); + child.start(); + QVERIFY(child.waitForFinished()); + QCOMPARE(child.exitCode(), 0); + QVERIFY(!child.readAllStandardOutput().contains("Checksum mismatch for cached version")); + QVERIFY(!child.readAllStandardError().contains("Checksum mismatch for cached version")); + } +#endif +} + QTEST_MAIN(tst_QQMLTypeLoader) #include "tst_qqmltypeloader.moc" -- cgit v1.2.3