aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorChris Adams <christopher.adams@nokia.com>2012-04-23 16:37:05 +1000
committerQt by Nokia <qt-info@nokia.com>2012-07-02 09:43:36 +0200
commitfdeee38b781376012c4f086276c3c376726c8839 (patch)
treee35e5f02ec00a1750854bb81c7e4d5d85a4dd8ae /tests
parent4c02780738241d784849f423944a8a4852022967 (diff)
Fix crash in QQmlXmlHttpRequest
If an onreadystatechange handler of a QQmlXmlHttpRequest uses code which requires the engine->callingContext() to be valid, a crash could previously occur (since the callingContext() would be null if the handler was called due to a network request finishing. This commit saves the calling context on send, so that on dispatch we can create an activation scope from that context and use it. Note that even in this case, if the original context had previously been deleted (e.g., by a loader deleting the item context on source change) the saved context could be invalid by the time the dispatch function was invoked. In that case, we simply do nothing as the function call cannot succeed (invalid context). Change-Id: Iba357829a69433c11cc279e6cc9fdc0bedaa31fb Reviewed-by: Yunqiao Yin <charles.yin@nokia.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/TestComponent.qml23
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/TestComponent2.qml7
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/TestComponent3.qml6
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml59
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/testlist3
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp20
6 files changed, 117 insertions, 1 deletions
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/TestComponent.qml b/tests/auto/qml/qqmlxmlhttprequest/data/TestComponent.qml
new file mode 100644
index 0000000000..c4ecbd8912
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/TestComponent.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int a: 4
+
+ Component.onCompleted: {
+ root.parent.finished();
+ triggerXmlHttpRequest();
+ }
+
+ function triggerXmlHttpRequest() {
+ var doc = new XMLHttpRequest();
+ doc.onreadystatechange = function() {
+ if (doc.readyState == XMLHttpRequest.DONE) {
+ var seqComponent = doc.responseText;
+ var o = Qt.createQmlObject(seqComponent,root);
+ }
+ }
+ doc.open("GET", "http://127.0.0.1:14445/TestComponent3.qml");
+ doc.send();
+ }
+}
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/TestComponent2.qml b/tests/auto/qml/qqmlxmlhttprequest/data/TestComponent2.qml
new file mode 100644
index 0000000000..f27a980f42
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/TestComponent2.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int a: 5
+ Component.onCompleted: root.parent.finished()
+}
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/TestComponent3.qml b/tests/auto/qml/qqmlxmlhttprequest/data/TestComponent3.qml
new file mode 100644
index 0000000000..763ec6de20
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/TestComponent3.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int a: 3
+}
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml b/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml
new file mode 100644
index 0000000000..1f679d829a
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ property int whichCount: 0
+ property bool success: false
+
+ SequentialAnimation {
+ id: anim
+ PauseAnimation { duration: 525 } // delay mode is 500 msec.
+ ScriptAction { script: loadcomponent(0) }
+ PauseAnimation { duration: 525 } // delay mode is 500 msec.
+ ScriptAction { script: loadcomponent(1) }
+ PauseAnimation { duration: 525 } // delay mode is 500 msec.
+ ScriptAction { script: if (whichCount == 2) root.success = true; else console.log("failed to load testlist"); }
+ }
+
+ Component.onCompleted: {
+ updateList();
+ anim.start();
+ }
+
+ function updateList() {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET","http://127.0.0.1:14445/testlist"); // list of components
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState == XMLHttpRequest.DONE) {
+ var components = xhr.responseText.split('\n');
+ var i;
+ for (i=0; i<components.length; i++) {
+ if (components[i].split(";").length == 2) {
+ componentlist.append({"Name" : components[i].split(";")[0], "url" : components[i].split(";")[1]})
+ }
+ }
+ }
+ }
+ xhr.send()
+ }
+
+ function loadcomponent(which) {
+ if (componentlist.count > which) {
+ loader.source = componentlist.get(which).url;
+ whichCount += 1;
+ }
+ }
+
+ Loader {
+ id: loader
+ signal finished
+
+ anchors.fill: parent
+ onStatusChanged: {
+ if (status == Loader.Error) { finished(); next(); }
+ }
+ }
+
+ ListModel { id: componentlist }
+}
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/testlist b/tests/auto/qml/qqmlxmlhttprequest/data/testlist
new file mode 100644
index 0000000000..cd9dd14511
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/testlist
@@ -0,0 +1,3 @@
+One;TestComponent.qml
+Two;TestComponent2.qml
+Three;TestComponent3.qml
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 7a65308b6e..8f57594e5b 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -117,6 +117,8 @@ private slots:
// void network_errors()
// void readyState()
+ void stateChangeCallingContext();
+
private:
QQmlEngine engine;
};
@@ -165,7 +167,7 @@ void tst_qqmlxmlhttprequest::callbackException()
QFETCH(QString, which);
QFETCH(int, line);
-
+
QString expect = testFileUrl("callbackException.qml").toString() + ":"+QString::number(line)+": Error: Exception from Callback";
QTest::ignoreMessage(QtWarningMsg, expect.toLatin1());
@@ -1155,6 +1157,22 @@ void tst_qqmlxmlhttprequest::cdata()
delete object;
}
+void tst_qqmlxmlhttprequest::stateChangeCallingContext()
+{
+ // ensure that we don't crash by attempting to evaluate
+ // without a valid calling context.
+
+ TestHTTPServer server(SERVER_PORT);
+ QVERIFY(server.isValid());
+ server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
+
+ QQmlComponent component(&engine, testFileUrl("stateChangeCallingContext.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QTRY_VERIFY(object->property("success").toBool() == true);
+ delete object;
+}
+
QTEST_MAIN(tst_qqmlxmlhttprequest)
#include "tst_qqmlxmlhttprequest.moc"