diff options
Diffstat (limited to 'src/testlib/qtestcase.h')
-rw-r--r-- | src/testlib/qtestcase.h | 458 |
1 files changed, 333 insertions, 125 deletions
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index e5f2a8bbbf..1a47382304 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QTESTCASE_H #define QTESTCASE_H @@ -48,6 +12,8 @@ #include <QtCore/qmetaobject.h> #include <QtCore/qsharedpointer.h> #include <QtCore/qtemporarydir.h> +#include <QtCore/qthread.h> +#include <QtCore/qxpfunctional.h> #include <string.h> @@ -57,136 +23,260 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_EXCEPTIONS + +#ifdef QTEST_THROW_ON_FAILURE +# define QTEST_FAIL_ACTION QTest::Internal::throwOnFail() +#else +# define QTEST_FAIL_ACTION do { QTest::Internal::maybeThrowOnFail(); return; } while (false) +#endif + +#ifdef QTEST_THROW_ON_SKIP +# define QTEST_SKIP_ACTION QTest::Internal::throwOnSkip() +#else +# define QTEST_SKIP_ACTION do { QTest::Internal::maybeThrowOnSkip(); return; } while (false) +#endif + +#else +# if defined(QTEST_THROW_ON_FAILURE) || defined(QTEST_THROW_ON_SKIP) +# error QTEST_THROW_ON_FAILURE/SKIP require exception support enabled. +# endif +#endif // QT_NO_EXCEPTIONS + +#ifndef QTEST_FAIL_ACTION +# define QTEST_FAIL_ACTION return +#endif + +#ifndef QTEST_SKIP_ACTION +# define QTEST_SKIP_ACTION return +#endif + class qfloat16; class QRegularExpression; #define QVERIFY(statement) \ do {\ if (!QTest::qVerify(static_cast<bool>(statement), #statement, "", __FILE__, __LINE__))\ - return;\ + QTEST_FAIL_ACTION; \ } while (false) #define QFAIL(message) \ do {\ QTest::qFail(static_cast<const char *>(message), __FILE__, __LINE__);\ - return;\ + QTEST_FAIL_ACTION; \ } while (false) #define QVERIFY2(statement, description) \ do {\ if (statement) {\ if (!QTest::qVerify(true, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\ - return;\ + QTEST_FAIL_ACTION; \ } else {\ if (!QTest::qVerify(false, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\ - return;\ + QTEST_FAIL_ACTION; \ }\ } while (false) #define QCOMPARE(actual, expected) \ do {\ if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\ - return;\ + QTEST_FAIL_ACTION; \ } while (false) +// A wrapper lambda is introduced to extend the lifetime of lhs and rhs in +// case they are temporary objects. +// We also use IILE to prevent potential name clashes and shadowing of variables +// from user code. A drawback of the approach is that it looks ugly :( +#define QCOMPARE_OP_IMPL(lhs, rhs, op, opId) \ +do { \ + if (![](auto &&qt_lhs_arg, auto &&qt_rhs_arg) { \ + /* assumes that op does not actually move from qt_{lhs, rhs}_arg */ \ + return QTest::reportResult(std::forward<decltype(qt_lhs_arg)>(qt_lhs_arg) \ + op \ + std::forward<decltype(qt_rhs_arg)>(qt_rhs_arg), \ + [&qt_lhs_arg] { return QTest::toString(qt_lhs_arg); }, \ + [&qt_rhs_arg] { return QTest::toString(qt_rhs_arg); }, \ + #lhs, #rhs, QTest::ComparisonOperation::opId, \ + __FILE__, __LINE__); \ + }(lhs, rhs)) { \ + QTEST_FAIL_ACTION; \ + } \ +} while (false) + +#define QCOMPARE_EQ(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, ==, Equal) +#define QCOMPARE_NE(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, !=, NotEqual) +#define QCOMPARE_LT(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, <, LessThan) +#define QCOMPARE_LE(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, <=, LessThanOrEqual) +#define QCOMPARE_GT(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, >, GreaterThan) +#define QCOMPARE_GE(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, >=, GreaterThanOrEqual) #ifndef QT_NO_EXCEPTIONS +# define QVERIFY_THROWS_NO_EXCEPTION(...) \ + do { \ + QT_TRY { \ + __VA_ARGS__; \ + /* success */ \ + } QT_CATCH (...) { \ + QTest::qCaught(nullptr, __FILE__, __LINE__); \ + QTEST_FAIL_ACTION; \ + } \ + } while (false) \ + /* end */ + +#if QT_DEPRECATED_SINCE(6, 3) +namespace QTest { +QT_DEPRECATED_VERSION_X_6_3("Don't use QVERIFY_EXCEPTION_THROWN(expr, type) anymore, " + "use QVERIFY_THROWS_EXCEPTION(type, expr...) instead") +inline void useVerifyThrowsException() {} +} // namespace QTest # define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \ + QVERIFY_THROWS_EXCEPTION(exceptiontype, QTest::useVerifyThrowsException(); expression) +#endif + +# define QVERIFY_THROWS_EXCEPTION(exceptiontype, ...) \ do {\ + bool qverify_throws_exception_did_not_throw = false; \ QT_TRY {\ - QT_TRY {\ - expression;\ - QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \ - " but no exception caught", __FILE__, __LINE__);\ - return;\ - } QT_CATCH (const exceptiontype &) {\ - }\ - } QT_CATCH (const std::exception &e) {\ - QByteArray msg = QByteArray() + "Expected exception of type " #exceptiontype \ - " to be thrown but std::exception caught with message: " + e.what(); \ - QTest::qFail(msg.constData(), __FILE__, __LINE__);\ - return;\ - } QT_CATCH (...) {\ + __VA_ARGS__; \ QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \ - " but unknown exception caught", __FILE__, __LINE__);\ - return;\ + " but no exception caught", __FILE__, __LINE__); \ + qverify_throws_exception_did_not_throw = true; \ + } QT_CATCH (const exceptiontype &) { \ + /* success */ \ + } QT_CATCH (...) {\ + QTest::qCaught(#exceptiontype, __FILE__, __LINE__); \ + QTEST_FAIL_ACTION; \ }\ + if (qverify_throws_exception_did_not_throw) \ + QTEST_FAIL_ACTION; \ } while (false) #else // QT_NO_EXCEPTIONS /* - * The expression passed to the macro should throw an exception and we can't - * catch it because Qt has been compiled without exception support. We can't + * These macros check whether the expression passed throws exceptions, but we can't + * catch them to check because Qt has been compiled without exception support. We can't * skip the expression because it may have side effects and must be executed. * So, users must use Qt with exception support enabled if they use exceptions * in their code. */ -# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \ - static_assert(false, "Support of exceptions is disabled") +# define QVERIFY_THROWS_EXCEPTION(...) \ + static_assert(false, "Support for exceptions is disabled") +# define QVERIFY_THROWS_NO_EXCEPTION(...) \ + static_assert(false, "Support for exceptions is disabled") #endif // !QT_NO_EXCEPTIONS +/* Ideally we would adapt qWaitFor(), or a variant on it, to implement roughly + * what the following provides as QTRY_LOOP_IMPL(); however, for now, the + * reporting of how much to increase the timeout to (if within a factor of two) + * on failure and the check for (QTest::runningTest() && + * QTest::currentTestResolved()) go beyond qWaitFor(). (We no longer care about + * the bug in MSVC < 2017 that precluded using qWaitFor() in the implementation + * here, see QTBUG-59096.) + */ +// NB: not do {...} while (0) wrapped, as qt_test_i is accessed after it #define QTRY_LOOP_IMPL(expr, timeoutValue, step) \ if (!(expr)) { \ QTest::qWait(0); \ } \ int qt_test_i = 0; \ - for (; qt_test_i < timeoutValue && !(expr); qt_test_i += step) { \ + for (; qt_test_i < timeoutValue && !(QTest::runningTest() && QTest::currentTestResolved()) \ + && !(expr); qt_test_i += step) { \ QTest::qWait(step); \ } - -#define QTRY_TIMEOUT_DEBUG_IMPL(expr, timeoutValue, step)\ - if (!(expr)) { \ - QTRY_LOOP_IMPL((expr), (2 * timeoutValue), step);\ - if (expr) { \ - QString msg = QString::fromUtf8("QTestLib: This test case check (\"%1\") failed because the requested timeout (%2 ms) was too short, %3 ms would have been sufficient this time."); \ - msg = msg.arg(QString::fromUtf8(#expr)).arg(timeoutValue).arg(timeoutValue + qt_test_i); \ - QFAIL(qPrintable(msg)); \ +// Ends in a for-block, so doesn't want a following semicolon. + +#define QTRY_TIMEOUT_DEBUG_IMPL(expr, timeoutValue, step) \ + if (!(QTest::runningTest() && QTest::currentTestResolved()) && !(expr)) { \ + QTRY_LOOP_IMPL(expr, 2 * (timeoutValue), step) \ + if ((expr)) { \ + QFAIL(qPrintable(QTest::Internal::formatTryTimeoutDebugMessage(\ + u8"" #expr, timeoutValue, timeoutValue + qt_test_i))); \ } \ } -// Ideally we'd use qWaitFor instead of QTRY_LOOP_IMPL, but due -// to a compiler bug on MSVC < 2017 we can't (see QTBUG-59096) -#define QTRY_IMPL(expr, timeout)\ - const int qt_test_step = timeout < 350 ? timeout / 7 + 1 : 50; \ - const int qt_test_timeoutValue = timeout; \ - { QTRY_LOOP_IMPL((expr), qt_test_timeoutValue, qt_test_step); } \ - QTRY_TIMEOUT_DEBUG_IMPL((expr), qt_test_timeoutValue, qt_test_step)\ +#define QTRY_IMPL(expr, timeoutAsGiven)\ + const auto qt_test_timeoutAsMs = [&] { \ + /* make 5s work w/o user action: */ \ + using namespace std::chrono_literals; \ + return std::chrono::milliseconds{timeoutAsGiven}; \ + }(); \ + const int qt_test_step = qt_test_timeoutAsMs.count() < 350 ? qt_test_timeoutAsMs.count() / 7 + 1 : 50; \ + const int qt_test_timeoutValue = qt_test_timeoutAsMs.count(); \ + { QTRY_LOOP_IMPL(expr, qt_test_timeoutValue, qt_test_step) } \ + QTRY_TIMEOUT_DEBUG_IMPL(expr, qt_test_timeoutValue, qt_test_step) +// Ends with an if-block, so doesn't want a following semicolon. // Will try to wait for the expression to become true while allowing event processing #define QTRY_VERIFY_WITH_TIMEOUT(expr, timeout) \ do { \ - QTRY_IMPL((expr), timeout);\ + QTRY_IMPL(expr, timeout) \ QVERIFY(expr); \ } while (false) -#define QTRY_VERIFY(expr) QTRY_VERIFY_WITH_TIMEOUT((expr), 5000) +#define QTRY_VERIFY(expr) QTRY_VERIFY_WITH_TIMEOUT(expr, 5s) // Will try to wait for the expression to become true while allowing event processing #define QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, timeout) \ do { \ - QTRY_IMPL((expr), timeout);\ + QTRY_IMPL(expr, timeout) \ QVERIFY2(expr, messageExpression); \ } while (false) -#define QTRY_VERIFY2(expr, messageExpression) QTRY_VERIFY2_WITH_TIMEOUT((expr), (messageExpression), 5000) +#define QTRY_VERIFY2(expr, messageExpression) QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, 5s) // Will try to wait for the comparison to become successful while allowing event processing #define QTRY_COMPARE_WITH_TIMEOUT(expr, expected, timeout) \ do { \ - QTRY_IMPL(((expr) == (expected)), timeout);\ - QCOMPARE((expr), expected); \ + QTRY_IMPL((expr) == (expected), timeout) \ + QCOMPARE(expr, expected); \ +} while (false) + +#define QTRY_COMPARE(expr, expected) QTRY_COMPARE_WITH_TIMEOUT(expr, expected, 5s) + +#define QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, op, opId, timeout) \ +do { \ + QTRY_IMPL(((computed) op (baseline)), timeout) \ + QCOMPARE_OP_IMPL(computed, baseline, op, opId); \ } while (false) -#define QTRY_COMPARE(expr, expected) QTRY_COMPARE_WITH_TIMEOUT((expr), expected, 5000) +#define QTRY_COMPARE_EQ_WITH_TIMEOUT(computed, baseline, timeout) \ + QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, ==, Equal, timeout) + +#define QTRY_COMPARE_EQ(computed, baseline) QTRY_COMPARE_EQ_WITH_TIMEOUT(computed, baseline, 5s) + +#define QTRY_COMPARE_NE_WITH_TIMEOUT(computed, baseline, timeout) \ + QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, !=, NotEqual, timeout) + +#define QTRY_COMPARE_NE(computed, baseline) QTRY_COMPARE_NE_WITH_TIMEOUT(computed, baseline, 5s) + +#define QTRY_COMPARE_LT_WITH_TIMEOUT(computed, baseline, timeout) \ + QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, <, LessThan, timeout) + +#define QTRY_COMPARE_LT(computed, baseline) QTRY_COMPARE_LT_WITH_TIMEOUT(computed, baseline, 5s) + +#define QTRY_COMPARE_LE_WITH_TIMEOUT(computed, baseline, timeout) \ + QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, <=, LessThanOrEqual, timeout) + +#define QTRY_COMPARE_LE(computed, baseline) QTRY_COMPARE_LE_WITH_TIMEOUT(computed, baseline, 5s) + +#define QTRY_COMPARE_GT_WITH_TIMEOUT(computed, baseline, timeout) \ + QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, >, GreaterThan, timeout) + +#define QTRY_COMPARE_GT(computed, baseline) QTRY_COMPARE_GT_WITH_TIMEOUT(computed, baseline, 5s) + +#define QTRY_COMPARE_GE_WITH_TIMEOUT(computed, baseline, timeout) \ + QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, >=, GreaterThanOrEqual, timeout) + +#define QTRY_COMPARE_GE(computed, baseline) QTRY_COMPARE_GE_WITH_TIMEOUT(computed, baseline, 5s) #define QSKIP_INTERNAL(statement) \ do {\ QTest::qSkip(static_cast<const char *>(statement), __FILE__, __LINE__);\ - return;\ + QTEST_SKIP_ACTION; \ } while (false) #define QSKIP(statement, ...) QSKIP_INTERNAL(statement) @@ -194,7 +284,7 @@ do {\ #define QEXPECT_FAIL(dataIndex, comment, mode)\ do {\ if (!QTest::qExpectFail(dataIndex, static_cast<const char *>(comment), QTest::mode, __FILE__, __LINE__))\ - return;\ + QTEST_FAIL_ACTION; \ } while (false) #define QFETCH(Type, name)\ @@ -206,12 +296,9 @@ do {\ #define QTEST(actual, testElement)\ do {\ if (!QTest::qTest(actual, testElement, #actual, #testElement, __FILE__, __LINE__))\ - return;\ + QTEST_FAIL_ACTION; \ } while (false) -#define QWARN(msg)\ - QTest::qWarn(static_cast<const char *>(msg), __FILE__, __LINE__) - #ifdef QT_TESTCASE_BUILDDIR #ifndef QT_TESTCASE_SOURCEDIR @@ -238,6 +325,13 @@ namespace QTest { namespace Internal { + [[noreturn]] Q_TESTLIB_EXPORT void throwOnFail(); + [[noreturn]] Q_TESTLIB_EXPORT void throwOnSkip(); + Q_TESTLIB_EXPORT void maybeThrowOnFail(); + Q_TESTLIB_EXPORT void maybeThrowOnSkip(); + + Q_TESTLIB_EXPORT QString formatTryTimeoutDebugMessage(q_no_char8_t::QUtf8StringView expr, int timeout, int actual); + template<typename T> // Output registered enums inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e) { @@ -245,17 +339,33 @@ namespace QTest return qstrdup(me.valueToKey(int(e))); // int cast is necessary to support enum classes } - template <typename T> // Fallback - inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(const T &) + template <typename T> + inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e) + { + return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData()); + } + + template <typename T> // Fallback; for built-in types debug streaming must be possible + inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char *>::type toString(const T &t) { - return nullptr; + char *result = nullptr; +#ifndef QT_NO_DEBUG_STREAM + if constexpr (QTypeTraits::has_ostream_operator_v<QDebug, T>) { + result = qstrdup(QDebug::toString(t).toUtf8().constData()); + } else { + static_assert(!QMetaTypeId2<T>::IsBuiltIn, + "Built-in type must implement debug streaming operator " + "or provide QTest::toString specialization"); + } +#endif + return result; } template<typename F> // Output QFlags of registered enumerations inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f) { const QMetaEnum me = QMetaEnum::fromType<F>(); - return qstrdup(me.valueToKeys(int(f)).constData()); + return qstrdup(me.valueToKeys(int(f.toInt())).constData()); } template <typename F> // Fallback: Output hex value @@ -263,10 +373,13 @@ namespace QTest { const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0' char *msg = new char[space]; - qsnprintf(msg, space, "0x%x", unsigned(f)); + qsnprintf(msg, space, "0x%x", unsigned(f.toInt())); return msg; } + // Exported so Qt Quick Test can also use it for generating backtraces upon crashes. + Q_TESTLIB_EXPORT extern bool noCrashHandler; + } // namespace Internal template<typename T> @@ -276,19 +389,21 @@ namespace QTest } template <typename T1, typename T2> - inline char *toString(const QPair<T1, T2> &pair); - - template <typename T1, typename T2> inline char *toString(const std::pair<T1, T2> &pair); template <class... Types> inline char *toString(const std::tuple<Types...> &tuple); - Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, int length); - Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, int length); + template <typename Rep, typename Period> + inline char *toString(std::chrono::duration<Rep, Period> duration); + + Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length); + Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length); Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string); Q_TESTLIB_EXPORT char *toString(const char *); - Q_TESTLIB_EXPORT char *toString(const void *); + Q_TESTLIB_EXPORT char *toString(const volatile void *); + Q_TESTLIB_EXPORT char *toString(const void *); // ### FIXME: Qt 7: Remove + Q_TESTLIB_EXPORT char *toString(const volatile QObject *); Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc = 0, char **argv = nullptr); Q_TESTLIB_EXPORT int qRun(); @@ -297,19 +412,66 @@ namespace QTest Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = nullptr); Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments); +#if QT_CONFIG(batch_test_support) || defined(Q_QDOC) + using TestEntryFunction = int (*)(int, char **); + Q_TESTLIB_EXPORT void qRegisterTestCase(const QString &name, TestEntryFunction entryFunction); +#endif // QT_CONFIG(batch_test_support) + Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir = nullptr); + Q_TESTLIB_EXPORT void setThrowOnFail(bool enable) noexcept; + Q_TESTLIB_EXPORT void setThrowOnSkip(bool enable) noexcept; + + class ThrowOnFailEnabler { + Q_DISABLE_COPY_MOVE(ThrowOnFailEnabler) + public: + ThrowOnFailEnabler() { setThrowOnFail(true); } + ~ThrowOnFailEnabler() { setThrowOnFail(false); } + }; + + class ThrowOnSkipEnabler { + Q_DISABLE_COPY_MOVE(ThrowOnSkipEnabler) + public: + ThrowOnSkipEnabler() { setThrowOnSkip(true); } + ~ThrowOnSkipEnabler() { setThrowOnSkip(false); } + }; + + class ThrowOnFailDisabler { + Q_DISABLE_COPY_MOVE(ThrowOnFailDisabler) + public: + ThrowOnFailDisabler() { setThrowOnFail(false); } + ~ThrowOnFailDisabler() { setThrowOnFail(true); } + }; + + class ThrowOnSkipDisabler { + Q_DISABLE_COPY_MOVE(ThrowOnSkipDisabler) + public: + ThrowOnSkipDisabler() { setThrowOnSkip(false); } + ~ThrowOnSkipDisabler() { setThrowOnSkip(true); } + }; Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description, const char *file, int line); - Q_TESTLIB_EXPORT void qFail(const char *statementStr, const char *file, int line); + Q_DECL_COLD_FUNCTION + Q_TESTLIB_EXPORT void qFail(const char *message, const char *file, int line); Q_TESTLIB_EXPORT void qSkip(const char *message, const char *file, int line); Q_TESTLIB_EXPORT bool qExpectFail(const char *dataIndex, const char *comment, TestFailMode mode, const char *file, int line); + Q_DECL_COLD_FUNCTION + Q_TESTLIB_EXPORT void qCaught(const char *expected, const char *what, const char *file, int line); + Q_DECL_COLD_FUNCTION + Q_TESTLIB_EXPORT void qCaught(const char *expected, const char *file, int line); +#if QT_DEPRECATED_SINCE(6, 3) + QT_DEPRECATED_VERSION_X_6_3("Use qWarning() instead") Q_TESTLIB_EXPORT void qWarn(const char *message, const char *file = nullptr, int line = 0); +#endif Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message); #if QT_CONFIG(regularexpression) Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern); #endif + Q_TESTLIB_EXPORT void failOnWarning(const char *message); +#if QT_CONFIG(regularexpression) + Q_TESTLIB_EXPORT void failOnWarning(const QRegularExpression &messagePattern); +#endif #if QT_CONFIG(temporaryfile) Q_TESTLIB_EXPORT QSharedPointer<QTemporaryDir> qExtractTestData(const QString &dirName); @@ -327,15 +489,32 @@ namespace QTest Q_TESTLIB_EXPORT const char *currentTestFunction(); Q_TESTLIB_EXPORT const char *currentDataTag(); Q_TESTLIB_EXPORT bool currentTestFailed(); + Q_TESTLIB_EXPORT bool currentTestResolved(); + Q_TESTLIB_EXPORT bool runningTest(); // Internal, for use by macros and QTestEventLoop. Q_TESTLIB_EXPORT Qt::Key asciiToKey(char ascii); Q_TESTLIB_EXPORT char keyToAscii(Qt::Key key); + // ### TODO: remove QTestResult::compare() overload that takes char * values + // when this overload is removed. +#if QT_DEPRECATED_SINCE(6, 4) + QT_DEPRECATED_VERSION_X_6_4("use an overload that takes function_ref as parameters, " + "or an overload that takes only failure message, if you " + "do not need to stringify the values") + Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg, + char *actualVal, char *expectedVal, + const char *actual, const char *expected, + const char *file, int line); +#endif // QT_DEPRECATED_SINCE(6, 4) Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg, - char *val1, char *val2, + qxp::function_ref<const char*()> actualVal, + qxp::function_ref<const char*()> expectedVal, const char *actual, const char *expected, const char *file, int line); - Q_TESTLIB_EXPORT void qSleep(int ms); + Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg, + const char *actual, const char *expected, + const char *file, int line); + Q_TESTLIB_EXPORT void addColumnInternal(int id, const char *name); template <typename T> @@ -348,17 +527,6 @@ namespace QTest Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag); Q_TESTLIB_EXPORT QTestData &addRow(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - // kept after adding implementation of <T1, T2> out of paranoia: - template <typename T> - inline bool qCompare(T const &t1, T const &t2, const char *actual, const char *expected, - const char *file, int line) - { - return compare_helper(t1 == t2, "Compared values are not the same", - toString(t1), toString(t2), actual, expected, file, line); - } -#endif - Q_TESTLIB_EXPORT bool qCompare(qfloat16 const &t1, qfloat16 const &t2, const char *actual, const char *expected, const char *file, int line); @@ -371,16 +539,21 @@ namespace QTest Q_TESTLIB_EXPORT bool qCompare(int t1, int t2, const char *actual, const char *expected, const char *file, int line); +#if QT_POINTER_SIZE == 8 + Q_TESTLIB_EXPORT bool qCompare(qsizetype t1, qsizetype t2, const char *actual, const char *expected, + const char *file, int line); +#endif + Q_TESTLIB_EXPORT bool qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected, const char *file, int line); Q_TESTLIB_EXPORT bool qCompare(QStringView t1, QStringView t2, const char *actual, const char *expected, const char *file, int line); - Q_TESTLIB_EXPORT bool qCompare(QStringView t1, const QLatin1String &t2, + Q_TESTLIB_EXPORT bool qCompare(QStringView t1, const QLatin1StringView &t2, const char *actual, const char *expected, const char *file, int line); - Q_TESTLIB_EXPORT bool qCompare(const QLatin1String &t1, QStringView t2, + Q_TESTLIB_EXPORT bool qCompare(const QLatin1StringView &t1, QStringView t2, const char *actual, const char *expected, const char *file, int line); inline bool qCompare(const QString &t1, const QString &t2, @@ -389,13 +562,13 @@ namespace QTest { return qCompare(QStringView(t1), QStringView(t2), actual, expected, file, line); } - inline bool qCompare(const QString &t1, const QLatin1String &t2, + inline bool qCompare(const QString &t1, const QLatin1StringView &t2, const char *actual, const char *expected, const char *file, int line) { return qCompare(QStringView(t1), t2, actual, expected, file, line); } - inline bool qCompare(const QLatin1String &t1, const QString &t2, + inline bool qCompare(const QLatin1StringView &t1, const QString &t2, const char *actual, const char *expected, const char *file, int line) { @@ -406,21 +579,48 @@ namespace QTest const char *expected, const char *file, int line) { return compare_helper(t1 == t2, "Compared pointers are not the same", - toString(t1), toString(t2), actual, expected, file, line); + [t1] { return toString(t1); }, [t2] { return toString(t2); }, + actual, expected, file, line); + } + + inline bool compare_ptr_helper(const volatile QObject *t1, const volatile QObject *t2, const char *actual, + const char *expected, const char *file, int line) + { + return compare_helper(t1 == t2, "Compared QObject pointers are not the same", + [t1] { return toString(t1); }, [t2] { return toString(t2); }, + actual, expected, file, line); + } + + inline bool compare_ptr_helper(const volatile QObject *t1, std::nullptr_t, const char *actual, + const char *expected, const char *file, int line) + { + return compare_helper(t1 == nullptr, "Compared QObject pointers are not the same", + [t1] { return toString(t1); }, [] { return toString(nullptr); }, + actual, expected, file, line); + } + + inline bool compare_ptr_helper(std::nullptr_t, const volatile QObject *t2, const char *actual, + const char *expected, const char *file, int line) + { + return compare_helper(nullptr == t2, "Compared QObject pointers are not the same", + [] { return toString(nullptr); }, [t2] { return toString(t2); }, + actual, expected, file, line); } inline bool compare_ptr_helper(const volatile void *t1, std::nullptr_t, const char *actual, const char *expected, const char *file, int line) { return compare_helper(t1 == nullptr, "Compared pointers are not the same", - toString(t1), toString(nullptr), actual, expected, file, line); + [t1] { return toString(t1); }, [] { return toString(nullptr); }, + actual, expected, file, line); } inline bool compare_ptr_helper(std::nullptr_t, const volatile void *t2, const char *actual, const char *expected, const char *file, int line) { return compare_helper(nullptr == t2, "Compared pointers are not the same", - toString(nullptr), toString(t2), actual, expected, file, line); + [] { return toString(nullptr); }, [t2] { return toString(t2); }, + actual, expected, file, line); } Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual, @@ -447,12 +647,13 @@ namespace QTest QTEST_COMPARE_DECL(bool) #endif - template <typename T1, typename T2> + template <typename T1, typename T2 = T1> inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected, const char *file, int line) { return compare_helper(t1 == t2, "Compared values are not the same", - toString(t1), toString(t2), actual, expected, file, line); + [&t1] { return toString(t1); }, [&t2] { return toString(t2); }, + actual, expected, file, line); } inline bool qCompare(double const &t1, float const &t2, const char *actual, @@ -538,10 +739,17 @@ namespace QTest return qCompare(actual, *static_cast<const T *>(QTest::qElementData(elementName, qMetaTypeId<T>())), actualStr, expected, file, line); } + + Q_TESTLIB_EXPORT bool reportResult(bool success, qxp::function_ref<const char*()> lhs, + qxp::function_ref<const char*()> rhs, + const char *lhsExpr, const char *rhsExpr, + ComparisonOperation op, const char *file, int line); } #undef QTEST_COMPARE_DECL +#define QWARN(msg) QTest::qWarn(static_cast<const char *>(msg), __FILE__, __LINE__) + QT_END_NAMESPACE #endif |