summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2023-09-13 17:21:34 +0200
committerIvan Solovev <ivan.solovev@qt.io>2023-11-13 16:35:54 +0100
commitbfb237d19a5319bfa020ad0cefaff72e8d94a9be (patch)
tree60c7d18596c120c71680960473201694be1a28b3
parente4bde15e149cf449911c9b871acfe8fafd4ac712 (diff)
TestLib: provide helper functions to test relational operators
The patch provides two sets of functions: * functions to perform compile-time check for all cv-ref combinations * functions that actually verify the comparison results for all cv-ref combinations. For now it does not test operator<=>(), even if compiled with C++20, because Qt types do not yet implement it. The patch uses the new helper functions to improve testing of date and time classes, because they already provide a full set of relational operators. Change-Id: I8bd869c489543719ea856d6609cac53cbd4dc122 Reviewed-by: Marc Mutz <marc.mutz@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
-rw-r--r--src/testlib/CMakeLists.txt1
-rw-r--r--src/testlib/qcomparisontesthelper.cpp22
-rw-r--r--src/testlib/qcomparisontesthelper_p.h239
-rw-r--r--tests/auto/corelib/time/qdate/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/time/qdate/tst_qdate.cpp212
-rw-r--r--tests/auto/corelib/time/qdatetime/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp88
-rw-r--r--tests/auto/corelib/time/qtime/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/time/qtime/tst_qtime.cpp196
9 files changed, 470 insertions, 291 deletions
diff --git a/src/testlib/CMakeLists.txt b/src/testlib/CMakeLists.txt
index 25d48a3f58..34f318f26e 100644
--- a/src/testlib/CMakeLists.txt
+++ b/src/testlib/CMakeLists.txt
@@ -21,6 +21,7 @@ qt_internal_add_module(Test
qbenchmarkmetric.cpp qbenchmarkmetric.h qbenchmarkmetric_p.h
qbenchmarkperfevents.cpp qbenchmarkperfevents_p.h
qbenchmarktimemeasurers_p.h
+ qcomparisontesthelper.cpp qcomparisontesthelper_p.h
qcsvbenchmarklogger.cpp qcsvbenchmarklogger_p.h
qemulationdetector_p.h
qjunittestlogger.cpp qjunittestlogger_p.h
diff --git a/src/testlib/qcomparisontesthelper.cpp b/src/testlib/qcomparisontesthelper.cpp
new file mode 100644
index 0000000000..b71267b625
--- /dev/null
+++ b/src/testlib/qcomparisontesthelper.cpp
@@ -0,0 +1,22 @@
+// Copyright (C) 2023 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
+
+#include "qcomparisontesthelper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QTestPrivate {
+
+QByteArray formatTypeWithCRefImpl(QMetaType type, bool isConst, bool isRef, bool isRvalueRef)
+{
+ QByteArray res(type.name());
+ if (isConst)
+ res.append(" const");
+ if (isRef)
+ res.append(isRvalueRef ? " &&" : " &");
+ return res;
+}
+
+} // namespace QTestPrivate
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qcomparisontesthelper_p.h b/src/testlib/qcomparisontesthelper_p.h
new file mode 100644
index 0000000000..6948da9c80
--- /dev/null
+++ b/src/testlib/qcomparisontesthelper_p.h
@@ -0,0 +1,239 @@
+// Copyright (C) 2023 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 QCOMPARISONTESTHELPER_P_H
+#define QCOMPARISONTESTHELPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/q20type_traits.h>
+#include <QtTest/qtest.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTestPrivate {
+
+Q_TESTLIB_EXPORT QByteArray formatTypeWithCRefImpl(QMetaType type, bool isConst,
+ bool isRef, bool isRvalueRef);
+
+template <typename T>
+QByteArray formatTypeWithCRef()
+{
+ return formatTypeWithCRefImpl(QMetaType::fromType<q20::remove_cvref_t<T>>(),
+ std::is_const_v<std::remove_reference_t<T>>,
+ std::is_reference_v<T>,
+ std::is_rvalue_reference_v<T>);
+}
+
+#define FOR_EACH_CREF(Func, Left, Right, Op, Result) \
+ Func(Left &, Right &, Op, Result) \
+ Func(Left &, Right const &, Op, Result) \
+ Func(Left &, Right &&, Op, Result) \
+ Func(Left &, Right const &&, Op, Result) \
+ Func(Left const &, Right &, Op, Result) \
+ Func(Left const &, Right const &, Op, Result) \
+ Func(Left const &, Right &&, Op, Result) \
+ Func(Left const &, Right const &&, Op, Result) \
+ Func(Left &&, Right &, Op, Result) \
+ Func(Left &&, Right const &, Op, Result) \
+ Func(Left &&, Right &&, Op, Result) \
+ Func(Left &&, Right const &&, Op, Result) \
+ Func(Left const &&, Right &, Op, Result) \
+ Func(Left const &&, Right const &, Op, Result) \
+ Func(Left const &&, Right &&, Op, Result) \
+ Func(Left const &&, Right const &&, Op, Result) \
+ /* END */
+
+#define CHECK_SINGLE_OPERATOR(Left, Right, Op, Result) \
+ do { \
+ constexpr bool qtest_op_check_isImplNoexcept \
+ = noexcept(std::declval<Left>() Op std::declval<Right>()); \
+ if constexpr (!qtest_op_check_isImplNoexcept) { \
+ QEXPECT_FAIL("", QByteArray("(" + formatTypeWithCRef<Left>() \
+ + " " #Op " " + formatTypeWithCRef<Right>() \
+ + ") is not noexcept").constData(), \
+ Continue); \
+ /* Ideally, operators should be noexcept, so warn if they are not. */ \
+ /* Do not make it a hard error, because the fix is not always trivial. */ \
+ QVERIFY(qtest_op_check_isImplNoexcept); \
+ } \
+ static_assert(std::is_convertible_v<decltype( \
+ std::declval<Left>() Op std::declval<Right>()), Result>); \
+ if constexpr (!std::is_same_v<Left, Right>) { \
+ static_assert(std::is_convertible_v<decltype( \
+ std::declval<Right>() Op std::declval<Left>()), Result>); \
+ } \
+ } while (false); \
+ /* END */
+
+/*!
+ \internal
+
+ This function checks that the types \c LeftType and \c RightType properly
+ define {in}equality operators (== and !=). The checks are performed for
+ all combinations of cvref-qualified lvalues and rvalues.
+*/
+template <typename LeftType, typename RightType = LeftType>
+void testEqualityOperatorsCompile()
+{
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, ==, bool)
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, !=, bool)
+}
+
+/*!
+ \internal
+
+ This function checks that the types \c LeftType and \c RightType properly
+ define all comparison operators (==, !=, <, >, <=, >=). The checks are
+ performed for all combinations of cvref-qualified lvalues and rvalues.
+*/
+template <typename LeftType, typename RightType = LeftType>
+void testAllComparisonOperatorsCompile()
+{
+ testEqualityOperatorsCompile<LeftType, RightType>();
+ if (QTest::currentTestFailed())
+ return;
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, >, bool)
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <, bool)
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, >=, bool)
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <=, bool)
+}
+
+#undef CHECK_SINGLE_OPERATOR
+#undef FOR_EACH_CREF
+
+#define CHECK_RUNTIME_LR(Left, Right, Op, Expected) \
+ do { \
+ QCOMPARE_EQ(Left Op Right, Expected); \
+ QCOMPARE_EQ(std::move(Left) Op Right, Expected); \
+ QCOMPARE_EQ(Left Op std::move(Right), Expected); \
+ QCOMPARE_EQ(std::move(Left) Op std::move(Right), Expected); \
+ } while (false); \
+ /* END */
+
+#define CHECK_RUNTIME_CREF(Func, Left, Right, Op, Expected) \
+ Func(Left, Right, Op, Expected); \
+ Func(std::as_const(Left), Right, Op, Expected); \
+ Func(Left, std::as_const(Right), Op, Expected); \
+ Func(std::as_const(Left), std::as_const(Right), Op, Expected); \
+ /* END */
+
+/*!
+ \internal
+ Basic testing of equality operators.
+
+ The helper function tests {in}equality operators (== and !=) for the \a lhs
+ operand of type \c {LeftType} and the \a rhs operand of type \c {RightType}.
+
+ The \a expectedEqual parameter is an expected result for \c {operator==()}.
+
+ \note Any test calling this method will need to check the test state after
+ doing so, if there is any later code in the test.
+
+ \code
+ QTime early(12, 34, 56, 00);
+ QTime later(12, 34, 56, 01);
+ QTestPrivate::testEqualityOperators(early, later, false);
+ if (QTest:currentTestFailed())
+ return;
+ \endcode
+*/
+template <typename LeftType, typename RightType>
+void testEqualityOperators(LeftType lhs, RightType rhs, bool expectedEqual)
+{
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, ==, expectedEqual)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, !=, !expectedEqual)
+ if constexpr (!std::is_same_v<LeftType, RightType>) {
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==, expectedEqual)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, !=, !expectedEqual)
+ }
+}
+
+/*!
+ \internal
+ Basic testing of equality and relation operators.
+
+ The helper function tests all six relation and equality operators
+ (==, !=, <, >, <=, >=) for the \a lhs operand of type \c {LeftType} and
+ the \a rhs operand of type \c {RightType}.
+
+ The \c OrderingType must be one of QPartialOrdering, QStrongOrdering, or
+ QWeakOrdering.
+
+ The \a expectedOrdering parameter provides the expected
+ relation between \a lhs and \a rhs.
+
+ \note Any test calling this method will need to check the test state after
+ doing so, if there is any later code in the test.
+
+ \code
+ QDateTime now = QDateTime::currentDateTime();
+ QDateTime later = now.addMSec(1);
+ QTestPrivate::testComparisonOperators(now, later, QWeakOrdering::Less);
+ if (QTest:currentTestFailed())
+ return;
+ \endcode
+*/
+template <typename LeftType, typename RightType, typename OrderingType>
+void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expectedOrdering)
+{
+ constexpr bool isQOrderingType = std::is_same_v<OrderingType, QPartialOrdering>
+ || std::is_same_v<OrderingType, QWeakOrdering>
+ || std::is_same_v<OrderingType, QStrongOrdering>;
+
+ static_assert(isQOrderingType,
+ "Please provide, as the expectedOrdering parameter, a value "
+ "of one of the Q{Partial,Weak,Strong}Ordering types.");
+
+ // We have all sorts of operator==() between Q*Ordering and std::*_ordering
+ // types, so we can just compare to QPartialOrdering.
+ const bool expectedEqual = expectedOrdering == QPartialOrdering::Equivalent;
+ const bool expectedLess = expectedOrdering == QPartialOrdering::Less;
+ const bool expectedUnordered = expectedOrdering == QPartialOrdering::Unordered;
+
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, ==,
+ !expectedUnordered && expectedEqual)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, !=,
+ expectedUnordered || !expectedEqual)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, <,
+ !expectedUnordered && expectedLess)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, >,
+ !expectedUnordered && !expectedLess && !expectedEqual)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, <=,
+ !expectedUnordered && (expectedEqual || expectedLess))
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, >=,
+ !expectedUnordered && !expectedLess)
+
+ if constexpr (!std::is_same_v<LeftType, RightType>) {
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==,
+ !expectedUnordered && expectedEqual)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, !=,
+ expectedUnordered || !expectedEqual)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, <,
+ !expectedUnordered && !expectedLess && !expectedEqual)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, >,
+ !expectedUnordered && expectedLess)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, <=,
+ !expectedUnordered && !expectedLess)
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, >=,
+ !expectedUnordered && (expectedEqual || expectedLess))
+ }
+}
+
+#undef CHECK_RUNTIME_CREF
+#undef CHECK_RUNTIME_LR
+
+} // namespace QTestPrivate
+
+QT_END_NAMESPACE
+
+#endif // QCOMPARISONTESTHELPER_P_H
diff --git a/tests/auto/corelib/time/qdate/CMakeLists.txt b/tests/auto/corelib/time/qdate/CMakeLists.txt
index 4dff2a6639..4d0f04a967 100644
--- a/tests/auto/corelib/time/qdate/CMakeLists.txt
+++ b/tests/auto/corelib/time/qdate/CMakeLists.txt
@@ -19,4 +19,5 @@ qt_internal_add_test(tst_qdate
QT_NO_KEYWORDS
LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/time/qdate/tst_qdate.cpp b/tests/auto/corelib/time/qdate/tst_qdate.cpp
index 2ab928ef82..4b3698e18c 100644
--- a/tests/auto/corelib/time/qdate/tst_qdate.cpp
+++ b/tests/auto/corelib/time/qdate/tst_qdate.cpp
@@ -10,6 +10,7 @@
#include <QTimeZone>
#include <private/qglobal_p.h> // for the icu feature test
+#include <private/qcomparisontesthelper_p.h>
#include <private/qdatetime_p.h>
#if !QT_CONFIG(timezone)
# include <private/qtenvironmentvariables_p.h> // for qTzName()
@@ -57,12 +58,12 @@ private Q_SLOTS:
void addYears_data();
void addYears();
void daysTo();
+ void orderingCompiles();
void operator_eq_eq_data();
void operator_eq_eq();
- void operator_lt();
- void operator_gt();
- void operator_lt_eq();
- void operator_gt_eq();
+ void ordering_data();
+ void ordering();
+ void ordering_chrono_types();
void operator_insert_extract_data();
void operator_insert_extract();
#if QT_CONFIG(datestring)
@@ -992,6 +993,17 @@ void tst_QDate::daysTo()
QCOMPARE(zeroDate.daysTo(minDate), minJd);
}
+void tst_QDate::orderingCompiles()
+{
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate>();
+#if __cpp_lib_chrono >= 201907L
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate, std::chrono::year_month_day>();
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate, std::chrono::year_month_day_last>();
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate, std::chrono::year_month_weekday>();
+ QTestPrivate::testAllComparisonOperatorsCompile<QDate, std::chrono::year_month_weekday_last>();
+#endif
+}
+
void tst_QDate::operator_eq_eq_data()
{
QTest::addColumn<QDate>("d1");
@@ -1028,137 +1040,91 @@ void tst_QDate::operator_eq_eq()
QFETCH(QDate, d2);
QFETCH(bool, expectEqual);
- bool equal = d1 == d2;
- QCOMPARE(equal, expectEqual);
- bool notEqual = d1 != d2;
- QCOMPARE(notEqual, !expectEqual);
+ QTestPrivate::testEqualityOperators(d1, d2, expectEqual);
+ if (QTest::currentTestFailed())
+ return;
- if (equal)
+ if (expectEqual)
QVERIFY(qHash(d1) == qHash(d2));
}
-void tst_QDate::operator_lt()
+void tst_QDate::ordering_data()
{
- QDate d1(2000,1,2);
- QDate d2(2000,1,2);
- QVERIFY( !(d1 < d2) );
-
- d1 = QDate(2001,12,4);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 < d2 );
-
- d1 = QDate(2001,11,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 < d2 );
-
- d1 = QDate(2000,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 < d2 );
-
- d1 = QDate(2002,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 < d2) );
-
- d1 = QDate(2001,12,5);
- d2 = QDate(2001,11,5);
- QVERIFY( !(d1 < d2) );
-
- d1 = QDate(2001,12,6);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 < d2) );
+ QTest::addColumn<QDate>("left");
+ QTest::addColumn<QDate>("right");
+ QTest::addColumn<QStrongOrdering>("expectedOrdering");
+
+ QTest::newRow("2000-1-2_vs_2000-1-2")
+ << QDate(2000, 1, 2) << QDate(2000, 1, 2) << QStrongOrdering::Equivalent;
+ QTest::newRow("2001-12-4_vs_2001-12-5")
+ << QDate(2001, 12, 4) << QDate(2001, 12, 5) << QStrongOrdering::Less;
+ QTest::newRow("2001-11-5_vs_2001-12-5")
+ << QDate(2001, 11, 5) << QDate(2001, 12, 5) << QStrongOrdering::Less;
+ QTest::newRow("2000-12-5_vs_2001-12-5")
+ << QDate(2000, 12, 5) << QDate(2001, 12, 5) << QStrongOrdering::Less;
+ QTest::newRow("2002-12-5_vs_2001-12-5")
+ << QDate(2002, 12, 5) << QDate(2001, 12, 5) << QStrongOrdering::Greater;
+ QTest::newRow("2001-12-5_vs_2001-11-5")
+ << QDate(2001, 12, 5) << QDate(2001, 11, 5) << QStrongOrdering::Greater;
+ QTest::newRow("2001-12-6_vs_2001-12-5")
+ << QDate(2001, 12, 6) << QDate(2001, 12, 5) << QStrongOrdering::Greater;
}
-void tst_QDate::operator_gt()
+void tst_QDate::ordering()
{
- QDate d1(2000,1,2);
- QDate d2(2000,1,2);
- QVERIFY( !(d1 > d2) );
-
- d1 = QDate(2001,12,4);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 > d2) );
-
- d1 = QDate(2001,11,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 > d2) );
-
- d1 = QDate(2000,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 > d2) );
+ QFETCH(QDate, left);
+ QFETCH(QDate, right);
+ QFETCH(QStrongOrdering, expectedOrdering);
- d1 = QDate(2002,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 > d2 );
-
- d1 = QDate(2001,12,5);
- d2 = QDate(2001,11,5);
- QVERIFY( d1 > d2 );
-
- d1 = QDate(2001,12,6);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 > d2 );
+ QTestPrivate::testAllComparisonOperators(left, right, expectedOrdering);
}
-void tst_QDate::operator_lt_eq()
+void tst_QDate::ordering_chrono_types()
{
- QDate d1(2000,1,2);
- QDate d2(2000,1,2);
- QVERIFY( d1 <= d2 );
-
- d1 = QDate(2001,12,4);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 <= d2 );
-
- d1 = QDate(2001,11,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 <= d2 );
-
- d1 = QDate(2000,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 <= d2 );
-
- d1 = QDate(2002,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 <= d2) );
-
- d1 = QDate(2001,12,5);
- d2 = QDate(2001,11,5);
- QVERIFY( !(d1 <= d2) );
-
- d1 = QDate(2001,12,6);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 <= d2) );
-}
-
-void tst_QDate::operator_gt_eq()
-{
- QDate d1(2000,1,2);
- QDate d2(2000,1,2);
- QVERIFY( d1 >= d2 );
-
- d1 = QDate(2001,12,4);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 >= d2) );
-
- d1 = QDate(2001,11,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 >= d2) );
-
- d1 = QDate(2000,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( !(d1 >= d2) );
-
- d1 = QDate(2002,12,5);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 >= d2 );
-
- d1 = QDate(2001,12,5);
- d2 = QDate(2001,11,5);
- QVERIFY( d1 >= d2 );
-
- d1 = QDate(2001,12,6);
- d2 = QDate(2001,12,5);
- QVERIFY( d1 >= d2 );
+#if __cpp_lib_chrono >= 201907L
+ using namespace std::chrono;
+ QDate friday(2001, 11, 30); // the 5th Friday of November 2001
+ // std::chrono::year_month_day
+ QTestPrivate::testAllComparisonOperators(friday, year_month_day(2001y, November, 29d),
+ QStrongOrdering::Greater);
+ QTestPrivate::testAllComparisonOperators(friday, year_month_day(2001y, November, 30d),
+ QStrongOrdering::Equivalent);
+ QTestPrivate::testAllComparisonOperators(friday, year_month_day(2001y, December, 1d),
+ QStrongOrdering::Less);
+
+ // std::chrono::year_month_day_last
+ QTestPrivate::testAllComparisonOperators(friday, year_month_day_last(2001y, {October / last}),
+ QStrongOrdering::Greater);
+ QTestPrivate::testAllComparisonOperators(friday, year_month_day_last(2001y, {November / last}),
+ QStrongOrdering::Equivalent);
+ QTestPrivate::testAllComparisonOperators(friday, year_month_day_last(2001y, {December / last}),
+ QStrongOrdering::Less);
+
+ // std::chrono::year_month_weekday
+ QTestPrivate::testAllComparisonOperators(friday,
+ year_month_weekday(2001y, November, Thursday[5]),
+ QStrongOrdering::Greater);
+ QTestPrivate::testAllComparisonOperators(friday,
+ year_month_weekday(2001y, November, Friday[5]),
+ QStrongOrdering::Equivalent);
+ QTestPrivate::testAllComparisonOperators(friday,
+ year_month_weekday(2001y, December, Saturday[1]),
+ QStrongOrdering::Less);
+
+ // std::chrono::year_month_weekday_last
+ QDate thursday(2001, 11, 29); // the last Thursday of November 2001
+ QTestPrivate::testAllComparisonOperators(thursday, year_month_weekday_last(2001y, November,
+ Wednesday[last]),
+ QStrongOrdering::Greater);
+ QTestPrivate::testAllComparisonOperators(thursday, year_month_weekday_last(2001y, November,
+ Thursday[last]),
+ QStrongOrdering::Equivalent);
+ QTestPrivate::testAllComparisonOperators(thursday, year_month_weekday_last(2001y, November,
+ Friday[last]),
+ QStrongOrdering::Less);
+#else
+ QSKIP("This test requires C++20-level <chrono> support enabled in the standard library.");
+#endif // __cpp_lib_chrono >= 201907L
}
Q_DECLARE_METATYPE(QDataStream::Version)
diff --git a/tests/auto/corelib/time/qdatetime/CMakeLists.txt b/tests/auto/corelib/time/qdatetime/CMakeLists.txt
index c1aed5aad5..499369c131 100644
--- a/tests/auto/corelib/time/qdatetime/CMakeLists.txt
+++ b/tests/auto/corelib/time/qdatetime/CMakeLists.txt
@@ -19,6 +19,7 @@ qt_internal_add_test(tst_qdatetime
QT_NO_KEYWORDS
LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
## Scopes:
diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
index 7ae4a8b52e..5f6cea2e3a 100644
--- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
@@ -8,6 +8,7 @@
#include <QTimeZone>
#include <private/qdatetime_p.h>
#include <private/qtenvironmentvariables_p.h> // for qTzSet(), qTzName()
+#include <private/qcomparisontesthelper_p.h>
#ifdef Q_OS_WIN
# include <qt_windows.h>
@@ -99,8 +100,11 @@ private Q_SLOTS:
void secsTo();
void msecsTo_data() { addMSecs_data(); }
void msecsTo();
+ void orderingCompiles();
void operator_eqeq_data();
void operator_eqeq();
+ void ordering_data();
+ void ordering();
void operator_insert_extract_data();
void operator_insert_extract();
void currentDateTime();
@@ -1985,6 +1989,11 @@ void tst_QDateTime::msecsTo()
}
}
+void tst_QDateTime::orderingCompiles()
+{
+ QTestPrivate::testAllComparisonOperatorsCompile<QDateTime>();
+}
+
void tst_QDateTime::currentDateTime()
{
time_t buf1, buf2;
@@ -2463,23 +2472,24 @@ void tst_QDateTime::operator_eqeq()
QFETCH(bool, expectEqual);
QFETCH(bool, checkEuro);
- QVERIFY(dt1 == dt1);
- QVERIFY(!(dt1 != dt1));
+ QTestPrivate::testEqualityOperators(dt1, dt1, true);
+ if (QTest::currentTestFailed())
+ return;
- QVERIFY(dt2 == dt2);
- QVERIFY(!(dt2 != dt2));
+ QTestPrivate::testEqualityOperators(dt2, dt2, true);
+ if (QTest::currentTestFailed())
+ return;
+
+ QTestPrivate::testEqualityOperators(dt1, dt2, expectEqual);
+ if (QTest::currentTestFailed())
+ return;
QVERIFY(dt1 != QDateTime::currentDateTime());
QVERIFY(dt2 != QDateTime::currentDateTime());
QVERIFY(dt1.toUTC() == dt1.toUTC());
- bool equal = dt1 == dt2;
- QCOMPARE(equal, expectEqual);
- bool notEqual = dt1 != dt2;
- QCOMPARE(notEqual, !expectEqual);
-
- if (equal)
+ if (expectEqual)
QVERIFY(qHash(dt1) == qHash(dt2));
if (checkEuro && zoneIsCET) {
@@ -2488,6 +2498,64 @@ void tst_QDateTime::operator_eqeq()
}
}
+void tst_QDateTime::ordering_data()
+{
+ QTest::addColumn<QDateTime>("left");
+ QTest::addColumn<QDateTime>("right");
+ QTest::addColumn<QWeakOrdering>("expectedOrdering");
+
+ Q_CONSTINIT static const auto constructName = [](const QDateTime &dt) -> QByteArray {
+ if (dt.isNull())
+ return "null";
+ if (!dt.isValid())
+ return "invalid";
+ return dt.toString(Qt::ISODateWithMs).toLatin1();
+ };
+
+ Q_CONSTINIT static const auto generateRow =
+ [](const QDateTime &left, const QDateTime &right, QWeakOrdering ordering) {
+ const QByteArray leftStr = constructName(left);
+ const QByteArray rightStr = constructName(right);
+ QTest::addRow("%s_vs_%s", leftStr.constData(), rightStr.constData())
+ << left << right << ordering;
+ };
+
+ QDateTime june(QDate(2012, 6, 20), QTime(14, 33, 2, 500));
+ QDateTime juneLater = june.addMSecs(1);
+ QDateTime badDay(QDate(2012, 20, 6), QTime(14, 33, 2, 500)); // Invalid
+ QDateTime epoch(QDate(1970, 1, 1), QTime(0, 0), UTC); // UTC epoch
+ QDateTime nextDay = epoch.addDays(1);
+ QDateTime prevDay = epoch.addDays(-1);
+ // Ensure that different times may be equal when considering timezone.
+ QDateTime epochEast1h(epoch.addSecs(3600));
+ epochEast1h.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(3600));
+ QDateTime epochWest1h(epoch.addSecs(-3600));
+ epochWest1h.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(-3600));
+ QDateTime local1970(epoch.date(), epoch.time()); // Local time's epoch
+
+ generateRow(june, june, QWeakOrdering::Equivalent);
+ generateRow(june, juneLater, QWeakOrdering::Less);
+ generateRow(june, badDay, QWeakOrdering::Greater);
+ generateRow(badDay, QDateTime(), QWeakOrdering::Equivalent);
+ generateRow(june, QDateTime(), QWeakOrdering::Greater);
+ generateRow(epoch, nextDay, QWeakOrdering::Less);
+ generateRow(epoch, prevDay, QWeakOrdering::Greater);
+ generateRow(epoch, epochEast1h, QWeakOrdering::Equivalent);
+ generateRow(epoch, epochWest1h, QWeakOrdering::Equivalent);
+ generateRow(epochEast1h, epochWest1h, QWeakOrdering::Equivalent);
+ if (epochTimeType == LocalTimeIsUtc)
+ generateRow(epoch, local1970, QWeakOrdering::Equivalent);
+}
+
+void tst_QDateTime::ordering()
+{
+ QFETCH(QDateTime, left);
+ QFETCH(QDateTime, right);
+ QFETCH(QWeakOrdering, expectedOrdering);
+
+ QTestPrivate::testAllComparisonOperators(left, right, expectedOrdering);
+}
+
Q_DECLARE_METATYPE(QDataStream::Version)
void tst_QDateTime::operator_insert_extract_data()
diff --git a/tests/auto/corelib/time/qtime/CMakeLists.txt b/tests/auto/corelib/time/qtime/CMakeLists.txt
index 9aff56bf41..6fe2968107 100644
--- a/tests/auto/corelib/time/qtime/CMakeLists.txt
+++ b/tests/auto/corelib/time/qtime/CMakeLists.txt
@@ -19,4 +19,5 @@ qt_internal_add_test(tst_qtime
QT_NO_KEYWORDS
LIBRARIES
Qt::CorePrivate
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/time/qtime/tst_qtime.cpp b/tests/auto/corelib/time/qtime/tst_qtime.cpp
index 74631229d1..d9d3698ef6 100644
--- a/tests/auto/corelib/time/qtime/tst_qtime.cpp
+++ b/tests/auto/corelib/time/qtime/tst_qtime.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <private/qglobal_p.h>
+#include <private/qcomparisontesthelper_p.h>
#include <QTest>
#include "qdatetime.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@@ -27,12 +28,11 @@ private Q_SLOTS:
void addMSecs();
void addSecs_data();
void addSecs();
+ void orderingCompiles();
void operator_eq_eq_data();
void operator_eq_eq();
- void operator_lt();
- void operator_gt();
- void operator_lt_eq();
- void operator_gt_eq();
+ void ordering_data();
+ void ordering();
#if QT_CONFIG(datestring)
# if QT_CONFIG(datetimeparser)
void fromStringFormat_data();
@@ -320,6 +320,11 @@ void tst_QTime::msecsTo()
QCOMPARE( t1.msecsTo( t2 ), delta );
}
+void tst_QTime::orderingCompiles()
+{
+ QTestPrivate::testAllComparisonOperatorsCompile<QTime>();
+}
+
void tst_QTime::operator_eq_eq_data()
{
QTest::addColumn<QTime>("t1");
@@ -345,169 +350,44 @@ void tst_QTime::operator_eq_eq()
QFETCH(QTime, t2);
QFETCH(bool, expectEqual);
- bool equal = t1 == t2;
- QCOMPARE(equal, expectEqual);
- bool notEqual = t1 != t2;
- QCOMPARE(notEqual, !expectEqual);
+ QTestPrivate::testEqualityOperators(t1, t2, expectEqual);
+ if (QTest::currentTestFailed())
+ return;
- if (equal)
+ if (expectEqual)
QVERIFY(qHash(t1) == qHash(t2));
}
-void tst_QTime::operator_lt()
-{
- QTime t1(0,0,0,0);
- QTime t2(0,0,0,0);
- QVERIFY( !(t1 < t2) );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(12,34,56,30);
- QVERIFY( t1 < t2 );
-
- t1 = QTime(13,34,46,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 < t2 );
-
- t1 = QTime(13,24,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 < t2 );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 < t2 );
-
- t1 = QTime(14,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 < t2) );
-
- t1 = QTime(13,44,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 < t2) );
-
- t1 = QTime(13,34,56,20);
- t2 = QTime(13,34,46,20);
- QVERIFY( !(t1 < t2) );
-
- t1 = QTime(13,44,56,30);
- t2 = QTime(13,44,56,20);
- QVERIFY( !(t1 < t2) );
-}
-
-void tst_QTime::operator_gt()
-{
- QTime t1(0,0,0,0);
- QTime t2(0,0,0,0);
- QVERIFY( !(t1 > t2) );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(12,34,56,30);
- QVERIFY( !(t1 > t2) );
-
- t1 = QTime(13,34,46,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 > t2) );
-
- t1 = QTime(13,24,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 > t2) );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 > t2) );
-
- t1 = QTime(14,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 > t2 );
-
- t1 = QTime(13,44,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 > t2 );
-
- t1 = QTime(13,34,56,20);
- t2 = QTime(13,34,46,20);
- QVERIFY( t1 > t2 );
-
- t1 = QTime(13,44,56,30);
- t2 = QTime(13,44,56,20);
- QVERIFY( t1 > t2 );
-}
-
-void tst_QTime::operator_lt_eq()
+void tst_QTime::ordering_data()
{
- QTime t1(0,0,0,0);
- QTime t2(0,0,0,0);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(12,34,56,30);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(13,34,46,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(13,24,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 <= t2 );
-
- t1 = QTime(14,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 <= t2) );
-
- t1 = QTime(13,44,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 <= t2) );
-
- t1 = QTime(13,34,56,20);
- t2 = QTime(13,34,46,20);
- QVERIFY( !(t1 <= t2) );
-
- t1 = QTime(13,44,56,30);
- t2 = QTime(13,44,56,20);
- QVERIFY( !(t1 <= t2) );
+ QTest::addColumn<QTime>("left");
+ QTest::addColumn<QTime>("right");
+ QTest::addColumn<QStrongOrdering>("expectedOrdering");
+
+ auto generateRow = [](QTime t1, QTime t2, QStrongOrdering ordering) {
+ const QByteArray t1Str = t1.toString("hh:mm:ss.zz").toLatin1();
+ const QByteArray t2Str = t2.toString("hh:mm:ss.zz").toLatin1();
+ QTest::addRow("%s_vs_%s", t1Str.constData(), t2Str.constData()) << t1 << t2 << ordering;
+ };
+
+ generateRow(QTime(0, 0), QTime(0, 0), QStrongOrdering::Equivalent);
+ generateRow(QTime(12, 34, 56, 20), QTime(12, 34, 56, 30), QStrongOrdering::Less);
+ generateRow(QTime(13, 34, 46, 20), QTime(13, 34, 56, 20), QStrongOrdering::Less);
+ generateRow(QTime(13, 24, 56, 20), QTime(13, 34, 56, 20), QStrongOrdering::Less);
+ generateRow(QTime(12, 34, 56, 20), QTime(13, 34, 56, 20), QStrongOrdering::Less);
+ generateRow(QTime(14, 34, 56, 20), QTime(13, 34, 56, 20), QStrongOrdering::Greater);
+ generateRow(QTime(13, 44, 56, 20), QTime(13, 34, 56, 20), QStrongOrdering::Greater);
+ generateRow(QTime(13, 34, 56, 20), QTime(13, 34, 46, 20), QStrongOrdering::Greater);
+ generateRow(QTime(13, 34, 56, 30), QTime(13, 34, 56, 20), QStrongOrdering::Greater);
}
-void tst_QTime::operator_gt_eq()
+void tst_QTime::ordering()
{
- QTime t1(0,0,0,0);
- QTime t2(0,0,0,0);
- QVERIFY( t1 >= t2 );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(12,34,56,30);
- QVERIFY( !(t1 >= t2) );
-
- t1 = QTime(13,34,46,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 >= t2) );
-
- t1 = QTime(13,24,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 >= t2) );
-
- t1 = QTime(12,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( !(t1 >= t2) );
-
- t1 = QTime(14,34,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 >= t2 );
-
- t1 = QTime(13,44,56,20);
- t2 = QTime(13,34,56,20);
- QVERIFY( t1 >= t2 );
-
- t1 = QTime(13,34,56,20);
- t2 = QTime(13,34,46,20);
- QVERIFY( t1 >= t2 );
+ QFETCH(QTime, left);
+ QFETCH(QTime, right);
+ QFETCH(QStrongOrdering, expectedOrdering);
- t1 = QTime(13,44,56,30);
- t2 = QTime(13,44,56,20);
- QVERIFY( t1 >= t2 );
+ QTestPrivate::testAllComparisonOperators(left, right, expectedOrdering);
}
#if QT_CONFIG(datestring)