diff options
Diffstat (limited to 'src/testlib')
-rw-r--r-- | src/testlib/qtestcase.cpp | 48 | ||||
-rw-r--r-- | src/testlib/qtestcase.h | 47 | ||||
-rw-r--r-- | src/testlib/qtestlog.cpp | 73 | ||||
-rw-r--r-- | src/testlib/qtestlog_p.h | 2 |
4 files changed, 152 insertions, 18 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index e170d2a044..224357dd85 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -165,6 +165,25 @@ QT_BEGIN_NAMESPACE \sa QVERIFY(), QTRY_COMPARE(), QTest::toString() */ +/*! \macro QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) + \since 5.3 + + \relates QTest + + The QVERIFY_EXCEPTION_THROWN macro executes an \a expression and tries + to catch an exception thrown from the \a expression. If the \a expression + throws an exception and its type is the same as \a exceptiontype + or \a exceptiontype is substitutable with the type of thrown exception + (i.e. usually the type of thrown exception is publically derived + from \a exceptiontype) then execution will be continued. If not-substitutable + type of exception is thrown or the \a expression doesn't throw an exception + at all, then a failure will be recorded in the test log and + the test won't be executed further. + + \note This macro can only be used in a test function that is invoked + by the test framework. +*/ + /*! \macro QTRY_VERIFY_WITH_TIMEOUT(condition, timeout) \since 5.0 @@ -1540,6 +1559,10 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) } else if (strcmp(argv[i], "-vb") == 0) { QBenchmarkGlobalData::current->verboseOutput = true; +#ifdef Q_OS_WINRT + } else if (strncmp(argv[i], "-ServerName:", 12) == 0) { + continue; +#endif } else if (argv[i][0] == '-') { fprintf(stderr, "Unknown option: '%s'\n\n%s", argv[i], testOptions); if (qml) { @@ -2170,13 +2193,15 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) qtest_qParseArgs(argc, argv, false); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (!noCrashHandler) { # ifndef Q_CC_MINGW _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); # endif +# ifndef Q_OS_WINRT SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX); SetUnhandledExceptionFilter(windowsFaultHandler); +# endif } // !noCrashHandler #endif // Q_OS_WIN) && !Q_OS_WINCE && !Q_OS_WINRT @@ -2325,6 +2350,27 @@ void QTest::ignoreMessage(QtMsgType type, const char *message) QTestLog::ignoreMessage(type, message); } +/*! + \overload + + Ignores messages created by qDebug() or qWarning(). If the \a message + matching \a messagePattern + with the corresponding \a type is outputted, it will be removed from the + test log. If the test finished and the \a message was not outputted, + a test failure is appended to the test log. + + \b {Note:} Invoking this function will only ignore one message. + If the message you want to ignore is outputted twice, you have to + call ignoreMessage() twice, too. + + \since 5.3 +*/ + +void QTest::ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern) +{ + QTestLog::ignoreMessage(type, messagePattern); +} + /*! \internal */ diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index ba727b5afe..f95a155ed9 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -51,8 +51,14 @@ #include <string.h> +#ifndef QT_NO_EXCEPTIONS +# include <exception> +#endif // QT_NO_EXCEPTIONS + + QT_BEGIN_NAMESPACE +class QRegularExpression; #define QVERIFY(statement) \ do {\ @@ -83,6 +89,46 @@ do {\ return;\ } while (0) + +#ifndef QT_NO_EXCEPTIONS + +# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \ + do {\ + QT_TRY {\ + QT_TRY {\ + expression;\ + QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \ + " but no exception caught", __FILE__, __LINE__);\ + return;\ + } QT_CATCH (const exceptiontype &) {\ + }\ + } QT_CATCH (const std::exception &e) {\ + QByteArray msg = QByteArray() + "Expected exception of type " #exceptiontype \ + " to be thrown but std::exception caught with message: " + e.what(); \ + QTest::qFail(msg.constData(), __FILE__, __LINE__);\ + return;\ + } QT_CATCH (...) {\ + QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \ + " but unknown exception caught", __FILE__, __LINE__);\ + return;\ + }\ + } while (0) + +#else // QT_NO_EXCEPTIONS + +/* + * The expression passed to the macro should throw an exception and we can't + * catch it because Qt has been compiled without exception support. We can't + * skip the expression because it may have side effects and must be executed. + * So, users must use Qt with exception support enabled if they use exceptions + * in their code. + */ +# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \ + Q_STATIC_ASSERT_X(false, "Support of exceptions is disabled") + +#endif // !QT_NO_EXCEPTIONS + + // Will try to wait for the expression to become true while allowing event processing #define QTRY_VERIFY_WITH_TIMEOUT(__expr, __timeout) \ do { \ @@ -191,6 +237,7 @@ namespace QTest const char *file, int line); Q_TESTLIB_EXPORT void qWarn(const char *message, const char *file = 0, int line = 0); Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message); + Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern); Q_TESTLIB_EXPORT QString qFindTestData(const char* basepath, const char* file = 0, int line = 0, const char* builddir = 0); Q_TESTLIB_EXPORT QString qFindTestData(const QString& basepath, const char* file = 0, int line = 0, const char* builddir = 0); diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp index bbca5b94e5..037bed643d 100644 --- a/src/testlib/qtestlog.cpp +++ b/src/testlib/qtestlog.cpp @@ -49,6 +49,8 @@ #include <QtTest/private/qxmltestlogger_p.h> #include <QtCore/qatomic.h> #include <QtCore/qbytearray.h> +#include <QtCore/QVariant> +#include <QtCore/QRegularExpression> #include <stdlib.h> #include <string.h> @@ -86,11 +88,8 @@ namespace QTest { struct IgnoreResultList { - inline IgnoreResultList(QtMsgType tp, const char *message) - : type(tp), next(0) - { msg = qstrdup(message); } - inline ~IgnoreResultList() - { delete [] msg; } + inline IgnoreResultList(QtMsgType tp, const QVariant &patternIn) + : type(tp), pattern(patternIn), next(0) {} static inline void clearList(IgnoreResultList *&list) { @@ -101,8 +100,43 @@ namespace QTest { } } + static void append(IgnoreResultList *&list, QtMsgType type, const QVariant &patternIn) + { + QTest::IgnoreResultList *item = new QTest::IgnoreResultList(type, patternIn); + + if (!list) { + list = item; + return; + } + IgnoreResultList *last = list; + for ( ; last->next; last = last->next) ; + last->next = item; + } + + static bool stringsMatch(const QString &expected, const QString &actual) + { + if (expected == actual) + return true; + + // ignore an optional whitespace at the end of str + // (the space was added automatically by ~QDebug() until Qt 5.3, + // so autotests still might expect it) + if (expected.endsWith(QLatin1Char(' '))) + return actual == expected.leftRef(expected.length() - 1); + + return false; + } + + inline bool matches(QtMsgType tp, const QString &message) const + { + return tp == type + && (pattern.type() == QVariant::String ? + stringsMatch(pattern.toString(), message) : + pattern.toRegularExpression().match(message).hasMatch()); + } + QtMsgType type; - char *msg; + QVariant pattern; IgnoreResultList *next; }; @@ -210,10 +244,13 @@ namespace QTest { static bool handleIgnoredMessage(QtMsgType type, const char *msg) { + if (!ignoreResultList) + return false; + const QString message = QString::fromLocal8Bit(msg); IgnoreResultList *last = 0; IgnoreResultList *list = ignoreResultList; while (list) { - if (list->type == type && strcmp(msg, list->msg) == 0) { + if (list->matches(type, message)) { // remove the item from the list if (last) last->next = list->next; @@ -320,7 +357,11 @@ void QTestLog::printUnhandledIgnoreMessages() char msg[1024]; QTest::IgnoreResultList *list = QTest::ignoreResultList; while (list) { - qsnprintf(msg, 1024, "Did not receive message: \"%s\"", list->msg); + if (list->pattern.type() == QVariant::String) { + qsnprintf(msg, 1024, "Did not receive message: \"%s\"", qPrintable(list->pattern.toString())); + } else { + qsnprintf(msg, 1024, "Did not receive any message matching: \"%s\"", qPrintable(list->pattern.toRegularExpression().pattern())); + } QTest::TestLoggers::addMessage(QAbstractTestLogger::Info, msg); list = list->next; @@ -466,16 +507,14 @@ void QTestLog::ignoreMessage(QtMsgType type, const char *msg) { QTEST_ASSERT(msg); - QTest::IgnoreResultList *item = new QTest::IgnoreResultList(type, msg); + QTest::IgnoreResultList::append(QTest::ignoreResultList, type, QString::fromLocal8Bit(msg)); +} - QTest::IgnoreResultList *list = QTest::ignoreResultList; - if (!list) { - QTest::ignoreResultList = item; - return; - } - while (list->next) - list = list->next; - list->next = item; +void QTestLog::ignoreMessage(QtMsgType type, const QRegularExpression &expression) +{ + QTEST_ASSERT(expression.isValid()); + + QTest::IgnoreResultList::append(QTest::ignoreResultList, type, QVariant(expression)); } void QTestLog::setMaxWarnings(int m) diff --git a/src/testlib/qtestlog_p.h b/src/testlib/qtestlog_p.h index df3e2ab5d4..bd83870934 100644 --- a/src/testlib/qtestlog_p.h +++ b/src/testlib/qtestlog_p.h @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE class QBenchmarkResult; +class QRegularExpression; class Q_TESTLIB_EXPORT QTestLog { @@ -75,6 +76,7 @@ public: static void addBenchmarkResult(const QBenchmarkResult &result); static void ignoreMessage(QtMsgType type, const char *msg); + static void ignoreMessage(QtMsgType type, const QRegularExpression &expression); static int unhandledIgnoreMessages(); static void printUnhandledIgnoreMessages(); static void clearIgnoreMessages(); |