/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtTest module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include // toString() specializations for QStringView #include #include #include #include #include #include static const char *currentAppName = nullptr; QT_BEGIN_NAMESPACE namespace QTest { static QTestData *currentTestData = nullptr; static QTestData *currentGlobalTestData = nullptr; static const char *currentTestFunc = nullptr; static const char *currentTestObjectName = nullptr; static bool failed = false; static bool skipCurrentTest = false; static bool blacklistCurrentTest = false; static const char *expectFailComment = nullptr; static int expectFailMode = 0; } void QTestResult::reset() { QTest::currentTestData = nullptr; QTest::currentGlobalTestData = nullptr; QTest::currentTestFunc = nullptr; QTest::currentTestObjectName = nullptr; QTest::failed = false; QTest::expectFailComment = nullptr; QTest::expectFailMode = 0; QTest::blacklistCurrentTest = false; QTestLog::resetCounters(); } void QTestResult::setBlacklistCurrentTest(bool b) { QTest::blacklistCurrentTest = b; } bool QTestResult::currentTestFailed() { return QTest::failed; } QTestData *QTestResult::currentGlobalTestData() { return QTest::currentGlobalTestData; } QTestData *QTestResult::currentTestData() { return QTest::currentTestData; } void QTestResult::setCurrentGlobalTestData(QTestData *data) { QTest::currentGlobalTestData = data; } void QTestResult::setCurrentTestData(QTestData *data) { QTest::currentTestData = data; QTest::failed = false; if (data) QTestLog::enterTestData(data); } void QTestResult::setCurrentTestFunction(const char *func) { QTest::currentTestFunc = func; QTest::failed = false; if (func) QTestLog::enterTestFunction(func); } static void clearExpectFail() { QTest::expectFailMode = 0; delete [] const_cast(QTest::expectFailComment); QTest::expectFailComment = nullptr; } void QTestResult::finishedCurrentTestData() { if (QTest::expectFailMode) addFailure("QEXPECT_FAIL was called without any subsequent verification statements", nullptr, 0); clearExpectFail(); if (!QTest::failed && QTestLog::unhandledIgnoreMessages()) { QTestLog::printUnhandledIgnoreMessages(); addFailure("Not all expected messages were received", nullptr, 0); } QTestLog::clearIgnoreMessages(); } void QTestResult::finishedCurrentTestDataCleanup() { // If the current test hasn't failed or been skipped, then it passes. if (!QTest::failed && !QTest::skipCurrentTest) { if (QTest::blacklistCurrentTest) QTestLog::addBPass(""); else QTestLog::addPass(""); } QTest::failed = false; } void QTestResult::finishedCurrentTestFunction() { QTest::currentTestFunc = nullptr; QTest::failed = false; QTestLog::leaveTestFunction(); } const char *QTestResult::currentTestFunction() { return QTest::currentTestFunc; } const char *QTestResult::currentDataTag() { return QTest::currentTestData ? QTest::currentTestData->dataTag() : nullptr; } const char *QTestResult::currentGlobalDataTag() { return QTest::currentGlobalTestData ? QTest::currentGlobalTestData->dataTag() : nullptr; } static bool isExpectFailData(const char *dataIndex) { if (!dataIndex || dataIndex[0] == '\0') return true; if (!QTest::currentTestData) return false; if (strcmp(dataIndex, QTest::currentTestData->dataTag()) == 0) return true; return false; } bool QTestResult::expectFail(const char *dataIndex, const char *comment, QTest::TestFailMode mode, const char *file, int line) { QTEST_ASSERT(comment); QTEST_ASSERT(mode > 0); if (!isExpectFailData(dataIndex)) { delete[] comment; return true; // we don't care } if (QTest::expectFailMode) { delete[] comment; clearExpectFail(); addFailure("Already expecting a fail", file, line); return false; } QTest::expectFailMode = mode; QTest::expectFailComment = comment; return true; } static bool checkStatement(bool statement, const char *msg, const char *file, int line) { if (statement) { if (QTest::expectFailMode) { if (QTest::blacklistCurrentTest) QTestLog::addBXPass(msg, file, line); else QTestLog::addXPass(msg, file, line); QTest::failed = true; bool doContinue = (QTest::expectFailMode == QTest::Continue); clearExpectFail(); return doContinue; } return true; } if (QTest::expectFailMode) { if (QTest::blacklistCurrentTest) QTestLog::addBXFail(QTest::expectFailComment, file, line); else QTestLog::addXFail(QTest::expectFailComment, file, line); bool doContinue = (QTest::expectFailMode == QTest::Continue); clearExpectFail(); return doContinue; } QTestResult::addFailure(msg, file, line); return false; } bool QTestResult::verify(bool statement, const char *statementStr, const char *description, const char *file, int line) { QTEST_ASSERT(statementStr); char msg[1024] = {'\0'}; if (QTestLog::verboseLevel() >= 2) { qsnprintf(msg, 1024, "QVERIFY(%s)", statementStr); QTestLog::info(msg, file, line); } if (!statement && !QTest::expectFailMode) qsnprintf(msg, 1024, "'%s' returned FALSE. (%s)", statementStr, description ? description : ""); else if (statement && QTest::expectFailMode) qsnprintf(msg, 1024, "'%s' returned TRUE unexpectedly. (%s)", statementStr, description ? description : ""); return checkStatement(statement, msg, file, line); } // Format failures using the toString() template template void formatFailMessage(char *msg, size_t maxMsgLen, const char *failureMsg, const Actual &val1, const Expected &val2, const char *actual, const char *expected) { 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 : "", expected, qMax(len1, len2) - len2 + 1, ":", val2S ? val2S : ""); delete [] val1S; delete [] val2S; } // 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) { 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 : "", expected, qMax(len1, len2) - len2 + 1, ":", val2 ? val2 : ""); } template static bool compareHelper(bool success, const char *failureMsg, const Actual &val1, const Expected &val2, const char *actual, const char *expected, const char *file, int line, bool hasValues = true) { const size_t maxMsgLen = 1024; char msg[maxMsgLen] = {'\0'}; QTEST_ASSERT(expected); QTEST_ASSERT(actual); if (QTestLog::verboseLevel() >= 2) { qsnprintf(msg, maxMsgLen, "QCOMPARE(%s, %s)", actual, expected); QTestLog::info(msg, file, line); } if (!failureMsg) failureMsg = "Compared values are not the same"; if (success) { if (QTest::expectFailMode) { qsnprintf(msg, maxMsgLen, "QCOMPARE(%s, %s) returned TRUE unexpectedly.", actual, expected); } return checkStatement(success, msg, file, line); } if (!hasValues) { qsnprintf(msg, maxMsgLen, "%s", failureMsg); return checkStatement(success, msg, file, line); } formatFailMessage(msg, maxMsgLen, failureMsg, val1, val2, actual, expected); return checkStatement(success, msg, file, line); } bool QTestResult::compare(bool success, const char *failureMsg, char *val1, char *val2, const char *actual, const char *expected, const char *file, int line) { const bool result = compareHelper(success, failureMsg, val1 != nullptr ? val1 : "", val2 != nullptr ? val2 : "", actual, expected, file, line, val1 != nullptr && val2 != nullptr); // Our caller got these from QTest::toString() delete [] val1; delete [] val2; return result; } bool QTestResult::compare(bool success, const char *failureMsg, double val1, double val2, const char *actual, const char *expected, const char *file, int line) { return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line); } bool QTestResult::compare(bool success, const char *failureMsg, float val1, float val2, const char *actual, const char *expected, const char *file, int line) { return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line); } bool QTestResult::compare(bool success, const char *failureMsg, int val1, int val2, const char *actual, const char *expected, const char *file, int line) { return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line); } bool QTestResult::compare(bool success, const char *failureMsg, unsigned val1, unsigned val2, const char *actual, const char *expected, const char *file, int line) { return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line); } bool QTestResult::compare(bool success, const char *failureMsg, QStringView val1, QStringView val2, const char *actual, const char *expected, const char *file, int line) { return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line); } bool QTestResult::compare(bool success, const char *failureMsg, QStringView val1, const QLatin1String &val2, const char *actual, const char *expected, const char *file, int line) { return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line); } bool QTestResult::compare(bool success, const char *failureMsg, const QLatin1String & val1, QStringView val2, const char *actual, const char *expected, const char *file, int line) { return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line); } void QTestResult::addFailure(const char *message, const char *file, int line) { clearExpectFail(); if (QTest::blacklistCurrentTest) QTestLog::addBFail(message, file, line); else QTestLog::addFail(message, file, line); QTest::failed = true; } void QTestResult::addSkip(const char *message, const char *file, int line) { clearExpectFail(); QTestLog::addSkip(message, file, line); } void QTestResult::setCurrentTestObject(const char *name) { QTest::currentTestObjectName = name; } const char *QTestResult::currentTestObjectName() { return QTest::currentTestObjectName ? QTest::currentTestObjectName : ""; } void QTestResult::setSkipCurrentTest(bool value) { QTest::skipCurrentTest = value; } bool QTestResult::skipCurrentTest() { return QTest::skipCurrentTest; } void QTestResult::setCurrentAppName(const char *appName) { ::currentAppName = appName; } const char *QTestResult::currentAppName() { return ::currentAppName; } QT_END_NAMESPACE