diff options
-rw-r--r-- | src/testlib/qtestcase.cpp | 6 | ||||
-rw-r--r-- | src/testlib/qtestmouse.h | 26 | ||||
-rw-r--r-- | tests/auto/gui/kernel/qwindow/tst_qwindow.cpp | 35 | ||||
-rw-r--r-- | tests/auto/testlib/selftests/mouse/mouse.pro | 7 | ||||
-rw-r--r-- | tests/auto/testlib/selftests/mouse/tst_mouse.cpp | 215 | ||||
-rw-r--r-- | tests/auto/testlib/selftests/selftests.pri | 3 |
6 files changed, 263 insertions, 29 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 497470464f..7e9c03dbd4 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -268,6 +268,11 @@ static bool isValidSlot(const QMetaMethod &sl) || name == "init" || name == "cleanup"); } +namespace QTestPrivate +{ + Q_TESTLIB_EXPORT Qt::MouseButtons qtestMouseButtons = Qt::NoButton; +} + namespace QTest { class WatchDog; @@ -1074,6 +1079,7 @@ bool TestMethods::invokeTest(int index, const char *data, WatchDog *watchDog) co QTestDataSetter s(curDataIndex >= dataCount ? static_cast<QTestData *>(0) : table.testData(curDataIndex)); + QTestPrivate::qtestMouseButtons = Qt::NoButton; if (watchDog) watchDog->beginTest(); invokeTestOnData(index); diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h index fa524fd8ca..e2835828a1 100644 --- a/src/testlib/qtestmouse.h +++ b/src/testlib/qtestmouse.h @@ -68,11 +68,16 @@ Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, con Qt::MouseButtons state, Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods, int timestamp); +namespace QTestPrivate +{ + extern Q_TESTLIB_EXPORT Qt::MouseButtons qtestMouseButtons; +} + namespace QTest { enum MouseAction { MousePress, MouseRelease, MouseClick, MouseDClick, MouseMove }; - extern Q_TESTLIB_EXPORT Qt::MouseButton lastMouseButton; + extern Q_TESTLIB_EXPORT Qt::MouseButton lastMouseButton; // ### unsued extern Q_TESTLIB_EXPORT int lastMouseTimestamp; // This value is used to emulate timestamps to avoid creating double clicks by mistake. @@ -117,30 +122,35 @@ namespace QTest QPointF global = window->mapToGlobal(pos); QPointer<QWindow> w(window); + using namespace QTestPrivate; switch (action) { case MouseDClick: - qt_handleMouseEvent(w, pos, global, button, button, QEvent::MouseButtonPress, + qtestMouseButtons.setFlag(button, true); + qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonPress, stateKey, ++lastMouseTimestamp); - qt_handleMouseEvent(w, pos, global, Qt::NoButton, button, QEvent::MouseButtonRelease, + qtestMouseButtons.setFlag(button, false); + qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonRelease, stateKey, ++lastMouseTimestamp); Q_FALLTHROUGH(); case MousePress: case MouseClick: - qt_handleMouseEvent(w, pos, global, button, button, QEvent::MouseButtonPress, + qtestMouseButtons.setFlag(button, true); + qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonPress, stateKey, ++lastMouseTimestamp); - lastMouseButton = button; + lastMouseButton = button; // ### unsued if (action == MousePress) break; Q_FALLTHROUGH(); case MouseRelease: - qt_handleMouseEvent(w, pos, global, Qt::NoButton, button, QEvent::MouseButtonRelease, + qtestMouseButtons.setFlag(button, false); + qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonRelease, stateKey, ++lastMouseTimestamp); lastMouseTimestamp += mouseDoubleClickInterval; // avoid double clicks being generated - lastMouseButton = Qt::NoButton; + lastMouseButton = Qt::NoButton; // ### unsued break; case MouseMove: - qt_handleMouseEvent(w, pos, global, lastMouseButton, Qt::NoButton, QEvent::MouseMove, + qt_handleMouseEvent(w, pos, global, qtestMouseButtons, Qt::NoButton, QEvent::MouseMove, stateKey, ++lastMouseTimestamp); break; default: diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index 18723458f6..34754670de 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -2320,49 +2320,44 @@ void tst_QWindow::generatedMouseMove() { InputTestWindow w; w.setGeometry(QRect(m_availableTopLeft + QPoint(100, 100), m_testWindowSize)); + w.setFlags(w.flags() | Qt::FramelessWindowHint); // ### FIXME: QTBUG-63542 w.show(); QVERIFY(QTest::qWaitForWindowActive(&w)); QPoint point(10, 10); QPoint step(2, 2); QVERIFY(w.mouseMovedCount == 0); - QWindowSystemInterface::handleMouseEvent(&w, point, point, Qt::NoButton, Qt::NoButton, QEvent::MouseMove); - QCoreApplication::processEvents(); + QTest::mouseMove(&w, point); QVERIFY(w.mouseMovedCount == 1); - // Press that does not change position should not generate mouse move - QWindowSystemInterface::handleMouseEvent(&w, point, point, Qt::LeftButton, Qt::LeftButton, QEvent::MouseButtonPress); - QWindowSystemInterface::handleMouseEvent(&w, point, point, Qt::LeftButton | Qt::RightButton, Qt::RightButton, QEvent::MouseButtonPress); - QCoreApplication::processEvents(); + // A press event that does not change position should not generate mouse move + QTest::mousePress(&w, Qt::LeftButton, 0, point); + QTest::mousePress(&w, Qt::RightButton, 0, point); + QVERIFY(w.mouseMovedCount == 1); - // Test moves generated for mouse release + // Verify that a move event is generated for a mouse release event that changes position point += step; - QWindowSystemInterface::handleMouseEvent(&w, point, point, Qt::RightButton, Qt::LeftButton, QEvent::MouseButtonRelease); - QCoreApplication::processEvents(); + QTest::mouseRelease(&w, Qt::LeftButton, 0, point); QVERIFY(w.mouseMovedCount == 2); QVERIFY(w.buttonStateInGeneratedMove == (Qt::LeftButton | Qt::RightButton)); point += step; - QWindowSystemInterface::handleMouseEvent(&w, point, point, Qt::NoButton, Qt::RightButton, QEvent::MouseButtonRelease); - QCoreApplication::processEvents(); + QTest::mouseRelease(&w, Qt::RightButton, 0, point); QVERIFY(w.mouseMovedCount == 3); QVERIFY(w.buttonStateInGeneratedMove == Qt::RightButton); - // Test moves generated for mouse press + // Verify that a move event is generated for a mouse press event that changes position point += step; - QWindowSystemInterface::handleMouseEvent(&w, point, point, Qt::LeftButton, Qt::LeftButton, QEvent::MouseButtonPress); - QCoreApplication::processEvents(); + QTest::mousePress(&w, Qt::LeftButton, 0, point); QVERIFY(w.mouseMovedCount == 4); QVERIFY(w.buttonStateInGeneratedMove == Qt::NoButton); point += step; - QWindowSystemInterface::handleMouseEvent(&w, point, point, Qt::LeftButton | Qt::RightButton, Qt::RightButton, QEvent::MouseButtonPress); - QCoreApplication::processEvents(); + QTest::mousePress(&w, Qt::RightButton, 0, point); QVERIFY(w.mouseMovedCount == 5); QVERIFY(w.buttonStateInGeneratedMove == Qt::LeftButton); - // Release that does not change position should not generate mouse move - QWindowSystemInterface::handleMouseEvent(&w, point, point, Qt::LeftButton, Qt::RightButton, QEvent::MouseButtonRelease); - QWindowSystemInterface::handleMouseEvent(&w, point, point, Qt::NoButton, Qt::LeftButton, QEvent::MouseButtonRelease); - QCoreApplication::processEvents(); + // A release event that does not change position should not generate mouse move + QTest::mouseRelease(&w, Qt::RightButton, 0, point); + QTest::mouseRelease(&w, Qt::LeftButton, 0, point); QVERIFY(w.mouseMovedCount == 5); } diff --git a/tests/auto/testlib/selftests/mouse/mouse.pro b/tests/auto/testlib/selftests/mouse/mouse.pro new file mode 100644 index 0000000000..7c06b8aa64 --- /dev/null +++ b/tests/auto/testlib/selftests/mouse/mouse.pro @@ -0,0 +1,7 @@ +SOURCES += tst_mouse.cpp +QT += testlib testlib-private gui gui-private + +mac:CONFIG -= app_bundle +CONFIG -= debug_and_release_target + +TARGET = mouse diff --git a/tests/auto/testlib/selftests/mouse/tst_mouse.cpp b/tests/auto/testlib/selftests/mouse/tst_mouse.cpp new file mode 100644 index 0000000000..3c731cde69 --- /dev/null +++ b/tests/auto/testlib/selftests/mouse/tst_mouse.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest> +#include <QtGui/QWindow> +#include <QtGui/QCursor> +#include <QtGui/private/qguiapplication_p.h> + +QT_BEGIN_NAMESPACE +namespace QTestPrivate { +extern Q_TESTLIB_EXPORT Qt::MouseButtons qtestMouseButtons; // from qtestcase.cpp +} +QT_END_NAMESPACE + +class tst_Mouse : public QObject +{ + Q_OBJECT + +private slots: + void stateHandlingPart1_data(); + void stateHandlingPart1(); + void stateHandlingPart2(); + void deterministicEvents_data(); + void deterministicEvents(); +}; + +class MouseWindow : public QWindow +{ +public: + Qt::MouseButtons stateInMouseMove = Qt::NoButton; + int moveCount = 0; + int pressCount = 0; + +protected: + void mousePressEvent(QMouseEvent *) + { + pressCount++; + } + + void mouseMoveEvent(QMouseEvent *e) + { + moveCount++; + stateInMouseMove = e->buttons(); + } +}; + +void tst_Mouse::stateHandlingPart1_data() +{ + QTest::addColumn<bool>("dummy"); + QTest::newRow("dummy-1") << true; + QTest::newRow("dummy-2") << true; +} + +void tst_Mouse::stateHandlingPart1() +{ + QFETCH(bool, dummy); + Q_UNUSED(dummy); + + QWindow w; + w.setFlags(w.flags() | Qt::FramelessWindowHint); // ### FIXME: QTBUG-63542 + w.show(); + w.setGeometry(100, 100, 200, 200); + QVERIFY(QTest::qWaitForWindowActive(&w)); + + QPoint point(10, 10); + QPoint step(1, 1); + + // verify that we have a clean state after the previous data set + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::NoButton); + + QTest::mousePress(&w, Qt::LeftButton, 0, point); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::LeftButton); + QTest::mousePress(&w, Qt::RightButton, 0, point); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::LeftButton | Qt::RightButton); + QTest::mouseMove(&w, point += step); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::LeftButton | Qt::RightButton); + QTest::mouseRelease(&w, Qt::LeftButton, 0, point); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::RightButton); + QTest::mouseMove(&w, point += step); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::RightButton); + // test invalid input - left button was already released + QTest::mouseRelease(&w, Qt::LeftButton, 0, point += point); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::RightButton); + // test invalid input - right button is already pressed + QTest::mousePress(&w, Qt::RightButton, 0, point); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::RightButton); + // now continue with valid input + QTest::mouseRelease(&w, Qt::RightButton, 0, point += point); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::NoButton); + QTest::mouseMove(&w, point += step); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::NoButton); + + // exit this test function with some button in a pressed state + QTest::mousePress(&w, Qt::LeftButton, 0, point); + QTest::mousePress(&w, Qt::RightButton, 0, point); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::LeftButton | Qt::RightButton); +} + +void tst_Mouse::stateHandlingPart2() +{ + MouseWindow w; + w.setFlags(w.flags() | Qt::FramelessWindowHint); // ### FIXME: QTBUG-63542 + w.show(); + w.setGeometry(100, 100, 200, 200); + QVERIFY(QTest::qWaitForWindowActive(&w)); + + // verify that we have a clean state after stateHandlingPart1() + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::NoButton); + +#if !QT_CONFIG(cursor) + QSKIP("This part of the test requires the QCursor API"); +#else + // The windowing system's view on a current button state might be different + // from the qtestlib's mouse button state. This test verifies that the mouse + // events generated by the system are adjusted to reflect qtestlib's view + // on the current button state. + // SKIP: not convinced yet that there is a valid use case for this. + + QSKIP("Not implemented beyond this point!"); + + QPoint point(40, 40); + QTest::mousePress(&w, Qt::LeftButton, 0, point); + QTest::mousePress(&w, Qt::RightButton, 0, point); + QCOMPARE(QTestPrivate::qtestMouseButtons, Qt::LeftButton | Qt::RightButton); + w.moveCount = 0; + // The windowing system will send mouse events with no buttons set + QPoint moveToPoint = w.mapToGlobal(point + QPoint(1, 1)); + if (QCursor::pos() == moveToPoint) + moveToPoint += QPoint(1, 1); + QCursor::setPos(moveToPoint); + QTRY_COMPARE(w.moveCount, 1); + // Verify that qtestlib adjusted the button state + QCOMPARE(w.stateInMouseMove, Qt::LeftButton | Qt::RightButton); +#endif +} + +void tst_Mouse::deterministicEvents_data() +{ + QTest::addColumn<bool>("firstRun"); + QTest::newRow("first-run-true") << true; + QTest::newRow("first-run-false") << false; +} + +void tst_Mouse::deterministicEvents() +{ + /* QGuiApplication uses QGuiApplicationPrivate::lastCursorPosition to + determine if it needs to generate an additional mouse move event for + mouse press/release. Verify that this property is reset to it's default + value, ensuring deterministic event generation behavior. Not resetting + this value might affect event generation for subsequent tests runs (in + unlikely case where a subsquent test does a mouse press in a pos that is + equal to QGuiApplicationPrivate::lastCursorPosition, not causing mouse + move to be generated. + NOTE: running this test alone as in "./mouse deterministicEvents:first-run-false" + won't test what this test is designed to test. */ + + QSKIP("Not implemented!"); + + /* It is undecided how and at what scope we want to handle reseting + lastCursorPosition, or perhaps Qt should not be generating mouse move + events as documented in QGuiApplicationPrivate::processMouseEvent(), + then the problem would go away - ### Qt6 ? */ + + QVERIFY(qIsInf(QGuiApplicationPrivate::lastCursorPosition.x())); + QVERIFY(qIsInf(QGuiApplicationPrivate::lastCursorPosition.y())); + + QFETCH(bool, firstRun); + + MouseWindow w; + w.setFlags(w.flags() | Qt::FramelessWindowHint); // ### FIXME: QTBUG-63542 + w.show(); + w.setGeometry(100, 100, 200, 200); + QVERIFY(QTest::qWaitForWindowActive(&w)); + + QCOMPARE(w.pressCount, 0); + QCOMPARE(w.moveCount, 0); + static QPoint m_cachedLastCursorPosition; + if (firstRun) { + QTest::mousePress(&w, Qt::LeftButton, 0, QPoint(40, 40)); + m_cachedLastCursorPosition = QGuiApplicationPrivate::lastCursorPosition.toPoint(); + } else { + QPoint point = w.mapFromGlobal(m_cachedLastCursorPosition); + QTest::mousePress(&w, Qt::LeftButton, 0, point); + } + QCOMPARE(w.pressCount, 1); + QCOMPARE(w.moveCount, 1); +} + +QTEST_MAIN(tst_Mouse) +#include "tst_mouse.moc" diff --git a/tests/auto/testlib/selftests/selftests.pri b/tests/auto/testlib/selftests/selftests.pri index 42c62d3b55..079f3f7959 100644 --- a/tests/auto/testlib/selftests/selftests.pri +++ b/tests/auto/testlib/selftests/selftests.pri @@ -47,7 +47,8 @@ SUBPROGRAMS = \ verbose2 \ verifyexceptionthrown \ warnings \ - xunit + xunit \ + mouse INCLUDEPATH += ../../../../shared/ HEADERS += ../../../../shared/emulationdetector.h |