QTest: replace the majority of the ugly QCOMPARE_xx macro
Using templates to make the code look nicer and be more debuggable. Previously, if you tried to step into the QCOMPARE_xx, you'd have the creations of qxp::function_ref from the lambdas before you got to the actual comparison. And all of this was in-place from macro expansion, so you couldn't tell what was happening. Now, if you step into QCOMPARE_xx, you go to qCompareOp. There are 5 frames between that point and the actual comparison (four std::forward() and the Compare::compare()) and debuggers could step over std::forward. Even if they can't, both libstdc++ and libc++ implementations are simple casts, so there's nothing more to step into. Change-Id: I12a088d1ae424825abd3fffd171dbbf7adb7e7e2 Reviewed-by: Ivan Solovev <ivan.solovev@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>bb10
parent
0756cc1eae
commit
f7e9bb7783
|
|
@ -84,23 +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 ( { \
|
||||
/* 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, 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)
|
||||
|
||||
|
|
@ -329,6 +317,38 @@ namespace QTest
|
|||
|
||||
Q_TESTLIB_EXPORT QString formatTryTimeoutDebugMessage(q_no_char8_t::QUtf8StringView expr, int timeout, int actual);
|
||||
|
||||
template <ComparisonOperation> struct Compare;
|
||||
template <> struct Compare<ComparisonOperation::Equal>
|
||||
{
|
||||
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>
|
||||
{
|
||||
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 T1> const char *genericToString(const void *arg)
|
||||
{
|
||||
using QTest::toString;
|
||||
|
|
@ -700,17 +720,21 @@ namespace QTest
|
|||
const char *lhsExpr, const char *rhsExpr,
|
||||
ComparisonOperation op, const char *file, int line);
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline bool reportResult(bool result, const T1 &lhs, const T2 &rhs,
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue