From 6d2ed5d0b645f5af383a123e869d061b235b4b85 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Thu, 19 Apr 2012 17:30:59 +1000 Subject: [PATCH] Add some component path canonicalization tests Previously, no unit test existed to ensure that url canonicalization worked correctly, which could result in two import statements using relative paths to the same actual component triggering two separate types being generated. This commit adds a unit test with various relative-addressing and both static and dynamic imports, to enforce type-consistency. Change-Id: I7772e3c531069322d5fa44063cbf57a758ed3710 Reviewed-by: Matthew Vogt --- .../qqmlcomponent/data/NestedDirectories/NDTLC.qml | 23 +++++++++ .../NestedDirOne/NDComponentOne.qml | 9 +++ .../NestedDirOne/NestedDirTwo/NDComponentTwo.qml | 6 ++ .../NestedDirOne/NestedDirTwo/qmldir | 1 + .../data/NestedDirectories/NestedDirOne/qmldir | 1 + .../qqmlcomponent/data/NestedDirectories/qmldir | 1 + .../data/OtherComponent/OtherComponent.qml | 6 ++ .../qml/qqmlcomponent/data/OtherComponent/qmldir | 1 + .../data/SpecificComponent/SpecificComponent.qml | 7 +++ .../qqmlcomponent/data/SpecificComponent/qmldir | 1 + .../data/componentUrlCanonicalization.2.qml | 24 +++++++++ .../data/componentUrlCanonicalization.3.qml | 53 ++++++++++++++++++++ .../data/componentUrlCanonicalization.qml | 31 +++++++++++ tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp | 37 ++++++++++++++ 14 files changed, 201 insertions(+), 0 deletions(-) create mode 100644 tests/auto/qml/qqmlcomponent/data/NestedDirectories/NDTLC.qml create mode 100644 tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NDComponentOne.qml create mode 100644 tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/NDComponentTwo.qml create mode 100644 tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/qmldir create mode 100644 tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/qmldir create mode 100644 tests/auto/qml/qqmlcomponent/data/NestedDirectories/qmldir create mode 100644 tests/auto/qml/qqmlcomponent/data/OtherComponent/OtherComponent.qml create mode 100644 tests/auto/qml/qqmlcomponent/data/OtherComponent/qmldir create mode 100644 tests/auto/qml/qqmlcomponent/data/SpecificComponent/SpecificComponent.qml create mode 100644 tests/auto/qml/qqmlcomponent/data/SpecificComponent/qmldir create mode 100644 tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.2.qml create mode 100644 tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.3.qml create mode 100644 tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.qml diff --git a/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NDTLC.qml b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NDTLC.qml new file mode 100644 index 0000000..b966cb3 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NDTLC.qml @@ -0,0 +1,23 @@ +import QtQuick 2.0 +import "NestedDirOne" +import "NestedDirOne/NestedDirTwo/../../../SpecificComponent" + +// NestedDirectoriesTopLevelComponent + +Item { + id: ndtlcId + property NDComponentOne a: NDComponentOne { } + property NDComponentOne b: NDComponentOne { } + property SpecificComponent scOne: SpecificComponent { } + property SpecificComponent scTwo + + function assignScTwo() { + // It seems that doing this in onCompleted doesn't work, + // since that handler will be evaluated after the + // componentUrlCanonicalization.3.qml onCompleted handler. + // So, call this function manually.... + var c1 = Qt.createComponent("NestedDirOne/NestedDirTwo/NDComponentTwo.qml"); + var o1 = c1.createObject(ndtlcId); + scTwo = o1.sc; + } +} diff --git a/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NDComponentOne.qml b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NDComponentOne.qml new file mode 100644 index 0000000..2cfcd47 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NDComponentOne.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 +import "../../SpecificComponent" +import "NestedDirTwo" + +Item { + property int a + property NDComponentTwo b: NDComponentTwo { } + property SpecificComponent sc: SpecificComponent { } +} diff --git a/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/NDComponentTwo.qml b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/NDComponentTwo.qml new file mode 100644 index 0000000..d2df36a --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/NDComponentTwo.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 +import "../../../SpecificComponent" + +Item { + property SpecificComponent sc: SpecificComponent { } +} diff --git a/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/qmldir b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/qmldir new file mode 100644 index 0000000..11c6fdd --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/qmldir @@ -0,0 +1 @@ +NDComponentTwo 1.0 NDComponentTwo.qml diff --git a/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/qmldir b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/qmldir new file mode 100644 index 0000000..5ef4d13 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/qmldir @@ -0,0 +1 @@ +NDComponentOne 1.0 NDComponentOne.qml diff --git a/tests/auto/qml/qqmlcomponent/data/NestedDirectories/qmldir b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/qmldir new file mode 100644 index 0000000..adb0fdc --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/qmldir @@ -0,0 +1 @@ +NDTLC 1.0 NDTLC.qml diff --git a/tests/auto/qml/qqmlcomponent/data/OtherComponent/OtherComponent.qml b/tests/auto/qml/qqmlcomponent/data/OtherComponent/OtherComponent.qml new file mode 100644 index 0000000..0b6623d --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/OtherComponent/OtherComponent.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 +import "../SpecificComponent" + +Item { + property SpecificComponent sc: SpecificComponent { } +} diff --git a/tests/auto/qml/qqmlcomponent/data/OtherComponent/qmldir b/tests/auto/qml/qqmlcomponent/data/OtherComponent/qmldir new file mode 100644 index 0000000..c592dc6 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/OtherComponent/qmldir @@ -0,0 +1 @@ +OtherComponent 1.0 OtherComponent.qml diff --git a/tests/auto/qml/qqmlcomponent/data/SpecificComponent/SpecificComponent.qml b/tests/auto/qml/qqmlcomponent/data/SpecificComponent/SpecificComponent.qml new file mode 100644 index 0000000..0086737 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/SpecificComponent/SpecificComponent.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Item { + // ensure we have a dynamic meta object + property int someInt: 5 + property var someVar: 12 +} diff --git a/tests/auto/qml/qqmlcomponent/data/SpecificComponent/qmldir b/tests/auto/qml/qqmlcomponent/data/SpecificComponent/qmldir new file mode 100644 index 0000000..1f96178 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/SpecificComponent/qmldir @@ -0,0 +1 @@ +SpecificComponent 1.0 SpecificComponent.qml diff --git a/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.2.qml b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.2.qml new file mode 100644 index 0000000..2e2d2de --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.2.qml @@ -0,0 +1,24 @@ +import QtQuick 2.0 +import "SpecificComponent" + +Item { + id: root + property SpecificComponent first + property SpecificComponent second + + property bool success: false + + Component.onCompleted: { + var c1 = Qt.createComponent("./SpecificComponent/SpecificComponent.qml"); + var o1 = c1.createObject(root); + first = o1; + + var c2 = Qt.createComponent("./OtherComponent/OtherComponent.qml"); + var o2 = c2.createObject(root); + second = o2.sc; + + var ft = first.toString().substr(0, first.toString().indexOf('(')); + var st = second.toString().substr(0, second.toString().indexOf('(')); + if (ft == st) success = true; + } +} diff --git a/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.3.qml b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.3.qml new file mode 100644 index 0000000..b520b7d --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.3.qml @@ -0,0 +1,53 @@ +import QtQuick 2.0 +import "SpecificComponent" +import "OtherComponent" +import "NestedDirectories" + +Item { + id: root + + property SpecificComponent scOne + property SpecificComponent scTwo + property SpecificComponent scThree + property SpecificComponent scFour + property SpecificComponent scFive + property SpecificComponent scSix + property SpecificComponent scSeven + property SpecificComponent scEight + + property OtherComponent ocOne: OtherComponent { } + property NDTLC ndtlc: NDTLC { } + + property bool success: false + + Component.onCompleted: { + var c1 = Qt.createComponent("./SpecificComponent/SpecificComponent.qml"); + var o1 = c1.createObject(root); + scOne = o1; + scTwo = ocOne.sc; + scThree = ndtlc.a.sc; + scFour = ndtlc.b.sc; + scFive = ndtlc.a.b.sc; + scSix = ndtlc.b.b.sc; + scSeven = ndtlc.scOne; + ndtlc.assignScTwo(); // XXX should be able to do this in NDTLC.onCompleted handler?! + scEight = ndtlc.scTwo; + + // in our case, the type string should be: + // SpecificComponent_QMLTYPE_0 + var t1 = scOne.toString().substr(0, scOne.toString().indexOf('(')); + var t2 = scTwo.toString().substr(0, scTwo.toString().indexOf('(')); + var t3 = scThree.toString().substr(0, scThree.toString().indexOf('(')); + var t4 = scFour.toString().substr(0, scFour.toString().indexOf('(')); + var t5 = scFive.toString().substr(0, scFive.toString().indexOf('(')); + var t6 = scSix.toString().substr(0, scSix.toString().indexOf('(')); + var t7 = scSeven.toString().substr(0, scSeven.toString().indexOf('(')); + var t8 = scEight.toString().substr(0, scEight.toString().indexOf('(')); + + if (t1 == t2 && t2 == t3 && t3 == t4 && t4 == t5 && t5 == t6 && t6 == t7 && t7 == t8) { + success = true; + } else { + success = false; + } + } +} diff --git a/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.qml b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.qml new file mode 100644 index 0000000..ad4cbbd --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.qml @@ -0,0 +1,31 @@ +import QtQuick 2.0 +import "SpecificComponent" +import "OtherComponent" + +Item { + id: root + property SpecificComponent first + property SpecificComponent second + property OtherComponent oc: OtherComponent { } + + property bool success: false + + Component.onCompleted: { + var c1 = Qt.createComponent("./SpecificComponent/SpecificComponent.qml"); + var o1 = c1.createObject(root); + first = o1; + second = oc.sc; + + // We want to ensure that the types are the same, ie, that the + // component hasn't been registered twice due to failed + // canonicalization of the component path when importing. + // The type is reported in the toString() output prior to the + // instance pointer value. + + // in our case, the type string should be: + // SpecificComponent_QMLTYPE_0 + var ft = first.toString().substr(0, first.toString().indexOf('(')); + var st = second.toString().substr(0, second.toString().indexOf('(')); + if (ft == st) success = true; + } +} diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 10181aa..eebb558 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -111,6 +111,7 @@ private slots: void qmlCreateParentReference(); void async(); void asyncHierarchy(); + void componentUrlCanonicalization(); private: QQmlEngine engine; @@ -314,6 +315,42 @@ void tst_qqmlcomponent::asyncHierarchy() delete root; } +void tst_qqmlcomponent::componentUrlCanonicalization() +{ + // ensure that url canonicalization succeeds so that type information + // is not generated multiple times for the same component. + { + // load components via import + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QVERIFY(object->property("success").toBool()); + delete object; + } + + { + // load one of the components dynamically, which would trigger + // import of the other if it were not already loaded. + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.2.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QVERIFY(object->property("success").toBool()); + delete object; + } + + { + // load components with more deeply nested imports + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.3.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QVERIFY(object->property("success").toBool()); + delete object; + } +} + QTEST_MAIN(tst_qqmlcomponent) #include "tst_qqmlcomponent.moc" -- 1.7.2.5