summaryrefslogtreecommitdiffstats
path: root/src/testlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/testlib')
-rw-r--r--src/testlib/qtestblacklist.cpp71
-rw-r--r--src/testlib/qtestcase.cpp91
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)
{