summaryrefslogtreecommitdiffstats
path: root/src/testlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/testlib')
-rw-r--r--src/testlib/qtest.h13
-rw-r--r--src/testlib/qtestblacklist.cpp14
-rw-r--r--src/testlib/qtestcase.cpp103
-rw-r--r--src/testlib/qtestcase.h32
-rw-r--r--src/testlib/qtestcase.qdoc34
-rw-r--r--src/testlib/qtestkeyboard.h20
6 files changed, 170 insertions, 46 deletions
diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h
index ba63df5f36..4abba93721 100644
--- a/src/testlib/qtest.h
+++ b/src/testlib/qtest.h
@@ -65,9 +65,14 @@ QT_BEGIN_NAMESPACE
namespace QTest
{
+template <> inline char *toString(const QStringView &str)
+{
+ return QTest::toPrettyUnicode(str);
+}
+
template<> inline char *toString(const QString &str)
{
- return QTest::toPrettyUnicode(reinterpret_cast<const ushort *>(str.constData()), str.length());
+ return toString(QStringView(str));
}
template<> inline char *toString(const QLatin1String &str)
@@ -84,21 +89,21 @@ template<> inline char *toString(const QByteArray &ba)
template<> inline char *toString(const QTime &time)
{
return time.isValid()
- ? qstrdup(qPrintable(time.toString(QLatin1String("hh:mm:ss.zzz"))))
+ ? qstrdup(qPrintable(time.toString(QStringViewLiteral("hh:mm:ss.zzz"))))
: qstrdup("Invalid QTime");
}
template<> inline char *toString(const QDate &date)
{
return date.isValid()
- ? qstrdup(qPrintable(date.toString(QLatin1String("yyyy/MM/dd"))))
+ ? qstrdup(qPrintable(date.toString(QStringViewLiteral("yyyy/MM/dd"))))
: qstrdup("Invalid QDate");
}
template<> inline char *toString(const QDateTime &dateTime)
{
return dateTime.isValid()
- ? qstrdup(qPrintable(dateTime.toString(QLatin1String("yyyy/MM/dd hh:mm:ss.zzz[t]"))))
+ ? qstrdup(qPrintable(dateTime.toString(QStringViewLiteral("yyyy/MM/dd hh:mm:ss.zzz[t]"))))
: qstrdup("Invalid QDateTime");
}
#endif // QT_NO_DATESTRING
diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp
index 57661bb389..b24ce0578e 100644
--- a/src/testlib/qtestblacklist.cpp
+++ b/src/testlib/qtestblacklist.cpp
@@ -58,9 +58,10 @@ QT_BEGIN_NAMESPACE
referring to this documentation is kind to readers. Comments can also be used
to indicate the reasons for ignoring particular cases.
- A key names a platform, O/S, distribution, tool-chain or architecture; a !
- prefix reverses what it checks. A version, joined to a key (at present, only
- for distributions and for msvc) with a hyphen, limits the key to the specific
+ The key "ci" applies only when run by COIN. Other keys name platforms,
+ operating systems, distributions, tool-chains or architectures; a ! prefix
+ reverses what it checks. A version, joined to a key (at present, only for
+ distributions and for msvc) with a hyphen, limits the key to the specific
version. A keyword line matches if every key on it applies to the present
run. Successive lines are alternate conditions for ignoring a test.
@@ -70,13 +71,18 @@ QT_BEGIN_NAMESPACE
Subsequent lines give conditions for ignoring this test.
# See qtbase/src/testlib/qtestblacklist.cpp for format
- osx
+ # Test doesn't work on QNX at all
+ qnx
# QTBUG-12345
[testFunction]
linux
windows 64bit
+ # Flaky in COIN on macOS, not reproducible by developers
+ [testSlowly]
+ ci osx
+
# Needs basic C++11 support
[testfunction2:testData]
msvc-2010
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index 8b0820b941..a4099c3cd8 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -275,6 +275,11 @@ namespace QTest
static QObject *currentTestObject = 0;
static QString mainSourcePath;
+#if defined(Q_OS_MACOS)
+ bool macNeedsActivate = false;
+ IOPMAssertionID powerID;
+#endif
+
class TestMethods {
Q_DISABLE_COPY(TestMethods)
public:
@@ -1271,6 +1276,16 @@ char *toPrettyCString(const char *p, int length)
return buffer.take();
}
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+// this used to be the signature up to and including Qt 5.9
+// keep it for BC reasons:
+Q_TESTLIB_EXPORT
+char *toPrettyUnicode(const ushort *p, int length)
+{
+ return toPrettyUnicode(QStringView(p, length));
+}
+#endif
+
/*!
\internal
Returns the same QString but with only the ASCII characters still shown;
@@ -1278,8 +1293,10 @@ char *toPrettyCString(const char *p, int length)
Similar to QDebug::putString().
*/
-char *toPrettyUnicode(const ushort *p, int length)
+char *toPrettyUnicode(QStringView string)
{
+ auto p = reinterpret_cast<const ushort *>(string.utf16());
+ auto length = string.size();
// keep it simple for the vast majority of cases
bool trimmed = false;
QScopedArrayPointer<char> buffer(new char[256]);
@@ -1345,9 +1362,7 @@ void TestMethods::invokeTests(QObject *testObject) const
{
const QMetaObject *metaObject = testObject->metaObject();
QTEST_ASSERT(metaObject);
- QTestLog::startLogging();
QTestResult::setCurrentTestFunction("initTestCase");
- QTestTable::globalTestTable();
if (m_initTestCaseDataMethod.isValid())
m_initTestCaseDataMethod.invoke(testObject, Qt::DirectConnection);
@@ -1392,9 +1407,6 @@ void TestMethods::invokeTests(QObject *testObject) const
}
QTestResult::finishedCurrentTestFunction();
QTestResult::setCurrentTestFunction(0);
- QTestTable::clearGlobalTestTable();
-
- QTestLog::stopLogging();
}
#if defined(Q_OS_UNIX)
@@ -1698,24 +1710,25 @@ static void initEnvironment()
int QTest::qExec(QObject *testObject, int argc, char **argv)
{
- initEnvironment();
- QBenchmarkGlobalData benchmarkData;
- QBenchmarkGlobalData::current = &benchmarkData;
+ qInit(testObject, argc, argv);
+ int ret = qRun();
+ qCleanup();
+ return ret;
+}
-#ifdef QTESTLIB_USE_VALGRIND
- int callgrindChildExitCode = 0;
-#endif
+/*! \internal
+ */
+void QTest::qInit(QObject *testObject, int argc, char **argv)
+{
+ initEnvironment();
+ QBenchmarkGlobalData::current = new QBenchmarkGlobalData;
#if defined(Q_OS_MACX)
- bool macNeedsActivate = qApp && (qstrcmp(qApp->metaObject()->className(), "QApplication") == 0);
- IOPMAssertionID powerID;
+ macNeedsActivate = qApp && (qstrcmp(qApp->metaObject()->className(), "QApplication") == 0);
// Don't restore saved window state for auto tests.
QTestPrivate::disableWindowRestore();
#endif
-#ifndef QT_NO_EXCEPTIONS
- try {
-#endif
#if defined(Q_OS_MACX)
if (macNeedsActivate) {
@@ -1745,6 +1758,24 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
qtest_qParseArgs(argc, argv, false);
+ QTestTable::globalTestTable();
+ QTestLog::startLogging();
+}
+
+/*! \internal
+ */
+int QTest::qRun()
+{
+ QTEST_ASSERT(currentTestObject);
+
+#ifdef QTESTLIB_USE_VALGRIND
+ int callgrindChildExitCode = 0;
+#endif
+
+#ifndef QT_NO_EXCEPTIONS
+ try {
+#endif
+
#if defined(Q_OS_WIN)
if (!noCrashHandler) {
# ifndef Q_CC_MINGW
@@ -1780,17 +1811,17 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
for (const QString &tf : qAsConst(QTest::testFunctions)) {
const QByteArray tfB = tf.toLatin1();
const QByteArray signature = tfB + QByteArrayLiteral("()");
- QMetaMethod m = TestMethods::findMethod(testObject, signature.constData());
+ QMetaMethod m = TestMethods::findMethod(currentTestObject, signature.constData());
if (!m.isValid() || !isValidSlot(m)) {
fprintf(stderr, "Unknown test function: '%s'. Possible matches:\n", tfB.constData());
qPrintTestSlots(stderr, tfB.constData());
- fprintf(stderr, "\n%s -functions\nlists all available test functions.\n", argv[0]);
+ fprintf(stderr, "\n%s -functions\nlists all available test functions.\n", QTestResult::currentAppName());
exit(1);
}
commandLineMethods.push_back(m);
}
- TestMethods test(testObject, commandLineMethods);
- test.invokeTests(testObject);
+ TestMethods test(currentTestObject, commandLineMethods);
+ test.invokeTests(currentTestObject);
}
#ifndef QT_NO_EXCEPTIONS
@@ -1815,16 +1846,6 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
}
#endif
- currentTestObject = 0;
-
- QSignalDumper::endDump();
-
-#if defined(Q_OS_MACX)
- if (macNeedsActivate) {
- IOPMAssertionRelease(powerID);
- }
-#endif
-
#ifdef QTESTLIB_USE_VALGRIND
if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess)
return callgrindChildExitCode;
@@ -1834,6 +1855,26 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
return qMin(QTestLog::failCount(), 127);
}
+/*! \internal
+ */
+void QTest::qCleanup()
+{
+ currentTestObject = 0;
+
+ QTestTable::clearGlobalTestTable();
+ QTestLog::stopLogging();
+
+ delete QBenchmarkGlobalData::current;
+ QBenchmarkGlobalData::current = 0;
+
+ QSignalDumper::endDump();
+
+#if defined(Q_OS_MACOS)
+ if (macNeedsActivate)
+ IOPMAssertionRelease(powerID);
+#endif
+}
+
/*!
\overload
\since 4.4
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h
index a59eb4ecb3..fafc0eb7d6 100644
--- a/src/testlib/qtestcase.h
+++ b/src/testlib/qtestcase.h
@@ -259,12 +259,32 @@ namespace QTest
return Internal::toString(t);
}
+ template <typename T1, typename T2>
+ inline char *toString(const QPair<T1, T2> &pair)
+ {
+ const QScopedArrayPointer<char> first(toString(pair.first));
+ const QScopedArrayPointer<char> second(toString(pair.second));
+ return toString(QString::asprintf("QPair(%s,%s)", first.data(), second.data()));
+ }
+
+ template <typename T1, typename T2>
+ inline char *toString(const std::pair<T1, T2> &pair)
+ {
+ const QScopedArrayPointer<char> first(toString(pair.first));
+ const QScopedArrayPointer<char> second(toString(pair.second));
+ return toString(QString::asprintf("std::pair(%s,%s)", first.data(), second.data()));
+ }
+
Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, int length);
Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, int length);
- Q_TESTLIB_EXPORT char *toPrettyUnicode(const ushort *unicode, int length);
+ Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
Q_TESTLIB_EXPORT char *toString(const char *);
Q_TESTLIB_EXPORT char *toString(const void *);
+ Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc = 0, char **argv = Q_NULLPTR);
+ Q_TESTLIB_EXPORT int qRun();
+ Q_TESTLIB_EXPORT void qCleanup();
+
Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = Q_NULLPTR);
Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments);
@@ -319,6 +339,8 @@ namespace QTest
Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag);
Q_TESTLIB_EXPORT QTestData &addRow(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ // kept after adding implementation of <T1, T2> out of paranoia:
template <typename T>
inline bool qCompare(T const &t1, T const &t2, const char *actual, const char *expected,
const char *file, int line)
@@ -326,6 +348,7 @@ namespace QTest
return compare_helper(t1 == t2, "Compared values are not the same",
toString(t1), toString(t2), actual, expected, file, line);
}
+#endif
Q_TESTLIB_EXPORT bool qCompare(float const &t1, float const &t2,
const char *actual, const char *expected, const char *file, int line);
@@ -376,7 +399,12 @@ namespace QTest
#endif
template <typename T1, typename T2>
- bool qCompare(T1 const &, T2 const &, const char *, const char *, const char *, int);
+ inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected,
+ const char *file, int line)
+ {
+ return compare_helper(t1 == t2, "Compared values are not the same",
+ toString(t1), toString(t2), actual, expected, file, line);
+ }
inline bool qCompare(double const &t1, float const &t2, const char *actual,
const char *expected, const char *file, int line)
diff --git a/src/testlib/qtestcase.qdoc b/src/testlib/qtestcase.qdoc
index 8f3d140add..2d1e27ec40 100644
--- a/src/testlib/qtestcase.qdoc
+++ b/src/testlib/qtestcase.qdoc
@@ -82,11 +82,6 @@
QCOMPARE tries to output the contents of the values if the comparison fails,
so it is visible from the test log why the comparison failed.
- QCOMPARE is very strict on the data types. Both \a actual and \a expected
- have to be of the same type, otherwise the test won't compile. This prohibits
- unspecified behavior from being introduced; that is behavior that usually
- occurs when the compiler implicitly casts the argument.
-
For your own classes, you can use \l QTest::toString() to format values for
outputting into the test log.
@@ -575,6 +570,15 @@
\sa QTest::keyClicks()
*/
+/*! \fn void QTest::keySequence(QWidget *widget, const QKeySequence &keySequence)
+ \overload
+ \since 5.10
+
+ Simulates typing of \a keySequence into a \a widget.
+
+ \sa QTest::keyClick(), QTest::keyClicks()
+*/
+
/*! \fn void QTest::keyClick(QWindow *window, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
\overload
\since 5.0
@@ -611,6 +615,15 @@
\sa QTest::keyClicks()
*/
+/*! \fn void QTest::keySequence(QWindow *window, const QKeySequence &keySequence)
+ \overload
+ \since 5.10
+
+ Simulates typing of \a keySequence into a \a window.
+
+ \sa QTest::keyClick(), QTest::keyClicks()
+*/
+
/*! \fn void QTest::keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
Sends a Qt key event to \a widget with the given \a key and an associated \a action.
@@ -1071,6 +1084,10 @@
This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some
time after being asked to show itself on the screen.
+ Note that a window that is mapped to screen may still not be considered exposed if the window client
+ area is completely covered by other windows, or if the window is otherwise not visible. This function
+ will then time out when waiting for such a window.
+
\sa QTest::qWaitForWindowActive(), QWindow::isExposed()
*/
@@ -1093,6 +1110,13 @@
This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some
time after being asked to show itself on the screen.
+ Note that a window that is mapped to screen may still not be considered exposed if the window client
+ area is completely covered by other windows, or if the window is otherwise not visible. This function
+ will then time out when waiting for such a window.
+
+ A specific configuration where this happens is when using QGLWidget as a viewport widget on macOS:
+ The viewport widget gets the expose event, not the parent widget.
+
\sa QTest::qWaitForWindowActive()
*/
diff --git a/src/testlib/qtestkeyboard.h b/src/testlib/qtestkeyboard.h
index e750fdb5a9..a7cf78f25a 100644
--- a/src/testlib/qtestkeyboard.h
+++ b/src/testlib/qtestkeyboard.h
@@ -54,6 +54,7 @@
#include <QtGui/qguiapplication.h>
#include <QtGui/qwindow.h>
#include <QtGui/qevent.h>
+#include <QtGui/qkeysequence.h>
#ifdef QT_WIDGETS_LIB
#include <QtWidgets/qwidget.h>
@@ -165,6 +166,15 @@ namespace QTest
Q_DECL_UNUSED inline static void keyPress(QWindow *window, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
{ keyEvent(Press, window, key, modifier, delay); }
+ Q_DECL_UNUSED inline static void keySequence(QWindow *window, const QKeySequence &keySequence)
+ {
+ for (int i = 0; i < keySequence.count(); ++i) {
+ const Qt::Key key = Qt::Key(keySequence[i] & ~Qt::KeyboardModifierMask);
+ const Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(keySequence[i] & Qt::KeyboardModifierMask);
+ keyClick(window, key, modifiers);
+ }
+ }
+
#ifdef QT_WIDGETS_LIB
static void simulateEvent(QWidget *widget, bool press, int code,
Qt::KeyboardModifiers modifier, QString text, bool repeat, int delay=-1)
@@ -294,6 +304,16 @@ namespace QTest
{ keyEvent(Release, widget, key, modifier, delay); }
inline static void keyClick(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
{ keyEvent(Click, widget, key, modifier, delay); }
+
+ inline static void keySequence(QWidget *widget, const QKeySequence &keySequence)
+ {
+ for (int i = 0; i < keySequence.count(); ++i) {
+ const Qt::Key key = Qt::Key(keySequence[i] & ~Qt::KeyboardModifierMask);
+ const Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(keySequence[i] & Qt::KeyboardModifierMask);
+ keyClick(widget, key, modifiers);
+ }
+ }
+
#endif // QT_WIDGETS_LIB
}