diff options
Diffstat (limited to 'src/testlib/qtestcase.h')
-rw-r--r-- | src/testlib/qtestcase.h | 226 |
1 files changed, 109 insertions, 117 deletions
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index 1a47382304..a855ace6a9 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -5,6 +5,7 @@ #define QTESTCASE_H #include <QtTest/qttestglobal.h> +#include <QtTest/qtesttostring.h> #include <QtCore/qstring.h> #include <QtCore/qnamespace.h> @@ -83,24 +84,10 @@ do {\ 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)) { \ + if (!QTest::qCompareOp<QTest::ComparisonOperation::opId>(lhs, rhs, #lhs, #rhs, __FILE__, __LINE__)) \ QTEST_FAIL_ACTION; \ - } \ } while (false) #define QCOMPARE_EQ(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, ==, Equal) @@ -239,7 +226,8 @@ do { \ #define QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, op, opId, timeout) \ do { \ - QTRY_IMPL(((computed) op (baseline)), timeout) \ + using Q_Cmp = QTest::Internal::Compare<QTest::ComparisonOperation::opId>; \ + QTRY_IMPL(Q_Cmp::compare((computed), (baseline)), timeout) \ QCOMPARE_OP_IMPL(computed, baseline, op, opId); \ } while (false) @@ -318,9 +306,6 @@ do {\ class QObject; class QTestData; -#define QTEST_COMPARE_DECL(KLASS)\ - template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &); - namespace QTest { namespace Internal { @@ -332,49 +317,54 @@ namespace QTest 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) + template <ComparisonOperation> struct Compare; + template <> struct Compare<ComparisonOperation::Equal> { - QMetaEnum me = QMetaEnum::fromType<T>(); - return qstrdup(me.valueToKey(int(e))); // int cast is necessary to support enum classes - } - - template <typename T> - inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e) + template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs) + { return std::forward<T1>(lhs) == std::forward<T2>(rhs); } + }; + template <> struct Compare<ComparisonOperation::NotEqual> { - return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData()); - } + template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs) + { return std::forward<T1>(lhs) != std::forward<T2>(rhs); } + }; + template <> struct Compare<ComparisonOperation::LessThan> + { + template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs) + { return std::forward<T1>(lhs) < std::forward<T2>(rhs); } + }; + template <> struct Compare<ComparisonOperation::LessThanOrEqual> + { + template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs) + { return std::forward<T1>(lhs) <= std::forward<T2>(rhs); } + }; + template <> struct Compare<ComparisonOperation::GreaterThan> + { + template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs) + { return std::forward<T1>(lhs) > std::forward<T2>(rhs); } + }; + template <> struct Compare<ComparisonOperation::GreaterThanOrEqual> + { + template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs) + { return std::forward<T1>(lhs) >= std::forward<T2>(rhs); } + }; - 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) - { - 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 T1> const char *genericToString(const void *arg) + { + using QTest::toString; + return toString(*static_cast<const T1 *>(arg)); } - template<typename F> // Output QFlags of registered enumerations - inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f) + template <> inline const char *genericToString<char *>(const void *arg) { - const QMetaEnum me = QMetaEnum::fromType<F>(); - return qstrdup(me.valueToKeys(int(f.toInt())).constData()); + using QTest::toString; + return toString(static_cast<const char *>(arg)); } - template <typename F> // Fallback: Output hex value - inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f) + template <typename T> const char *pointerToString(const void *arg) { - 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.toInt())); - return msg; + using QTest::toString; + return toString(static_cast<const T *>(arg)); } // Exported so Qt Quick Test can also use it for generating backtraces upon crashes. @@ -382,29 +372,6 @@ namespace QTest } // namespace Internal - template<typename T> - inline char *toString(const T &t) - { - return Internal::toString(t); - } - - 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); - - 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 *); - 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(); Q_TESTLIB_EXPORT void qCleanup(); @@ -468,6 +435,7 @@ namespace QTest #if QT_CONFIG(regularexpression) Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern); #endif + Q_TESTLIB_EXPORT void failOnWarning(); Q_TESTLIB_EXPORT void failOnWarning(const char *message); #if QT_CONFIG(regularexpression) Q_TESTLIB_EXPORT void failOnWarning(const QRegularExpression &messagePattern); @@ -495,10 +463,8 @@ namespace QTest 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, " + QT_DEPRECATED_VERSION_X_6_4("use an overload that takes a formatter callback, " "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, @@ -506,11 +472,22 @@ namespace QTest const char *actual, const char *expected, const char *file, int line); #endif // QT_DEPRECATED_SINCE(6, 4) +#if QT_DEPRECATED_SINCE(6, 8) + QT_DEPRECATED_VERSION_X_6_8("use an overload that takes a formatter callback, " + "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, qxp::function_ref<const char*()> actualVal, qxp::function_ref<const char*()> expectedVal, const char *actual, const char *expected, const char *file, int line); +#endif // QT_DEPRECATED_SINCE(6, 8) + Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg, + const void *actualPtr, const void *expectedPtr, + const char *(*actualFormatter)(const void *), + const char *(*expectedFormatter)(const void *), + 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); @@ -578,81 +555,71 @@ namespace QTest inline bool compare_ptr_helper(const volatile void *t1, const volatile void *t2, const char *actual, const char *expected, const char *file, int line) { + auto formatter = Internal::pointerToString<void>; return compare_helper(t1 == t2, "Compared pointers are not the same", - [t1] { return toString(t1); }, [t2] { return toString(t2); }, - actual, expected, file, line); + const_cast<const void *>(t1), const_cast<const void *>(t2), + formatter, formatter, 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) { + auto formatter = Internal::pointerToString<QObject>; return compare_helper(t1 == t2, "Compared QObject pointers are not the same", - [t1] { return toString(t1); }, [t2] { return toString(t2); }, - actual, expected, file, line); + const_cast<const QObject *>(t1), const_cast<const QObject *>(t2), + formatter, formatter, 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) { + auto lhsFormatter = Internal::pointerToString<QObject>; + auto rhsFormatter = Internal::genericToString<std::nullptr_t>; return compare_helper(t1 == nullptr, "Compared QObject pointers are not the same", - [t1] { return toString(t1); }, [] { return toString(nullptr); }, - actual, expected, file, line); + const_cast<const QObject *>(t1), nullptr, + lhsFormatter, rhsFormatter, 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) { + auto lhsFormatter = Internal::genericToString<std::nullptr_t>; + auto rhsFormatter = Internal::pointerToString<QObject>; return compare_helper(nullptr == t2, "Compared QObject pointers are not the same", - [] { return toString(nullptr); }, [t2] { return toString(t2); }, - actual, expected, file, line); + nullptr, const_cast<const QObject *>(t2), + lhsFormatter, rhsFormatter, 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) { + auto lhsFormatter = Internal::pointerToString<void>; + auto rhsFormatter = Internal::genericToString<std::nullptr_t>; return compare_helper(t1 == nullptr, "Compared pointers are not the same", - [t1] { return toString(t1); }, [] { return toString(nullptr); }, - actual, expected, file, line); + const_cast<const void *>(t1), nullptr, + lhsFormatter, rhsFormatter, 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) { + auto lhsFormatter = Internal::genericToString<std::nullptr_t>; + auto rhsFormatter = Internal::pointerToString<void>; return compare_helper(nullptr == t2, "Compared pointers are not the same", - [] { return toString(nullptr); }, [t2] { return toString(t2); }, - actual, expected, file, line); + nullptr, const_cast<const void *>(t2), + lhsFormatter, rhsFormatter, actual, expected, file, line); } - Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual, - const char *expected, const char *file, int line); - - Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...); - -#ifndef Q_QDOC - QTEST_COMPARE_DECL(short) - QTEST_COMPARE_DECL(ushort) - QTEST_COMPARE_DECL(int) - QTEST_COMPARE_DECL(uint) - QTEST_COMPARE_DECL(long) - QTEST_COMPARE_DECL(ulong) - QTEST_COMPARE_DECL(qint64) - QTEST_COMPARE_DECL(quint64) - - QTEST_COMPARE_DECL(float) - QTEST_COMPARE_DECL(double) - QTEST_COMPARE_DECL(qfloat16) - QTEST_COMPARE_DECL(char) - QTEST_COMPARE_DECL(signed char) - QTEST_COMPARE_DECL(unsigned char) - QTEST_COMPARE_DECL(bool) -#endif - 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) { + using D1 = std::decay_t<T1>; + using D2 = std::decay_t<T2>; + using Internal::genericToString; return compare_helper(t1 == t2, "Compared values are not the same", - [&t1] { return toString(t1); }, [&t2] { return toString(t2); }, + std::addressof(t1), std::addressof(t2), + genericToString<D1>, genericToString<D2>, actual, expected, file, line); } @@ -740,13 +707,38 @@ namespace QTest qMetaTypeId<T>())), actualStr, expected, file, line); } +#if QT_DEPRECATED_SINCE(6, 8) + QT_DEPRECATED_VERSION_X_6_8("use the overload without qxp::function_ref") 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); +#endif // QT_DEPRECATED_SINCE(6, 8) + + Q_TESTLIB_EXPORT bool 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, + ComparisonOperation op, const char *file, int line); + + template <ComparisonOperation op, typename T1, typename T2 = T1> + inline bool qCompareOp(T1 &&lhs, T2 &&rhs, const char *lhsExpr, const char *rhsExpr, + const char *file, int line) + { + using D1 = std::decay_t<T1>; + using D2 = std::decay_t<T2>; + using Internal::genericToString; + using Comparator = Internal::Compare<op>; + + /* assumes that op does not actually move from lhs and rhs */ + bool result = Comparator::compare(std::forward<T1>(lhs), std::forward<T2>(rhs)); + return reportResult(result, std::addressof(lhs), std::addressof(rhs), + genericToString<D1>, genericToString<D2>, + lhsExpr, rhsExpr, op, file, line); + + } } -#undef QTEST_COMPARE_DECL #define QWARN(msg) QTest::qWarn(static_cast<const char *>(msg), __FILE__, __LINE__) |