Move the formatting of <chrono> durations to QDebug & QtTest
[ChangeLog][QtCore][QDebug] Added pretty formatting of C++ <chrono> durations. [ChangeLog][QtTest] Added pretty formatting of C++ <chrono> durations for QCOMPARE expressions. Change-Id: I3b169860d8bd41e9be6bfffd1757cc087ba957fa Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
59f8da17e6
commit
a2551c45d4
@ -15,6 +15,8 @@
|
|||||||
#include <private/qtextstream_p.h>
|
#include <private/qtextstream_p.h>
|
||||||
#include <private/qtools_p.h>
|
#include <private/qtools_p.h>
|
||||||
|
|
||||||
|
#include <q20chrono.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
using namespace QtMiscUtils;
|
using namespace QtMiscUtils;
|
||||||
@ -345,6 +347,90 @@ void QDebug::putByteArray(const char *begin, size_t length, Latin1Content conten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\since 6.6
|
||||||
|
\internal
|
||||||
|
Helper to the std::chrono::duration debug streaming output.
|
||||||
|
*/
|
||||||
|
QByteArray QDebug::timeUnit(qint64 num, qint64 den)
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
using namespace q20::chrono;
|
||||||
|
|
||||||
|
if (num == 1 && den > 1) {
|
||||||
|
// sub-multiple of seconds
|
||||||
|
char prefix = '\0';
|
||||||
|
auto tryprefix = [&](auto d, char c) {
|
||||||
|
static_assert(decltype(d)::num == 1, "not an SI prefix");
|
||||||
|
if (den == decltype(d)::den)
|
||||||
|
prefix = c;
|
||||||
|
};
|
||||||
|
|
||||||
|
// "u" should be "µ", but debugging output is not always UTF-8-safe
|
||||||
|
tryprefix(std::milli{}, 'm');
|
||||||
|
tryprefix(std::micro{}, 'u');
|
||||||
|
tryprefix(std::nano{}, 'n');
|
||||||
|
tryprefix(std::pico{}, 'p');
|
||||||
|
tryprefix(std::femto{}, 'f');
|
||||||
|
tryprefix(std::atto{}, 'a');
|
||||||
|
// uncommon ones later
|
||||||
|
tryprefix(std::centi{}, 'c');
|
||||||
|
tryprefix(std::deci{}, 'd');
|
||||||
|
if (prefix) {
|
||||||
|
char unit[3] = { prefix, 's' };
|
||||||
|
return QByteArray(unit, sizeof(unit) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *unit = nullptr;
|
||||||
|
if (num > 1 && den == 1) {
|
||||||
|
// multiple of seconds - but we don't use SI prefixes
|
||||||
|
auto tryunit = [&](auto d, const char *name) {
|
||||||
|
static_assert(decltype(d)::period::den == 1, "not a multiple of a second");
|
||||||
|
if (unit || num % decltype(d)::period::num)
|
||||||
|
return;
|
||||||
|
unit = name;
|
||||||
|
num /= decltype(d)::period::num;
|
||||||
|
};
|
||||||
|
tryunit(years{}, "yr");
|
||||||
|
tryunit(weeks{}, "wk");
|
||||||
|
tryunit(days{}, "d");
|
||||||
|
tryunit(hours{}, "h");
|
||||||
|
tryunit(minutes{}, "min");
|
||||||
|
}
|
||||||
|
if (!unit)
|
||||||
|
unit = "s";
|
||||||
|
|
||||||
|
if (num == 1 && den == 1)
|
||||||
|
return unit;
|
||||||
|
if (Q_UNLIKELY(num < 1 || den < 1))
|
||||||
|
return QString::asprintf("<invalid time unit %lld/%lld>", num, den).toLatin1();
|
||||||
|
|
||||||
|
// uncommon units: will return something like "[2/3]s"
|
||||||
|
// strlen("[/]min") = 6
|
||||||
|
char buf[2 * (std::numeric_limits<qint64>::digits10 + 2) + 10];
|
||||||
|
size_t len = 0;
|
||||||
|
auto appendChar = [&](char c) {
|
||||||
|
Q_ASSERT(len < sizeof(buf));
|
||||||
|
buf[len++] = c;
|
||||||
|
};
|
||||||
|
auto appendNumber = [&](qint64 value) {
|
||||||
|
if (value >= 10'000 && (value % 1000) == 0)
|
||||||
|
len += qsnprintf(buf + len, sizeof(buf) - len, "%.6g", double(value)); // "1e+06"
|
||||||
|
else
|
||||||
|
len += qsnprintf(buf + len, sizeof(buf) - len, "%lld", value);
|
||||||
|
};
|
||||||
|
appendChar('[');
|
||||||
|
appendNumber(num);
|
||||||
|
if (den != 1) {
|
||||||
|
appendChar('/');
|
||||||
|
appendNumber(den);
|
||||||
|
}
|
||||||
|
appendChar(']');
|
||||||
|
memcpy(buf + len, unit, strlen(unit));
|
||||||
|
return QByteArray(buf, len + strlen(unit));
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn QDebug::swap(QDebug &other)
|
\fn QDebug::swap(QDebug &other)
|
||||||
\since 5.0
|
\since 5.0
|
||||||
@ -776,6 +862,18 @@ QDebug &QDebug::resetFormat()
|
|||||||
\endlist
|
\endlist
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\since 6.6
|
||||||
|
\fn template <typename Rep, typename Period> QDebug &QDebug::operator<<(std::chrono::duration<Rep, Period> duration)
|
||||||
|
|
||||||
|
Prints the time duration \a duration to the stream and returns a reference
|
||||||
|
to the stream. The printed string is the numeric representation of the
|
||||||
|
period followed by the time unit, similar to what the C++ Standard Library
|
||||||
|
would produce with \c{std::ostream}.
|
||||||
|
|
||||||
|
The unit is not localized.
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn template <class T> QString QDebug::toString(T &&object)
|
\fn template <class T> QString QDebug::toString(T &&object)
|
||||||
\since 6.0
|
\since 6.0
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <QtCore/qsharedpointer.h>
|
#include <QtCore/qsharedpointer.h>
|
||||||
|
|
||||||
// all these have already been included by various headers above, but don't rely on indirect includes:
|
// all these have already been included by various headers above, but don't rely on indirect includes:
|
||||||
|
#include <chrono>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -67,6 +68,7 @@ class QT6_ONLY(Q_CORE_EXPORT) QDebug : public QIODeviceBase
|
|||||||
QT7_ONLY(Q_CORE_EXPORT) void putUcs4(uint ucs4);
|
QT7_ONLY(Q_CORE_EXPORT) void putUcs4(uint ucs4);
|
||||||
QT7_ONLY(Q_CORE_EXPORT) void putString(const QChar *begin, size_t length);
|
QT7_ONLY(Q_CORE_EXPORT) void putString(const QChar *begin, size_t length);
|
||||||
QT7_ONLY(Q_CORE_EXPORT) void putByteArray(const char *begin, size_t length, Latin1Content content);
|
QT7_ONLY(Q_CORE_EXPORT) void putByteArray(const char *begin, size_t length, Latin1Content content);
|
||||||
|
QT7_ONLY(Q_CORE_EXPORT) static QByteArray timeUnit(qint64 num, qint64 den);
|
||||||
public:
|
public:
|
||||||
explicit QDebug(QIODevice *device) : stream(new Stream(device)) {}
|
explicit QDebug(QIODevice *device) : stream(new Stream(device)) {}
|
||||||
explicit QDebug(QString *string) : stream(new Stream(string)) {}
|
explicit QDebug(QString *string) : stream(new Stream(string)) {}
|
||||||
@ -189,6 +191,13 @@ public:
|
|||||||
{ return *this << QString::fromUcs4(s.data(), s.size()); }
|
{ return *this << QString::fromUcs4(s.data(), s.size()); }
|
||||||
#endif // !Q_QDOC
|
#endif // !Q_QDOC
|
||||||
|
|
||||||
|
template <typename Rep, typename Period>
|
||||||
|
QDebug &operator<<(std::chrono::duration<Rep, Period> duration)
|
||||||
|
{
|
||||||
|
stream->ts << duration.count() << timeUnit(Period::num, Period::den);
|
||||||
|
return maybeSpace();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static QString toString(T &&object)
|
static QString toString(T &&object)
|
||||||
{
|
{
|
||||||
|
@ -356,6 +356,19 @@ template<> inline char *toString(const QCborMap &m)
|
|||||||
return Internal::QCborValueFormatter::format(m);
|
return Internal::QCborValueFormatter::format(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Rep, typename Period> char *toString(std::chrono::duration<Rep, Period> dur)
|
||||||
|
{
|
||||||
|
QString r;
|
||||||
|
QDebug d(&r);
|
||||||
|
d.nospace() << qSetRealNumberPrecision(9) << dur;
|
||||||
|
if constexpr (Period::num != 1 || Period::den != 1) {
|
||||||
|
// include the equivalent value in seconds, in parentheses
|
||||||
|
using namespace std::chrono;
|
||||||
|
d << " (" << duration_cast<duration<qreal>>(dur).count() << "s)";
|
||||||
|
}
|
||||||
|
return qstrdup(std::move(r).toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
inline char *toString(const std::pair<T1, T2> &pair)
|
inline char *toString(const std::pair<T1, T2> &pair)
|
||||||
{
|
{
|
||||||
|
@ -360,6 +360,9 @@ namespace QTest
|
|||||||
template <class... Types>
|
template <class... Types>
|
||||||
inline char *toString(const std::tuple<Types...> &tuple);
|
inline char *toString(const std::tuple<Types...> &tuple);
|
||||||
|
|
||||||
|
template <typename Rep, typename Period>
|
||||||
|
inline char *toString(std::chrono::duration<Rep, Period> duration);
|
||||||
|
|
||||||
Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length);
|
Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length);
|
||||||
Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length);
|
Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length);
|
||||||
Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
|
Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#include <QMimeDatabase>
|
#include <QMimeDatabase>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
|
||||||
|
#include <q20chrono.h>
|
||||||
|
|
||||||
#ifdef __cpp_lib_memory_resource
|
#ifdef __cpp_lib_memory_resource
|
||||||
# include <memory_resource>
|
# include <memory_resource>
|
||||||
namespace pmr = std::pmr;
|
namespace pmr = std::pmr;
|
||||||
@ -23,6 +25,8 @@ namespace pmr = std::pmr;
|
|||||||
namespace pmr = std;
|
namespace pmr = std;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
using namespace q20::chrono;
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
static_assert(QTypeTraits::has_ostream_operator_v<QDebug, int>);
|
static_assert(QTypeTraits::has_ostream_operator_v<QDebug, int>);
|
||||||
@ -83,6 +87,8 @@ private slots:
|
|||||||
void qDebugQByteArray() const;
|
void qDebugQByteArray() const;
|
||||||
void qDebugQByteArrayView() const;
|
void qDebugQByteArrayView() const;
|
||||||
void qDebugQFlags() const;
|
void qDebugQFlags() const;
|
||||||
|
void qDebugStdChrono_data() const;
|
||||||
|
void qDebugStdChrono() const;
|
||||||
void textStreamModifiers() const;
|
void textStreamModifiers() const;
|
||||||
void resetFormat() const;
|
void resetFormat() const;
|
||||||
void defaultMessagehandler() const;
|
void defaultMessagehandler() const;
|
||||||
@ -1102,6 +1108,107 @@ void tst_QDebug::qDebugQFlags() const
|
|||||||
QCOMPARE(s_msg, QString::fromLatin1("QFlags<tst_QDebug::FlagType>(EnumFlag1)"));
|
QCOMPARE(s_msg, QString::fromLatin1("QFlags<tst_QDebug::FlagType>(EnumFlag1)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using ToStringFunction = std::function<QString()>;
|
||||||
|
void tst_QDebug::qDebugStdChrono_data() const
|
||||||
|
{
|
||||||
|
using attoseconds = duration<int64_t, std::atto>;
|
||||||
|
using femtoseconds = duration<int64_t, std::femto>;
|
||||||
|
using picoseconds = duration<int64_t, std::pico>;
|
||||||
|
using centiseconds = duration<int64_t, std::centi>;
|
||||||
|
using deciseconds = duration<int64_t, std::deci>;
|
||||||
|
|
||||||
|
using quadriennia = duration<int, std::ratio_multiply<std::ratio<4>, years::period>>;
|
||||||
|
using decades = duration<int, std::ratio_multiply<years::period, std::deca>>; // decayears
|
||||||
|
using centuries = duration<int16_t, std::ratio_multiply<years::period, std::hecto>>; // hectoyears
|
||||||
|
using millennia = duration<int16_t, std::ratio_multiply<years::period, std::kilo>>; // kiloyears
|
||||||
|
using gigayears = duration<int8_t, std::ratio_multiply<years::period, std::giga>>;
|
||||||
|
using fortnights = duration<int, std::ratio_multiply<days::period, std::ratio<14>>>;
|
||||||
|
using microfortnights = duration<int64_t, std::ratio_multiply<fortnights::period, std::micro>>;
|
||||||
|
using telecom = duration<int64_t, std::ratio<1, 8000>>; // 8 kHz
|
||||||
|
|
||||||
|
using kiloseconds = duration<int64_t, std::kilo>;
|
||||||
|
using exaseconds = duration<int8_t, std::exa>;
|
||||||
|
using meter_per_light = duration<int64_t, std::ratio<1, 299'792'458>>;
|
||||||
|
using kilometer_per_light = duration<int64_t, std::ratio<1000, 299'792'458>>;
|
||||||
|
|
||||||
|
QTest::addColumn<ToStringFunction>("fn");
|
||||||
|
QTest::addColumn<QString>("expected");
|
||||||
|
|
||||||
|
auto addRow = [](const char *name, auto duration, const char *expected) {
|
||||||
|
auto toString = [duration]() { return QDebug::toString(duration); };
|
||||||
|
QTest::newRow(name) << ToStringFunction(toString) << expected;
|
||||||
|
};
|
||||||
|
|
||||||
|
addRow("1as", attoseconds{1}, "1as");
|
||||||
|
addRow("1fs", femtoseconds{1}, "1fs");
|
||||||
|
addRow("1ps", picoseconds{1}, "1ps");
|
||||||
|
addRow("0ns", 0ns, "0ns");
|
||||||
|
addRow("1000ns", 1000ns, "1000ns");
|
||||||
|
addRow("0us", 0us, "0us");
|
||||||
|
addRow("0ms", 0ms, "0ms");
|
||||||
|
addRow("1cs", centiseconds{1}, "1cs");
|
||||||
|
addRow("2ds", deciseconds{2}, "2ds");
|
||||||
|
addRow("-1s", -1s, "-1s");
|
||||||
|
addRow("0s", 0s, "0s");
|
||||||
|
addRow("1s", 1s, "1s");
|
||||||
|
addRow("60s", 60s, "60s");
|
||||||
|
addRow("1min", 1min, "1min");
|
||||||
|
addRow("1h", 1h, "1h");
|
||||||
|
addRow("1days", days{1}, "1d");
|
||||||
|
addRow("365days", days{365}, "365d");
|
||||||
|
addRow("1weeks", weeks{1}, "1wk");
|
||||||
|
addRow("1years", years{1}, "1yr"); // 365.2425 days
|
||||||
|
addRow("42years", years{42}, "42yr");
|
||||||
|
|
||||||
|
addRow("1ks", kiloseconds{1}, "1[1000]s");
|
||||||
|
addRow("2fortnights", fortnights{2}, "2[2]wk");
|
||||||
|
addRow("1quadriennia", quadriennia{1}, "1[4]yr");
|
||||||
|
addRow("1decades", decades{1}, "1[10]yr");
|
||||||
|
addRow("1centuries", centuries{1}, "1[100]yr");
|
||||||
|
addRow("1millennia", millennia{1}, "1[1000]yr");
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN)
|
||||||
|
// some OSes print the exponent differently
|
||||||
|
addRow("1Es", exaseconds{1}, "1[1e+18]s");
|
||||||
|
addRow("13gigayears", gigayears{13}, "13[1e+09]yr");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// months are one twelfth of a Gregorian year, not 30 days
|
||||||
|
addRow("1months", months{1}, "1[2629746]s");
|
||||||
|
|
||||||
|
// weird units
|
||||||
|
addRow("2microfortnights", microfortnights{2}, "2[756/625]s");
|
||||||
|
addRow("1telecom", telecom{1}, "1[1/8000]s");
|
||||||
|
addRow("10m/c", meter_per_light{10}, "10[1/299792458]s");
|
||||||
|
addRow("10km/c", kilometer_per_light{10}, "10[500/149896229]s");
|
||||||
|
|
||||||
|
// real floting point
|
||||||
|
using fpsec = duration<double>;
|
||||||
|
using fpmsec = duration<double, std::milli>;
|
||||||
|
using fpnsec = duration<double, std::nano>;
|
||||||
|
addRow("1.0s", fpsec{1}, "1s");
|
||||||
|
addRow("1.5s", fpsec{1.5}, "1.5s");
|
||||||
|
addRow("1.0ms", fpmsec{1}, "1ms");
|
||||||
|
addRow("1.5ms", fpmsec{1.5}, "1.5ms");
|
||||||
|
addRow("1.0ns", fpnsec{1}, "1ns");
|
||||||
|
addRow("1.5ns", fpnsec{1.5}, "1.5ns");
|
||||||
|
|
||||||
|
// and some precision setting too
|
||||||
|
QTest::newRow("1.00000ns")
|
||||||
|
<< ToStringFunction([]() {
|
||||||
|
QString buffer;
|
||||||
|
QDebug d(&buffer);
|
||||||
|
d.nospace() << qSetRealNumberPrecision(5) << Qt::fixed << fpnsec{1};
|
||||||
|
return buffer;
|
||||||
|
}) << "1.00000ns";
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QDebug::qDebugStdChrono() const
|
||||||
|
{
|
||||||
|
QFETCH(ToStringFunction, fn);
|
||||||
|
QFETCH(QString, expected);
|
||||||
|
QCOMPARE(fn(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QDebug::textStreamModifiers() const
|
void tst_QDebug::textStreamModifiers() const
|
||||||
{
|
{
|
||||||
QString file, function;
|
QString file, function;
|
||||||
|
@ -27,52 +27,6 @@ template<> char *toString(const QDeadlineTimer &dt)
|
|||||||
dt.hasExpired() ? " (expired)" : "");
|
dt.hasExpired() ? " (expired)" : "");
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Rep, typename Period> char *toString(std::chrono::duration<Rep, Period> dur)
|
|
||||||
{
|
|
||||||
using namespace std::chrono;
|
|
||||||
static_assert(sizeof(double) == sizeof(qlonglong));
|
|
||||||
|
|
||||||
if constexpr (Period::num == 1 && sizeof(Rep) <= sizeof(qlonglong)) {
|
|
||||||
// typical case: second or sub-multiple of second, in a representation
|
|
||||||
// we can directly use
|
|
||||||
char *buf = new char[128];
|
|
||||||
if constexpr (std::is_integral_v<Rep>) {
|
|
||||||
char unit[] = "ss";
|
|
||||||
if constexpr (std::is_same_v<Period, std::atto>) { // from Norwegian "atten", 18
|
|
||||||
unit[0] = 'a';
|
|
||||||
} else if constexpr (std::is_same_v<Period, std::femto>) { // Norwegian "femten", 15
|
|
||||||
unit[0] = 'f';
|
|
||||||
} else if constexpr (std::is_same_v<Period, std::pico>) {
|
|
||||||
unit[0] = 'p';
|
|
||||||
} else if constexpr (std::is_same_v<Period, std::nano>) {
|
|
||||||
unit[0] = 'n';
|
|
||||||
} else if constexpr (std::is_same_v<Period, std::micro>) {
|
|
||||||
unit[0] = 'u'; // µ, really, but the output may not be UTF-8-safe
|
|
||||||
} else if constexpr (std::is_same_v<Period, std::milli>) {
|
|
||||||
unit[0] = 'm';
|
|
||||||
} else {
|
|
||||||
// deci, centi, cycles of something (60 Hz, 8000 Hz, etc.)
|
|
||||||
static_assert(Period::den == 1,
|
|
||||||
"Unsupported std::chrono::duration of a sub-multiple of second");
|
|
||||||
unit[1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// cast to qlonglong in case Rep is not int64_t
|
|
||||||
qsnprintf(buf, 128, "%lld %s", qlonglong(dur.count()), unit);
|
|
||||||
} else {
|
|
||||||
auto secs = duration_cast<duration<double>>(dur);
|
|
||||||
qsnprintf(buf, 128, "%g s", secs.count());
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
} else if constexpr (std::is_integral_v<Rep> && Period::den == 1) {
|
|
||||||
// multiple of second, so just print it in seconds
|
|
||||||
return toString(std::chrono::seconds(dur));
|
|
||||||
} else {
|
|
||||||
// something else, use floating-point seconds
|
|
||||||
return toString(std::chrono::duration_cast<double>(dur));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
add_subdirectory(qsignalspy)
|
add_subdirectory(qsignalspy)
|
||||||
|
add_subdirectory(tostring)
|
||||||
|
|
||||||
# QTBUG-88507
|
# QTBUG-88507
|
||||||
if(QT_FEATURE_process AND NOT ANDROID)
|
if(QT_FEATURE_process AND NOT ANDROID)
|
||||||
|
7
tests/auto/testlib/tostring/CMakeLists.txt
Normal file
7
tests/auto/testlib/tostring/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Copyright (C) 2023 Intel Corporation.
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
qt_internal_add_test(tst_tostring
|
||||||
|
SOURCES
|
||||||
|
tst_tostring.cpp
|
||||||
|
)
|
150
tests/auto/testlib/tostring/tst_tostring.cpp
Normal file
150
tests/auto/testlib/tostring/tst_tostring.cpp
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// Copyright (C) 2023 Intel Corporation.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include <QTest>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <q20chrono.h>
|
||||||
|
|
||||||
|
using ToStringFunction = std::function<char *()>;
|
||||||
|
class tst_toString : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
void addColumns();
|
||||||
|
void testRows();
|
||||||
|
private slots:
|
||||||
|
void chrono_duration_data();
|
||||||
|
void chrono_duration() { testRows(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_toString::addColumns()
|
||||||
|
{
|
||||||
|
QTest::addColumn<ToStringFunction>("fn");
|
||||||
|
QTest::addColumn<QByteArrayView>("expected");
|
||||||
|
QTest::addColumn<QByteArrayView>("expr");
|
||||||
|
QTest::addColumn<QByteArrayView>("file");
|
||||||
|
QTest::addColumn<int>("line");
|
||||||
|
}
|
||||||
|
void tst_toString::testRows()
|
||||||
|
{
|
||||||
|
QFETCH(ToStringFunction, fn);
|
||||||
|
QFETCH(QByteArrayView, expected);
|
||||||
|
QFETCH(QByteArrayView, expr);
|
||||||
|
QFETCH(QByteArrayView, file);
|
||||||
|
QFETCH(int, line);
|
||||||
|
|
||||||
|
std::unique_ptr<char []> ptr{fn()};
|
||||||
|
QTest::qCompare(ptr.get(), expected, expr.data(), expected.data(), file.data(), line);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void addRow(QByteArrayView name, T &&value, QByteArrayView expression,
|
||||||
|
QByteArrayView expected, QByteArrayView file, int line)
|
||||||
|
{
|
||||||
|
ToStringFunction fn = [v = std::move(value)]() { return QTest::toString(v); };
|
||||||
|
QTest::newRow(name.data()) << fn << expected << expression << file << line;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADD_ROW(name, expr, expected) \
|
||||||
|
::addRow(name, expr, #expr, expected, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
void tst_toString::chrono_duration_data()
|
||||||
|
{
|
||||||
|
addColumns();
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
using namespace q20::chrono;
|
||||||
|
|
||||||
|
using attoseconds = duration<int64_t, std::atto>;
|
||||||
|
using femtoseconds = duration<int64_t, std::femto>;
|
||||||
|
using picoseconds = duration<int64_t, std::pico>;
|
||||||
|
using centiseconds = duration<int64_t, std::centi>;
|
||||||
|
using deciseconds = duration<int64_t, std::deci>;
|
||||||
|
using kiloseconds = duration<int64_t, std::kilo>;
|
||||||
|
using decades = duration<int, std::ratio_multiply<years::period, std::deca>>; // decayears
|
||||||
|
using centuries = duration<int16_t, std::ratio_multiply<years::period, std::hecto>>; // hectoyears
|
||||||
|
using millennia = duration<int16_t, std::ratio_multiply<years::period, std::kilo>>; // kiloyears
|
||||||
|
using gigayears = duration<int8_t, std::ratio_multiply<years::period, std::giga>>;
|
||||||
|
using fortnights = duration<int, std::ratio_multiply<days::period, std::ratio<14>>>;
|
||||||
|
using microfortnights = duration<int64_t, std::ratio_multiply<fortnights::period, std::micro>>;
|
||||||
|
using meter_per_light = duration<int64_t, std::ratio<1, 299'792'458>>;
|
||||||
|
using kilometer_per_light = duration<int64_t, std::ratio<1000, 299'792'458>>;
|
||||||
|
using AU_per_light = duration<int64_t, std::ratio<149'597'871'800, 299'792'458>>;
|
||||||
|
using pstn_rate = duration<int64_t, std::ratio<1, 8000>>; // PSTN sampling rate (8 kHz)
|
||||||
|
using hyperfine = duration<int64_t, std::ratio<1, 9'192'631'770>>; // definition of second
|
||||||
|
|
||||||
|
ADD_ROW("1as", attoseconds{1}, "1as (1e-18s)"); // from Norwegian "atten" (18)
|
||||||
|
ADD_ROW("1fs", femtoseconds{1}, "1fs (1e-15s)"); // from Norwegian "femten" (15)
|
||||||
|
ADD_ROW("1ps", picoseconds{1}, "1ps (1e-12s)"); // from Italian piccolo?
|
||||||
|
ADD_ROW("0ns", 0ns, "0ns (0s)");
|
||||||
|
ADD_ROW("1000ns", 1000ns, "1000ns (1e-06s)");
|
||||||
|
ADD_ROW("1us", 1us, "1us (1e-06s)");
|
||||||
|
ADD_ROW("125us", 125us, "125us (0.000125s)");
|
||||||
|
ADD_ROW("0ms", 0ms, "0ms (0s)");
|
||||||
|
ADD_ROW("-1s", -1s, "-1s");
|
||||||
|
ADD_ROW("0s", 0s, "0s");
|
||||||
|
ADD_ROW("1cs", centiseconds{1}, "1cs (0.01s)");
|
||||||
|
ADD_ROW("2ds", deciseconds{2}, "2ds (0.2s)");
|
||||||
|
ADD_ROW("1s", 1s, "1s");
|
||||||
|
ADD_ROW("60s", 60s, "60s");
|
||||||
|
ADD_ROW("1min", 1min, "1min (60s)");
|
||||||
|
ADD_ROW("1h", 1h, "1h (3600s)");
|
||||||
|
ADD_ROW("1days", days{1}, "1d (86400s)");
|
||||||
|
ADD_ROW("7days", days{7}, "7d (604800s)");
|
||||||
|
ADD_ROW("1weeks", weeks{1}, "1wk (604800s)");
|
||||||
|
ADD_ROW("365days", days{365}, "365d (31536000s)");
|
||||||
|
ADD_ROW("1years", years{1}, "1yr (31556952s)"); // 365.2425 days
|
||||||
|
|
||||||
|
ADD_ROW("2ks", kiloseconds{2}, "2[1000]s (2000s)");
|
||||||
|
ADD_ROW("1fortnights", fortnights{1}, "1[2]wk (1209600s)");
|
||||||
|
ADD_ROW("1decades", decades{1}, "1[10]yr (315569520s)");
|
||||||
|
ADD_ROW("1centuries", centuries{1}, "1[100]yr (3.1556952e+09s)");
|
||||||
|
ADD_ROW("1millennia", millennia{1}, "1[1000]yr (3.1556952e+10s)");
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN)
|
||||||
|
// some OSes print the exponent differently
|
||||||
|
ADD_ROW("13gigayears", gigayears{13}, "13[1e+09]yr (4.10240376e+17s)");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// months are one twelfth of a Gregorian year, not 30 days
|
||||||
|
ADD_ROW("1months", months{1}, "1[2629746]s (2629746s)");
|
||||||
|
ADD_ROW("12months", months{12}, "12[2629746]s (31556952s)");
|
||||||
|
|
||||||
|
// weird units
|
||||||
|
ADD_ROW("2microfortnights", microfortnights{2}, "2[756/625]s (2.4192s)");
|
||||||
|
ADD_ROW("1pstn_rate", pstn_rate{1}, "1[1/8000]s (0.000125s)"); // 125µs
|
||||||
|
ADD_ROW("10m/c", meter_per_light{10}, "10[1/299792458]s (3.33564095e-08s)");
|
||||||
|
ADD_ROW("10km/c", kilometer_per_light{10}, "10[500/149896229]s (3.33564095e-05s)");
|
||||||
|
ADD_ROW("1AU/c", AU_per_light{1}, "1[74798935900/149896229]s (499.004788s)");
|
||||||
|
ADD_ROW("Cs133-hyperfine", hyperfine{1}, "1[1/9192631770]s (1.08782776e-10s)");
|
||||||
|
ADD_ROW("1sec-definition", hyperfine{9'192'631'770}, "9192631770[1/9192631770]s (1s)");
|
||||||
|
ADD_ROW("8000pstn_rate", pstn_rate{8000}, "8000[1/8000]s (1s)");
|
||||||
|
|
||||||
|
// real floting point
|
||||||
|
// current (2023) best estimate is 13.813 ± 0.038 billion years (Plank Collaboration)
|
||||||
|
using universe = duration<double, std::ratio_multiply<std::ratio<13'813'000'000>, years::period>>;
|
||||||
|
using fpksec = duration<double, std::kilo>;
|
||||||
|
using fpsec = duration<double>;
|
||||||
|
using fpmsec = duration<double, std::milli>;
|
||||||
|
using fpnsec = duration<double, std::nano>;
|
||||||
|
using fpGyr = duration<double, std::ratio_multiply<years::period, std::giga>>;
|
||||||
|
|
||||||
|
ADD_ROW("1.0s", fpsec{1}, "1s");
|
||||||
|
ADD_ROW("1.5s", fpsec{1.5}, "1.5s");
|
||||||
|
ADD_ROW("-1.0ms", fpmsec{-1}, "-1ms (-0.001s)");
|
||||||
|
ADD_ROW("1.5ms", fpmsec{1.5}, "1.5ms (0.0015s)");
|
||||||
|
ADD_ROW("1.0ns", fpnsec{1}, "1ns (1e-09s)");
|
||||||
|
ADD_ROW("-1.5ns", fpnsec{-1.5}, "-1.5ns (-1.5e-09s)");
|
||||||
|
ADD_ROW("1.0ks", fpksec{1}, "1[1000]s (1000s)");
|
||||||
|
ADD_ROW("-1.5ks", fpksec{-1.5}, "-1.5[1000]s (-1500s)");
|
||||||
|
ADD_ROW("1.0zs", fpsec{1e-21}, "1e-21s"); // zeptosecond
|
||||||
|
ADD_ROW("1.0ys", fpsec{1e-24}, "1e-24s"); // yoctosecond
|
||||||
|
ADD_ROW("planck-time", fpsec(5.39124760e-44), "5.3912476e-44s");
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN)
|
||||||
|
// some OSes print the exponent differently
|
||||||
|
ADD_ROW("13.813Gyr", fpGyr(13.813), "13.813[1e+09]yr (4.35896178e+17s)");
|
||||||
|
ADD_ROW("1universe", universe{1}, "1[1.3813e+10]yr (4.35896178e+17s)");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_APPLESS_MAIN(tst_toString)
|
||||||
|
#include "tst_tostring.moc"
|
Loading…
x
Reference in New Issue
Block a user