diff options
Diffstat (limited to 'src/imports')
-rw-r--r-- | src/imports/folderlistmodel/fileinfothread_p.h | 2 | ||||
-rw-r--r-- | src/imports/folderlistmodel/fileproperty_p.h | 20 | ||||
-rw-r--r-- | src/imports/folderlistmodel/qquickfolderlistmodel.h | 12 | ||||
-rw-r--r-- | src/imports/layouts/qquickgridlayoutengine_p.h | 6 | ||||
-rw-r--r-- | src/imports/layouts/qquicklinearlayout_p.h | 4 | ||||
-rw-r--r-- | src/imports/localstorage/plugin.cpp | 2 | ||||
-rw-r--r-- | src/imports/settings/qqmlsettings_p.h | 6 | ||||
-rw-r--r-- | src/imports/statemachine/state.h | 4 | ||||
-rw-r--r-- | src/imports/statemachine/statemachine.h | 4 | ||||
-rw-r--r-- | src/imports/statemachine/timeouttransition.h | 4 | ||||
-rw-r--r-- | src/imports/testlib/TestCase.qml | 258 | ||||
-rw-r--r-- | src/imports/testlib/main.cpp | 1 | ||||
-rw-r--r-- | src/imports/testlib/qmldir | 1 | ||||
-rw-r--r-- | src/imports/testlib/toucheventsequence.qdoc | 110 | ||||
-rw-r--r-- | src/imports/xmllistmodel/qqmlxmllistmodel.cpp | 4 | ||||
-rw-r--r-- | src/imports/xmllistmodel/qqmlxmllistmodel_p.h | 14 |
16 files changed, 411 insertions, 41 deletions
diff --git a/src/imports/folderlistmodel/fileinfothread_p.h b/src/imports/folderlistmodel/fileinfothread_p.h index 75da12a421..b505ece750 100644 --- a/src/imports/folderlistmodel/fileinfothread_p.h +++ b/src/imports/folderlistmodel/fileinfothread_p.h @@ -94,7 +94,7 @@ public Q_SLOTS: #endif protected: - void run(); + void run() override; void getFileInfos(const QString &path); void findChangeRange(const QList<FileProperty> &list, int &fromIndex, int &toIndex); diff --git a/src/imports/folderlistmodel/fileproperty_p.h b/src/imports/folderlistmodel/fileproperty_p.h index f385cdfdb4..48be4a3d85 100644 --- a/src/imports/folderlistmodel/fileproperty_p.h +++ b/src/imports/folderlistmodel/fileproperty_p.h @@ -57,17 +57,17 @@ class FileProperty { public: - FileProperty(const QFileInfo &info) + FileProperty(const QFileInfo &info) : + mFileName(info.fileName()), + mFilePath(info.filePath()), + mBaseName(info.baseName()), + mSuffix(info.completeSuffix()), + mSize(info.size()), + mIsDir(info.isDir()), + mIsFile(info.isFile()), + mLastModified(info.lastModified()), + mLastRead(info.lastRead()) { - mFileName = info.fileName(); - mFilePath = info.filePath(); - mBaseName = info.baseName(); - mSize = info.size(); - mSuffix = info.completeSuffix(); - mIsDir = info.isDir(); - mIsFile = info.isFile(); - mLastModified = info.lastModified(); - mLastRead = info.lastRead(); } ~FileProperty() {} diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.h b/src/imports/folderlistmodel/qquickfolderlistmodel.h index aae6df452d..dee73dff3e 100644 --- a/src/imports/folderlistmodel/qquickfolderlistmodel.h +++ b/src/imports/folderlistmodel/qquickfolderlistmodel.h @@ -94,10 +94,10 @@ public: FileUrlRole = Qt::UserRole + 9 }; - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - virtual QHash<int, QByteArray> roleNames() const; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash<int, QByteArray> roleNames() const override; //![abslistmodel] //![count] @@ -144,8 +144,8 @@ public: Q_INVOKABLE int indexOf(const QUrl &file) const; //![parserstatus] - virtual void classBegin(); - virtual void componentComplete(); + void classBegin() override; + void componentComplete() override; //![parserstatus] int roleFromString(const QString &roleName) const; diff --git a/src/imports/layouts/qquickgridlayoutengine_p.h b/src/imports/layouts/qquickgridlayoutengine_p.h index 86f56a5af4..2810e2e5d0 100644 --- a/src/imports/layouts/qquickgridlayoutengine_p.h +++ b/src/imports/layouts/qquickgridlayoutengine_p.h @@ -67,7 +67,7 @@ public: : QGridLayoutItem(row, column, rowSpan, columnSpan, alignment), m_item(item), sizeHintCacheDirty(true), useFallbackToWidthOrHeight(true) {} - QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const override { Q_UNUSED(constraint); // Quick Layouts does not support constraint atm return effectiveSizeHints()[which]; @@ -99,12 +99,12 @@ public: sizeHintCacheDirty = true; } - QLayoutPolicy::Policy sizePolicy(Qt::Orientation orientation) const + QLayoutPolicy::Policy sizePolicy(Qt::Orientation orientation) const override { return QQuickLayout::effectiveSizePolicy_helper(m_item, orientation, attachedLayoutObject(m_item, false)); } - void setGeometry(const QRectF &rect) + void setGeometry(const QRectF &rect) override { QQuickLayoutAttached *info = attachedLayoutObject(m_item, false); const QRectF r = info ? rect.marginsRemoved(info->qMargins()) : rect; diff --git a/src/imports/layouts/qquicklinearlayout_p.h b/src/imports/layouts/qquicklinearlayout_p.h index c289416540..b425df0fa4 100644 --- a/src/imports/layouts/qquicklinearlayout_p.h +++ b/src/imports/layouts/qquicklinearlayout_p.h @@ -157,7 +157,7 @@ public: Flow flow() const; void setFlow(Flow flow); - void insertLayoutItems(); + void insertLayoutItems() override; signals: void columnSpacingChanged(); @@ -199,7 +199,7 @@ public: qreal spacing() const; void setSpacing(qreal spacing); - void insertLayoutItems(); + void insertLayoutItems() override; signals: void spacingChanged(); diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 6704283cb9..d3ea93c80a 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -812,7 +812,7 @@ public: } void registerTypes(const char *uri) Q_DECL_OVERRIDE { - Q_ASSERT(QLatin1String(uri) == "QtQuick.LocalStorage"); + Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.LocalStorage")); qmlRegisterSingletonType<QQuickLocalStorage>(uri, 2, 0, "LocalStorage", module_api_factory); } }; diff --git a/src/imports/settings/qqmlsettings_p.h b/src/imports/settings/qqmlsettings_p.h index 0ed55579dd..ce942d7564 100644 --- a/src/imports/settings/qqmlsettings_p.h +++ b/src/imports/settings/qqmlsettings_p.h @@ -74,10 +74,10 @@ public: void setCategory(const QString &category); protected: - void timerEvent(QTimerEvent *event); + void timerEvent(QTimerEvent *event) override; - void classBegin(); - void componentComplete(); + void classBegin() override; + void componentComplete() override; private: Q_DISABLE_COPY(QQmlSettings) diff --git a/src/imports/statemachine/state.h b/src/imports/statemachine/state.h index 73e4ecda6b..8e8cefab19 100644 --- a/src/imports/statemachine/state.h +++ b/src/imports/statemachine/state.h @@ -58,8 +58,8 @@ class State : public QState, public QQmlParserStatus public: explicit State(QState *parent = 0); - void classBegin() {} - void componentComplete(); + void classBegin() override {} + void componentComplete() override; QQmlListProperty<QObject> children(); diff --git a/src/imports/statemachine/statemachine.h b/src/imports/statemachine/statemachine.h index 59a810f387..cb0ab43f8b 100644 --- a/src/imports/statemachine/statemachine.h +++ b/src/imports/statemachine/statemachine.h @@ -62,8 +62,8 @@ class StateMachine : public QStateMachine, public QQmlParserStatus public: explicit StateMachine(QObject *parent = 0); - void classBegin() {} - void componentComplete(); + void classBegin() override {} + void componentComplete() override; QQmlListProperty<QObject> children(); bool isRunning() const; diff --git a/src/imports/statemachine/timeouttransition.h b/src/imports/statemachine/timeouttransition.h index 5d71e86bb4..0e5f5377e3 100644 --- a/src/imports/statemachine/timeouttransition.h +++ b/src/imports/statemachine/timeouttransition.h @@ -59,8 +59,8 @@ public: int timeout() const; void setTimeout(int timeout); - void classBegin() {} - void componentComplete(); + void classBegin() override {} + void componentComplete() override; Q_SIGNALS: void timeoutChanged(); diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index d22ec7c44f..18c70e1169 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -206,6 +206,59 @@ import Qt.test.qtestroot 1.0 will fail. Use the \l when and windowShown properties to track when the main window has been shown. + \section1 Managing Dynamically Created Test Objects + + A typical pattern with QML tests is to + \l {Dynamic QML Object Creation from JavaScript}{dynamically create} + an item and then destroy it at the end of the test function: + + \code + TestCase { + id: testCase + name: "MyTest" + when: windowShown + + function test_click() { + var item = Qt.createQmlObject("import QtQuick 2.0; Item {}", testCase); + verify(item); + + // Test item... + + item.destroy(); + } + } + \endcode + + The problem with this pattern is that any failures in the test function + will cause the call to \c item.destroy() to be skipped, leaving the item + hanging around in the scene until the test case has finished. This can + result in interference with future tests; for example, by blocking input + events or producing unrelated debug output that makes it difficult to + follow the code's execution. + + By calling \l createTemporaryQmlObject() instead, the object is guaranteed + to be destroyed at the end of the test function: + + \code + TestCase { + id: testCase + name: "MyTest" + when: windowShown + + function test_click() { + var item = createTemporaryQmlObject("import QtQuick 2.0; Item {}", testCase); + verify(item); + + // Test item... + + // Don't need to worry about destroying "item" here. + } + } + \endcode + + For objects that are created via the \l {Component::}{createObject()} function + of \l Component, the \l createTemporaryObject() function can be used. + \sa {QtTest::SignalSpy}{SignalSpy}, {Qt Quick Test Reference Documentation} */ @@ -358,6 +411,8 @@ Item { /*! \internal */ property var qtest_events: qtest_events_normal TestEvent { id: qtest_events_normal } + /*! \internal */ + property var qtest_temporaryObjects: [] /*! \qmlmethod TestCase::fail(message = "") @@ -461,6 +516,105 @@ Item { throw new Error("QtQuickTest::fail") } + /*! + \since 5.9 + \qmlmethod object TestCase::createTemporaryQmlObject(string qml, object parent, string filePath) + + This function dynamically creates a QML object from the given \a qml + string with the specified \a parent. The returned object will be + destroyed (if it was not already) after \l cleanup() has finished + executing, meaning that objects created with this function are + guaranteed to be destroyed after each test, regardless of whether or + not the tests fail. + + If there was an error while creating the object, \c null will be + returned. + + If \a filePath is specified, it will be used for error reporting for + the created object. + + This function calls + \l {QtQml::Qt::createQmlObject()}{Qt.createQmlObject()} internally. + + \sa {Managing Dynamically Created Test Objects} + */ + function createTemporaryQmlObject(qml, parent, filePath) { + if (typeof qml !== "string") { + qtest_results.fail("First argument must be a string of QML; actual type is " + typeof qml, + util.callerFile(), util.callerLine()); + throw new Error("QtQuickTest::fail"); + } + + if (!parent || typeof parent !== "object") { + qtest_results.fail("Second argument must be a valid parent object; actual type is " + typeof parent, + util.callerFile(), util.callerLine()); + throw new Error("QtQuickTest::fail"); + } + + if (filePath !== undefined && typeof filePath !== "string") { + qtest_results.fail("Third argument must be a file path string; actual type is " + typeof filePath, + util.callerFile(), util.callerLine()); + throw new Error("QtQuickTest::fail"); + } + + var object = Qt.createQmlObject(qml, parent, filePath); + qtest_temporaryObjects.push(object); + return object; + } + + /*! + \since 5.9 + \qmlmethod object TestCase::createTemporaryObject(Component component, object parent, object properties) + + This function dynamically creates a QML object from the given + \a component with the specified optional \a parent and \a properties. + The returned object will be destroyed (if it was not already) after + \l cleanup() has finished executing, meaning that objects created with + this function are guaranteed to be destroyed after each test, + regardless of whether or not the tests fail. + + If there was an error while creating the object, \c null will be + returned. + + This function calls + \l {QtQml::Component::createObject()}{component.createObject()} + internally. + + \sa {Managing Dynamically Created Test Objects} + */ + function createTemporaryObject(component, parent, properties) { + if (typeof component !== "object") { + qtest_results.fail("First argument must be a Component; actual type is " + typeof component, + util.callerFile(), util.callerLine()); + throw new Error("QtQuickTest::fail"); + } + + if (properties && typeof properties !== "object") { + qtest_results.fail("Third argument must be an object; actual type is " + typeof properties, + util.callerFile(), util.callerLine()); + throw new Error("QtQuickTest::fail"); + } + + var object = component.createObject(parent, properties ? properties : ({})); + qtest_temporaryObjects.push(object); + return object; + } + + /*! + \internal + + Destroys all temporary objects that still exist. + */ + function qtest_destroyTemporaryObjects() { + for (var i = 0; i < qtest_temporaryObjects.length; ++i) { + var temporaryObject = qtest_temporaryObjects[i]; + // ### the typeof check can be removed when QTBUG-57749 is fixed + if (temporaryObject && typeof temporaryObject.destroy === "function") + temporaryObject.destroy(); + } + qtest_temporaryObjects = []; + } + /*! \internal */ // Determine what is o. // Discussions and reference: http://philrathe.com/articles/equiv @@ -1317,6 +1471,109 @@ Item { qtest_fail("window not shown", 2) } + /*! + \qmlmethod TouchEventSequence TestCase::touchEvent(object item) + + \since 5.9 + + Begins a sequence of touch events through a simulated QTouchDevice::TouchScreen. + Events are delivered to the window containing \a item. + + The returned object is used to enumerate events to be delivered through a single + QTouchEvent. Touches are delivered to the window containing the TestCase unless + otherwise specified. + + \code + Rectangle { + width: 640; height: 480 + + MultiPointTouchArea { + id: area + anchors.fill: parent + + property bool touched: false + + onPressed: touched = true + } + + TestCase { + name: "ItemTests" + when: area.pressed + id: test1 + + function test_touch() { + var touch = touchEvent(area); + touch.press(0, area, 10, 10); + touch.commit(); + verify(area.touched); + } + } + } + \endcode + + \sa TouchEventSequence::press(), TouchEventSequence::move(), TouchEventSequence::release(), TouchEventSequence::stationary(), TouchEventSequence::commit(), QTouchDevice::TouchScreen + */ + + function touchEvent(item) { + if (!item) + qtest_fail("No item given to touchEvent", 1) + + return { + _defaultItem: item, + _sequence: qtest_events.touchEvent(item), + + press: function (id, target, x, y) { + if (!target) + target = this._defaultItem; + if (id === undefined) + qtest_fail("No id given to TouchEventSequence::press", 1); + if (x === undefined) + x = target.width / 2; + if (y === undefined) + y = target.height / 2; + this._sequence.press(id, target, x, y); + return this; + }, + + move: function (id, target, x, y) { + if (!target) + target = this._defaultItem; + if (id === undefined) + qtest_fail("No id given to TouchEventSequence::move", 1); + if (x === undefined) + x = target.width / 2; + if (y === undefined) + y = target.height / 2; + this._sequence.move(id, target, x, y); + return this; + }, + + stationary: function (id) { + if (id === undefined) + qtest_fail("No id given to TouchEventSequence::stationary", 1); + this._sequence.stationary(id); + return this; + }, + + release: function (id, target, x, y) { + if (!target) + target = this._defaultItem; + if (id === undefined) + qtest_fail("No id given to TouchEventSequence::release", 1); + if (x === undefined) + x = target.width / 2; + if (y === undefined) + y = target.height / 2; + this._sequence.release(id, target, x, y); + return this; + }, + + commit: function () { + this._sequence.commit(); + return this; + } + }; + } // Functions that can be overridden in subclasses for init/cleanup duties. /*! @@ -1389,6 +1646,7 @@ Item { qtest_runInternal(prop, arg) qtest_results.finishTestData() qtest_runInternal("cleanup") + qtest_destroyTemporaryObjects() qtest_results.finishTestDataCleanup() // wait(0) will call processEvents() so objects marked for deletion // in the test function will be deleted. diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 4e2bd919e9..3c28000e35 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -158,6 +158,7 @@ public: qmlRegisterType<QuickTestResult, 1>(uri,1,1,"TestResult"); qmlRegisterType<QuickTestEvent>(uri,1,0,"TestEvent"); qmlRegisterType<QuickTestUtil>(uri,1,0,"TestUtil"); + qmlRegisterType<QQuickTouchEventSequence>(); } }; diff --git a/src/imports/testlib/qmldir b/src/imports/testlib/qmldir index 9da8ebb4be..e5757f6a88 100644 --- a/src/imports/testlib/qmldir +++ b/src/imports/testlib/qmldir @@ -3,4 +3,5 @@ plugin qmltestplugin classname QTestQmlModule typeinfo plugins.qmltypes TestCase 1.0 TestCase.qml +TestCase 1.2 TestCase.qml SignalSpy 1.0 SignalSpy.qml diff --git a/src/imports/testlib/toucheventsequence.qdoc b/src/imports/testlib/toucheventsequence.qdoc new file mode 100644 index 0000000000..f85a1cd4f9 --- /dev/null +++ b/src/imports/testlib/toucheventsequence.qdoc @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jeremy Katz +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \qmltype TouchEventSequence + \inqmlmodule QtTest + \ingroup qtquicktest + \brief TouchEventSequence is used to build and dispatch touch events + for testing. + + \since 5.9 + + A TouchEventSequence is created by calling \l [QML] {TestCase::touchEvent()}{TestCase.touchEvent()}. + The type can not be directly instantiated. Each method provided by the type returns + the same object, allowing chained calls. + + For example: + \code + touchEvent(item).press(0).commit(); + \endcode + is equivalent to: + \code + var sequence = touchEvent(item); + sequence.press(0); + sequence.commit(); + \endcode + + Events are delivered to the window which contains the item specified in touchEvent. + + \sa TestCase::touchEvent(), QTest::QTouchEventSequence +*/ + +/*! + \qmlmethod TouchEventSequence TouchEventSequence::press(int touchId, object item, real x = item.width / 2, real y = item.height / 2) + + Creates a new point identified as \a touchId, at the point indicated by \a x and \a y relative to \a item. + Further use of the same touch point should maintain the same touchId. + + Item defaults to the value provided via touchEvent(). + X and y default to the midpoint of the item. +*/ + +/*! + \qmlmethod TouchEventSequence TouchEventSequence::move(int touchId, object item, real x = item.width / 2, real y = item.height / 2) + + Moves \a touchId to the point indicated by \a x and \a y relative to \a item. + + Item defaults to the value provided via touchEvent(). + X and y default to the midpoint of the item. +*/ + +/*! + \qmlmethod TouchEventSequence TouchEventSequence::release(int touchId, object item, real x = item.width / 2, real y = item.height / 2) + + Removes \a touchId at the point indicated by \a x and \a y relative to \a item. + + Item defaults to the value provided via touchEvent(). + X and y default to the midpoint of the item. +*/ + +/*! + \qmlmethod TouchEventSequence TouchEventSequence::stationary(int touchId) + + Indicates that \a touchId is present but otherwise unchanged from prior events. +*/ + +/*! + \qmlmethod TouchEventSequence TouchEventSequence::commit() + + Sends the touch event composed by prior use of press(), move(), release(), and stationary(). + Following commit's return, the TouchEventSequence can be used to compose a new event. + + \code + var sequence = touchEvent(target); + // Touch the middle of target with 1 point + sequence.press(1); + sequence.commit(); + + // Begin a new event + // Move the point to target's upper left corner + sequence.move(1, target, 0, 0); + sequence.commit(); + \endcode + + Commit is automatically invoked when the TouchEventSequence object is destroyed. +*/ diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp index 6e9e57a046..4306f477e9 100644 --- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp +++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp @@ -176,7 +176,7 @@ public: QQuickXmlQueryThreadObject(QQuickXmlQueryEngine *); void processJobs(); - virtual bool event(QEvent *e); + bool event(QEvent *e) override; private: QQuickXmlQueryEngine *m_queryEngine; @@ -202,7 +202,7 @@ signals: void error(void*, const QString&); protected: - void run(); + void run() override; private: void processQuery(XmlQueryJob *job); diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h index f0096a9125..3a4487a085 100644 --- a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h +++ b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h @@ -95,10 +95,10 @@ public: QQuickXmlListModel(QObject *parent = 0); ~QQuickXmlListModel(); - QModelIndex index(int row, int column, const QModelIndex &parent) const; - int rowCount(const QModelIndex &parent) const; - QVariant data(const QModelIndex &index, int role) const; - QHash<int, QByteArray> roleNames() const; + QModelIndex index(int row, int column, const QModelIndex &parent) const override; + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash<int, QByteArray> roleNames() const override; int count() const; @@ -124,8 +124,8 @@ public: Q_INVOKABLE QString errorString() const; - virtual void classBegin(); - virtual void componentComplete(); + void classBegin() override; + void componentComplete() override; Q_SIGNALS: void statusChanged(QQuickXmlListModel::Status); @@ -194,7 +194,7 @@ public: Q_EMIT isKeyChanged(); } - bool isValid() { + bool isValid() const { return !m_name.isEmpty() && !m_query.isEmpty(); } |