diff options
Diffstat (limited to 'src/testlib/qtestcase.cpp')
-rw-r--r-- | src/testlib/qtestcase.cpp | 88 |
1 files changed, 63 insertions, 25 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 242246d279..6aa747fa7f 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -358,7 +358,9 @@ static void printTestRunTime() { const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime()); const int msecsTotalTime = qRound(QTestLog::msecsTotalTime()); - writeToStderr("\n Function time: ", asyncSafeToString(msecsFunctionTime), + const char *const name = QTest::currentTestFunction(); + writeToStderr("\n ", name ? name : "[Non-test]", + " function time: ", asyncSafeToString(msecsFunctionTime), "ms, total time: ", asyncSafeToString(msecsTotalTime), "ms\n"); } @@ -462,6 +464,7 @@ class WatchDog; static QObject *currentTestObject = nullptr; static QString mainSourcePath; +static bool inTestFunction = false; #if defined(Q_OS_MACOS) static IOPMAssertionID macPowerSavingDisabled = 0; @@ -639,7 +642,7 @@ static void qPrintDataTags(FILE *stream) // Print all tag combinations: if (gTable->dataCount() == 0) { - if (localTags.count() == 0) { + if (localTags.size() == 0) { // No tags at all, so just print the test function: fprintf(stream, "%s %s\n", currTestMetaObj->className(), slot); } else { @@ -651,7 +654,7 @@ static void qPrintDataTags(FILE *stream) } } else { for (int j = 0; j < gTable->dataCount(); ++j) { - if (localTags.count() == 0) { + if (localTags.size() == 0) { // Only global tags, so print the current one: fprintf( stream, "%s %s __global__ %s\n", @@ -1053,7 +1056,7 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) { QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container) { - const int count = container.count(); + const int count = container.size(); if (count == 0) return QBenchmarkResult(); @@ -1105,6 +1108,7 @@ void TestMethods::invokeTestOnData(int index) const /* Benchmarking: for each accumulation iteration*/ bool invokeOk; do { + QTest::inTestFunction = true; if (m_initMethod.isValid()) m_initMethod.invoke(QTest::currentTestObject, Qt::DirectConnection); @@ -1126,6 +1130,7 @@ void TestMethods::invokeTestOnData(int index) const invokeOk = false; } + QTest::inTestFunction = false; QTestResult::finishedCurrentTestData(); if (!initQuit) { @@ -1193,17 +1198,30 @@ void TestMethods::invokeTestOnData(int index) const class WatchDog : public QThread { - enum Expectation { + enum Expectation : std::size_t { + // bits 0..1: state ThreadStart, TestFunctionStart, TestFunctionEnd, ThreadEnd, + + // bits 2..: generation }; + static constexpr auto ExpectationMask = Expectation{ThreadStart | TestFunctionStart | TestFunctionEnd | ThreadEnd}; + static_assert(size_t(ExpectationMask) == 0x3); + static constexpr size_t GenerationShift = 2; + + static constexpr Expectation state(Expectation e) noexcept + { return Expectation{e & ExpectationMask}; } + static constexpr size_t generation(Expectation e) noexcept + { return e >> GenerationShift; } + static constexpr Expectation combine(Expectation e, size_t gen) noexcept + { return Expectation{e | (gen << GenerationShift)}; } bool waitFor(std::unique_lock<QtPrivate::mutex> &m, Expectation e) { auto expectationChanged = [this, e] { return expecting.load(std::memory_order_relaxed) != e; }; - switch (e) { + switch (state(e)) { case TestFunctionEnd: return waitCondition.wait_for(m, defaultTimeout(), expectationChanged); case ThreadStart: @@ -1216,6 +1234,19 @@ class WatchDog : public QThread return false; } + void setExpectation(Expectation e) + { + Q_ASSERT(generation(e) == 0); // no embedded generation allowed + const auto locker = qt_scoped_lock(mutex); + auto cur = expecting.load(std::memory_order_relaxed); + auto gen = generation(cur); + if (e == TestFunctionStart) + ++gen; + e = combine(e, gen); + expecting.store(e, std::memory_order_relaxed); + waitCondition.notify_all(); + } + public: WatchDog() { @@ -1228,26 +1259,18 @@ public: ~WatchDog() { - { - const auto locker = qt_scoped_lock(mutex); - expecting.store(ThreadEnd, std::memory_order_relaxed); - waitCondition.notify_all(); - } + setExpectation(ThreadEnd); wait(); } void beginTest() { - const auto locker = qt_scoped_lock(mutex); - expecting.store(TestFunctionEnd, std::memory_order_relaxed); - waitCondition.notify_all(); + setExpectation(TestFunctionEnd); } void testFinished() { - const auto locker = qt_scoped_lock(mutex); - expecting.store(TestFunctionStart, std::memory_order_relaxed); - waitCondition.notify_all(); + setExpectation(TestFunctionStart); } void run() override @@ -1257,7 +1280,7 @@ public: waitCondition.notify_all(); while (true) { Expectation e = expecting.load(std::memory_order_acquire); - switch (e) { + switch (state(e)) { case ThreadEnd: return; case ThreadStart: @@ -1869,12 +1892,14 @@ private: const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime()); const int msecsTotalTime = qRound(QTestLog::msecsTotalTime()); const void *exceptionAddress = exInfo->ExceptionRecord->ExceptionAddress; - printf("A crash occurred in %s.\n" - "Function time: %dms Total time: %dms\n\n" + printf("A crash occurred in %s.\n", appName); + if (const char *name = QTest::currentTestFunction()) + printf("While testing %s\n", name); + printf("Function time: %dms Total time: %dms\n\n" "Exception address: 0x%p\n" "Exception code : 0x%lx\n", - appName, msecsFunctionTime, msecsTotalTime, - exceptionAddress, exInfo->ExceptionRecord->ExceptionCode); + msecsFunctionTime, msecsTotalTime, exceptionAddress, + exInfo->ExceptionRecord->ExceptionCode); DebugSymbolResolver resolver(GetCurrentProcess()); if (resolver.isValid()) { @@ -2300,7 +2325,7 @@ int QTest::qRun() bool seenBad = false; TestMethods::MetaMethods commandLineMethods; commandLineMethods.reserve(static_cast<size_t>(QTest::testFunctions.size())); - for (const QString &tf : qAsConst(QTest::testFunctions)) { + for (const QString &tf : std::as_const(QTest::testFunctions)) { const QByteArray tfB = tf.toLatin1(); const QByteArray signature = tfB + QByteArrayLiteral("()"); QMetaMethod m = TestMethods::findMethod(currentTestObject, signature.constData()); @@ -2385,7 +2410,7 @@ void QTest::qCleanup() */ int QTest::qExec(QObject *testObject, const QStringList &arguments) { - const int argc = arguments.count(); + const int argc = arguments.size(); QVarLengthArray<char *> argv(argc); QList<QByteArray> args; @@ -2635,7 +2660,7 @@ QSharedPointer<QTemporaryDir> QTest::qExtractTestData(const QString &dirName) QFileInfo fileInfo = it.nextFileInfo(); if (!fileInfo.isDir()) { - const QString destination = dataPath + u'/' + QStringView{fileInfo.filePath()}.mid(resourcePath.length()); + const QString destination = dataPath + u'/' + QStringView{fileInfo.filePath()}.mid(resourcePath.size()); QFileInfo destinationFileInfo(destination); QDir().mkpath(destinationFileInfo.path()); if (!QFile::copy(fileInfo.filePath(), destination)) { @@ -2970,6 +2995,19 @@ bool QTest::currentTestFailed() return QTestResult::currentTestFailed(); } +/*! + \internal + \since 6.4 + Returns \c true during the run of the test-function and its set-up. + + Used by the \c{QTRY_*} macros and \l QTestEventLoop to check whether to + return when QTest::currentTestFailed() is true. +*/ +bool QTest::runningTest() +{ + return QTest::inTestFunction; +} + /*! \internal */ QObject *QTest::testObject() |