summaryrefslogtreecommitdiffstats
path: root/src/testlib/qtestcase.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/testlib/qtestcase.h')
-rw-r--r--src/testlib/qtestcase.h418
1 files changed, 296 insertions, 122 deletions
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h
index 158fce4e3d..1a47382304 100644
--- a/src/testlib/qtestcase.h
+++ b/src/testlib/qtestcase.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 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
@@ -49,6 +13,7 @@
#include <QtCore/qsharedpointer.h>
#include <QtCore/qtemporarydir.h>
#include <QtCore/qthread.h>
+#include <QtCore/qxpfunctional.h>
#include <string.h>
@@ -58,134 +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); \
}
+// Ends in a for-block, so doesn't want a following semicolon.
-#define QTRY_TIMEOUT_DEBUG_IMPL(expr, timeoutValue, step)\
- if (!(expr)) { \
- QTRY_LOOP_IMPL((expr), (2 * timeoutValue), step);\
- if (expr) { \
- QFAIL(qPrintable(QTest::Internal::formatTryTimeoutDebugMessage(u8"" #expr, timeoutValue, timeoutValue + qt_test_i))); \
+#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(QTest::currentTestFailed() || (expr), qt_test_timeoutValue, qt_test_step); } \
- QTRY_TIMEOUT_DEBUG_IMPL(QTest::currentTestFailed() || (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)
@@ -193,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)\
@@ -205,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
@@ -237,6 +325,11 @@ 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
@@ -252,17 +345,27 @@ namespace QTest
return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData());
}
- template <typename T> // Fallback
- inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char*>::type toString(const T &)
+ 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
@@ -270,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>
@@ -283,16 +389,16 @@ 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 volatile void *);
@@ -306,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_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);
@@ -336,14 +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 *val1, char *val2,
+ 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,
+ 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 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>
@@ -356,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);
@@ -390,10 +550,10 @@ namespace QTest
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,
@@ -402,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)
{
@@ -419,42 +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",
- 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, 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",
- 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 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",
- toString(nullptr), toString(t2), actual, expected, file, line);
+ [] { 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,
@@ -481,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,
@@ -572,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