Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qcomparisontesthelper_p.h
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QCOMPARISONTESTHELPER_P_H
5#define QCOMPARISONTESTHELPER_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/q20type_traits.h>
19#include <QtCore/qxptype_traits.h>
20#include <QtTest/qtest.h>
21
23
24namespace QTestPrivate {
25
26#ifdef __cpp_lib_three_way_comparison
27template <typename LT, typename RT>
28using HasThreeWayComparisonOp = decltype(std::declval<LT>() <=> std::declval<RT>());
29
30template <typename LT, typename RT>
31constexpr bool implementsThreeWayComparisonOp_v = qxp::is_detected_v<HasThreeWayComparisonOp,
32 LT, RT>;
33#endif
34
35Q_TESTLIB_EXPORT QByteArray formatTypeWithCRefImpl(QMetaType type, bool isConst,
36 bool isRef, bool isRvalueRef);
37
38template <typename T>
40{
42 std::is_const_v<std::remove_reference_t<T>>,
43 std::is_reference_v<T>,
44 std::is_rvalue_reference_v<T>);
45}
46
47#define FOR_EACH_CREF(Func, Left, Right, Op, Result) \
48 Func(Left &, Right &, Op, Result) \
49 Func(Left &, Right const &, Op, Result) \
50 Func(Left &, Right &&, Op, Result) \
51 Func(Left &, Right const &&, Op, Result) \
52 Func(Left const &, Right &, Op, Result) \
53 Func(Left const &, Right const &, Op, Result) \
54 Func(Left const &, Right &&, Op, Result) \
55 Func(Left const &, Right const &&, Op, Result) \
56 Func(Left &&, Right &, Op, Result) \
57 Func(Left &&, Right const &, Op, Result) \
58 Func(Left &&, Right &&, Op, Result) \
59 Func(Left &&, Right const &&, Op, Result) \
60 Func(Left const &&, Right &, Op, Result) \
61 Func(Left const &&, Right const &, Op, Result) \
62 Func(Left const &&, Right &&, Op, Result) \
63 Func(Left const &&, Right const &&, Op, Result) \
64 /* END */
65
66#define CHECK_SINGLE_OPERATOR(Left, Right, Op, Result) \
67 do { \
68 constexpr bool qtest_op_check_isImplNoexcept \
69 = noexcept(std::declval<Left>() Op std::declval<Right>()); \
70 if constexpr (!qtest_op_check_isImplNoexcept) { \
71 QEXPECT_FAIL("", QByteArray("(" + formatTypeWithCRef<Left>() \
72 + " " #Op " " + formatTypeWithCRef<Right>() \
73 + ") is not noexcept").constData(), \
74 Continue); \
75 /* Ideally, operators should be noexcept, so warn if they are not. */ \
76 /* Do not make it a hard error, because the fix is not always trivial. */ \
77 QVERIFY(qtest_op_check_isImplNoexcept); \
78 } \
79 static_assert(std::is_convertible_v<decltype( \
80 std::declval<Left>() Op std::declval<Right>()), Result>); \
81 if constexpr (!std::is_same_v<Left, Right>) { \
82 static_assert(std::is_convertible_v<decltype( \
83 std::declval<Right>() Op std::declval<Left>()), Result>); \
84 } \
85 } while (false); \
86 /* END */
87
95template <typename LeftType, typename RightType = LeftType>
97{
98 FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, ==, bool)
99 FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, !=, bool)
100}
101
112template <typename LeftType, typename RightType = LeftType>
114{
115 testEqualityOperatorsCompile<LeftType, RightType>();
117 return;
118 FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, >, bool)
119 FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <, bool)
120 FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, >=, bool)
121 FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <=, bool)
122#ifdef __cpp_lib_three_way_comparison
123 if constexpr (implementsThreeWayComparisonOp_v<LeftType, RightType>) {
124 FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <=>, std::partial_ordering)
125 }
126#endif
127}
128
129#undef CHECK_SINGLE_OPERATOR
130#undef FOR_EACH_CREF
131
132#define CHECK_RUNTIME_CREF(Func, Left, Right, Op, Expected) \
133 do { \
134 Func(Left, Right, Op, Expected); \
135 Func(std::as_const(Left), Right, Op, Expected); \
136 Func(Left, std::as_const(Right), Op, Expected); \
137 Func(std::as_const(Left), std::as_const(Right), Op, Expected); \
138 } while (false) \
139 /* END */
140
141#define CHECK_RUNTIME_LR(Left, Right, Op, Expected) \
142 do { \
143 QCOMPARE_EQ(Left Op Right, Expected); \
144 QCOMPARE_EQ(std::move(Left) Op Right, Expected); \
145 QCOMPARE_EQ(Left Op std::move(Right), Expected); \
146 QCOMPARE_EQ(std::move(Left) Op std::move(Right), Expected); \
147 } while (false) \
148 /* END */
149
150#ifdef __cpp_lib_three_way_comparison
151
152// Hide the macro under an ifdef, because it otherwise triggers a warning
153// in Clang C++17 build.
154#define CHECK_RUNTIME_3WAY(Left, Right, Op, Expected) \
155 do { \
156 QCOMPARE_EQ((Left <=> Right) Op 0, Expected); \
157 QCOMPARE_EQ((std::move(Left) <=> Right) Op 0, Expected); \
158 QCOMPARE_EQ((Left <=> std::move(Right)) Op 0, Expected); \
159 QCOMPARE_EQ((std::move(Left) <=> std::move(Right)) Op 0, Expected); \
160 } while (false) \
161 /* END */
162
163#endif // __cpp_lib_three_way_comparison
164
186template <typename LeftType, typename RightType>
187void testEqualityOperators(LeftType lhs, RightType rhs, bool expectedEqual)
188{
189 CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, ==, expectedEqual);
190 CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, !=, !expectedEqual);
191 CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==, expectedEqual);
192 CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, !=, !expectedEqual);
193}
194
225template <typename LeftType, typename RightType, typename OrderingType>
226void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expectedOrdering)
227{
228 constexpr bool isQOrderingType = std::is_same_v<OrderingType, Qt::partial_ordering>
229 || std::is_same_v<OrderingType, Qt::weak_ordering>
230 || std::is_same_v<OrderingType, Qt::strong_ordering>;
231#ifdef __cpp_lib_three_way_comparison
232 constexpr bool isStdOrderingType = std::is_same_v<OrderingType, std::partial_ordering>
233 || std::is_same_v<OrderingType, std::weak_ordering>
234 || std::is_same_v<OrderingType, std::strong_ordering>;
235#else
236 constexpr bool isStdOrderingType = false;
237#endif
238
239 static_assert(isQOrderingType || isStdOrderingType,
240 "Please provide, as the expectedOrdering parameter, a value "
241 "of one of the Qt::{partial,weak,strong}_ordering or "
242 "std::{partial,weak,strong}_ordering types.");
243
244 // We have all sorts of operator==() between Q*Ordering and std::*_ordering
245 // types, so we can just compare to Qt::partial_ordering.
246 const bool expectedEqual = expectedOrdering == Qt::partial_ordering::equivalent;
247 const bool expectedLess = expectedOrdering == Qt::partial_ordering::less;
248 const bool expectedUnordered = expectedOrdering == Qt::partial_ordering::unordered;
249
251 !expectedUnordered && expectedEqual);
253 expectedUnordered || !expectedEqual);
255 !expectedUnordered && expectedLess);
257 !expectedUnordered && !expectedLess && !expectedEqual);
259 !expectedUnordered && (expectedEqual || expectedLess));
261 !expectedUnordered && !expectedLess);
262#ifdef __cpp_lib_three_way_comparison
263 if constexpr (implementsThreeWayComparisonOp_v<LeftType, RightType>) {
264 if constexpr (std::is_convertible_v<OrderingType, std::strong_ordering>)
265 static_assert(std::is_same_v<decltype(lhs <=> rhs), std::strong_ordering>);
266 else if constexpr (std::is_convertible_v<OrderingType, std::weak_ordering>)
267 static_assert(std::is_same_v<decltype(lhs <=> rhs), std::weak_ordering>);
268 else
269 static_assert(std::is_same_v<decltype(lhs <=> rhs), std::partial_ordering>);
270
271 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, ==,
272 !expectedUnordered && expectedEqual);
273 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, !=,
274 expectedUnordered || !expectedEqual);
275 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, <,
276 !expectedUnordered && expectedLess);
277 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, >,
278 !expectedUnordered && !expectedLess && !expectedEqual);
279 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, <=,
280 !expectedUnordered && (expectedEqual || expectedLess));
281 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, >=,
282 !expectedUnordered && !expectedLess);
283 }
284#endif
285
287 !expectedUnordered && expectedEqual);
289 expectedUnordered || !expectedEqual);
291 !expectedUnordered && !expectedLess && !expectedEqual);
293 !expectedUnordered && expectedLess);
295 !expectedUnordered && !expectedLess);
297 !expectedUnordered && (expectedEqual || expectedLess));
298#ifdef __cpp_lib_three_way_comparison
299 if constexpr (implementsThreeWayComparisonOp_v<LeftType, RightType>) {
300 if constexpr (std::is_convertible_v<OrderingType, std::strong_ordering>)
301 static_assert(std::is_same_v<decltype(rhs <=> lhs), std::strong_ordering>);
302 else if constexpr (std::is_convertible_v<OrderingType, std::weak_ordering>)
303 static_assert(std::is_same_v<decltype(rhs <=> lhs), std::weak_ordering>);
304 else
305 static_assert(std::is_same_v<decltype(rhs <=> lhs), std::partial_ordering>);
306
307 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, ==,
308 !expectedUnordered && expectedEqual);
309 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, !=,
310 expectedUnordered || !expectedEqual);
311 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, <,
312 !expectedUnordered && !expectedLess && !expectedEqual);
313 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, >,
314 !expectedUnordered && expectedLess);
315 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, <=,
316 !expectedUnordered && !expectedLess);
317 CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, >=,
318 !expectedUnordered && (expectedEqual || expectedLess));
319 }
320#endif
321}
322
323#ifdef __cpp_lib_three_way_comparison
324#undef CHECK_RUNTIME_3WAY
325#endif
326#undef CHECK_RUNTIME_LR
327#undef CHECK_RUNTIME_CREF
328
329} // namespace QTestPrivate
330
339#define QT_TEST_EQUALITY_OPS(Left, Right, Expected) \
340 do { \
341 auto report = qScopeGuard([] { \
342 qDebug("testEqualityOperators(" #Left ", " #Right ", " #Expected ") " \
343 "failed in " __FILE__ " on line %d", __LINE__); \
344 }); \
345 QTestPrivate::testEqualityOperators(Left, Right, Expected); \
346 if (QTest::currentTestFailed()) \
347 return; \
348 report.dismiss(); \
349 } while (false)
350
359#define QT_TEST_ALL_COMPARISON_OPS(Left, Right, Expected) \
360 do { \
361 auto report = qScopeGuard([] { \
362 qDebug("testAllComparisonOperators(" #Left ", " #Right ", " #Expected ") " \
363 "failed in " __FILE__ " on line %d", __LINE__); \
364 }); \
365 QTestPrivate::testAllComparisonOperators(Left, Right, Expected); \
366 if (QTest::currentTestFailed()) \
367 return; \
368 report.dismiss(); \
369 } while (false)
370
372
373#endif // QCOMPARISONTESTHELPER_P_H
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qmetatype.h:341
static constexpr QMetaType fromType()
Definition qmetatype.h:2642
static const partial_ordering equivalent
Definition qcompare.h:69
static const partial_ordering unordered
Definition qcompare.h:71
static const partial_ordering less
Definition qcompare.h:68
Combined button and popup list for selecting options.
void testEqualityOperators(LeftType lhs, RightType rhs, bool expectedEqual)
QByteArray formatTypeWithCRef()
void testAllComparisonOperatorsCompile()
void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expectedOrdering)
QByteArray formatTypeWithCRefImpl(QMetaType type, bool isConst, bool isRef, bool isRvalueRef)
Q_TESTLIB_EXPORT bool currentTestFailed()
Returns true if the current test function has failed, otherwise false.
std::remove_cv_t< std::remove_reference_t< T > > remove_cvref_t
constexpr bool is_detected_v
#define CHECK_SINGLE_OPERATOR(Left, Right, Op, Result)
#define FOR_EACH_CREF(Func, Left, Right, Op, Result)
#define CHECK_RUNTIME_CREF(Func, Left, Right, Op, Expected)
#define CHECK_RUNTIME_LR(Left, Right, Op, Expected)
GLenum type