diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2023-09-13 17:21:34 +0200 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2023-11-13 16:35:54 +0100 |
commit | bfb237d19a5319bfa020ad0cefaff72e8d94a9be (patch) | |
tree | 60c7d18596c120c71680960473201694be1a28b3 | |
parent | e4bde15e149cf449911c9b871acfe8fafd4ac712 (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.txt | 1 | ||||
-rw-r--r-- | src/testlib/qcomparisontesthelper.cpp | 22 | ||||
-rw-r--r-- | src/testlib/qcomparisontesthelper_p.h | 239 | ||||
-rw-r--r-- | tests/auto/corelib/time/qdate/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/corelib/time/qdate/tst_qdate.cpp | 212 | ||||
-rw-r--r-- | tests/auto/corelib/time/qdatetime/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp | 88 | ||||
-rw-r--r-- | tests/auto/corelib/time/qtime/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/corelib/time/qtime/tst_qtime.cpp | 196 |
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) |