From 30609e684f90d07c66114f2ae5144e0d38f52219 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 5 Sep 2017 12:37:10 +0200 Subject: testlib: Print event coordinates and window size when event is outside of window This gives the user a much clearer understanding of which part of the test caused the warning. Old warning: WARNING: tst_controls::Default::Dial::test_linearInputMode(mouse) Mouse event occurs outside of target window. New warning: WARNING: tst_controls::Default::Dial::test_linearInputMode(mouse) Mouse event at 501, 179 occurs outside of target window (450x450). Change-Id: I2943d79bab5a808e9b5b721758db216b91a07bbd Reviewed-by: Liang Qi Reviewed-by: Friedemann Kleint --- src/testlib/qtestmouse.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/testlib') diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h index 166622e950..8f55c1801f 100644 --- a/src/testlib/qtestmouse.h +++ b/src/testlib/qtestmouse.h @@ -94,8 +94,10 @@ namespace QTest extern int Q_TESTLIB_EXPORT defaultMouseDelay(); // pos is in window local coordinates - if (window->geometry().width() <= pos.x() || window->geometry().height() <= pos.y()) { - QTest::qWarn("Mouse event occurs outside of target window."); + const QSize windowSize = window->geometry().size(); + if (windowSize.width() <= pos.x() || windowSize.height() <= pos.y()) { + QTest::qWarn(qPrintable(QString::fromLatin1("Mouse event at %1, %2 occurs outside of target window (%3x%4).") + .arg(pos.x()).arg(pos.y()).arg(windowSize.width()).arg(windowSize.height()))); } if (delay == -1 || delay < defaultMouseDelay()) -- cgit v1.2.3 From 01ea60fdd2cb0b0f0ffc45ec7fba84ef2a7dff00 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 4 Sep 2017 09:32:24 +0200 Subject: Testlib: Do not list unsupported option This option is listed when displaying the help of Quick tests, but was never actively supported as it had been removed before Qt5.0 was finally released. Change-Id: I4cdf8d86471ab72e289f27a07a5f04c0338bfdbd Reviewed-by: Friedemann Kleint --- src/testlib/qtestcase.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/testlib') diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 74a5d0ac19..4c5c9e1eb8 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -577,7 +577,6 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) " -import dir : Specify an import directory.\n" " -plugins dir : Specify a directory where to search for plugins.\n" " -input dir/file : Specify the root directory for test cases or a single test case file.\n" - " -qtquick1 : Run with QtQuick 1 rather than QtQuick 2.\n" " -translation file : Specify the translation file.\n" ); } @@ -774,7 +773,6 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) " -import : Specify an import directory.\n" " -plugins : Specify a directory where to search for plugins.\n" " -input : Specify the root directory for test cases.\n" - " -qtquick1 : Run with QtQuick 1 rather than QtQuick 2.\n" ); } -- cgit v1.2.3 From 292cb12e024e63f17c501611e021b6f8da7d6dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 7 Feb 2017 14:09:04 +0100 Subject: testlib: Add qWaitFor to wait for predicate Reduces duplication of logic and allows other primitives to be built on top. Change-Id: Ia100014cfb0c09ac2f47c3a156d0c76f0fddafa8 Reviewed-by: Gatis Paeglis --- .../doc/snippets/code/src_qtestlib_qtestcase.cpp | 8 +++ src/testlib/qtestcase.h | 2 + src/testlib/qtestcase.qdoc | 15 +++++ src/testlib/qtestsystem.h | 67 +++++++++++++--------- 4 files changed, 64 insertions(+), 28 deletions(-) (limited to 'src/testlib') diff --git a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp index 01ee8102f4..990b7a38d7 100644 --- a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp +++ b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp @@ -306,5 +306,13 @@ QTest::keyClick(myWindow, Qt::Key_Escape); QTest::keyClick(myWindow, Qt::Key_Escape, Qt::ShiftModifier, 200); //! [29] +//! [30] +MyObject obj; +obj.startup(); +QTest::qWaitFor([&]() { + return obj.isReady(); +}, 3000); +//! [30] + } diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index b738043cb7..2605325a94 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -147,6 +147,8 @@ do {\ } \ } +// Ideally we'd use qWaitFor instead of QTRY_LOOP_IMPL, but due +// to a compiler bug on MSVC < 2017 we can't (see QTBUG-59096) #define QTRY_IMPL(expr, timeout)\ const int qt_test_step = 50; \ const int qt_test_timeoutValue = timeout; \ diff --git a/src/testlib/qtestcase.qdoc b/src/testlib/qtestcase.qdoc index 2d1e27ec40..5b90419e28 100644 --- a/src/testlib/qtestcase.qdoc +++ b/src/testlib/qtestcase.qdoc @@ -1075,6 +1075,21 @@ \sa QTest::qSleep(), QSignalSpy::wait() */ +/*! \fn void QTest::qWaitFor(Functor predicate, int timeout) + + Waits for \a timeout milliseconds or until the \a predicate returns true. + + Returns \c true if the \a predicate returned true at any point, otherwise returns \c false. + + Example: + \snippet code/src_qtestlib_qtestcase.cpp 30 + + The code above will wait for the object to become ready, for a + maximum of three seconds. + + \since 5.10 +*/ + /*! \fn bool QTest::qWaitForWindowExposed(QWindow *window, int timeout) \since 5.0 diff --git a/src/testlib/qtestsystem.h b/src/testlib/qtestsystem.h index f38a156936..04c9c574f7 100644 --- a/src/testlib/qtestsystem.h +++ b/src/testlib/qtestsystem.h @@ -54,41 +54,60 @@ QT_BEGIN_NAMESPACE namespace QTest { - Q_DECL_UNUSED inline static void qWait(int ms) + template + static Q_REQUIRED_RESULT bool qWaitFor(Functor predicate, int timeout = 5000) { - Q_ASSERT(QCoreApplication::instance()); + // We should not spint the event loop in case the predicate is already true, + // otherwise we might send new events that invalidate the predicate. + if (predicate()) + return true; + + // qWait() is expected to spin the event loop, even when called with a small + // timeout like 1ms, so we we can't use a simple while-loop here based on + // the deadline timer not having timed out. Use do-while instead. + + int remaining = timeout; + QDeadlineTimer deadline(remaining, Qt::PreciseTimer); - QDeadlineTimer timer(ms, Qt::PreciseTimer); - int remaining = ms; do { QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); - QCoreApplication::sendPostedEvents(Q_NULLPTR, QEvent::DeferredDelete); - remaining = timer.remainingTime(); - if (remaining <= 0) - break; - QTest::qSleep(qMin(10, remaining)); - remaining = timer.remainingTime(); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + + remaining = deadline.remainingTime(); + if (remaining > 0) { + QTest::qSleep(qMin(10, remaining)); + remaining = deadline.remainingTime(); + } + + if (predicate()) + return true; + + remaining = deadline.remainingTime(); } while (remaining > 0); + + return predicate(); // Last chance + } + + Q_DECL_UNUSED inline static void qWait(int ms) + { + Q_ASSERT(QCoreApplication::instance()); + auto unconditionalWait = []() { return false; }; + bool timedOut = !qWaitFor(unconditionalWait, ms); + Q_UNUSED(timedOut); } #ifdef QT_GUI_LIB inline static bool qWaitForWindowActive(QWindow *window, int timeout = 5000) { - QDeadlineTimer timer(timeout, Qt::PreciseTimer); - int remaining = timeout; - while (!window->isActive() && remaining > 0) { - QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); - QCoreApplication::sendPostedEvents(Q_NULLPTR, QEvent::DeferredDelete); - QTest::qSleep(10); - remaining = timer.remainingTime(); - } + bool becameActive = qWaitFor([&]() { return window->isActive(); }, timeout); + // Try ensuring the platform window receives the real position. // (i.e. that window->pos() reflects reality) // isActive() ( == FocusIn in case of X) does not guarantee this. It seems some WMs randomly // send the final ConfigureNotify (the one with the non-bogus 0,0 position) after the FocusIn. // If we just let things go, every mapTo/FromGlobal call the tests perform directly after // qWaitForWindowShown() will generate bogus results. - if (window->isActive()) { + if (becameActive) { int waitNo = 0; // 0, 0 might be a valid position after all, so do not wait for ever while (window->position().isNull()) { if (waitNo++ > timeout / 10) @@ -101,15 +120,7 @@ namespace QTest inline static bool qWaitForWindowExposed(QWindow *window, int timeout = 5000) { - QDeadlineTimer timer(timeout, Qt::PreciseTimer); - int remaining = timeout; - while (!window->isExposed() && remaining > 0) { - QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); - QCoreApplication::sendPostedEvents(Q_NULLPTR, QEvent::DeferredDelete); - QTest::qSleep(10); - remaining = timer.remainingTime(); - } - return window->isExposed(); + return qWaitFor([&]() { return window->isExposed(); }, timeout); } #endif -- cgit v1.2.3