diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-01-04 18:45:18 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2021-01-12 20:58:41 +0100 |
commit | 843be43f18ecb007a0bb5fbb9034b8643a28b196 (patch) | |
tree | 107ee060136fdbf717cf9ca94f5e1deffd106901 /src/qmltest | |
parent | 06ab8d790dfab32472bcc20736c7486bf43beeba (diff) |
Merge the QtTest and Qt.test.qtestroot QML modules
There is no point in having them separate and this way the plugin can be
optional.
Fixes: QTBUG-89804
Change-Id: Ic7de35f6ee7abde4840841e17d21c2b709f6db7d
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Diffstat (limited to 'src/qmltest')
-rw-r--r-- | src/qmltest/.prev_CMakeLists.txt | 20 | ||||
-rw-r--r-- | src/qmltest/CMakeLists.txt | 32 | ||||
-rw-r--r-- | src/qmltest/qmldir | 2 | ||||
-rw-r--r-- | src/qmltest/qmltest.pro | 12 | ||||
-rw-r--r-- | src/qmltest/quicktest.cpp | 12 | ||||
-rw-r--r-- | src/qmltest/quicktest_p.h | 22 | ||||
-rw-r--r-- | src/qmltest/quicktestevent.cpp | 481 | ||||
-rw-r--r-- | src/qmltest/quicktestevent_p.h | 134 | ||||
-rw-r--r-- | src/qmltest/quicktestglobal_p.h | 61 | ||||
-rw-r--r-- | src/qmltest/quicktestresult_p.h | 7 | ||||
-rw-r--r-- | src/qmltest/quicktestutil.cpp | 113 | ||||
-rw-r--r-- | src/qmltest/quicktestutil_p.h | 89 |
12 files changed, 918 insertions, 67 deletions
diff --git a/src/qmltest/.prev_CMakeLists.txt b/src/qmltest/.prev_CMakeLists.txt index f121d217ff..556bd0e5db 100644 --- a/src/qmltest/.prev_CMakeLists.txt +++ b/src/qmltest/.prev_CMakeLists.txt @@ -33,11 +33,9 @@ qt_internal_add_module(QuickTest #### Keys ignored in scope 1:.:.:qmltest.pro:<TRUE>: # MODULE_CONFIG = "$${QT.testlib.CONFIG}" # QMLTYPES_FILENAME = "plugins.qmltypes" -# QMLTYPES_INSTALL_DIR = "$$[QT_INSTALL_QML]/Qt/test/qtestroot" -# QML_IMPORT_NAME = "Qt.test.qtestroot" -# QML_IMPORT_VERSION = "1.0" -# qmldir.files = "$$PWD/qmldir" -# qmldir.path = "$$QMLTYPES_INSTALL_DIR" +# QMLTYPES_INSTALL_DIR = "$$[QT_INSTALL_QML]/QtTest" +# QML_IMPORT_NAME = "QtTest" +# QML_IMPORT_VERSION = "$$QT_VERSION" ## Scopes: ##################################################################### @@ -53,12 +51,6 @@ qt_internal_extend_target(QuickTest CONDITION QT_FEATURE_qml_debug DEFINES QT_QML_DEBUG_NO_WARNING ) - -#### Keys ignored in scope 4:.:.:qmltest.pro:prefix_build: -# INSTALLS = "qmldir" - -#### Keys ignored in scope 5:.:.:qmltest.pro:else: -# COPIES = "qmldir" qt_internal_add_docs(QuickTest doc/qtqmltest.qdocconf ) @@ -66,10 +58,10 @@ qt_internal_add_docs(QuickTest set_target_properties(QuickTest PROPERTIES QT_QML_MODULE_INSTALL_QMLTYPES TRUE - QT_QML_MODULE_VERSION 1.0 - QT_QML_MODULE_URI Qt.test.qtestroot + QT_QML_MODULE_VERSION ${CMAKE_PROJECT_VERSION} + QT_QML_MODULE_URI QtTest QT_QMLTYPES_FILENAME plugins.qmltypes - QT_QML_MODULE_INSTALL_DIR "${INSTALL_QMLDIR}/Qt/test/qtestroot" + QT_QML_MODULE_INSTALL_DIR "${INSTALL_QMLDIR}/QtTest" ) qt6_qml_type_registration(QuickTest) diff --git a/src/qmltest/CMakeLists.txt b/src/qmltest/CMakeLists.txt index 92ff99765d..dd8139af9d 100644 --- a/src/qmltest/CMakeLists.txt +++ b/src/qmltest/CMakeLists.txt @@ -11,8 +11,10 @@ qt_internal_add_module(QuickTest SOURCES qtestoptions_p.h quicktest.cpp quicktest.h quicktest_p.h - quicktestglobal.h + quicktestevent.cpp quicktestevent_p.h + quicktestglobal.h quicktestglobal_p.h quicktestresult.cpp quicktestresult_p.h + quicktestutil.cpp quicktestutil_p.h DEFINES QT_NO_FOREACH QT_NO_URL_CAST_FROM_STRING @@ -34,11 +36,9 @@ qt_internal_add_module(QuickTest #### Keys ignored in scope 1:.:.:qmltest.pro:<TRUE>: # MODULE_CONFIG = "$${QT.testlib.CONFIG}" # QMLTYPES_FILENAME = "plugins.qmltypes" -# QMLTYPES_INSTALL_DIR = "$$[QT_INSTALL_QML]/Qt/test/qtestroot" -# QML_IMPORT_NAME = "Qt.test.qtestroot" -# QML_IMPORT_VERSION = "1.0" -# qmldir.files = "$$PWD/qmldir" -# qmldir.path = "$$QMLTYPES_INSTALL_DIR" +# QMLTYPES_INSTALL_DIR = "$$[QT_INSTALL_QML]/QtTest" +# QML_IMPORT_NAME = "QtTest" +# QML_IMPORT_VERSION = "$$QT_VERSION" ## Scopes: ##################################################################### @@ -54,12 +54,6 @@ qt_internal_extend_target(QuickTest CONDITION QT_FEATURE_qml_debug DEFINES QT_QML_DEBUG_NO_WARNING ) - -#### Keys ignored in scope 4:.:.:qmltest.pro:prefix_build: -# INSTALLS = "qmldir" - -#### Keys ignored in scope 5:.:.:qmltest.pro:else: -# COPIES = "qmldir" qt_internal_add_docs(QuickTest doc/qtqmltest.qdocconf ) @@ -67,18 +61,10 @@ qt_internal_add_docs(QuickTest set_target_properties(QuickTest PROPERTIES QT_QML_MODULE_INSTALL_QMLTYPES TRUE - QT_QML_MODULE_VERSION 1.0 - QT_QML_MODULE_URI Qt.test.qtestroot + QT_QML_MODULE_VERSION ${CMAKE_PROJECT_VERSION} + QT_QML_MODULE_URI QtTest QT_QMLTYPES_FILENAME plugins.qmltypes - QT_QML_MODULE_INSTALL_DIR "${INSTALL_QMLDIR}/Qt/test/qtestroot" + QT_QML_MODULE_INSTALL_DIR "${INSTALL_QMLDIR}/QtTest" ) qt6_qml_type_registration(QuickTest) - -#special case begin -if (QT_WILL_INSTALL) - install(FILES qmldir DESTINATION "${INSTALL_QMLDIR}/Qt/test/qtestroot") -else() - file(COPY qmldir DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/Qt/test/qtestroot") -endif() -#special case end diff --git a/src/qmltest/qmldir b/src/qmltest/qmldir deleted file mode 100644 index 5e9d5e2c95..0000000000 --- a/src/qmltest/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -module Qt.test.qtestroot -typeinfo plugins.qmltypes diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro index c2e8068fc6..2f26448707 100644 --- a/src/qmltest/qmltest.pro +++ b/src/qmltest/qmltest.pro @@ -31,14 +31,8 @@ qtConfig(qml-debug): DEFINES += QT_QML_DEBUG_NO_WARNING load(qt_module) QMLTYPES_FILENAME = plugins.qmltypes -QMLTYPES_INSTALL_DIR = $$[QT_INSTALL_QML]/Qt/test/qtestroot -QML_IMPORT_NAME = Qt.test.qtestroot -QML_IMPORT_VERSION = 1.0 +QMLTYPES_INSTALL_DIR = $$[QT_INSTALL_QML]/QtTest +QML_IMPORT_NAME = QtTest +QML_IMPORT_VERSION = $$QT_VERSION CONFIG += qmltypes install_qmltypes install_metatypes -# Install qmldir -qmldir.files = $$PWD/qmldir -qmldir.path = $$QMLTYPES_INSTALL_DIR - -prefix_build: INSTALLS += qmldir -else: COPIES += qmldir diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index 5962af8569..9085f96337 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -133,13 +133,6 @@ bool QQuickTest::qWaitForItemPolished(const QQuickItem *item, int timeout) return QTest::qWaitFor([&]() { return !QQuickItemPrivate::get(item)->polishScheduled; }, timeout); } -static QObject *testRootObject(QQmlEngine *engine, QJSEngine *jsEngine) -{ - Q_UNUSED(engine); - Q_UNUSED(jsEngine); - return QTestRootObject::instance(); -} - static inline QString stripQuotes(const QString &s) { if (s.length() >= 2 && s.startsWith(QLatin1Char('"')) && s.endsWith(QLatin1Char('"'))) @@ -534,9 +527,6 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch qputenv("QT_QTESTLIB_RUNNING", "1"); - // Register the custom factory function - qmlRegisterSingletonType<QTestRootObject>("Qt.test.qtestroot", 1, 0, "QTestRootObject", testRootObject); - QSet<QString> commandLineTestFunctions(QTest::testFunctions.cbegin(), QTest::testFunctions.cend()); const bool filteringTestFunctions = !commandLineTestFunctions.isEmpty(); @@ -594,7 +584,7 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch QObject::connect(view.engine(), SIGNAL(quit()), &eventLoop, SLOT(quit())); view.rootContext()->setContextProperty - (QLatin1String("qtest"), QTestRootObject::instance()); // Deprecated. Use QTestRootObject from Qt.test.qtestroot instead + (QLatin1String("qtest"), QTestRootObject::instance()); // Deprecated. Use QTestRootObject from QtTest instead view.setObjectName(fi.baseName()); view.setTitle(view.objectName()); diff --git a/src/qmltest/quicktest_p.h b/src/qmltest/quicktest_p.h index 50fc3be050..88f56d3038 100644 --- a/src/qmltest/quicktest_p.h +++ b/src/qmltest/quicktest_p.h @@ -64,16 +64,18 @@ class QTestRootObject : public QObject Q_PROPERTY(bool windowShown READ windowShown NOTIFY windowShownChanged) Q_PROPERTY(bool hasTestCase READ hasTestCase WRITE setHasTestCase NOTIFY hasTestCaseChanged) Q_PROPERTY(QObject *defined READ defined) + QML_SINGLETON QML_ELEMENT + QML_ADDED_IN_VERSION(1, 0) public: - QTestRootObject(QObject *parent = nullptr) - : QObject(parent), hasQuit(false), m_windowShown(false), m_hasTestCase(false) { - m_defined = new QQmlPropertyMap(this); -#if defined(QT_OPENGL_ES_2_ANGLE) - m_defined->insert(QLatin1String("QT_OPENGL_ES_2_ANGLE"), QVariant(true)); -#endif + static QTestRootObject *create(QQmlEngine *q, QJSEngine *) + { + QTestRootObject *result = instance(); + QQmlEngine *engine = qmlEngine(result); + // You can only test on one engine at a time + return (engine == nullptr || engine == q) ? result : nullptr; } static QTestRootObject *instance() { @@ -103,6 +105,14 @@ private Q_SLOTS: void quit() { hasQuit = true; } private: + QTestRootObject(QObject *parent = nullptr) + : QObject(parent), hasQuit(false), m_windowShown(false), m_hasTestCase(false) { + m_defined = new QQmlPropertyMap(this); +#if defined(QT_OPENGL_ES_2_ANGLE) + m_defined->insert(QLatin1String("QT_OPENGL_ES_2_ANGLE"), QVariant(true)); +#endif + } + bool m_windowShown : 1; bool m_hasTestCase :1; QQmlPropertyMap *m_defined; diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp new file mode 100644 index 0000000000..a1a707d2d6 --- /dev/null +++ b/src/qmltest/quicktestevent.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "quicktestevent_p.h" +#include <QtTest/qtestkeyboard.h> +#include <QtQml/qqml.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickwindow.h> +#include <qpa/qwindowsysteminterface.h> + +QT_BEGIN_NAMESPACE + +namespace QTest { + extern int Q_TESTLIB_EXPORT defaultMouseDelay(); +} + +QuickTestEvent::QuickTestEvent(QObject *parent) + : QObject(parent) +{ +} + +QuickTestEvent::~QuickTestEvent() +{ +} + +int QuickTestEvent::defaultMouseDelay() const +{ + return QTest::defaultMouseDelay(); +} + +bool QuickTestEvent::keyPress(int key, int modifiers, int delay) +{ + QWindow *window = activeWindow(); + if (!window) + return false; + QTest::keyPress(window, Qt::Key(key), Qt::KeyboardModifiers(modifiers), delay); + return true; +} + +bool QuickTestEvent::keyRelease(int key, int modifiers, int delay) +{ + QWindow *window = activeWindow(); + if (!window) + return false; + QTest::keyRelease(window, Qt::Key(key), Qt::KeyboardModifiers(modifiers), delay); + return true; +} + +bool QuickTestEvent::keyClick(int key, int modifiers, int delay) +{ + QWindow *window = activeWindow(); + if (!window) + return false; + QTest::keyClick(window, Qt::Key(key), Qt::KeyboardModifiers(modifiers), delay); + return true; +} + +bool QuickTestEvent::keyPressChar(const QString &character, int modifiers, int delay) +{ + QTEST_ASSERT(character.length() == 1); + QWindow *window = activeWindow(); + if (!window) + return false; + QTest::keyPress(window, character[0].toLatin1(), Qt::KeyboardModifiers(modifiers), delay); + return true; +} + +bool QuickTestEvent::keyReleaseChar(const QString &character, int modifiers, int delay) +{ + QTEST_ASSERT(character.length() == 1); + QWindow *window = activeWindow(); + if (!window) + return false; + QTest::keyRelease(window, character[0].toLatin1(), Qt::KeyboardModifiers(modifiers), delay); + return true; +} + +bool QuickTestEvent::keyClickChar(const QString &character, int modifiers, int delay) +{ + QTEST_ASSERT(character.length() == 1); + QWindow *window = activeWindow(); + if (!window) + return false; + QTest::keyClick(window, character[0].toLatin1(), Qt::KeyboardModifiers(modifiers), delay); + return true; +} + +#if QT_CONFIG(shortcut) +// valueToKeySequence() is copied from qquickshortcut.cpp +static QKeySequence valueToKeySequence(const QVariant &value) +{ + if (value.userType() == QMetaType::Int) + return QKeySequence(static_cast<QKeySequence::StandardKey>(value.toInt())); + return QKeySequence::fromString(value.toString()); +} +#endif + +bool QuickTestEvent::keySequence(const QVariant &keySequence) +{ + QWindow *window = activeWindow(); + if (!window) + return false; +#if QT_CONFIG(shortcut) + QTest::keySequence(window, valueToKeySequence(keySequence)); +#else + Q_UNUSED(keySequence); +#endif + return true; +} + +namespace QtQuickTest +{ + enum MouseAction { MousePress, MouseRelease, MouseClick, MouseDoubleClick, MouseMove, MouseDoubleClickSequence }; + + int lastMouseTimestamp = 0; + + // TODO should be Qt::MouseButtons buttons in case multiple buttons are pressed + static void mouseEvent(MouseAction action, QWindow *window, + QObject *item, Qt::MouseButton button, + Qt::KeyboardModifiers stateKey, const QPointF &_pos, int delay=-1) + { + QTEST_ASSERT(window); + QTEST_ASSERT(item); + + if (delay == -1 || delay < QTest::defaultMouseDelay()) + delay = QTest::defaultMouseDelay(); + if (delay > 0) { + QTest::qWait(delay); + lastMouseTimestamp += delay; + } + + if (action == MouseClick) { + mouseEvent(MousePress, window, item, button, stateKey, _pos); + mouseEvent(MouseRelease, window, item, button, stateKey, _pos); + return; + } + + if (action == MouseDoubleClickSequence) { + mouseEvent(MousePress, window, item, button, stateKey, _pos); + mouseEvent(MouseRelease, window, item, button, stateKey, _pos); + mouseEvent(MousePress, window, item, button, stateKey, _pos); + mouseEvent(MouseDoubleClick, window, item, button, stateKey, _pos); + mouseEvent(MouseRelease, window, item, button, stateKey, _pos); + return; + } + + QPoint pos = _pos.toPoint(); + QQuickItem *sgitem = qobject_cast<QQuickItem *>(item); + if (sgitem) + pos = sgitem->mapToScene(_pos).toPoint(); + QTEST_ASSERT(button == Qt::NoButton || button & Qt::MouseButtonMask); + QTEST_ASSERT(stateKey == 0 || stateKey & Qt::KeyboardModifierMask); + + stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask); + + QEvent::Type meType; + Qt::MouseButton meButton; + Qt::MouseButtons meButtons; + switch (action) + { + case MousePress: + meType = QEvent::MouseButtonPress; + meButton = button; + meButtons = button; + break; + case MouseRelease: + meType = QEvent::MouseButtonRelease; + meButton = button; + meButtons = Qt::MouseButton(); + break; + case MouseDoubleClick: + meType = QEvent::MouseButtonDblClick; + meButton = button; + meButtons = button; + break; + case MouseMove: + meType = QEvent::MouseMove; + meButton = Qt::NoButton; + meButtons = button; + break; + default: + QTEST_ASSERT(false); + } + QMouseEvent me(meType, pos, window->mapToGlobal(pos), meButton, meButtons, stateKey); + me.setTimestamp(++lastMouseTimestamp); + if (action == MouseRelease) // avoid double clicks being generated + lastMouseTimestamp += 500; + + QSpontaneKeyEvent::setSpontaneous(&me); + if (!qApp->notify(window, &me)) { + static const char *mouseActionNames[] = + { "MousePress", "MouseRelease", "MouseClick", "MouseDoubleClick", "MouseMove", "MouseDoubleClickSequence" }; + QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving window"); + QWARN(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(action)])).toLatin1().data()); + } + } + +#if QT_CONFIG(wheelevent) + static void mouseWheel(QWindow* window, QObject* item, Qt::MouseButtons buttons, + Qt::KeyboardModifiers stateKey, + QPointF _pos, int xDelta, int yDelta, int delay = -1) + { + QTEST_ASSERT(window); + QTEST_ASSERT(item); + if (delay == -1 || delay < QTest::defaultMouseDelay()) + delay = QTest::defaultMouseDelay(); + if (delay > 0) + QTest::qWait(delay); + + QPoint pos; + QQuickItem *sgitem = qobject_cast<QQuickItem *>(item); + if (sgitem) + pos = sgitem->mapToScene(_pos).toPoint(); + + QTEST_ASSERT(buttons == Qt::NoButton || buttons & Qt::MouseButtonMask); + QTEST_ASSERT(stateKey == 0 || stateKey & Qt::KeyboardModifierMask); + + stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask); + QWheelEvent we(pos, window->mapToGlobal(pos), QPoint(0, 0), QPoint(xDelta, yDelta), buttons, + stateKey, Qt::NoScrollPhase, false); + + QSpontaneKeyEvent::setSpontaneous(&we); // hmmmm + if (!qApp->notify(window, &we)) + QTest::qWarn("Wheel event not accepted by receiving window"); + } +#endif +}; + +bool QuickTestEvent::mousePress + (QObject *item, qreal x, qreal y, int button, + int modifiers, int delay) +{ + QWindow *view = eventWindow(item); + if (!view) + return false; + m_pressedButtons.setFlag(Qt::MouseButton(button), true); + QtQuickTest::mouseEvent(QtQuickTest::MousePress, view, item, + Qt::MouseButton(button), + Qt::KeyboardModifiers(modifiers), + QPointF(x, y), delay); + return true; +} + +#if QT_CONFIG(wheelevent) +bool QuickTestEvent::mouseWheel( + QObject *item, qreal x, qreal y, int buttons, + int modifiers, int xDelta, int yDelta, int delay) +{ + QWindow *view = eventWindow(item); + if (!view) + return false; + QtQuickTest::mouseWheel(view, item, Qt::MouseButtons(buttons), + Qt::KeyboardModifiers(modifiers), + QPointF(x, y), xDelta, yDelta, delay); + return true; +} +#endif + +bool QuickTestEvent::mouseRelease + (QObject *item, qreal x, qreal y, int button, + int modifiers, int delay) +{ + QWindow *view = eventWindow(item); + if (!view) + return false; + m_pressedButtons.setFlag(Qt::MouseButton(button), false); + QtQuickTest::mouseEvent(QtQuickTest::MouseRelease, view, item, + Qt::MouseButton(button), + Qt::KeyboardModifiers(modifiers), + QPointF(x, y), delay); + return true; +} + +bool QuickTestEvent::mouseClick + (QObject *item, qreal x, qreal y, int button, + int modifiers, int delay) +{ + QWindow *view = eventWindow(item); + if (!view) + return false; + QtQuickTest::mouseEvent(QtQuickTest::MouseClick, view, item, + Qt::MouseButton(button), + Qt::KeyboardModifiers(modifiers), + QPointF(x, y), delay); + return true; +} + +bool QuickTestEvent::mouseDoubleClick + (QObject *item, qreal x, qreal y, int button, + int modifiers, int delay) +{ + QWindow *view = eventWindow(item); + if (!view) + return false; + QtQuickTest::mouseEvent(QtQuickTest::MouseDoubleClick, view, item, + Qt::MouseButton(button), + Qt::KeyboardModifiers(modifiers), + QPointF(x, y), delay); + return true; +} + +bool QuickTestEvent::mouseDoubleClickSequence + (QObject *item, qreal x, qreal y, int button, + int modifiers, int delay) +{ + QWindow *view = eventWindow(item); + if (!view) + return false; + QtQuickTest::mouseEvent(QtQuickTest::MouseDoubleClickSequence, view, item, + Qt::MouseButton(button), + Qt::KeyboardModifiers(modifiers), + QPointF(x, y), delay); + return true; +} + +bool QuickTestEvent::mouseMove + (QObject *item, qreal x, qreal y, int delay, int buttons) +{ + QWindow *view = eventWindow(item); + if (!view) + return false; + const Qt::MouseButtons effectiveButtons = buttons ? Qt::MouseButtons(buttons) : m_pressedButtons; + QtQuickTest::mouseEvent(QtQuickTest::MouseMove, view, item, + Qt::MouseButton(int(effectiveButtons)), Qt::NoModifier, + QPointF(x, y), delay); + return true; +} + +QWindow *QuickTestEvent::eventWindow(QObject *item) +{ + QWindow * window = qobject_cast<QWindow *>(item); + if (window) + return window; + + QQuickItem *quickItem = qobject_cast<QQuickItem *>(item); + if (quickItem) + return quickItem->window(); + + QQuickItem *testParentitem = qobject_cast<QQuickItem *>(parent()); + if (testParentitem) + return testParentitem->window(); + return nullptr; +} + +QWindow *QuickTestEvent::activeWindow() +{ + if (QWindow *window = QGuiApplication::focusWindow()) + return window; + return eventWindow(); +} + +QQuickTouchEventSequence::QQuickTouchEventSequence(QuickTestEvent *testEvent, QObject *item) + : QObject(testEvent) + , m_sequence(QTest::touchEvent(testEvent->eventWindow(item), testEvent->touchDevice())) + , m_testEvent(testEvent) +{ +} + +QObject *QQuickTouchEventSequence::press(int touchId, QObject *item, qreal x, qreal y) +{ + QWindow *view = m_testEvent->eventWindow(item); + if (view) { + QPointF pos(x, y); + QQuickItem *quickItem = qobject_cast<QQuickItem *>(item); + if (quickItem) { + pos = quickItem->mapToScene(pos); + } + m_sequence.press(touchId, pos.toPoint(), view); + } + return this; +} + +QObject *QQuickTouchEventSequence::move(int touchId, QObject *item, qreal x, qreal y) +{ + QWindow *view = m_testEvent->eventWindow(item); + if (view) { + QPointF pos(x, y); + QQuickItem *quickItem = qobject_cast<QQuickItem *>(item); + if (quickItem) { + pos = quickItem->mapToScene(pos); + } + m_sequence.move(touchId, pos.toPoint(), view); + } + return this; +} + +QObject *QQuickTouchEventSequence::release(int touchId, QObject *item, qreal x, qreal y) +{ + QWindow *view = m_testEvent->eventWindow(item); + if (view) { + QPointF pos(x, y); + QQuickItem *quickItem = qobject_cast<QQuickItem *>(item); + if (quickItem) { + pos = quickItem->mapToScene(pos); + } + m_sequence.release(touchId, pos.toPoint(), view); + } + return this; +} + +QObject *QQuickTouchEventSequence::stationary(int touchId) +{ + m_sequence.stationary(touchId); + return this; +} + +QObject *QQuickTouchEventSequence::commit() +{ + m_sequence.commit(); + return this; +} + +/*! + Return a simulated touchscreen, creating one if necessary + + \internal +*/ + +QPointingDevice *QuickTestEvent::touchDevice() +{ + static QPointingDevice *device(nullptr); + + if (!device) { + device = new QPointingDevice(QLatin1String("test touchscreen"), 42, + QInputDevice::DeviceType::TouchScreen, QPointingDevice::PointerType::Finger, + QInputDevice::Capability::Position, 10, 0); + QWindowSystemInterface::registerInputDevice(device); + } + return device; +} + +/*! + Creates a new QQuickTouchEventSequence. + + If valid, \a item determines the QWindow that touch events are sent to. + Test code should use touchEvent() from the QML TestCase type. + + \internal +*/ +QQuickTouchEventSequence *QuickTestEvent::touchEvent(QObject *item) +{ + return new QQuickTouchEventSequence(this, item); +} + +QT_END_NAMESPACE diff --git a/src/qmltest/quicktestevent_p.h b/src/qmltest/quicktestevent_p.h new file mode 100644 index 0000000000..4e63a2e47e --- /dev/null +++ b/src/qmltest/quicktestevent_p.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUICKTESTEVENT_P_H +#define QUICKTESTEVENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtGui/QWindow> +#include <QtQml/qqml.h> +#include <QtTest/qtesttouch.h> + +QT_BEGIN_NAMESPACE + +class QuickTestEvent; +class QQuickTouchEventSequence : public QObject +{ + Q_OBJECT + QML_ANONYMOUS + QML_ADDED_IN_VERSION(1, 0) + +public: + explicit QQuickTouchEventSequence(QuickTestEvent *testEvent, QObject *item = nullptr); +public slots: + QObject* press(int touchId, QObject *item, qreal x, qreal y); + QObject* move(int touchId, QObject *item, qreal x, qreal y); + QObject* release(int touchId, QObject *item, qreal x, qreal y); + QObject* stationary(int touchId); + QObject* commit(); + +private: + QTest::QTouchEventSequence m_sequence; + QuickTestEvent * const m_testEvent; +}; + +class QuickTestEvent : public QObject +{ + Q_OBJECT + Q_PROPERTY(int defaultMouseDelay READ defaultMouseDelay FINAL) + QML_NAMED_ELEMENT(TestEvent) + QML_ADDED_IN_VERSION(1, 0) +public: + QuickTestEvent(QObject *parent = nullptr); + ~QuickTestEvent() override; + int defaultMouseDelay() const; + +public Q_SLOTS: + bool keyPress(int key, int modifiers, int delay); + bool keyRelease(int key, int modifiers, int delay); + bool keyClick(int key, int modifiers, int delay); + + bool keyPressChar(const QString &character, int modifiers, int delay); + bool keyReleaseChar(const QString &character, int modifiers, int delay); + bool keyClickChar(const QString &character, int modifiers, int delay); + + Q_REVISION(1, 2) bool keySequence(const QVariant &keySequence); + + bool mousePress(QObject *item, qreal x, qreal y, int button, + int modifiers, int delay); + bool mouseRelease(QObject *item, qreal x, qreal y, int button, + int modifiers, int delay); + bool mouseClick(QObject *item, qreal x, qreal y, int button, + int modifiers, int delay); + bool mouseDoubleClick(QObject *item, qreal x, qreal y, int button, + int modifiers, int delay); + bool mouseDoubleClickSequence(QObject *item, qreal x, qreal y, int button, + int modifiers, int delay); + bool mouseMove(QObject *item, qreal x, qreal y, int delay, int buttons); + +#if QT_CONFIG(wheelevent) + bool mouseWheel(QObject *item, qreal x, qreal y, int buttons, + int modifiers, int xDelta, int yDelta, int delay); +#endif + + QQuickTouchEventSequence *touchEvent(QObject *item = nullptr); +private: + QWindow *eventWindow(QObject *item = nullptr); + QWindow *activeWindow(); + QPointingDevice *touchDevice(); + + Qt::MouseButtons m_pressedButtons; + + friend class QQuickTouchEventSequence; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/qmltest/quicktestglobal_p.h b/src/qmltest/quicktestglobal_p.h new file mode 100644 index 0000000000..4a70c2478d --- /dev/null +++ b/src/qmltest/quicktestglobal_p.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUICKTESTGLOBAL_P_H +#define QUICKTESTGLOBAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "quicktestglobal.h" + +#define Q_QUICK_TEST_PRIVATE_EXPORT Q_QUICK_TEST_EXPORT + +void Q_QUICK_TEST_PRIVATE_EXPORT qml_register_types_QtTest(); + + +#endif // QUICKTESTGLOBAL_P_H diff --git a/src/qmltest/quicktestresult_p.h b/src/qmltest/quicktestresult_p.h index 7ebfb21186..54799e40aa 100644 --- a/src/qmltest/quicktestresult_p.h +++ b/src/qmltest/quicktestresult_p.h @@ -51,7 +51,7 @@ // We mean it. // -#include <QtQuickTest/quicktestglobal.h> +#include <QtQuickTest/private/quicktestglobal_p.h> #include <QtCore/qobject.h> #include <QtCore/qstring.h> #include <QtCore/qstringlist.h> @@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE class QUrl; class QuickTestResultPrivate; -class Q_QUICK_TEST_EXPORT QuickTestResult : public QObject +class Q_QUICK_TEST_PRIVATE_EXPORT QuickTestResult : public QObject { Q_OBJECT Q_PROPERTY(QString testCaseName READ testCaseName WRITE setTestCaseName NOTIFY testCaseNameChanged) @@ -77,6 +77,9 @@ class Q_QUICK_TEST_EXPORT QuickTestResult : public QObject Q_PROPERTY(QStringList functionsToRun READ functionsToRun) Q_PROPERTY(QStringList tagsToRun READ tagsToRun) + QML_NAMED_ELEMENT(TestResult) + QML_ADDED_IN_VERSION(1, 0) + public: QuickTestResult(QObject *parent = nullptr); ~QuickTestResult() override; diff --git a/src/qmltest/quicktestutil.cpp b/src/qmltest/quicktestutil.cpp new file mode 100644 index 0000000000..994c66845b --- /dev/null +++ b/src/qmltest/quicktestutil.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "quicktestutil_p.h" + +#include <QtQuickTest/private/qtestoptions_p.h> +#include <QtQml/private/qqmltype_p.h> +#include <QtQml/private/qqmlmetatype_p.h> +#include <QtQml/private/qv4engine_p.h> +#include <QtQml/private/qv4scopedvalue_p.h> +#include <QtQml/private/qjsvalue_p.h> + +#include <QtGui/qguiapplication.h> +#include <QtGui/qstylehints.h> +#include <QtQml/qqmlengine.h> + +QT_BEGIN_NAMESPACE + +bool QuickTestUtil::printAvailableFunctions() const +{ + return QTest::printAvailableFunctions; +} + +int QuickTestUtil::dragThreshold() const +{ + return QGuiApplication::styleHints()->startDragDistance(); +} + +QJSValue QuickTestUtil::typeName(const QVariant &v) const +{ + QString name = QString::fromUtf8(v.typeName()); + if (v.canConvert<QObject*>()) { + QQmlType type; + const QMetaObject *mo = v.value<QObject*>()->metaObject(); + while (!type.isValid() && mo) { + type = QQmlMetaType::qmlType(mo); + mo = mo->superClass(); + } + if (type.isValid()) { + name = type.qmlTypeName(); + } + } + + QQmlEngine *engine = qmlEngine(this); + QV4::ExecutionEngine *v4 = engine->handle(); + return QJSValuePrivate::fromReturnedValue(v4->newString(name)->asReturnedValue()); +} + +bool QuickTestUtil::compare(const QVariant &act, const QVariant &exp) const { + return act == exp; +} + +QJSValue QuickTestUtil::callerFile(int frameIndex) const +{ + QQmlEngine *engine = qmlEngine(this); + QV4::ExecutionEngine *v4 = engine->handle(); + QV4::Scope scope(v4); + + QVector<QV4::StackFrame> stack = v4->stackTrace(frameIndex + 2); + return (stack.size() > frameIndex + 1) + ? QJSValuePrivate::fromReturnedValue( + v4->newString(stack.at(frameIndex + 1).source)->asReturnedValue()) + : QJSValue(); +} + +int QuickTestUtil::callerLine(int frameIndex) const +{ + QQmlEngine *engine = qmlEngine(this); + QV4::ExecutionEngine *v4 = engine->handle(); + + QVector<QV4::StackFrame> stack = v4->stackTrace(frameIndex + 2); + if (stack.size() > frameIndex + 1) + return stack.at(frameIndex + 1).line; + return -1; +} + +QT_END_NAMESPACE diff --git a/src/qmltest/quicktestutil_p.h b/src/qmltest/quicktestutil_p.h new file mode 100644 index 0000000000..7e90c1cd1d --- /dev/null +++ b/src/qmltest/quicktestutil_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUICKTESTUTIL_P_H +#define QUICKTESTUTIL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtQml/qqml.h> +#include <QtQml/qjsvalue.h> + +QT_BEGIN_NAMESPACE + +class QuickTestUtil : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool printAvailableFunctions READ printAvailableFunctions NOTIFY printAvailableFunctionsChanged) + Q_PROPERTY(int dragThreshold READ dragThreshold NOTIFY dragThresholdChanged) + QML_NAMED_ELEMENT(TestUtil) + QML_ADDED_IN_VERSION(1, 0) +public: + QuickTestUtil(QObject *parent = nullptr) :QObject(parent) {} + ~QuickTestUtil() override {} + + bool printAvailableFunctions() const; + int dragThreshold() const; + +Q_SIGNALS: + void printAvailableFunctionsChanged(); + void dragThresholdChanged(); + +public Q_SLOTS: + + QJSValue typeName(const QVariant& v) const; + bool compare(const QVariant& act, const QVariant& exp) const; + + QJSValue callerFile(int frameIndex = 0) const; + int callerLine(int frameIndex = 0) const; +}; + +QT_END_NAMESPACE + +#endif // QUICKTESTUTIL_P_H |