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.h226
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__)