diff options
Diffstat (limited to 'src/testlib/qtestresult.cpp')
-rw-r--r-- | src/testlib/qtestresult.cpp | 220 |
1 files changed, 184 insertions, 36 deletions
diff --git a/src/testlib/qtestresult.cpp b/src/testlib/qtestresult.cpp index beb6291008..7c5ce9ce54 100644 --- a/src/testlib/qtestresult.cpp +++ b/src/testlib/qtestresult.cpp @@ -149,13 +149,6 @@ void QTestResult::finishedCurrentTestData() addFailure("QEXPECT_FAIL was called without any subsequent verification statements"); clearExpectFail(); - - if (!QTest::hasFailed() && QTestLog::unhandledIgnoreMessages()) { - QTestLog::printUnhandledIgnoreMessages(); - addFailure("Not all expected messages were received"); - } - QTestLog::clearIgnoreMessages(); - QTestLog::clearFailOnWarnings(); } /*! @@ -175,6 +168,11 @@ void QTestResult::finishedCurrentTestData() */ void QTestResult::finishedCurrentTestDataCleanup() { + if (!QTest::hasFailed() && QTestLog::unhandledIgnoreMessages()) { + QTestLog::printUnhandledIgnoreMessages(); + addFailure("Not all expected messages were received"); + } + // If the current test hasn't failed or been skipped, then it passes. if (!QTest::hasFailed() && !QTest::skipCurrentTest) { if (QTest::blacklistCurrentTest) @@ -289,20 +287,27 @@ void QTestResult::fail(const char *msg, const char *file, int line) checkStatement(false, msg, file, line); } +// QPalette's << operator produces 1363 characters. A comparison failure +// involving two palettes can therefore require 2726 characters, not including +// the other output produced by QTest. Users might also have their own types +// with large amounts of output, so use a sufficiently high value here. +static constexpr size_t maxMsgLen = 4096; + bool QTestResult::verify(bool statement, const char *statementStr, const char *description, const char *file, int line) { QTEST_ASSERT(statementStr); - char msg[1024] = {'\0'}; + char msg[maxMsgLen]; + msg[0] = '\0'; if (QTestLog::verboseLevel() >= 2) { - qsnprintf(msg, 1024, "QVERIFY(%s)", statementStr); + qsnprintf(msg, maxMsgLen, "QVERIFY(%s)", statementStr); QTestLog::info(msg, file, line); } if (statement == !!QTest::expectFailMode) { - qsnprintf(msg, 1024, + qsnprintf(msg, maxMsgLen, statement ? "'%s' returned TRUE unexpectedly. (%s)" : "'%s' returned FALSE. (%s)", statementStr, description ? description : ""); } @@ -310,39 +315,57 @@ bool QTestResult::verify(bool statement, const char *statementStr, return checkStatement(statement, msg, file, line); } -// Format failures using the toString() template -template <class Actual, class Expected> -void formatFailMessage(char *msg, size_t maxMsgLen, - const char *failureMsg, - const Actual &val1, const Expected &val2, - const char *actual, const char *expected) +static const char *leftArgNameForOp(QTest::ComparisonOperation op) { - auto val1S = QTest::toString(val1); - auto val2S = QTest::toString(val2); - - size_t len1 = mbstowcs(nullptr, actual, maxMsgLen); // Last parameter is not ignored on QNX - size_t len2 = mbstowcs(nullptr, expected, maxMsgLen); // (result is never larger than this). - qsnprintf(msg, maxMsgLen, "%s\n Actual (%s)%*s %s\n Expected (%s)%*s %s", - failureMsg, - actual, qMax(len1, len2) - len1 + 1, ":", val1S ? val1S : "<null>", - expected, qMax(len1, len2) - len2 + 1, ":", val2S ? val2S : "<null>"); + return op == QTest::ComparisonOperation::CustomCompare ? "Actual " : "Computed "; +} - delete [] val1S; - delete [] val2S; +static const char *rightArgNameForOp(QTest::ComparisonOperation op) +{ + return op == QTest::ComparisonOperation::CustomCompare ? "Expected " : "Baseline "; } // Overload to format failures for "const char *" - no need to strdup(). void formatFailMessage(char *msg, size_t maxMsgLen, const char *failureMsg, const char *val1, const char *val2, - const char *actual, const char *expected) + const char *actual, const char *expected, + QTest::ComparisonOperation op) { size_t len1 = mbstowcs(nullptr, actual, maxMsgLen); // Last parameter is not ignored on QNX size_t len2 = mbstowcs(nullptr, expected, maxMsgLen); // (result is never larger than this). - qsnprintf(msg, maxMsgLen, "%s\n Actual (%s)%*s %s\n Expected (%s)%*s %s", - failureMsg, - actual, qMax(len1, len2) - len1 + 1, ":", val1 ? val1 : "<null>", - expected, qMax(len1, len2) - len2 + 1, ":", val2 ? val2 : "<null>"); + const int written = qsnprintf(msg, maxMsgLen, "%s\n", failureMsg); + msg += written; + maxMsgLen -= written; + + if (val1 || val2) { + qsnprintf(msg, maxMsgLen, " %s(%s)%*s %s\n %s(%s)%*s %s", + leftArgNameForOp(op), actual, qMax(len1, len2) - len1 + 1, ":", + val1 ? val1 : "<null>", + rightArgNameForOp(op), expected, qMax(len1, len2) - len2 + 1, ":", + val2 ? val2 : "<null>"); + } else { + // only print variable names if neither value can be represented as a string + qsnprintf(msg, maxMsgLen, " %s: %s\n %s: %s", + leftArgNameForOp(op), actual, rightArgNameForOp(op), expected); + } +} + +// Format failures using the toString() template +template <class Actual, class Expected> +void formatFailMessage(char *msg, size_t maxMsgLen, + const char *failureMsg, + const Actual &val1, const Expected &val2, + const char *actual, const char *expected, + QTest::ComparisonOperation op) +{ + const char *val1S = QTest::toString(val1); + const char *val2S = QTest::toString(val2); + + formatFailMessage(msg, maxMsgLen, failureMsg, val1S, val2S, actual, expected, op); + + delete [] val1S; + delete [] val2S; } template <class Actual, class Expected> @@ -352,8 +375,8 @@ static bool compareHelper(bool success, const char *failureMsg, const char *file, int line, bool hasValues = true) { - const size_t maxMsgLen = 1024; - char msg[maxMsgLen] = {'\0'}; + char msg[maxMsgLen]; + msg[0] = '\0'; QTEST_ASSERT(expected); QTEST_ASSERT(actual); @@ -380,11 +403,44 @@ static bool compareHelper(bool success, const char *failureMsg, return checkStatement(success, msg, file, line); } - formatFailMessage(msg, maxMsgLen, failureMsg, val1, val2, actual, expected); + formatFailMessage(msg, maxMsgLen, failureMsg, val1, val2, actual, expected, + QTest::ComparisonOperation::CustomCompare); return checkStatement(success, msg, file, line); } +// A simplified version of compareHelper that does not use string +// representations of the values, and prints only failureMsg when the +// comparison fails. +static bool compareHelper(bool success, const char *failureMsg, + const char *actual, const char *expected, + const char *file, int line) +{ + const size_t maxMsgLen = 1024; + char msg[maxMsgLen]; + msg[0] = '\0'; + + QTEST_ASSERT(expected); + QTEST_ASSERT(actual); + // failureMsg can be null, if we do not use it + QTEST_ASSERT(success || failureMsg); + + if (QTestLog::verboseLevel() >= 2) { + qsnprintf(msg, maxMsgLen, "QCOMPARE(%s, %s)", actual, expected); + QTestLog::info(msg, file, line); + } + + if (success) { + if (QTest::expectFailMode) { + qsnprintf(msg, maxMsgLen, "QCOMPARE(%s, %s) returned TRUE unexpectedly.", + actual, expected); + } + return checkStatement(success, msg, file, line); + } + + return checkStatement(success, failureMsg, file, line); +} + bool QTestResult::compare(bool success, const char *failureMsg, char *val1, char *val2, const char *actual, const char *expected, @@ -469,10 +525,20 @@ bool QTestResult::compare(bool success, const char *failureMsg, return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line); } +// Simplified version of compare() that does not take the values, because they +// can't be converted to strings (or the user didn't want to do that). +bool QTestResult::compare(bool success, const char *failureMsg, + const char *actual, const char *expeceted, + const char *file, int line) +{ + return compareHelper(success, failureMsg, actual, expeceted, file, line); +} + void QTestResult::addFailure(const char *message, const char *file, int line) { clearExpectFail(); - QTestEventLoop::instance().exitLoop(); + if (qApp && QThread::currentThread() == qApp->thread()) + QTestEventLoop::instance().exitLoop(); if (QTest::blacklistCurrentTest) QTestLog::addBFail(message, file, line); @@ -518,4 +584,86 @@ const char *QTestResult::currentAppName() return ::currentAppName; } +static const char *macroNameForOp(QTest::ComparisonOperation op) +{ + using namespace QTest; + switch (op) { + case ComparisonOperation::CustomCompare: + return "QCOMPARE"; /* not used */ + case ComparisonOperation::Equal: + return "QCOMPARE_EQ"; + case ComparisonOperation::NotEqual: + return "QCOMPARE_NE"; + case ComparisonOperation::LessThan: + return "QCOMPARE_LT"; + case ComparisonOperation::LessThanOrEqual: + return "QCOMPARE_LE"; + case ComparisonOperation::GreaterThan: + return "QCOMPARE_GT"; + case ComparisonOperation::GreaterThanOrEqual: + return "QCOMPARE_GE"; + } + Q_UNREACHABLE_RETURN(""); +} + +static const char *failureMessageForOp(QTest::ComparisonOperation op) +{ + using namespace QTest; + switch (op) { + case ComparisonOperation::CustomCompare: + return "Compared values are not the same"; /* not used */ + case ComparisonOperation::Equal: + return "The computed value is expected to be equal to the baseline, but is not"; + case ComparisonOperation::NotEqual: + return "The computed value is expected to be different from the baseline, but is not"; + case ComparisonOperation::LessThan: + return "The computed value is expected to be less than the baseline, but is not"; + case ComparisonOperation::LessThanOrEqual: + return "The computed value is expected to be less than or equal to the baseline, but is not"; + case ComparisonOperation::GreaterThan: + return "The computed value is expected to be greater than the baseline, but is not"; + case ComparisonOperation::GreaterThanOrEqual: + return "The computed value is expected to be greater than or equal to the baseline, but is not"; + } + Q_UNREACHABLE_RETURN(""); +} + +bool QTestResult::reportResult(bool success, const void *lhs, const void *rhs, + const char *(*lhsFormatter)(const void*), + const char *(*rhsFormatter)(const void*), + const char *lhsExpr, const char *rhsExpr, + QTest::ComparisonOperation op, const char *file, int line, + const char *failureMessage) +{ + char msg[maxMsgLen]; + msg[0] = '\0'; + + QTEST_ASSERT(lhsExpr); + QTEST_ASSERT(rhsExpr); + + if (QTestLog::verboseLevel() >= 2) { + qsnprintf(msg, maxMsgLen, "%s(%s, %s)", macroNameForOp(op), lhsExpr, rhsExpr); + QTestLog::info(msg, file, line); + } + + if (success) { + if (QTest::expectFailMode) { + qsnprintf(msg, maxMsgLen, "%s(%s, %s) returned TRUE unexpectedly.", + macroNameForOp(op), lhsExpr, rhsExpr); + } + return checkStatement(success, msg, file, line); + } + + const std::unique_ptr<const char[]> lhsPtr{ lhsFormatter(lhs) }; + const std::unique_ptr<const char[]> rhsPtr{ rhsFormatter(rhs) }; + + if (!failureMessage) + failureMessage = failureMessageForOp(op); + + formatFailMessage(msg, maxMsgLen, failureMessage, lhsPtr.get(), rhsPtr.get(), + lhsExpr, rhsExpr, op); + + return checkStatement(success, msg, file, line); +} + QT_END_NAMESPACE |