aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2017-09-21 14:53:44 +0200
committerUlf Hermann <ulf.hermann@qt.io>2017-11-22 08:43:04 +0000
commitc9a6f55659bc054f835aa682a521425f8fa2bf07 (patch)
tree45b9dbc65b92bdb66edeff5533f63d6498ca1df5 /tests/auto/qml
parentd710a3a5b7a0b120d84674dc328418930b87b774 (diff)
Fix URL interception for qmldir files
We need to intercept the URL when it is created. This relieves us of the need to hack around in it when actually retrieving the content of the qmldir file and prevents the futile attempt to load remote qmldir files via the code path that should load local ones (or vice versa). The back and forth conversion between URLs and strings is unfortunate, but can only be solved by using QUrl rather than QString where we actually mean URL. This would be a bigger change which is unsuitable for 5.9. Mind that nothing changes for code that doesn't use URL interceptors. Task-number: QTBUG-36773 Change-Id: I6bff3ae352009fdc0a17ec209691c7b390367f11 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'tests/auto/qml')
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Intercept.qml41
-rw-r--r--tests/auto/qml/qqmltypeloader/data/test_intercept.qml53
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp168
3 files changed, 262 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmltypeloader/data/Intercept.qml b/tests/auto/qml/qqmltypeloader/data/Intercept.qml
new file mode 100644
index 0000000000..b557b4b941
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Intercept.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import Fast 1.0
+
+Item {
+ Rectangle {
+ color: "red"
+ width: 100
+ height: 100
+ }
+ Fast {
+
+ }
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/test_intercept.qml b/tests/auto/qml/qqmltypeloader/data/test_intercept.qml
new file mode 100644
index 0000000000..091fbe7f49
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/test_intercept.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+ListView {
+ width: 400
+ height: 500
+ model: 2
+
+ id: test
+ property int created: 0
+ property int loaded: 0
+
+ delegate: Loader {
+ width: ListView.view.width
+ height: 100
+ asynchronous: true
+ source: "Intercept.qml"
+
+ onLoaded: {
+ test.loaded++
+ }
+ Component.onCompleted: {
+ test.created++
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index 68b450ab26..12aeff7591 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -28,6 +28,7 @@
#include <QtTest/QtTest>
#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
#include <QtQml/private/qqmlengine_p.h>
@@ -45,6 +46,7 @@ private slots:
void trimCache2();
void keepSingleton();
void keepRegistrations();
+ void intercept();
};
void tst_QQMLTypeLoader::testLoadComplete()
@@ -192,6 +194,172 @@ void tst_QQMLTypeLoader::keepRegistrations()
verifyTypes(true, false); // qmlRegisterType creates an undeletable type.
}
+class NetworkReply : public QNetworkReply
+{
+public:
+ NetworkReply()
+ {
+ open(QIODevice::ReadOnly);
+ }
+
+ void setData(const QByteArray &data)
+ {
+ if (isFinished())
+ return;
+ m_buffer = data;
+ emit readyRead();
+ setFinished(true);
+ emit finished();
+ }
+
+ void fail()
+ {
+ if (isFinished())
+ return;
+ m_buffer.clear();
+ setError(ContentNotFoundError, "content not found");
+ emit error(ContentNotFoundError);
+ setFinished(true);
+ emit finished();
+ }
+
+ qint64 bytesAvailable() const override
+ {
+ return m_buffer.size();
+ }
+
+ qint64 readData(char *data, qint64 maxlen) override
+ {
+ if (m_buffer.length() < maxlen)
+ maxlen = m_buffer.length();
+ std::memcpy(data, m_buffer.data(), maxlen);
+ m_buffer.remove(0, maxlen);
+ return maxlen;
+ }
+
+ void abort() override
+ {
+ if (isFinished())
+ return;
+ m_buffer.clear();
+ setFinished(true);
+ emit finished();
+ }
+
+private:
+ QByteArray m_buffer;
+};
+
+class NetworkAccessManager : public QNetworkAccessManager
+{
+ Q_OBJECT
+public:
+
+ NetworkAccessManager(QObject *parent) : QNetworkAccessManager(parent)
+ {
+ }
+
+ QNetworkReply *createRequest(Operation op, const QNetworkRequest &request,
+ QIODevice *outgoingData) override
+ {
+ QUrl url = request.url();
+ QString scheme = url.scheme();
+ if (op != GetOperation || !scheme.endsWith("+debug"))
+ return QNetworkAccessManager::createRequest(op, request, outgoingData);
+
+ scheme.chop(sizeof("+debug") - 1);
+ url.setScheme(scheme);
+
+ NetworkReply *reply = new NetworkReply;
+ QString filename = QQmlFile::urlToLocalFileOrQrc(url);
+ QTimer::singleShot(10, reply, [this, reply, filename]() {
+ if (filename.isEmpty()) {
+ reply->fail();
+ } else {
+ QFile file(filename);
+ if (file.open(QIODevice::ReadOnly)) {
+ emit loaded(filename);
+ reply->setData(file.readAll());
+ } else
+ reply->fail();
+ }
+ });
+ return reply;
+ }
+
+signals:
+ void loaded(const QString &filename);
+};
+
+class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory
+{
+public:
+ QStringList loadedFiles;
+
+ QNetworkAccessManager *create(QObject *parent) override
+ {
+ NetworkAccessManager *manager = new NetworkAccessManager(parent);
+ QObject::connect(manager, &NetworkAccessManager::loaded, [this](const QString &filename) {
+ loadedFiles.append(filename);
+ });
+ return manager;
+ }
+};
+
+class UrlInterceptor : public QQmlAbstractUrlInterceptor
+{
+public:
+ QUrl intercept(const QUrl &path, DataType type) override
+ {
+ Q_UNUSED(type);
+ if (!QQmlFile::isLocalFile(path))
+ return path;
+
+ // Don't rewrite internal Qt paths. We'd hit C++ plugins there.
+ QString filename = QQmlFile::urlToLocalFileOrQrc(path);
+ if (filename.startsWith(":/qt-project.org/")
+ || filename.startsWith(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath))) {
+ return path;
+ }
+
+ QUrl result = path;
+ QString scheme = result.scheme();
+ if (!scheme.endsWith("+debug"))
+ result.setScheme(scheme + "+debug");
+ return result;
+ }
+};
+
+void tst_QQMLTypeLoader::intercept()
+{
+ QQmlEngine engine;
+ engine.addImportPath(dataDirectory());
+
+ UrlInterceptor interceptor;
+ NetworkAccessManagerFactory factory;
+
+ engine.setUrlInterceptor(&interceptor);
+ engine.setNetworkAccessManagerFactory(&factory);
+
+ QQmlComponent component(&engine, testFileUrl("test_intercept.qml"));
+
+ QVERIFY(component.status() != QQmlComponent::Ready);
+ QTRY_VERIFY2(component.status() == QQmlComponent::Ready,
+ component.errorString().toUtf8().constData());
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o.data());
+
+ QTRY_COMPARE(o->property("created").toInt(), 2);
+ QTRY_COMPARE(o->property("loaded").toInt(), 2);
+
+ QCOMPARE(factory.loadedFiles.length(), 4);
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/test_intercept.qml"));
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Intercept.qml"));
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Fast/qmldir"));
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Fast/Fast.qml"));
+}
+
QTEST_MAIN(tst_QQMLTypeLoader)
#include "tst_qqmltypeloader.moc"