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>
This commit is contained in:
Ivan Solovev 2023-09-13 17:21:34 +02:00
parent e4bde15e14
commit bfb237d19a
9 changed files with 464 additions and 285 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -19,4 +19,5 @@ qt_internal_add_test(tst_qdate
QT_NO_KEYWORDS
LIBRARIES
Qt::CorePrivate
Qt::TestPrivate
)

View File

@ -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) );
QTest::addColumn<QDate>("left");
QTest::addColumn<QDate>("right");
QTest::addColumn<QStrongOrdering>("expectedOrdering");
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::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) );
QFETCH(QDate, left);
QFETCH(QDate, right);
QFETCH(QStrongOrdering, expectedOrdering);
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 );
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 );
#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);
d1 = QDate(2001,12,4);
d2 = QDate(2001,12,5);
QVERIFY( d1 <= d2 );
// 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);
d1 = QDate(2001,11,5);
d2 = QDate(2001,12,5);
QVERIFY( d1 <= d2 );
// 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);
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 );
// 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)

View File

@ -19,6 +19,7 @@ qt_internal_add_test(tst_qdatetime
QT_NO_KEYWORDS
LIBRARIES
Qt::CorePrivate
Qt::TestPrivate
)
## Scopes:

View File

@ -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()

View File

@ -19,4 +19,5 @@ qt_internal_add_test(tst_qtime
QT_NO_KEYWORDS
LIBRARIES
Qt::CorePrivate
Qt::TestPrivate
)

View File

@ -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()
void tst_QTime::ordering_data()
{
QTime t1(0,0,0,0);
QTime t2(0,0,0,0);
QVERIFY( !(t1 < t2) );
QTest::addColumn<QTime>("left");
QTest::addColumn<QTime>("right");
QTest::addColumn<QStrongOrdering>("expectedOrdering");
t1 = QTime(12,34,56,20);
t2 = QTime(12,34,56,30);
QVERIFY( t1 < t2 );
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;
};
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) );
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()
void tst_QTime::ordering()
{
QTime t1(0,0,0,0);
QTime t2(0,0,0,0);
QVERIFY( !(t1 > t2) );
QFETCH(QTime, left);
QFETCH(QTime, right);
QFETCH(QStrongOrdering, expectedOrdering);
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()
{
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_eq()
{
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 );
QTestPrivate::testAllComparisonOperators(left, right, expectedOrdering);
}
#if QT_CONFIG(datestring)