diff options
Diffstat (limited to 'src/testlib')
-rw-r--r-- | src/testlib/doc/qttestlib.qdocconf | 3 | ||||
-rw-r--r-- | src/testlib/qtest.h | 31 | ||||
-rw-r--r-- | src/testlib/qtestblacklist.cpp | 27 | ||||
-rw-r--r-- | src/testlib/qtestblacklist_p.h | 6 | ||||
-rw-r--r-- | src/testlib/qtestcase.cpp | 24 | ||||
-rw-r--r-- | src/testlib/qtestcase.h | 2 | ||||
-rw-r--r-- | src/testlib/qtestmouse.cpp | 47 | ||||
-rw-r--r-- | src/testlib/qtestmouse.h | 80 | ||||
-rw-r--r-- | src/testlib/testlib.pro | 1 |
9 files changed, 180 insertions, 41 deletions
diff --git a/src/testlib/doc/qttestlib.qdocconf b/src/testlib/doc/qttestlib.qdocconf index 35b4fbcb7b..0fafc733b1 100644 --- a/src/testlib/doc/qttestlib.qdocconf +++ b/src/testlib/doc/qttestlib.qdocconf @@ -40,5 +40,8 @@ excludedirs += ../../../examples/widgets/doc imagedirs += images +# Add a thumbnail for examples that do not have images +manifestmeta.thumbnail.names = "QtTestLib/Chapter *" + navigation.landingpage = "Qt Test" navigation.cppclassespage = "Qt Test C++ Classes" diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h index 81cc07c410..994179958b 100644 --- a/src/testlib/qtest.h +++ b/src/testlib/qtest.h @@ -274,14 +274,33 @@ inline bool qCompare(quint32 const &t1, quint64 const &t2, const char *actual, } QT_END_NAMESPACE +#ifdef QT_TESTCASE_BUILDDIR +# define QTEST_SET_MAIN_SOURCE_PATH QTest::setMainSourcePath(__FILE__, QT_TESTCASE_BUILDDIR); +#else +# define QTEST_SET_MAIN_SOURCE_PATH QTest::setMainSourcePath(__FILE__); +#endif + #define QTEST_APPLESS_MAIN(TestObject) \ int main(int argc, char *argv[]) \ { \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } #include <QtTest/qtestsystem.h> +#include <set> + +#ifndef QT_NO_OPENGL +# define QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \ + extern Q_TESTLIB_EXPORT std::set<QByteArray> *(*qgpu_features_ptr)(const QString &); \ + extern Q_GUI_EXPORT std::set<QByteArray> *qgpu_features(const QString &); +# define QTEST_ADD_GPU_BLACKLIST_SUPPORT \ + qgpu_features_ptr = qgpu_features; +#else +# define QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS +# define QTEST_ADD_GPU_BLACKLIST_SUPPORT +#endif #if defined(QT_WIDGETS_LIB) @@ -294,12 +313,17 @@ int main(int argc, char *argv[]) \ #endif #define QTEST_MAIN(TestObject) \ +QT_BEGIN_NAMESPACE \ +QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \ +QT_END_NAMESPACE \ int main(int argc, char *argv[]) \ { \ QApplication app(argc, argv); \ app.setAttribute(Qt::AA_Use96Dpi, true); \ QTEST_DISABLE_KEYPAD_NAVIGATION \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } @@ -308,11 +332,16 @@ int main(int argc, char *argv[]) \ #include <QtTest/qtest_gui.h> #define QTEST_MAIN(TestObject) \ +QT_BEGIN_NAMESPACE \ +QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \ +QT_END_NAMESPACE \ int main(int argc, char *argv[]) \ { \ QGuiApplication app(argc, argv); \ app.setAttribute(Qt::AA_Use96Dpi, true); \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } @@ -324,6 +353,7 @@ int main(int argc, char *argv[]) \ QCoreApplication app(argc, argv); \ app.setAttribute(Qt::AA_Use96Dpi, true); \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } @@ -335,6 +365,7 @@ int main(int argc, char *argv[]) \ QCoreApplication app(argc, argv); \ app.setAttribute(Qt::AA_Use96Dpi, true); \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp index bfeca08617..f9ce908a00 100644 --- a/src/testlib/qtestblacklist.cpp +++ b/src/testlib/qtestblacklist.cpp @@ -34,6 +34,7 @@ #include "qtestresult_p.h" #include <QtTest/qtestcase.h> +#include <QtTest/qtest.h> #include <QtCore/qbytearray.h> #include <QtCore/qfile.h> #include <QtCore/qset.h> @@ -161,6 +162,9 @@ static bool checkCondition(const QByteArray &condition) static bool ignoreAll = false; static std::set<QByteArray> *ignoredTests = 0; +static std::set<QByteArray> *gpuFeatures = 0; + +Q_TESTLIB_EXPORT std::set<QByteArray> *(*qgpu_features_ptr)(const QString &) = 0; namespace QTestPrivate { @@ -196,7 +200,18 @@ void parseBlackList() } } -void checkBlackList(const char *slot, const char *data) +void parseGpuBlackList() +{ + if (!qgpu_features_ptr) + return; + QString filename = QTest::qFindTestData(QStringLiteral("GPU_BLACKLIST")); + if (filename.isEmpty()) + return; + if (!gpuFeatures) + gpuFeatures = qgpu_features_ptr(filename); +} + +void checkBlackLists(const char *slot, const char *data) { bool ignore = ignoreAll; @@ -211,6 +226,16 @@ void checkBlackList(const char *slot, const char *data) } QTestResult::setBlacklistCurrentTest(ignore); + + // Tests blacklisted in GPU_BLACKLIST are to be skipped. Just ignoring the result is + // not sufficient since these are expected to crash or behave in undefined ways. + if (!ignore && gpuFeatures) { + const QByteArray disableKey = QByteArrayLiteral("disable_") + QByteArray(slot); + if (gpuFeatures->find(disableKey) != gpuFeatures->end()) { + const QByteArray msg = QByteArrayLiteral("Skipped due to GPU blacklist: ") + disableKey; + QTest::qSkip(msg.constData(), __FILE__, __LINE__); + } + } } } diff --git a/src/testlib/qtestblacklist_p.h b/src/testlib/qtestblacklist_p.h index 158d99593e..87f4dfdb5e 100644 --- a/src/testlib/qtestblacklist_p.h +++ b/src/testlib/qtestblacklist_p.h @@ -50,8 +50,10 @@ QT_BEGIN_NAMESPACE namespace QTestPrivate { - void parseBlackList(); - void checkBlackList(const char *slot, const char *data); + // Export functions so they can also be used by QQuickTest + Q_TESTLIB_EXPORT void parseBlackList(); + Q_TESTLIB_EXPORT void parseGpuBlackList(); + Q_TESTLIB_EXPORT void checkBlackLists(const char *slot, const char *data); } QT_END_NAMESPACE diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index e1e6805a0f..858475f396 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1374,6 +1374,7 @@ static bool installCoverageTool(const char * appname, const char * testname) namespace QTest { static QObject *currentTestObject = 0; + static QString mainSourcePath; class TestFunction { public: @@ -2167,7 +2168,7 @@ static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog * if (!data || !qstrcmp(data, table.testData(curDataIndex)->dataTag())) { foundFunction = true; - QTestPrivate::checkBlackList(slot, dataCount ? table.testData(curDataIndex)->dataTag() : 0); + QTestPrivate::checkBlackLists(slot, dataCount ? table.testData(curDataIndex)->dataTag() : 0); QTestDataSetter s(curDataIndex >= dataCount ? static_cast<QTestData *>(0) : table.testData(curDataIndex)); @@ -2682,6 +2683,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) #endif QTestPrivate::parseBlackList(); + QTestPrivate::parseGpuBlackList(); QTestResult::reset(); @@ -3032,6 +3034,13 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co found = candidate; } + // 6. Try main source directory + if (found.isEmpty()) { + QString candidate = QTest::mainSourcePath % QLatin1Char('/') % base; + if (QFileInfo(candidate).exists()) + found = candidate; + } + if (found.isEmpty()) { QTest::qWarn(qPrintable( QString::fromLatin1("testdata %1 could not be located!").arg(base)), @@ -3219,6 +3228,19 @@ QObject *QTest::testObject() } /*! \internal + */ +void QTest::setMainSourcePath(const char *file, const char *builddir) +{ + QString mainSourceFile = QFile::decodeName(file); + QFileInfo fi; + if (builddir) + fi.setFile(QDir(QFile::decodeName(builddir)), mainSourceFile); + else + fi.setFile(mainSourceFile); + QTest::mainSourcePath = fi.absolutePath(); +} + +/*! \internal This function is called by various specializations of QTest::qCompare to decide whether to report a failure and to produce verbose test output. diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index 45290de6de..2c6a94faa1 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -236,6 +236,8 @@ namespace QTest Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = 0); Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments); + Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir = 0); + Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description, const char *file, int line); Q_TESTLIB_EXPORT void qFail(const char *statementStr, const char *file, int line); diff --git a/src/testlib/qtestmouse.cpp b/src/testlib/qtestmouse.cpp new file mode 100644 index 0000000000..99a75744fa --- /dev/null +++ b/src/testlib/qtestmouse.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtTest module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtGlobal> +#include <QtCore/qnamespace.h> +#include <QtTest/qtest_global.h> + +QT_BEGIN_NAMESPACE + +namespace QTest { + +Q_TESTLIB_EXPORT Qt::MouseButton lastMouseButton = Qt::NoButton; +Q_TESTLIB_EXPORT int lastMouseTimestamp = 0; + +} // namespace QTest + +QT_END_NAMESPACE diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h index 2cf84a7ea0..cd3901ae6f 100644 --- a/src/testlib/qtestmouse.h +++ b/src/testlib/qtestmouse.h @@ -45,6 +45,7 @@ #include <QtTest/qtestspontaneevent.h> #include <QtCore/qpoint.h> #include <QtCore/qstring.h> +#include <QtCore/qpointer.h> #include <QtGui/qevent.h> #include <QtGui/qwindow.h> @@ -57,12 +58,15 @@ QT_BEGIN_NAMESPACE -Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier); +Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp); namespace QTest { enum MouseAction { MousePress, MouseRelease, MouseClick, MouseDClick, MouseMove }; + extern Q_TESTLIB_EXPORT Qt::MouseButton lastMouseButton; + extern Q_TESTLIB_EXPORT int lastMouseTimestamp; + static void waitForEvents() { #ifdef Q_OS_MAC @@ -83,52 +87,48 @@ namespace QTest QTest::qWarn("Mouse event occurs outside of target window."); } - static Qt::MouseButton lastButton = Qt::NoButton; - if (delay == -1 || delay < defaultMouseDelay()) delay = defaultMouseDelay(); - if (delay > 0) + if (delay > 0) { QTest::qWait(delay); + lastMouseTimestamp += delay; + } if (pos.isNull()) pos = window->geometry().center(); - if (action == MouseClick) { - mouseEvent(MousePress, window, button, stateKey, pos); - mouseEvent(MouseRelease, window, button, stateKey, pos); - return; - } QTEST_ASSERT(uint(stateKey) == 0 || stateKey & Qt::KeyboardModifierMask); stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask); + QPointF global = window->mapToGlobal(pos); + QPointer<QWindow> w(window); switch (action) { - case MousePress: - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),button,stateKey); - lastButton = button; - break; - case MouseRelease: - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),Qt::NoButton,stateKey); - lastButton = Qt::NoButton; - break; - case MouseDClick: - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),button,stateKey); - qWait(10); - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),Qt::NoButton,stateKey); - qWait(20); - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),button,stateKey); - qWait(10); - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),Qt::NoButton,stateKey); - break; - case MouseMove: - qt_handleMouseEvent(window,pos,window->mapToGlobal(pos),lastButton,stateKey); - // No QCursor::setPos() call here. That could potentially result in mouse events sent by the windowing system - // which is highly undesired here. Tests must avoid relying on QCursor. + case MouseDClick: + qt_handleMouseEvent(w, pos, global, button, stateKey, ++lastMouseTimestamp); + qt_handleMouseEvent(w, pos, global, Qt::NoButton, stateKey, ++lastMouseTimestamp); + // fall through + case MousePress: + case MouseClick: + qt_handleMouseEvent(w, pos, global, button, stateKey, ++lastMouseTimestamp); + lastMouseButton = button; + if (action == MousePress) break; - default: - QTEST_ASSERT(false); + // fall through + case MouseRelease: + qt_handleMouseEvent(w, pos, global, Qt::NoButton, stateKey, ++lastMouseTimestamp); + lastMouseTimestamp += 500; // avoid double clicks being generated + lastMouseButton = Qt::NoButton; + break; + case MouseMove: + qt_handleMouseEvent(w, pos, global, lastMouseButton, stateKey, ++lastMouseTimestamp); + // No QCursor::setPos() call here. That could potentially result in mouse events sent by the windowing system + // which is highly undesired here. Tests must avoid relying on QCursor. + break; + default: + QTEST_ASSERT(false); } waitForEvents(); } @@ -153,6 +153,15 @@ namespace QTest Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1) { QTEST_ASSERT(widget); + + if (pos.isNull()) + pos = widget->rect().center(); + +#ifdef QTEST_QPA_MOUSE_HANDLING + QWindow *w = widget->window()->windowHandle(); + QTEST_ASSERT(w); + mouseEvent(action, w, button, stateKey, w->mapFromGlobal(widget->mapToGlobal(pos)), delay); +#else extern int Q_TESTLIB_EXPORT defaultMouseDelay(); if (delay == -1 || delay < defaultMouseDelay()) @@ -160,9 +169,6 @@ namespace QTest if (delay > 0) QTest::qWait(delay); - if (pos.isNull()) - pos = widget->rect().center(); - if (action == MouseClick) { mouseEvent(MousePress, widget, button, stateKey, pos); mouseEvent(MouseRelease, widget, button, stateKey, pos); @@ -198,12 +204,12 @@ namespace QTest } QSpontaneKeyEvent::setSpontaneous(&me); if (!qApp->notify(widget, &me)) { - static const char *mouseActionNames[] = + static const char *const mouseActionNames[] = { "MousePress", "MouseRelease", "MouseClick", "MouseDClick", "MouseMove" }; QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving widget"); QTest::qWarn(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(action)])).toLatin1().data()); } - +#endif } inline void mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index 52bcdd097b..2d9bae5f31 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -56,6 +56,7 @@ SOURCES = qtestcase.cpp \ qcsvbenchmarklogger.cpp \ qtestelement.cpp \ qtestelementattribute.cpp \ + qtestmouse.cpp \ qtestxunitstreamer.cpp \ qxunittestlogger.cpp \ qtestblacklist.cpp |