summaryrefslogtreecommitdiffstats
path: root/src/testlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/testlib')
-rw-r--r--src/testlib/qtestcase.cpp48
-rw-r--r--src/testlib/qtestcase.h47
-rw-r--r--src/testlib/qtestlog.cpp73
-rw-r--r--src/testlib/qtestlog_p.h2
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();