diff options
Diffstat (limited to 'src/testlib')
-rw-r--r-- | src/testlib/doc/qttestlib.qdocconf | 1 | ||||
-rw-r--r-- | src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp | 5 | ||||
-rw-r--r-- | src/testlib/qabstracttestlogger_p.h | 4 | ||||
-rw-r--r-- | src/testlib/qbenchmarkvalgrind.cpp | 2 | ||||
-rw-r--r-- | src/testlib/qplaintestlogger.cpp | 31 | ||||
-rw-r--r-- | src/testlib/qsignalspy.h | 57 | ||||
-rw-r--r-- | src/testlib/qsignalspy.qdoc | 14 | ||||
-rw-r--r-- | src/testlib/qtest.h | 6 | ||||
-rw-r--r-- | src/testlib/qtestaccessible.h | 51 | ||||
-rw-r--r-- | src/testlib/qtestblacklist.cpp | 201 | ||||
-rw-r--r-- | src/testlib/qtestblacklist_p.h | 67 | ||||
-rw-r--r-- | src/testlib/qtestcase.cpp | 18 | ||||
-rw-r--r-- | src/testlib/qtestlog.cpp | 33 | ||||
-rw-r--r-- | src/testlib/qtestlog_p.h | 3 | ||||
-rw-r--r-- | src/testlib/qtestresult.cpp | 17 | ||||
-rw-r--r-- | src/testlib/qtestresult_p.h | 1 | ||||
-rw-r--r-- | src/testlib/qxmltestlogger.cpp | 11 | ||||
-rw-r--r-- | src/testlib/qxunittestlogger.cpp | 28 | ||||
-rw-r--r-- | src/testlib/testlib.pro | 7 |
19 files changed, 512 insertions, 45 deletions
diff --git a/src/testlib/doc/qttestlib.qdocconf b/src/testlib/doc/qttestlib.qdocconf index 92e5c97aab..35b4fbcb7b 100644 --- a/src/testlib/doc/qttestlib.qdocconf +++ b/src/testlib/doc/qttestlib.qdocconf @@ -2,7 +2,6 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) project = QtTestLib description = Qt Test Reference Documentation -url = http://qt-project.org/doc/qt-$QT_VER version = $QT_VERSION examplesinstallpath = testlib diff --git a/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp b/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp index e4702c6e0b..0856de9450 100644 --- a/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp +++ b/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp @@ -83,3 +83,8 @@ QSignalSpy spy(myPushButton, SIGNAL(clicked(bool))); //! [5] QVERIFY(spy.wait(1000)); //! [5] + +//! [6] +QSignalSpy spy(myPushButton, &QPushButton::clicked); +//! [6] + diff --git a/src/testlib/qabstracttestlogger_p.h b/src/testlib/qabstracttestlogger_p.h index c549233ddb..6bb54d1af8 100644 --- a/src/testlib/qabstracttestlogger_p.h +++ b/src/testlib/qabstracttestlogger_p.h @@ -68,7 +68,9 @@ public: Pass, XFail, Fail, - XPass + XPass, + BlacklistedPass, + BlacklistedFail }; enum MessageTypes { diff --git a/src/testlib/qbenchmarkvalgrind.cpp b/src/testlib/qbenchmarkvalgrind.cpp index 545de3bb65..cd804774e9 100644 --- a/src/testlib/qbenchmarkvalgrind.cpp +++ b/src/testlib/qbenchmarkvalgrind.cpp @@ -66,7 +66,7 @@ bool QBenchmarkValgrindUtils::haveValgrind() if (!process.waitForFinished(-1)) return false; const QByteArray out = process.readAllStandardOutput(); - QRegExp rx(QLatin1String("^valgrind-([0-9]).([0-9]).[0-9]")); + QRegExp rx(QLatin1String("^valgrind-([0-9]+).([0-9]+).[0-9]+")); if (rx.indexIn(QLatin1String(out.data())) == -1) return false; bool ok; diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp index 39580f22d4..74f0290f38 100644 --- a/src/testlib/qplaintestlogger.cpp +++ b/src/testlib/qplaintestlogger.cpp @@ -51,21 +51,29 @@ #include <stdlib.h> #include <string.h> -#ifdef Q_OS_WIN -#include <windows.h> -#endif - #ifdef Q_OS_WINCE #include <QtCore/QString> #endif +#ifdef min // windows.h without NOMINMAX is included by the benchmark headers. +# undef min +#endif +#ifdef max +# undef max +#endif + #include <QtCore/QByteArray> #include <QtCore/qmath.h> +#include <QtCore/QLibraryInfo> #ifdef Q_OS_ANDROID # include <android/log.h> #endif +#ifdef Q_OS_WIN +# include <qt_windows.h> +#endif + QT_BEGIN_NAMESPACE namespace QTest { @@ -81,6 +89,10 @@ namespace QTest { return "FAIL! "; case QAbstractTestLogger::XPass: return "XPASS "; + case QAbstractTestLogger::BlacklistedPass: + return "BPASS "; + case QAbstractTestLogger::BlacklistedFail: + return "BFAIL "; } return "??????"; } @@ -334,7 +346,7 @@ void QPlainTestLogger::startLogging() qsnprintf(buf, sizeof(buf), "********* Start testing of %s *********\n" "Config: Using QtTest library " QTEST_VERSION_STR - ", Qt %s\n", QTestResult::currentTestObjectName(), qVersion()); + ", %s\n", QTestResult::currentTestObjectName(), QLibraryInfo::build()); } outputMessage(buf); } @@ -343,15 +355,16 @@ void QPlainTestLogger::stopLogging() { char buf[1024]; if (QTestLog::verboseLevel() < 0) { - qsnprintf(buf, sizeof(buf), "Totals: %d passed, %d failed, %d skipped\n", + qsnprintf(buf, sizeof(buf), "Totals: %d passed, %d failed, %d skipped, %d blacklisted\n", QTestLog::passCount(), QTestLog::failCount(), - QTestLog::skipCount()); + QTestLog::skipCount(), QTestLog::blacklistCount()); } else { qsnprintf(buf, sizeof(buf), - "Totals: %d passed, %d failed, %d skipped\n" + "Totals: %d passed, %d failed, %d skipped, %d blacklisted\n" "********* Finished testing of %s *********\n", QTestLog::passCount(), QTestLog::failCount(), - QTestLog::skipCount(), QTestResult::currentTestObjectName()); + QTestLog::skipCount(), QTestLog::blacklistCount(), + QTestResult::currentTestObjectName()); } outputMessage(buf); diff --git a/src/testlib/qsignalspy.h b/src/testlib/qsignalspy.h index 72a5df1ed9..3ce1c6f99b 100644 --- a/src/testlib/qsignalspy.h +++ b/src/testlib/qsignalspy.h @@ -98,6 +98,48 @@ public: initArgs(mo->method(sigIndex), obj); } +#ifdef Q_QDOC + QSignalSpy(const QObject *object, PointerToMemberFunction signal); +#else + template <typename Func> + QSignalSpy(const typename QtPrivate::FunctionPointer<Func>::Object *obj, Func signal0) + : m_waiting(false) + { +#ifdef Q_CC_BOR + const int memberOffset = QObject::staticMetaObject.methodCount(); +#else + static const int memberOffset = QObject::staticMetaObject.methodCount(); +#endif + if (!obj) { + qWarning("QSignalSpy: Cannot spy on a null object"); + return; + } + + if (!signal0) { + qWarning("QSignalSpy: Null signal name is not valid"); + return; + } + + const QMetaObject * const mo = obj->metaObject(); + const QMetaMethod signalMetaMethod = QMetaMethod::fromSignal(signal0); + const int sigIndex = signalMetaMethod.methodIndex(); + if (!signalMetaMethod.isValid() || + signalMetaMethod.methodType() != QMetaMethod::Signal) { + qWarning("QSignalSpy: Not a valid signal: '%s'", + signalMetaMethod.methodSignature().constData()); + return; + } + + if (!QMetaObject::connect(obj, sigIndex, this, memberOffset, + Qt::DirectConnection, 0)) { + qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect."); + return; + } + sig = signalMetaMethod.methodSignature(); + initArgs(mo->method(sigIndex), obj); + } +#endif // Q_QDOC + inline bool isValid() const { return !sig.isEmpty(); } inline QByteArray signal() const { return sig; } @@ -127,17 +169,11 @@ public: } private: - void initArgs(const QMetaMethod &member) - { - initArgs(member, 0); - } - void initArgs(const QMetaMethod &member, const QObject *obj) { - const QList<QByteArray> params = member.parameterTypes(); - args.reserve(params.size()); - for (int i = 0; i < params.count(); ++i) { - int tp = QMetaType::type(params.at(i).constData()); + args.reserve(member.parameterCount()); + for (int i = 0; i < member.parameterCount(); ++i) { + int tp = member.parameterType(i); if (tp == QMetaType::UnknownType && obj) { void *argv[] = { &tp, &i }; QMetaObject::metacall(const_cast<QObject*>(obj), @@ -147,9 +183,8 @@ private: tp = QMetaType::UnknownType; } if (tp == QMetaType::UnknownType) { - Q_ASSERT(tp != QMetaType::Void); // void parameter => metaobject is corrupt qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.", - params.at(i).constData()); + member.parameterNames().at(i).constData()); } args << tp; } diff --git a/src/testlib/qsignalspy.qdoc b/src/testlib/qsignalspy.qdoc index 9559090e8f..31cdeaba6a 100644 --- a/src/testlib/qsignalspy.qdoc +++ b/src/testlib/qsignalspy.qdoc @@ -72,6 +72,20 @@ \snippet code/doc_src_qsignalspy.cpp 4 */ +/*! \fn QSignalSpy::QSignalSpy(const QObject *object, PointerToMemberFunction signal) + \since 5.4 + + Constructs a new QSignalSpy that listens for emissions of the \a signal + from the QObject \a object. If QSignalSpy is not able to listen for a + valid signal (for example, because \a object is null or \a signal does + not denote a valid signal of \a object), an explanatory warning message + will be output using qWarning() and subsequent calls to \c isValid() will + return false. + + Example: + \snippet code/doc_src_qsignalspy.cpp 6 +*/ + /*! \fn QSignalSpy::isValid() const Returns \c true if the signal spy listens to a valid signal, otherwise false. diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h index 7d2f3cea72..8a18ea7541 100644 --- a/src/testlib/qtest.h +++ b/src/testlib/qtest.h @@ -54,6 +54,7 @@ #include <QtCore/qobject.h> #include <QtCore/qvariant.h> #include <QtCore/qurl.h> +#include <QtCore/qversionnumber.h> #include <QtCore/qpoint.h> #include <QtCore/qsize.h> @@ -171,6 +172,11 @@ template<> inline char *toString(const QVariant &v) return qstrdup(vstring.constData()); } +template<> inline char *toString(const QVersionNumber &version) +{ + return toString(version.toString()); +} + template<> inline bool qCompare(QString const &t1, QLatin1String const &t2, const char *actual, const char *expected, const char *file, int line) diff --git a/src/testlib/qtestaccessible.h b/src/testlib/qtestaccessible.h index ef6f61bd82..65fbd4c818 100644 --- a/src/testlib/qtestaccessible.h +++ b/src/testlib/qtestaccessible.h @@ -194,42 +194,75 @@ private: { QAccessibleEvent *ev; if (event->type() == QAccessible::StateChanged) { - ev = new QAccessibleStateChangeEvent(event->object(), + if (event->object()) + ev = new QAccessibleStateChangeEvent(event->object(), + static_cast<QAccessibleStateChangeEvent*>(event)->changedStates()); + else + ev = new QAccessibleStateChangeEvent(event->accessibleInterface(), static_cast<QAccessibleStateChangeEvent*>(event)->changedStates()); } else if (event->type() == QAccessible::TextCaretMoved) { - ev = new QAccessibleTextCursorEvent(event->object(), static_cast<QAccessibleTextCursorEvent*>(event)->cursorPosition()); + if (event->object()) + ev = new QAccessibleTextCursorEvent(event->object(), static_cast<QAccessibleTextCursorEvent*>(event)->cursorPosition()); + else + ev = new QAccessibleTextCursorEvent(event->accessibleInterface(), static_cast<QAccessibleTextCursorEvent*>(event)->cursorPosition()); } else if (event->type() == QAccessible::TextSelectionChanged) { const QAccessibleTextSelectionEvent *original = static_cast<QAccessibleTextSelectionEvent*>(event); - QAccessibleTextSelectionEvent *sel = new QAccessibleTextSelectionEvent(event->object(), original->selectionStart(), original->selectionEnd()); + QAccessibleTextSelectionEvent *sel; + if (event->object()) + sel = new QAccessibleTextSelectionEvent(event->object(), original->selectionStart(), original->selectionEnd()); + else + sel = new QAccessibleTextSelectionEvent(event->accessibleInterface(), original->selectionStart(), original->selectionEnd()); sel->setCursorPosition(original->cursorPosition()); ev = sel; } else if (event->type() == QAccessible::TextInserted) { const QAccessibleTextInsertEvent *original = static_cast<QAccessibleTextInsertEvent*>(event); - QAccessibleTextInsertEvent *ins = new QAccessibleTextInsertEvent(event->object(), original->changePosition(), original->textInserted()); + QAccessibleTextInsertEvent *ins; + if (original->object()) + ins = new QAccessibleTextInsertEvent(event->object(), original->changePosition(), original->textInserted()); + else + ins = new QAccessibleTextInsertEvent(event->accessibleInterface(), original->changePosition(), original->textInserted()); ins->setCursorPosition(original->cursorPosition()); ev = ins; } else if (event->type() == QAccessible::TextRemoved) { const QAccessibleTextRemoveEvent *original = static_cast<QAccessibleTextRemoveEvent*>(event); - QAccessibleTextRemoveEvent *rem = new QAccessibleTextRemoveEvent(event->object(), original->changePosition(), original->textRemoved()); + QAccessibleTextRemoveEvent *rem; + if (event->object()) + rem = new QAccessibleTextRemoveEvent(event->object(), original->changePosition(), original->textRemoved()); + else + rem = new QAccessibleTextRemoveEvent(event->accessibleInterface(), original->changePosition(), original->textRemoved()); rem->setCursorPosition(original->cursorPosition()); ev = rem; } else if (event->type() == QAccessible::TextUpdated) { const QAccessibleTextUpdateEvent *original = static_cast<QAccessibleTextUpdateEvent*>(event); - QAccessibleTextUpdateEvent *upd = new QAccessibleTextUpdateEvent(event->object(), original->changePosition(), original->textRemoved(), original->textInserted()); + QAccessibleTextUpdateEvent *upd; + if (event->object()) + upd = new QAccessibleTextUpdateEvent(event->object(), original->changePosition(), original->textRemoved(), original->textInserted()); + else + upd = new QAccessibleTextUpdateEvent(event->accessibleInterface(), original->changePosition(), original->textRemoved(), original->textInserted()); upd->setCursorPosition(original->cursorPosition()); ev = upd; } else if (event->type() == QAccessible::ValueChanged) { - ev = new QAccessibleValueChangeEvent(event->object(), static_cast<QAccessibleValueChangeEvent*>(event)->value()); + if (event->object()) + ev = new QAccessibleValueChangeEvent(event->object(), static_cast<QAccessibleValueChangeEvent*>(event)->value()); + else + ev = new QAccessibleValueChangeEvent(event->accessibleInterface(), static_cast<QAccessibleValueChangeEvent*>(event)->value()); } else if (event->type() == QAccessible::TableModelChanged) { QAccessibleTableModelChangeEvent *oldEvent = static_cast<QAccessibleTableModelChangeEvent*>(event); - QAccessibleTableModelChangeEvent *newEvent = new QAccessibleTableModelChangeEvent(event->object(), oldEvent->modelChangeType()); + QAccessibleTableModelChangeEvent *newEvent; + if (event->object()) + newEvent = new QAccessibleTableModelChangeEvent(event->object(), oldEvent->modelChangeType()); + else + newEvent = new QAccessibleTableModelChangeEvent(event->accessibleInterface(), oldEvent->modelChangeType()); newEvent->setFirstRow(oldEvent->firstRow()); newEvent->setFirstColumn(oldEvent->firstColumn()); newEvent->setLastRow(oldEvent->lastRow()); newEvent->setLastColumn(oldEvent->lastColumn()); ev = newEvent; } else { - ev = new QAccessibleEvent(event->object(), event->type()); + if (event->object()) + ev = new QAccessibleEvent(event->object(), event->type()); + else + ev = new QAccessibleEvent(event->accessibleInterface(), event->type()); } ev->setChild(event->child()); return ev; diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp new file mode 100644 index 0000000000..7921b350b5 --- /dev/null +++ b/src/testlib/qtestblacklist.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtTest module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qtestblacklist_p.h" +#include "qtestresult_p.h" + +#include <QtTest/qtestcase.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qfile.h> + +#include <set> + +QT_BEGIN_NAMESPACE + +/* + The file format is simply a grouped listing of keywords + Ungrouped entries at the beginning apply to the whole testcase + Groups define testfunctions or specific test data to ignore. + After the groups come a list of entries (one per line) that define + for which platform/os combination to ignore the test result. + All keys in a single line have to match to blacklist the test. + + mac + [testFunction] + linux + windows 64bit + [testfunction2:testData] + msvc + + The known keys are listed below: +*/ + +// this table can be extended with new keywords as required +const char *matchedConditions[] = +{ +#ifdef Q_OS_LINUX + "linux", +#endif +#ifdef Q_OS_OSX + "osx", +#endif +#ifdef Q_OS_WIN + "windows", +#endif +#ifdef Q_OS_IOS + "ios", +#endif +#ifdef Q_OS_ANDROID + "android", +#endif +#ifdef Q_OS_QNX + "qnx", +#endif +#ifdef Q_OS_WINRT + "winrt", +#endif +#ifdef Q_OS_WINCE + "wince", +#endif + +#if QT_POINTER_SIZE == 8 + "64bit", +#else + "32bit", +#endif + +#ifdef Q_CC_GNU + "gcc", +#endif +#ifdef Q_CC_CLANG + "clang", +#endif +#ifdef Q_CC_MSVC + "msvc", +#endif + +#ifdef Q_AUTOTEST_EXPORT + "developer-build", +#endif + 0 +}; + + +static bool checkCondition(const QByteArray &condition) +{ + QList<QByteArray> conds = condition.split(' '); + std::set<QByteArray> matches; + const char **m = matchedConditions; + while (*m) { + matches.insert(*m); + ++m; + } + + for (int i = 0; i < conds.size(); ++i) { + QByteArray c = conds.at(i); + bool result = c.startsWith('!'); + if (result) + c = c.mid(1); + + result ^= (matches.find(c) != matches.end()); + if (!result) + return false; + } + return true; +} + +static bool ignoreAll = false; +static std::set<QByteArray> *ignoredTests = 0; + +namespace QTestPrivate { + +void parseBlackList() +{ + QString filename = QTest::qFindTestData(QStringLiteral("BLACKLIST")); + if (filename.isEmpty()) + return; + QFile ignored(filename); + if (!ignored.open(QIODevice::ReadOnly)) + return; + + QByteArray function; + + while (!ignored.atEnd()) { + QByteArray line = ignored.readLine().simplified(); + if (line.isEmpty() || line.startsWith('#')) + continue; + if (line.startsWith('[')) { + function = line.mid(1, line.length() - 2); + continue; + } + bool condition = checkCondition(line); + if (condition) { + if (!function.size()) { + ignoreAll = true; + } else { + if (!ignoredTests) + ignoredTests = new std::set<QByteArray>; + ignoredTests->insert(function); + } + } + } +} + +void checkBlackList(const char *slot, const char *data) +{ + bool ignore = ignoreAll; + + if (!ignore && ignoredTests) { + QByteArray s = slot; + ignore = (ignoredTests->find(s) != ignoredTests->end()); + if (!ignore && data) { + s += ':'; + s += data; + ignore = (ignoredTests->find(s) != ignoredTests->end()); + } + } + + QTestResult::setBlacklistCurrentTest(ignore); +} + +} + + +QT_END_NAMESPACE diff --git a/src/testlib/qtestblacklist_p.h b/src/testlib/qtestblacklist_p.h new file mode 100644 index 0000000000..a9d07ae024 --- /dev/null +++ b/src/testlib/qtestblacklist_p.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtTest module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTESTBLACKLIST_P_H +#define QTESTBLACKLIST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtTest/qtest_global.h> + +QT_BEGIN_NAMESPACE + +namespace QTestPrivate { + void parseBlackList(); + void checkBlackList(const char *slot, const char *data); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 83cba0d672..877be81fb9 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -63,6 +63,7 @@ #include <QtTest/private/qsignaldumper_p.h> #include <QtTest/private/qbenchmark_p.h> #include <QtTest/private/cycle_p.h> +#include <QtTest/private/qtestblacklist_p.h> #include <numeric> #include <algorithm> @@ -1034,6 +1035,13 @@ QT_BEGIN_NAMESPACE Returns a textual representation of the given \a variant. */ +/*! + \fn char *QTest::toString(const QVersionNumber &version) + \overload + + Returns a textual representation of the given \a version. +*/ + /*! \fn void QTest::qWait(int ms) Waits for \a ms milliseconds. While waiting, events will be processed and @@ -2009,6 +2017,9 @@ static bool qInvokeTestMethod(const char *slotName, const char *data=0) QTestResult::setSkipCurrentTest(false); if (!data || !qstrcmp(data, table.testData(curDataIndex)->dataTag())) { foundFunction = true; + + QTestPrivate::checkBlackList(slot, dataCount ? table.testData(curDataIndex)->dataTag() : 0); + QTestDataSetter s(curDataIndex >= dataCount ? static_cast<QTestData *>(0) : table.testData(curDataIndex)); @@ -2426,6 +2437,8 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) } #endif + QTestPrivate::parseBlackList(); + QTestResult::reset(); QTEST_ASSERT(testObject); @@ -2601,6 +2614,7 @@ void QTest::ignoreMessage(QtMsgType type, const char *message) QTestLog::ignoreMessage(type, message); } +#ifndef QT_NO_REGULAREXPRESSION /*! \overload @@ -2616,13 +2630,11 @@ void QTest::ignoreMessage(QtMsgType type, const char *message) \since 5.3 */ - -#ifndef QT_NO_REGULAREXPRESSION void QTest::ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern) { QTestLog::ignoreMessage(type, messagePattern); } -#endif +#endif // QT_NO_REGULAREXPRESSION /*! \internal */ diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp index 4ef1113641..b7ed3d0763 100644 --- a/src/testlib/qtestlog.cpp +++ b/src/testlib/qtestlog.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtTest module of the Qt Toolkit. @@ -59,8 +59,6 @@ QT_BEGIN_NAMESPACE -Q_CORE_EXPORT QString qMessageFormatString(QtMsgType type, const QMessageLogContext &context, const QString& msg); - static void saveCoverageTool(const char * appname, bool testfailed, bool installedTestCoverage) { #ifdef __COVERAGESCANNER__ @@ -86,6 +84,7 @@ namespace QTest { int fails = 0; int passes = 0; int skips = 0; + int blacklists = 0; struct IgnoreResultList { @@ -287,7 +286,7 @@ namespace QTest { // the message is expected, so just swallow it. return; - QString msg = qMessageFormatString(type, context, message); + QString msg = qFormatLogMessage(type, context, message); msg.chop(1); // remove trailing newline if (type != QtFatalMsg) { @@ -417,6 +416,25 @@ void QTestLog::addXPass(const char *msg, const char *file, int line) QTest::TestLoggers::addIncident(QAbstractTestLogger::XPass, msg, file, line); } +void QTestLog::addBPass(const char *msg) +{ + QTEST_ASSERT(msg); + + ++QTest::blacklists; + + QTest::TestLoggers::addIncident(QAbstractTestLogger::BlacklistedPass, msg); +} + +void QTestLog::addBFail(const char *msg, const char *file, int line) +{ + QTEST_ASSERT(msg); + QTEST_ASSERT(file); + + ++QTest::blacklists; + + QTest::TestLoggers::addIncident(QAbstractTestLogger::BlacklistedFail, msg, file, line); +} + void QTestLog::addSkip(const char *msg, const char *file, int line) { QTEST_ASSERT(msg); @@ -525,7 +543,7 @@ void QTestLog::ignoreMessage(QtMsgType type, const QRegularExpression &expressio QTest::IgnoreResultList::append(QTest::ignoreResultList, type, QVariant(expression)); } -#endif +#endif // QT_NO_REGULAREXPRESSION void QTestLog::setMaxWarnings(int m) { @@ -554,6 +572,11 @@ int QTestLog::skipCount() return QTest::skips; } +int QTestLog::blacklistCount() +{ + return QTest::blacklists; +} + void QTestLog::resetCounters() { QTest::passes = 0; diff --git a/src/testlib/qtestlog_p.h b/src/testlib/qtestlog_p.h index 0ed6750f63..5d5ffd3f6f 100644 --- a/src/testlib/qtestlog_p.h +++ b/src/testlib/qtestlog_p.h @@ -72,6 +72,8 @@ public: static void addFail(const char *msg, const char *file, int line); static void addXFail(const char *msg, const char *file, int line); static void addXPass(const char *msg, const char *file, int line); + static void addBPass(const char *msg); + static void addBFail(const char *msg, const char *file, int line); static void addSkip(const char *msg, const char *file, int line); static void addBenchmarkResult(const QBenchmarkResult &result); @@ -104,6 +106,7 @@ public: static int passCount(); static int failCount(); static int skipCount(); + static int blacklistCount(); static void resetCounters(); diff --git a/src/testlib/qtestresult.cpp b/src/testlib/qtestresult.cpp index 8eb1fa2d9c..8d1a942d8b 100644 --- a/src/testlib/qtestresult.cpp +++ b/src/testlib/qtestresult.cpp @@ -62,6 +62,7 @@ namespace QTest static const char *currentTestObjectName = 0; static bool failed = false; static bool skipCurrentTest = false; + static bool blacklistCurrentTest = false; static const char *expectFailComment = 0; static int expectFailMode = 0; @@ -77,10 +78,16 @@ void QTestResult::reset() QTest::expectFailComment = 0; QTest::expectFailMode = 0; + QTest::blacklistCurrentTest = false; QTestLog::resetCounters(); } +void QTestResult::setBlacklistCurrentTest(bool b) +{ + QTest::blacklistCurrentTest = b; +} + bool QTestResult::currentTestFailed() { return QTest::failed; @@ -139,7 +146,10 @@ void QTestResult::finishedCurrentTestDataCleanup() { // If the current test hasn't failed or been skipped, then it passes. if (!QTest::failed && !QTest::skipCurrentTest) { - QTestLog::addPass(""); + if (QTest::blacklistCurrentTest) + QTestLog::addBPass(""); + else + QTestLog::addPass(""); } QTest::failed = false; @@ -290,7 +300,10 @@ void QTestResult::addFailure(const char *message, const char *file, int line) { clearExpectFail(); - QTestLog::addFail(message, file, line); + if (QTest::blacklistCurrentTest) + QTestLog::addBFail(message, file, line); + else + QTestLog::addFail(message, file, line); QTest::failed = true; } diff --git a/src/testlib/qtestresult_p.h b/src/testlib/qtestresult_p.h index ea8173b169..8454acd5f8 100644 --- a/src/testlib/qtestresult_p.h +++ b/src/testlib/qtestresult_p.h @@ -74,6 +74,7 @@ public: static void finishedCurrentTestDataCleanup(); static void finishedCurrentTestFunction(); static void reset(); + static void setBlacklistCurrentTest(bool b); static void addFailure(const char *message, const char *file, int line); static bool compare(bool success, const char *failureMsg, diff --git a/src/testlib/qxmltestlogger.cpp b/src/testlib/qxmltestlogger.cpp index 3fff753c5c..52dc5db69f 100644 --- a/src/testlib/qxmltestlogger.cpp +++ b/src/testlib/qxmltestlogger.cpp @@ -42,6 +42,7 @@ #include <stdio.h> #include <string.h> #include <QtCore/qglobal.h> +#include <QtCore/qlibraryinfo.h> #include <QtTest/private/qxmltestlogger_p.h> #include <QtTest/private/qtestresult_p.h> @@ -85,6 +86,10 @@ namespace QTest { return "fail"; case QAbstractTestLogger::XPass: return "xpass"; + case QAbstractTestLogger::BlacklistedPass: + return "bpass"; + case QAbstractTestLogger::BlacklistedFail: + return "bfail"; } return "??????"; } @@ -115,11 +120,15 @@ void QXmlTestLogger::startLogging() outputString(buf.constData()); } + QTestCharBuffer quotedBuild; + xmlQuote("edBuild, QLibraryInfo::build()); + QTest::qt_asprintf(&buf, "<Environment>\n" " <QtVersion>%s</QtVersion>\n" + " <QtBuild>%s</QtBuild>\n" " <QTestVersion>" QTEST_VERSION_STR "</QTestVersion>\n" - "</Environment>\n", qVersion()); + "</Environment>\n", qVersion(), quotedBuild.constData()); outputString(buf.constData()); m_totalTime.start(); } diff --git a/src/testlib/qxunittestlogger.cpp b/src/testlib/qxunittestlogger.cpp index a47f77ae49..5d860cf1c9 100644 --- a/src/testlib/qxunittestlogger.cpp +++ b/src/testlib/qxunittestlogger.cpp @@ -46,6 +46,15 @@ #include <QtTest/private/qtestresult_p.h> #include <QtTest/private/qbenchmark_p.h> +#ifdef min // windows.h without NOMINMAX is included by the benchmark headers. +# undef min +#endif +#ifdef max +# undef max +#endif + +#include <QtCore/qlibraryinfo.h> + #include <string.h> QT_BEGIN_NAMESPACE @@ -108,6 +117,11 @@ void QXunitTestLogger::stopLogging() property->addAttribute(QTest::AI_PropertyValue, qVersion()); properties->addLogElement(property); + property = new QTestElement(QTest::LET_Property); + property->addAttribute(QTest::AI_Name, "QtBuild"); + property->addAttribute(QTest::AI_PropertyValue, QLibraryInfo::build()); + properties->addLogElement(property); + currentLogElement->addLogElement(properties); currentLogElement->addLogElement(iterator); @@ -161,6 +175,13 @@ void QXunitTestLogger::addIncident(IncidentTypes type, const char *description, ++failureCounter; typeBuf = "fail"; break; + case QAbstractTestLogger::BlacklistedPass: + typeBuf = "bpass"; + break; + case QAbstractTestLogger::BlacklistedFail: + ++failureCounter; + typeBuf = "bfail"; + break; default: typeBuf = "??????"; break; @@ -193,6 +214,13 @@ void QXunitTestLogger::addIncident(IncidentTypes type, const char *description, if (!strcmp(oldResult, "pass")) { overwrite = true; } + else if (!strcmp(oldResult, "bpass")) { + overwrite = (type == QAbstractTestLogger::XPass || type == QAbstractTestLogger::Fail) || (type == QAbstractTestLogger::XFail) + || (type == QAbstractTestLogger::BlacklistedFail); + } + else if (!strcmp(oldResult, "bfail")) { + overwrite = (type == QAbstractTestLogger::XPass || type == QAbstractTestLogger::Fail) || (type == QAbstractTestLogger::XFail); + } else if (!strcmp(oldResult, "xfail")) { overwrite = (type == QAbstractTestLogger::XPass || type == QAbstractTestLogger::Fail); } diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index 1fb6d6df18..17a03781c2 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -33,7 +33,8 @@ HEADERS = qbenchmark.h \ qtestmouse.h \ qtestspontaneevent.h \ qtestsystem.h \ - qtesttouch.h + qtesttouch.h \ + qtestblacklist_p.h SOURCES = qtestcase.cpp \ qtestlog.cpp \ @@ -55,7 +56,9 @@ SOURCES = qtestcase.cpp \ qtestelement.cpp \ qtestelementattribute.cpp \ qtestxunitstreamer.cpp \ - qxunittestlogger.cpp + qxunittestlogger.cpp \ + qtestblacklist.cpp + DEFINES *= QT_NO_CAST_TO_ASCII \ QT_NO_CAST_FROM_ASCII \ QT_NO_DATASTREAM |