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