Add some component path canonicalization tests
authorChris Adams <christopher.adams@nokia.com>
Thu, 19 Apr 2012 07:30:59 +0000 (17:30 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 23 Apr 2012 00:05:22 +0000 (02:05 +0200)
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 <matthew.vogt@nokia.com>
14 files changed:
tests/auto/qml/qqmlcomponent/data/NestedDirectories/NDTLC.qml [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NDComponentOne.qml [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/NDComponentTwo.qml [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/NestedDirTwo/qmldir [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/NestedDirectories/NestedDirOne/qmldir [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/NestedDirectories/qmldir [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/OtherComponent/OtherComponent.qml [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/OtherComponent/qmldir [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/SpecificComponent/SpecificComponent.qml [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/SpecificComponent/qmldir [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.2.qml [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.3.qml [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/data/componentUrlCanonicalization.qml [new file with mode: 0644]
tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp

diff --git a/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NDTLC.qml b/tests/auto/qml/qqmlcomponent/data/NestedDirectories/NDTLC.qml
new file mode 100644 (file)
index 0000000..b966cb3
--- /dev/null
@@ -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 (file)
index 0000000..2cfcd47
--- /dev/null
@@ -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 (file)
index 0000000..d2df36a
--- /dev/null
@@ -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 (file)
index 0000000..11c6fdd
--- /dev/null
@@ -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 (file)
index 0000000..5ef4d13
--- /dev/null
@@ -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 (file)
index 0000000..adb0fdc
--- /dev/null
@@ -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 (file)
index 0000000..0b6623d
--- /dev/null
@@ -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 (file)
index 0000000..c592dc6
--- /dev/null
@@ -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 (file)
index 0000000..0086737
--- /dev/null
@@ -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 (file)
index 0000000..1f96178
--- /dev/null
@@ -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 (file)
index 0000000..2e2d2de
--- /dev/null
@@ -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 (file)
index 0000000..b520b7d
--- /dev/null
@@ -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 (file)
index 0000000..ad4cbbd
--- /dev/null
@@ -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;
+    }
+}
index 10181aa..eebb558 100644 (file)
@@ -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"