aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/qml/qmlextensionplugins/plugins.qmlproject2
-rw-r--r--examples/qml/qmlextensionplugins/qmlextensionplugins.pro21
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp4
-rw-r--r--src/qml/qml/qqmlengine.cpp4
-rw-r--r--src/qml/qml/qqmltypemodule.cpp8
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp36
-rw-r--r--src/quick/handlers/qquickmultipointhandler_p.h1
-rw-r--r--src/quick/handlers/qquickwheelhandler.cpp9
-rw-r--r--src/quick/items/qquickevents.cpp133
-rw-r--r--src/quick/items/qquickitemsmodule.cpp2
-rw-r--r--tests/auto/qml/qqmlengine/data/evilSingletonInstantiation.qml6
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp31
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp1
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h13
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp24
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/file_request.qml32
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp346
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST1
18 files changed, 578 insertions, 96 deletions
diff --git a/examples/qml/qmlextensionplugins/plugins.qmlproject b/examples/qml/qmlextensionplugins/plugins.qmlproject
index 771ab45b66..c2de5f5703 100644
--- a/examples/qml/qmlextensionplugins/plugins.qmlproject
+++ b/examples/qml/qmlextensionplugins/plugins.qmlproject
@@ -13,4 +13,6 @@ Project {
ImageFiles {
directory: "."
}
+
+ importPaths: [ "imports" ]
}
diff --git a/examples/qml/qmlextensionplugins/qmlextensionplugins.pro b/examples/qml/qmlextensionplugins/qmlextensionplugins.pro
index 40c2b396a3..c074b8d671 100644
--- a/examples/qml/qmlextensionplugins/qmlextensionplugins.pro
+++ b/examples/qml/qmlextensionplugins/qmlextensionplugins.pro
@@ -7,6 +7,7 @@ QML_IMPORT_MAJOR_VERSION = 1
DESTDIR = imports/$$QML_IMPORT_NAME
TARGET = qmlqtimeexampleplugin
+QMLTYPES_FILENAME = $$DESTDIR/plugins.qmltypes
SOURCES += \
plugin.cpp \
@@ -23,14 +24,22 @@ PLUGINFILES = \
imports/$$QML_IMPORT_NAME/hour.png \
imports/$$QML_IMPORT_NAME/minute.png
-pluginfiles.files += $$PLUGINFILES
+target.path = $$[QT_INSTALL_EXAMPLES]/qml/qmlextensionplugins/imports/$$QML_IMPORT_NAME
-qml.files = plugins.qml
-qml.path += $$[QT_INSTALL_EXAMPLES]/qml/qmlextensionplugins
-target.path += $$[QT_INSTALL_EXAMPLES]/qml/qmlextensionplugins/imports/$$QML_IMPORT_NAME
-pluginfiles.path += $$[QT_INSTALL_EXAMPLES]/qml/qmlextensionplugins/imports/$$QML_IMPORT_NAME
+pluginfiles_copy.files = $$PLUGINFILES
+pluginfiles_copy.path = $$DESTDIR
-INSTALLS += target qml pluginfiles
+pluginfiles_install.files = $$PLUGINFILES $$OUT_PWD/$$DESTDIR/plugins.qmltypes
+pluginfiles_install.path = $$[QT_INSTALL_EXAMPLES]/qml/qmlextensionplugins/imports/$$QML_IMPORT_NAME
+
+qml_copy.files = plugins.qml plugins.qmlproject
+qml_copy.path = $$OUT_PWD
+
+qml_install.files = plugins.qml plugins.qmlproject
+qml_install.path = $$[QT_INSTALL_EXAMPLES]/qml/qmlextensionplugins
+
+INSTALLS += target qml_install pluginfiles_install
+COPIES += qml_copy pluginfiles_copy
OTHER_FILES += $$PLUGINFILES plugins.qml
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 82436bcd5d..ee42342bf2 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -304,8 +304,10 @@ public:
return false;
}
- if (d()->isReadOnly)
+ if (d()->isReadOnly) {
+ engine()->throwTypeError(QLatin1String("Cannot insert into a readonly container"));
return false;
+ }
if (d()->isReference) {
if (!d()->object)
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 84f56eb051..6cdb012e26 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -985,8 +985,6 @@ QQmlEngine::~QQmlEngine()
Q_D(QQmlEngine);
QJSEnginePrivate::removeFromDebugServer(this);
- d->typeLoader.invalidate();
-
// Emit onDestruction signals for the root context before
// we destroy the contexts, engine, Singleton Types etc. that
// may be required to handle the destruction signal.
@@ -1002,6 +1000,8 @@ QQmlEngine::~QQmlEngine()
delete d->rootContext;
d->rootContext = nullptr;
+
+ d->typeLoader.invalidate();
}
/*! \fn void QQmlEngine::quit()
diff --git a/src/qml/qml/qqmltypemodule.cpp b/src/qml/qml/qqmltypemodule.cpp
index 9c9bf3e48f..9d6f269030 100644
--- a/src/qml/qml/qqmltypemodule.cpp
+++ b/src/qml/qml/qqmltypemodule.cpp
@@ -97,10 +97,14 @@ void QQmlTypeModule::add(QQmlTypePrivate *type)
QList<QQmlTypePrivate *> &list = d->typeHash[type->elementName];
for (int ii = 0; ii < list.count(); ++ii) {
- Q_ASSERT(list.at(ii));
- if (list.at(ii)->version_min < type->version_min) {
+ QQmlTypePrivate *in_list = list.at(ii);
+ Q_ASSERT(in_list);
+ if (in_list->version_min < type->version_min) {
list.insert(ii, type);
return;
+ } else if (in_list->version_min == type->version_min) {
+ list[ii] = type;
+ return;
}
}
list.append(type);
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index c2e7be73e7..2afbdb616b 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -54,6 +54,7 @@
#include <QtCore/qobject.h>
#include <QtQml/qjsvalue.h>
#include <QtQml/qjsengine.h>
+#include <QtQml/qqmlfile.h>
#include <QtNetwork/qnetworkreply.h>
#include <QtCore/qtextcodec.h>
#include <QtCore/qxmlstream.h>
@@ -77,6 +78,8 @@ using namespace QV4;
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+DEFINE_BOOL_CONFIG_OPTION(xhrFileWrite, QML_XHR_ALLOW_FILE_WRITE);
+DEFINE_BOOL_CONFIG_OPTION(xhrFileRead, QML_XHR_ALLOW_FILE_READ);
struct QQmlXMLHttpRequestData {
QQmlXMLHttpRequestData();
@@ -1195,6 +1198,37 @@ void QQmlXMLHttpRequest::fillHeadersList()
void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
{
QNetworkRequest request = m_request;
+
+ if (QQmlFile::isLocalFile(url)) {
+ if (m_method == QLatin1String("PUT"))
+ {
+ if (!xhrFileWrite()) {
+ if (qEnvironmentVariableIsSet("QML_XHR_ALLOW_FILE_WRITE")) {
+ qWarning("XMLHttpRequest: Tried to use PUT on a local file despite being disabled.");
+ return;
+ } else {
+ qWarning("XMLHttpRequest: Using PUT on a local file is dangerous "
+ "and will be disabled by default in a future Qt version."
+ "Set QML_XHR_ALLOW_FILE_WRITE to 1 if you wish to continue using this feature.");
+ }
+ }
+ } else if (m_method == QLatin1String("GET")) {
+ if (!xhrFileRead()) {
+ if (qEnvironmentVariableIsSet("QML_XHR_ALLOW_FILE_READ")) {
+ qWarning("XMLHttpRequest: Tried to use GET on a local file despite being disabled.");
+ return;
+ } else {
+ qWarning("XMLHttpRequest: Using GET on a local file is dangerous "
+ "and will be disabled by default in a future Qt version."
+ "Set QML_XHR_ALLOW_FILE_READ to 1 if you wish to continue using this feature.");
+ }
+ }
+ } else {
+ qWarning("XMLHttpRequest: Unsupported method used on a local file");
+ return;
+ }
+ }
+
request.setUrl(url);
if(m_method == QLatin1String("POST") ||
m_method == QLatin1String("PUT")) {
@@ -1389,7 +1423,7 @@ void QQmlXMLHttpRequest::finished()
QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (redirect.isValid()) {
QUrl url = m_network->url().resolved(redirect.toUrl());
- if (url.scheme() != QLatin1String("file")) {
+ if (!QQmlFile::isLocalFile(url)) {
// See http://www.ietf.org/rfc/rfc2616.txt, section 10.3.4 "303 See Other":
// Result of 303 redirection should be a new "GET" request.
const QVariant code = m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute);
diff --git a/src/quick/handlers/qquickmultipointhandler_p.h b/src/quick/handlers/qquickmultipointhandler_p.h
index 480f69035b..c0751aa5c5 100644
--- a/src/quick/handlers/qquickmultipointhandler_p.h
+++ b/src/quick/handlers/qquickmultipointhandler_p.h
@@ -81,7 +81,6 @@ public:
signals:
void minimumPointCountChanged();
void maximumPointCountChanged();
- void marginChanged();
void centroidChanged();
protected:
diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp
index aef2e8ebfb..16f38af962 100644
--- a/src/quick/handlers/qquickwheelhandler.cpp
+++ b/src/quick/handlers/qquickwheelhandler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -500,6 +500,13 @@ void QQuickWheelHandler::timerEvent(QTimerEvent *event)
}
}
+/*!
+ \qmlsignal QtQuick::WheelHandler::wheel(PointerScrollEvent event)
+
+ This signal is emitted every time this handler receives a \l QWheelEvent:
+ that is, every time the wheel is moved or the scrolling gesture is updated.
+*/
+
QQuickWheelHandlerPrivate::QQuickWheelHandlerPrivate()
: QQuickSinglePointHandlerPrivate()
{
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 89340dd992..03280e4c1f 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -448,7 +448,7 @@ Item {
*/
/*!
- \qmlproperty int QtQuick::WheelEvent::inverted
+ \qmlproperty bool QtQuick::WheelEvent::inverted
Returns whether the delta values delivered with the event are inverted.
@@ -1431,6 +1431,135 @@ QQuickEventPoint *QQuickSinglePointEvent::point(int i) const
return nullptr;
}
+
+/*!
+ \qmltype PointerScrollEvent
+ \instantiates QQuickPointerScrollEvent
+ \inqmlmodule QtQuick
+ \ingroup qtquick-input-events
+ \brief Provides information about a scrolling event, such as from a mouse wheel.
+
+ \sa WheelHandler
+*/
+
+/*!
+ \internal
+ \class QQuickPointerScrollEvent
+*/
+
+/*!
+ \readonly
+ \qmlproperty PointerDevice QtQuick::PointerScrollEvent::device
+
+ This property holds the device that generated the event.
+*/
+
+/*!
+ \qmlproperty int QtQuick::PointerScrollEvent::buttons
+
+ This property holds the mouse buttons pressed when the wheel event was generated.
+
+ It contains a bitwise combination of:
+ \list
+ \li \l {Qt::LeftButton} {Qt.LeftButton}
+ \li \l {Qt::RightButton} {Qt.RightButton}
+ \li \l {Qt::MiddleButton} {Qt.MiddleButton}
+ \endlist
+*/
+
+/*!
+ \readonly
+ \qmlproperty int QtQuick::PointerScrollEvent::modifiers
+
+ This property holds the \l {Qt::KeyboardModifier}{keyboard modifier} keys
+ that were pressed immediately before the event occurred.
+
+ It contains a bitwise combination of the following flags:
+ \value Qt.NoModifier
+ No modifier key is pressed.
+ \value Qt.ShiftModifier
+ A Shift key on the keyboard is pressed.
+ \value Qt.ControlModifier
+ A Ctrl key on the keyboard is pressed.
+ \value Qt.AltModifier
+ An Alt key on the keyboard is pressed.
+ \value Qt.MetaModifier
+ A Meta key on the keyboard is pressed.
+ \value Qt.KeypadModifier
+ A keypad button is pressed.
+
+ For example, to react to a Shift key + Left mouse button click:
+ \qml
+ Item {
+ TapHandler {
+ onTapped: {
+ if ((event.button == Qt.LeftButton) && (event.modifiers & Qt.ShiftModifier))
+ doSomething();
+ }
+ }
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty point QtQuick::PointerScrollEvent::angleDelta
+
+ This property holds the distance that the wheel is rotated in wheel degrees.
+ The x and y cordinate of this property holds the delta in horizontal and
+ vertical orientation.
+
+ A positive value indicates that the wheel was rotated up/right;
+ a negative value indicates that the wheel was rotated down/left.
+
+ Most mouse types work in steps of 15 degrees, in which case the delta value is a
+ multiple of 120; i.e., 120 units * 1/8 = 15 degrees.
+*/
+
+/*!
+ \qmlproperty point QtQuick::PointerScrollEvent::pixelDelta
+
+ This property holds the delta in screen pixels and is available in platforms that
+ have high-resolution trackpads, such as \macos.
+ The x and y coordinates of this property hold the delta in horizontal and
+ vertical orientation. The value should be used directly to scroll content on screen.
+
+ For platforms without high-resolution touchpad support, pixelDelta will
+ always be (0,0), and angleDelta should be used instead.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PointerScrollEvent::hasAngleDelta
+
+ Returns whether the \l angleDelta property has a non-null value.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PointerScrollEvent::hasPixelDelta
+
+ Returns whether the \l pixelDelta property has a non-null value.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PointerScrollEvent::inverted
+
+ Returns whether the delta values delivered with the event are inverted.
+
+ Normally, a vertical wheel will produce a PointerScrollEvent with positive delta
+ values if the top of the wheel is rotating away from the hand operating it.
+ Similarly, a horizontal wheel movement will produce a PointerScrollEvent with
+ positive delta values if the top of the wheel is moved to the left.
+
+ However, on some platforms this is configurable, so that the same
+ operations described above will produce negative delta values (but with the
+ same magnitude). In a QML component (such as a tumbler or a slider) where
+ it is appropriate to synchronize the movement or rotation of an item with
+ the direction of the wheel, regardless of the system settings, the wheel
+ event handler can use the inverted property to decide whether to negate the
+ \l angleDelta or \l pixelDelta values.
+
+ \note Many platforms provide no such information. On such platforms,
+ \c inverted always returns false.
+*/
QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event)
{
m_event = static_cast<QInputEvent*>(event);
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index f9b0a61b81..bd6b9d741e 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
diff --git a/tests/auto/qml/qqmlengine/data/evilSingletonInstantiation.qml b/tests/auto/qml/qqmlengine/data/evilSingletonInstantiation.qml
new file mode 100644
index 0000000000..757b0c90bb
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/evilSingletonInstantiation.qml
@@ -0,0 +1,6 @@
+import QtQml 2.12
+import foo.foo 1.0
+
+QtObject {
+ objectName: Singleton.objectName
+}
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 2a3b945509..d782df3e7f 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -83,6 +83,7 @@ private slots:
void singletonInstance();
void aggressiveGc();
void cachedGetterLookup_qtbug_75335();
+ void createComponentOnSingletonDestruction();
public slots:
QObject *createAQObjectForOwnershipTest ()
@@ -1144,6 +1145,36 @@ void tst_qqmlengine::cachedGetterLookup_qtbug_75335()
QVERIFY(object != nullptr);
}
+class EvilSingleton : public QObject
+{
+ Q_OBJECT
+public:
+ QPointer<QQmlEngine> m_engine;
+ EvilSingleton(QQmlEngine *engine) : m_engine(engine) {
+ connect(this, &QObject::destroyed, this, [this]() {
+ QQmlComponent component(m_engine);
+ component.setData("import QtQml 2.0\nQtObject {}", QUrl("file://Stuff.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj);
+ });
+ }
+};
+
+void tst_qqmlengine::createComponentOnSingletonDestruction()
+{
+ qmlRegisterSingletonType<EvilSingleton>("foo.foo", 1, 0, "Singleton",
+ [](QQmlEngine *engine, QJSEngine *) {
+ return new EvilSingleton(engine);
+ });
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("evilSingletonInstantiation.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj);
+}
+
QTEST_MAIN(tst_qqmlengine)
#include "tst_qqmlengine.moc"
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index 462745eb93..0ddb1b1491 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -120,6 +120,7 @@ void registerTypes()
qmlRegisterType<DeferredProperties>("Test", 1, 0, "DeferredProperties");
qmlRegisterTypesAndRevisions<Extended, Foreign, ForeignExtended>("Test", 1);
+ qmlRegisterTypesAndRevisions<BareSingleton>("Test", 1);
}
QVariant myCustomVariantTypeConverter(const QString &data)
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index bfbd3e66f5..a7410e190b 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -1455,6 +1455,19 @@ class ForeignExtended
QML_EXTENDED(Extension)
};
+class BareSingleton : public QObject
+{
+ Q_OBJECT
+ QML_SINGLETON
+ QML_ELEMENT
+
+public:
+ BareSingleton(QObject *parent = nullptr) : QObject(parent)
+ {
+ setObjectName("statically registered");
+ }
+};
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index fca398d7b2..7b4662a5cd 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -310,6 +310,7 @@ private slots:
void selfReferencingSingleton();
void listContainingDeletedObject();
+ void overrideSingleton();
private:
QQmlEngine engine;
@@ -5375,6 +5376,29 @@ void tst_qqmllanguage::listContainingDeletedObject()
}
+void tst_qqmllanguage::overrideSingleton()
+{
+ auto check = [](const QString &name) {
+ const QByteArray testQml = "import Test 1.0\n"
+ "import QtQml 2.0\n"
+ "QtObject { objectName: BareSingleton.objectName }";
+ QQmlEngine engine;
+ QQmlComponent component(&engine, nullptr);
+ component.setData(testQml, QUrl());
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QCOMPARE(obj->objectName(), name);
+ };
+
+ check("statically registered");
+
+ BareSingleton singleton;
+ singleton.setObjectName("dynamically registered");
+ qmlRegisterSingletonInstance("Test", 1, 0, "BareSingleton", &singleton);
+
+ check("dynamically registered");
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/file_request.qml b/tests/auto/qml/qqmlxmlhttprequest/data/file_request.qml
new file mode 100644
index 0000000000..51020c185e
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/file_request.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.0
+
+QtObject {
+ // Inputs
+
+ id: root
+
+ property string writeURL
+ property string readURL
+ // Outputs
+ property bool writeDone: false
+ property variant readResult
+
+ Component.onCompleted: {
+ // PUT
+ var xhrWrite = new XMLHttpRequest;
+ xhrWrite.open("PUT", writeURL);
+ xhrWrite.onreadystatechange = function() {
+ if (xhrWrite.readyState === XMLHttpRequest.DONE)
+ writeDone = true;
+ };
+ xhrWrite.send("Test-String");
+ // GET
+ var xhrRead = new XMLHttpRequest;
+ xhrRead.open("GET", readURL);
+ xhrRead.onreadystatechange = function() {
+ if (xhrRead.readyState === XMLHttpRequest.DONE)
+ readResult = xhrRead.responseText;
+ };
+ xhrRead.send();
+ }
+}
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 6cf80ccfdb..ae794e76a9 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -35,6 +35,13 @@
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
+#include <QTemporaryFile>
+
+#if QT_CONFIG(process)
+#include <QProcess>
+#include <QProcessEnvironment>
+#endif
+
#include "testhttpserver.h"
#include "../../shared/util.h"
@@ -45,6 +52,8 @@ public:
tst_qqmlxmlhttprequest() {}
private slots:
+ void initTestCase();
+
void domExceptionCodes();
void callbackException();
void callbackException_data();
@@ -97,6 +106,14 @@ private slots:
void nonUtf8();
void nonUtf8_data();
+ void sendFileRequest();
+
+#if QT_CONFIG(process)
+ void sendFileRequestNotSet();
+ void sendFileRequestNoWrite();
+ void sendFileRequestNoRead();
+#endif
+
// WebDAV
void sendPropfind();
void sendPropfind_data();
@@ -119,13 +136,27 @@ private slots:
void stateChangeCallingContext();
private:
- QQmlEngine engine;
+ void doFileRequest(std::function<void(QObject *component, QTemporaryFile &writeFile)> verifyFunction);
+
+ QScopedPointer<QQmlEngine> engine;
};
+void tst_qqmlxmlhttprequest::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+
+ if (!qEnvironmentVariableIsSet("TEST_CUSTOM_PERMISSIONS")) {
+ qputenv("QML_XHR_ALLOW_FILE_READ", "1");
+ qputenv("QML_XHR_ALLOW_FILE_WRITE", "1");
+ }
+
+ engine.reset(new QQmlEngine);
+}
+
// Test that the dom exception codes are correct
void tst_qqmlxmlhttprequest::domExceptionCodes()
{
- QQmlComponent component(&engine, testFileUrl("domExceptionCodes.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("domExceptionCodes.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -168,8 +199,8 @@ void tst_qqmlxmlhttprequest::callbackException()
QString expect = testFileUrl("callbackException.qml").toString() + ":"+QString::number(line)+": Error: Exception from Callback";
QTest::ignoreMessage(QtWarningMsg, expect.toLatin1());
- QQmlComponent component(&engine, testFileUrl("callbackException.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("callbackException.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
object->setProperty("which", which);
@@ -182,7 +213,7 @@ void tst_qqmlxmlhttprequest::callbackException()
// ### WebKit does not do this, but it seems to fit the standard and QML better
void tst_qqmlxmlhttprequest::staticStateValues()
{
- QQmlComponent component(&engine, testFileUrl("staticStateValues.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("staticStateValues.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -196,7 +227,7 @@ void tst_qqmlxmlhttprequest::staticStateValues()
// Test that the state value properties on instances have the correct values.
void tst_qqmlxmlhttprequest::instanceStateValues()
{
- QQmlComponent component(&engine, testFileUrl("instanceStateValues.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("instanceStateValues.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -210,7 +241,7 @@ void tst_qqmlxmlhttprequest::instanceStateValues()
// Test calling constructor
void tst_qqmlxmlhttprequest::constructor()
{
- QQmlComponent component(&engine, testFileUrl("constructor.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("constructor.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -221,7 +252,7 @@ void tst_qqmlxmlhttprequest::constructor()
// Test that all the properties are set correctly before any request is sent
void tst_qqmlxmlhttprequest::defaultState()
{
- QQmlComponent component(&engine, testFileUrl("defaultState.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("defaultState.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -248,8 +279,8 @@ void tst_qqmlxmlhttprequest::open()
url = server.urlString(url);
}
- QQmlComponent component(&engine, qmlFile);
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), qmlFile);
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", url);
component.completeCreate();
@@ -281,7 +312,7 @@ void tst_qqmlxmlhttprequest::open_data()
// Test that calling XMLHttpRequest.open() with an invalid method raises an exception
void tst_qqmlxmlhttprequest::open_invalid_method()
{
- QQmlComponent component(&engine, testFileUrl("open_invalid_method.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("open_invalid_method.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -330,8 +361,8 @@ void tst_qqmlxmlhttprequest::open_sync()
{
TestThreadedHTTPServer server(testFileUrl("open_network.expect"), testFileUrl("open_network.reply"), testFileUrl("testdocument.html"));
- QQmlComponent component(&engine, testFileUrl("open_sync.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("open_sync.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.serverBaseUrl.resolved(QStringLiteral("/testdocument.html")).toString());
component.completeCreate();
@@ -343,7 +374,7 @@ void tst_qqmlxmlhttprequest::open_sync()
void tst_qqmlxmlhttprequest::open_arg_count()
{
{
- QQmlComponent component(&engine, testFileUrl("open_arg_count.1.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("open_arg_count.1.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -351,7 +382,7 @@ void tst_qqmlxmlhttprequest::open_arg_count()
}
{
- QQmlComponent component(&engine, testFileUrl("open_arg_count.2.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("open_arg_count.2.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -368,8 +399,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader()
testFileUrl("setRequestHeader.reply"),
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl("setRequestHeader.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("setRequestHeader.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/testdocument.html"));
component.completeCreate();
@@ -386,8 +417,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_caseInsensitive()
testFileUrl("setRequestHeader.reply"),
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl("setRequestHeader_caseInsensitive.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("setRequestHeader_caseInsensitive.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/testdocument.html"));
component.completeCreate();
@@ -397,7 +428,7 @@ void tst_qqmlxmlhttprequest::setRequestHeader_caseInsensitive()
// Test setting headers before open() throws exception
void tst_qqmlxmlhttprequest::setRequestHeader_unsent()
{
- QQmlComponent component(&engine, testFileUrl("setRequestHeader_unsent.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("setRequestHeader_unsent.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -443,8 +474,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName()
testFileUrl("open_network.reply"),
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl("setRequestHeader_illegalName.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("setRequestHeader_illegalName.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/testdocument.html"));
object->setProperty("header", name);
@@ -469,8 +500,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_sent()
testFileUrl("open_network.reply"),
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl("setRequestHeader_sent.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("setRequestHeader_sent.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/testdocument.html"));
component.completeCreate();
@@ -483,7 +514,7 @@ void tst_qqmlxmlhttprequest::setRequestHeader_sent()
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::setRequestHeader_args()
{
- QQmlComponent component(&engine, testFileUrl("setRequestHeader_args.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("setRequestHeader_args.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -493,7 +524,7 @@ void tst_qqmlxmlhttprequest::setRequestHeader_args()
// Test that calling send() in UNSENT state throws an exception
void tst_qqmlxmlhttprequest::send_unsent()
{
- QQmlComponent component(&engine, testFileUrl("send_unsent.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("send_unsent.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -503,7 +534,7 @@ void tst_qqmlxmlhttprequest::send_unsent()
// Test attempting to resend a sent request throws an exception
void tst_qqmlxmlhttprequest::send_alreadySent()
{
- QQmlComponent component(&engine, testFileUrl("send_alreadySent.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("send_alreadySent.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -521,8 +552,8 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
testFileUrl("send_ignoreData.reply"),
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("send_ignoreData.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("reqType", "GET");
object->setProperty("url", server.urlString("/testdocument.html"));
@@ -538,8 +569,8 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
testFileUrl("send_ignoreData.reply"),
QUrl()));
- QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("send_ignoreData.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("reqType", "HEAD");
object->setProperty("url", server.urlString("/testdocument.html"));
@@ -555,8 +586,8 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
testFileUrl("send_ignoreData.reply"),
QUrl()));
- QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("send_ignoreData.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("reqType", "DELETE");
object->setProperty("url", server.urlString("/testdocument.html"));
@@ -578,8 +609,8 @@ void tst_qqmlxmlhttprequest::send_withdata()
testFileUrl("send_data.reply"),
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl(file_qml));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl(file_qml));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/testdocument.html"));
component.completeCreate();
@@ -615,8 +646,8 @@ void tst_qqmlxmlhttprequest::send_options()
testFileUrl(file_reply),
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl(file_qml));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl(file_qml));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
QString url = server.baseUrl().toString();
if (url_suffix != "/")
@@ -652,8 +683,8 @@ void tst_qqmlxmlhttprequest::send_patch()
// the content of response file will be ignored due to 204 status code
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl("send_patch.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("send_patch.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/qqmlxmlhttprequest.cpp"));
component.completeCreate();
@@ -666,8 +697,8 @@ void tst_qqmlxmlhttprequest::send_patch()
// Test abort() has no effect in unsent state
void tst_qqmlxmlhttprequest::abort_unsent()
{
- QQmlComponent component(&engine, testFileUrl("abort_unsent.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("abort_unsent.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
component.completeCreate();
@@ -685,8 +716,8 @@ void tst_qqmlxmlhttprequest::abort_unsent()
// Test abort() cancels an open (but unsent) request
void tst_qqmlxmlhttprequest::abort_opened()
{
- QQmlComponent component(&engine, testFileUrl("abort_opened.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("abort_opened.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
component.completeCreate();
@@ -710,8 +741,8 @@ void tst_qqmlxmlhttprequest::abort()
testFileUrl("abort.reply"),
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl("abort.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("abort.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
const QUrl url = server.url("/testdocument.html");
QUrl dummyUrl = url;
@@ -767,7 +798,7 @@ void tst_qqmlxmlhttprequest::getResponseHeader()
// Test getResponseHeader throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getResponseHeader_unsent()
{
- QQmlComponent component(&engine, testFileUrl("getResponseHeader_unsent.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("getResponseHeader_unsent.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -777,7 +808,7 @@ void tst_qqmlxmlhttprequest::getResponseHeader_unsent()
// Test getResponseHeader throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getResponseHeader_sent()
{
- QQmlComponent component(&engine, testFileUrl("getResponseHeader_sent.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("getResponseHeader_sent.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -787,7 +818,7 @@ void tst_qqmlxmlhttprequest::getResponseHeader_sent()
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::getResponseHeader_args()
{
- QQmlComponent component(&engine, testFileUrl("getResponseHeader_args.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("getResponseHeader_args.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -827,7 +858,7 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders()
// Test getAllResponseHeaders throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getAllResponseHeaders_unsent()
{
- QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_unsent.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("getAllResponseHeaders_unsent.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -837,7 +868,7 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders_unsent()
// Test getAllResponseHeaders throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getAllResponseHeaders_sent()
{
- QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_sent.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("getAllResponseHeaders_sent.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -847,7 +878,7 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders_sent()
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::getAllResponseHeaders_args()
{
- QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_args.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("getAllResponseHeaders_args.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -862,8 +893,8 @@ void tst_qqmlxmlhttprequest::getBinaryData()
testFileUrl("receive_binary_data.reply"),
testFileUrl("qml_logo.png")));
- QQmlComponent component(&engine, testFileUrl("receiveBinaryData.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("receiveBinaryData.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/gml_logo.png"));
component.completeCreate();
@@ -881,8 +912,8 @@ void tst_qqmlxmlhttprequest::getJsonData()
testFileUrl("receive_binary_data.reply"),
testFileUrl("json.data")));
- QQmlComponent component(&engine, testFileUrl("receiveJsonData.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("receiveJsonData.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/json.data"));
component.completeCreate();
@@ -901,8 +932,8 @@ void tst_qqmlxmlhttprequest::status()
replyUrl,
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl("status.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("status.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/testdocument.html"));
object->setProperty("expectedStatus", status);
@@ -943,8 +974,8 @@ void tst_qqmlxmlhttprequest::statusText()
replyUrl,
testFileUrl("testdocument.html")));
- QQmlComponent component(&engine, testFileUrl("statusText.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("statusText.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/testdocument.html"));
object->setProperty("expectedStatus", statusText);
@@ -983,8 +1014,8 @@ void tst_qqmlxmlhttprequest::responseText()
replyUrl,
bodyUrl));
- QQmlComponent component(&engine, testFileUrl("responseText.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("responseText.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/testdocument.html"));
object->setProperty("expectedText", responseText);
@@ -1020,7 +1051,7 @@ void tst_qqmlxmlhttprequest::nonUtf8()
QFETCH(QString, responseText);
QFETCH(QString, xmlRootNodeValue);
- QQmlComponent component(&engine, testFileUrl("utf16.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("utf16.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -1053,6 +1084,163 @@ void tst_qqmlxmlhttprequest::nonUtf8_data()
QTest::newRow("responseXML") << "utf16.xml" << "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone='yes'?>\n<root>\n" + uc + "\n</root>\n" << QString('\n' + uc + '\n');
}
+static const QString testString = QStringLiteral("Test-String");
+
+void tst_qqmlxmlhttprequest::doFileRequest(std::function<void(QObject *component, QTemporaryFile &writeFile)> verifyFunction)
+{
+ // Create test files
+ QTemporaryFile writeFile;
+ QTemporaryFile readFile;
+
+ writeFile.open();
+ writeFile.close();
+
+ QVERIFY(readFile.open());
+ readFile.write(testString.toUtf8());
+ readFile.close();
+
+ // Avoid cached environment variables
+ QQmlEngine engine;
+
+ QQmlComponent component(&engine, testFileUrl("file_request.qml"));
+
+ const QVariantMap properties = {
+ {"writeURL", QUrl::fromLocalFile(writeFile.fileName()).toString()},
+ {"readURL", QUrl::fromLocalFile(readFile.fileName()).toString()}
+ };
+
+ QScopedPointer<QObject> object(component.createWithInitialProperties(properties, engine.rootContext()));
+ QVERIFY(!object.isNull());
+
+ verifyFunction(object.get(), writeFile);
+}
+
+// Test file:// requests
+void tst_qqmlxmlhttprequest::sendFileRequest()
+{
+ // Test with both writing and reading allowed
+ doFileRequest([](QObject* object, QTemporaryFile &writeFile) {
+ QTRY_COMPARE(object->property("readResult").toString(), testString);
+
+ QTRY_VERIFY(object->property("writeDone").toBool());
+
+ QVERIFY(writeFile.open());
+ QCOMPARE(QString::fromUtf8(writeFile.readAll()), testString);
+ writeFile.close();
+ });
+}
+
+#if QT_CONFIG(process)
+void tst_qqmlxmlhttprequest::sendFileRequestNotSet() {
+ if (qEnvironmentVariableIsSet("TEST_CUSTOM_PERMISSIONS")) {
+ // Test with no settings
+ // Should just result in warnings in Qt 5
+ doFileRequest([](QObject* object, QTemporaryFile &writeFile) {
+ QTRY_COMPARE(object->property("readResult").toString(), testString);
+
+ QTRY_VERIFY(object->property("writeDone").toBool());
+
+ QVERIFY(writeFile.open());
+ QCOMPARE(QString::fromUtf8(writeFile.readAll()), testString);
+ writeFile.close();
+ });
+ return;
+ }
+
+ QProcess child;
+ child.setProgram(QCoreApplication::applicationFilePath());
+ child.setArguments(QStringList(QLatin1String("sendFileRequestNotSet")));
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert(QLatin1String("TEST_CUSTOM_PERMISSIONS"), QLatin1String("1"));
+ env.remove("QML_XHR_ALLOW_FILE_WRITE");
+ env.remove("QML_XHR_ALLOW_FILE_READ");
+ child.setProcessEnvironment(env);
+ child.start();
+ QVERIFY(child.waitForFinished());
+
+ // Check exit code
+ QCOMPARE(child.exitCode(), 0);
+
+ // Check if all warnings were printed
+ QString output = QString::fromUtf8(child.readAllStandardOutput());
+
+
+ const QString readingWarning = QLatin1String(
+ "XMLHttpRequest: Using GET on a local file is dangerous "
+ "and will be disabled by default in a future Qt version."
+ "Set QML_XHR_ALLOW_FILE_READ to 1 if you wish to continue using this feature.");
+
+ const QString writingWarning = QLatin1String(
+ "XMLHttpRequest: Using PUT on a local file is dangerous "
+ "and will be disabled by default in a future Qt version."
+ "Set QML_XHR_ALLOW_FILE_WRITE to 1 if you wish to continue using this feature.");
+
+ QVERIFY(output.contains(readingWarning));
+ QVERIFY(output.contains(writingWarning));
+}
+#endif
+
+#if QT_CONFIG(process)
+void tst_qqmlxmlhttprequest::sendFileRequestNoWrite() {
+ if (qEnvironmentVariableIsSet("TEST_CUSTOM_PERMISSIONS")) {
+ // Test with no writing enabled
+ doFileRequest([](QObject* object, QTemporaryFile &writeFile) {
+ QTRY_COMPARE(object->property("readResult").toString(), testString);
+
+ // Check that the file stays empty
+ QVERIFY(writeFile.open());
+ QCOMPARE(QString::fromUtf8(writeFile.readAll()), "");
+ writeFile.close();
+ });
+ return;
+ }
+
+ QProcess child;
+ child.setProgram(QCoreApplication::applicationFilePath());
+ child.setArguments(QStringList(QLatin1String("sendFileRequestNoWrite")));
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert(QLatin1String("TEST_CUSTOM_PERMISSIONS"), QLatin1String("1"));
+ env.insert(QLatin1String("QML_XHR_ALLOW_FILE_WRITE"), QLatin1String("0"));
+ env.insert(QLatin1String("QML_XHR_ALLOW_FILE_READ"), QLatin1String("1"));
+ child.setProcessEnvironment(env);
+ child.start();
+ QVERIFY(child.waitForFinished());
+ QCOMPARE(child.exitCode(), 0);
+}
+#endif
+
+#if QT_CONFIG(process)
+void tst_qqmlxmlhttprequest::sendFileRequestNoRead() {
+ if (qEnvironmentVariableIsSet("TEST_CUSTOM_PERMISSIONS")) {
+ // Test with no reading enabled
+ doFileRequest([](QObject* object, QTemporaryFile &writeFile) {
+ // Check that the write happens
+ QTRY_VERIFY(object->property("writeDone").toBool());
+
+ QVERIFY(writeFile.open());
+ QCOMPARE(QString::fromUtf8(writeFile.readAll()), testString);
+ writeFile.close();
+
+ // Verify that the read has not yielded any value
+ QVERIFY(object->property("readResult").isNull());
+ });
+ return;
+ }
+
+ QProcess child;
+ child.setProgram(QCoreApplication::applicationFilePath());
+ child.setArguments(QStringList(QLatin1String("sendFileRequestNoRead")));
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert(QLatin1String("TEST_CUSTOM_PERMISSIONS"), QLatin1String("1"));
+ env.insert(QLatin1String("QML_XHR_ALLOW_FILE_WRITE"), QLatin1String("1"));
+ env.insert(QLatin1String("QML_XHR_ALLOW_FILE_READ"), QLatin1String("0"));
+ child.setProcessEnvironment(env);
+ child.start();
+ QVERIFY(child.waitForFinished());
+ QCOMPARE(child.exitCode(), 0);
+}
+#endif
+
void tst_qqmlxmlhttprequest::sendPropfind()
{
const QString prefix = "WebDAV//";
@@ -1070,8 +1258,8 @@ void tst_qqmlxmlhttprequest::sendPropfind()
testFileUrl(prefix + replyHeader),
testFileUrl(prefix + replyBody)));
- QQmlComponent component(&engine, testFileUrl(prefix + qml));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl(prefix + qml));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString(resource));
component.completeCreate();
@@ -1097,7 +1285,7 @@ void tst_qqmlxmlhttprequest::sendPropfind_data()
// throws an exception
void tst_qqmlxmlhttprequest::invalidMethodUsage()
{
- QQmlComponent component(&engine, testFileUrl("invalidMethodUsage.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("invalidMethodUsage.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -1124,8 +1312,8 @@ void tst_qqmlxmlhttprequest::redirects()
server.addRedirect("redirect.html", server.urlString("/redirecttarget.html"));
server.serveDirectory(dataDirectory());
- QQmlComponent component(&engine, testFileUrl("redirects.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("redirects.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/redirect.html"));
object->setProperty("expectedText", "");
@@ -1141,8 +1329,8 @@ void tst_qqmlxmlhttprequest::redirects()
server.addRedirect("redirect.html", server.urlString("/redirectmissing.html"));
server.serveDirectory(dataDirectory());
- QQmlComponent component(&engine, testFileUrl("redirectError.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("redirectError.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/redirect.html"));
object->setProperty("expectedText", "");
@@ -1158,8 +1346,8 @@ void tst_qqmlxmlhttprequest::redirects()
server.addRedirect("redirect.html", server.urlString("/redirect.html"));
server.serveDirectory(dataDirectory());
- QQmlComponent component(&engine, testFileUrl("redirectRecur.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("redirectRecur.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("url", server.urlString("/redirect.html"));
object->setProperty("expectedText", "");
@@ -1177,7 +1365,7 @@ void tst_qqmlxmlhttprequest::redirects()
void tst_qqmlxmlhttprequest::responseXML_invalid()
{
- QQmlComponent component(&engine, testFileUrl("responseXML_invalid.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("responseXML_invalid.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -1189,7 +1377,7 @@ void tst_qqmlxmlhttprequest::responseXML_invalid()
// Test the Document DOM element
void tst_qqmlxmlhttprequest::document()
{
- QQmlComponent component(&engine, testFileUrl("document.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("document.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -1201,7 +1389,7 @@ void tst_qqmlxmlhttprequest::document()
// Test the Element DOM element
void tst_qqmlxmlhttprequest::element()
{
- QQmlComponent component(&engine, testFileUrl("element.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("element.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -1213,7 +1401,7 @@ void tst_qqmlxmlhttprequest::element()
// Test the Attr DOM element
void tst_qqmlxmlhttprequest::attr()
{
- QQmlComponent component(&engine, testFileUrl("attr.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("attr.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -1225,7 +1413,7 @@ void tst_qqmlxmlhttprequest::attr()
// Test the Text DOM element
void tst_qqmlxmlhttprequest::text()
{
- QQmlComponent component(&engine, testFileUrl("text.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("text.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -1238,7 +1426,7 @@ void tst_qqmlxmlhttprequest::text()
// Test the CDataSection DOM element
void tst_qqmlxmlhttprequest::cdata()
{
- QQmlComponent component(&engine, testFileUrl("cdata.qml"));
+ QQmlComponent component(engine.get(), testFileUrl("cdata.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -1285,8 +1473,8 @@ void tst_qqmlxmlhttprequest::stateChangeCallingContext()
QVERIFY2(server.listen(), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
- QQmlComponent component(&engine, testFileUrl("stateChangeCallingContext.qml"));
- QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QQmlComponent component(engine.get(), testFileUrl("stateChangeCallingContext.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.get()->rootContext()));
QVERIFY(!object.isNull());
object->setProperty("serverBaseUrl", server.baseUrl().toString());
component.completeCreate();
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST
index 20f989fc50..92903955ac 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST
@@ -1,5 +1,6 @@
[touchAndDragHandlerOnFlickable]
windows gcc
+opensuse-leap
[touchDragFlickableBehindSlider]
windows gcc
[touchDragFlickableBehindButton]