diff options
Diffstat (limited to 'src/testlib')
-rw-r--r-- | src/testlib/qtestblacklist.cpp | 71 | ||||
-rw-r--r-- | src/testlib/qtestcase.cpp | 91 |
2 files changed, 127 insertions, 35 deletions
diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp index f8285c3ea9..bfeca08617 100644 --- a/src/testlib/qtestblacklist.cpp +++ b/src/testlib/qtestblacklist.cpp @@ -36,6 +36,9 @@ #include <QtTest/qtestcase.h> #include <QtCore/qbytearray.h> #include <QtCore/qfile.h> +#include <QtCore/qset.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qvariant.h> #include <QtCore/QSysInfo> #include <set> @@ -60,83 +63,87 @@ QT_BEGIN_NAMESPACE The known keys are listed below: */ -// this table can be extended with new keywords as required -const char *matchedConditions[] = +static QSet<QByteArray> keywords() { - "*", + // this list can be extended with new keywords as required + QSet<QByteArray> set = QSet<QByteArray>() + << "*" #ifdef Q_OS_LINUX - "linux", + << "linux" #endif #ifdef Q_OS_OSX - "osx", + << "osx" #endif #ifdef Q_OS_WIN - "windows", + << "windows" #endif #ifdef Q_OS_IOS - "ios", + << "ios" #endif #ifdef Q_OS_ANDROID - "android", + << "android" #endif #ifdef Q_OS_QNX - "qnx", + << "qnx" #endif #ifdef Q_OS_WINRT - "winrt", + << "winrt" #endif #ifdef Q_OS_WINCE - "wince", + << "wince" #endif #if QT_POINTER_SIZE == 8 - "64bit", + << "64bit" #else - "32bit", + << "32bit" #endif #ifdef Q_CC_GNU - "gcc", + << "gcc" #endif #ifdef Q_CC_CLANG - "clang", + << "clang" #endif #ifdef Q_CC_MSVC - "msvc", + << "msvc" #ifdef _MSC_VER #if _MSC_VER == 1800 - "msvc-2013", + << "msvc-2013" #elif _MSC_VER == 1700 - "msvc-2012", + << "msvc-2012" #elif _MSC_VER == 1600 - "msvc-2010", + << "msvc-2010" #endif #endif #endif #ifdef Q_AUTOTEST_EXPORT - "developer-build", + << "developer-build" #endif - 0 -}; + ; + QCoreApplication *app = QCoreApplication::instance(); + if (app) { + const QVariant platformName = app->property("platformName"); + if (platformName.isValid()) + set << platformName.toByteArray(); + } + + return set; +} static bool checkCondition(const QByteArray &condition) { + static QSet<QByteArray> matchedConditions = keywords(); QList<QByteArray> conds = condition.split(' '); - std::set<QByteArray> matches; - const char **m = matchedConditions; - while (*m) { - matches.insert(*m); - ++m; - } QByteArray distributionName = QSysInfo::productType().toLower().toUtf8(); QByteArray distributionRelease = QSysInfo::productVersion().toLower().toUtf8(); if (!distributionName.isEmpty()) { - if (matches.find(distributionName) == matches.end()) - matches.insert(distributionName); - matches.insert(distributionName + "-" + distributionRelease); + if (matchedConditions.find(distributionName) == matchedConditions.end()) + matchedConditions.insert(distributionName); + matchedConditions.insert(distributionName + "-" + distributionRelease); } for (int i = 0; i < conds.size(); ++i) { @@ -145,7 +152,7 @@ static bool checkCondition(const QByteArray &condition) if (result) c = c.mid(1); - result ^= (matches.find(c) != matches.end()); + result ^= matchedConditions.contains(c); if (!result) return false; } diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index e2f98c2f04..4d4a3cd7b2 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -50,6 +50,9 @@ #include <QtCore/private/qtools_p.h> #include <QtCore/qdiriterator.h> #include <QtCore/qtemporarydir.h> +#include <QtCore/qthread.h> +#include <QtCore/qwaitcondition.h> +#include <QtCore/qmutex.h> #include <QtTest/private/qtestlog_p.h> #include <QtTest/private/qtesttable_p.h> @@ -70,6 +73,11 @@ #include <stdio.h> #include <stdlib.h> +#if defined(Q_OS_LINUX) +#include <sys/types.h> +#include <unistd.h> +#endif + #ifdef Q_OS_WIN #ifndef Q_OS_WINCE # if !defined(Q_CC_MINGW) || (defined(Q_CC_MINGW) && defined(__MINGW64_VERSION_MAJOR)) @@ -93,6 +101,28 @@ QT_BEGIN_NAMESPACE using QtMiscUtils::toHexUpper; using QtMiscUtils::fromHex; + +static void stackTrace() +{ + bool ok = false; + const int disableStackDump = qEnvironmentVariableIntValue("QTEST_DISABLE_STACK_DUMP", &ok); + if (ok && disableStackDump == 1) + return; +#ifdef Q_OS_LINUX + fprintf(stderr, "\n========= Received signal, dumping stack ==============\n"); + char cmd[512]; + qsnprintf(cmd, 512, "gdb --pid %d 2>/dev/null <<EOF\n" + "set prompt\n" + "thread apply all where\n" + "detach\n" + "quit\n" + "EOF\n", + (int)getpid()); + system(cmd); + fprintf(stderr, "========= End of stack trace ==============\n"); +#endif +} + /*! \namespace QTest \inmodule QtTest @@ -2010,6 +2040,55 @@ static void qInvokeTestMethodDataEntry(char *slot) } } +class WatchDog : public QThread +{ +public: + WatchDog() + { + timeout.store(-1); + start(); + } + ~WatchDog() { + { + QMutexLocker locker(&mutex); + timeout.store(0); + waitCondition.wakeAll(); + } + wait(); + } + + void beginTest() { + QMutexLocker locker(&mutex); + timeout.store(5*60*1000); + waitCondition.wakeAll(); + } + + void testFinished() { + QMutexLocker locker(&mutex); + timeout.store(-1); + waitCondition.wakeAll(); + } + + void run() { + QMutexLocker locker(&mutex); + while (1) { + int t = timeout.load(); + if (!t) + break; + if (!waitCondition.wait(&mutex, t)) { + stackTrace(); + qFatal("Test function timed out"); + } + } + } + +private: + QBasicAtomicInt timeout; + QMutex mutex; + QWaitCondition waitCondition; +}; + + /*! \internal @@ -2019,7 +2098,7 @@ static void qInvokeTestMethodDataEntry(char *slot) If the function was successfully called, true is returned, otherwise false. */ -static bool qInvokeTestMethod(const char *slotName, const char *data=0) +static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog *watchDog) { QTEST_ASSERT(slotName); @@ -2078,7 +2157,9 @@ static bool qInvokeTestMethod(const char *slotName, const char *data=0) QTestDataSetter s(curDataIndex >= dataCount ? static_cast<QTestData *>(0) : table.testData(curDataIndex)); + watchDog->beginTest(); qInvokeTestMethodDataEntry(slot); + watchDog->testFinished(); if (data) break; @@ -2359,6 +2440,8 @@ static void qInvokeTestMethods(QObject *testObject) QTestTable::globalTestTable(); invokeMethod(testObject, "initTestCase_data()"); + WatchDog watchDog; + if (!QTestResult::skipCurrentTest() && !QTest::currentTestFailed()) { invokeMethod(testObject, "initTestCase()"); @@ -2373,7 +2456,7 @@ static void qInvokeTestMethods(QObject *testObject) if (QTest::testFuncs) { for (int i = 0; i != QTest::testFuncCount; i++) { if (!qInvokeTestMethod(metaObject->method(QTest::testFuncs[i].function()).methodSignature().constData(), - QTest::testFuncs[i].data())) { + QTest::testFuncs[i].data(), &watchDog)) { break; } } @@ -2386,7 +2469,7 @@ static void qInvokeTestMethods(QObject *testObject) for (int i = 0; i != methodCount; i++) { if (!isValidSlot(testMethods[i])) continue; - if (!qInvokeTestMethod(testMethods[i].methodSignature().constData())) + if (!qInvokeTestMethod(testMethods[i].methodSignature().constData(), 0, &watchDog)) break; } delete[] testMethods; @@ -2422,6 +2505,8 @@ private: void FatalSignalHandler::signal(int signum) { + if (signum != SIGINT) + stackTrace(); qFatal("Received signal %d", signum); #if defined(Q_OS_INTEGRITY) { |