diff options
Diffstat (limited to 'tests/auto/corelib/io/qdebug/tst_qdebug.cpp')
-rw-r--r-- | tests/auto/corelib/io/qdebug/tst_qdebug.cpp | 693 |
1 files changed, 662 insertions, 31 deletions
diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp index 949882b578..15da0758d0 100644 --- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp +++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp @@ -1,42 +1,36 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore/QCoreApplication> #include <QtCore/QtDebug> -#include <QtTest/QtTest> +#include <QTest> #include <QtConcurrentRun> #include <QFutureSynchronizer> #include <QVariant> +#include <QSemaphore> +#include <QLine> +#include <QMimeType> +#include <QMimeDatabase> +#include <QMetaType> + +#include <q20chrono.h> + +#ifdef __cpp_lib_memory_resource +# include <memory_resource> +namespace pmr = std::pmr; +#else +namespace pmr = std; +#endif + +using namespace std::chrono; +using namespace q20::chrono; +using namespace Qt::StringLiterals; static_assert(QTypeTraits::has_ostream_operator_v<QDebug, int>); +static_assert(QTypeTraits::has_ostream_operator_v<QDebug, QMetaType>); static_assert(QTypeTraits::has_ostream_operator_v<QDebug, QList<int>>); static_assert(QTypeTraits::has_ostream_operator_v<QDebug, QMap<int, QString>>); struct NonStreamable {}; @@ -48,6 +42,10 @@ struct ConvertsToQVariant { }; static_assert(!QTypeTraits::has_ostream_operator_v<QDebug, ConvertsToQVariant>); +#if defined(Q_OS_DARWIN) +#include <objc/runtime.h> +#include <Foundation/Foundation.h> +#endif class tst_QDebug: public QObject { @@ -71,17 +69,39 @@ private slots: void stateSaver() const; void veryLongWarningMessage() const; void qDebugQChar() const; + void qDebugQMetaType() const; void qDebugQString() const; void qDebugQStringView() const; + void qDebugQUtf8StringView() const; void qDebugQLatin1String() const; + void qDebugStdString() const; + void qDebugStdStringView() const; + void qDebugStdWString() const; + void qDebugStdWStringView() const; + void qDebugStdU8String() const; + void qDebugStdU8StringView() const; + void qDebugStdU16String() const; + void qDebugStdU16StringView() const; + void qDebugStdU32String() const; + void qDebugStdU32StringView() const; void qDebugQByteArray() const; + void qDebugQByteArrayView() const; void qDebugQFlags() const; + void qDebugStdChrono_data() const; + void qDebugStdChrono() const; + void qDebugStdOptional() const; void textStreamModifiers() const; void resetFormat() const; void defaultMessagehandler() const; void threadSafety() const; void toString() const; void noQVariantEndlessRecursion() const; +#if defined(Q_OS_DARWIN) + void objcInCppMode_data() const; + void objcInCppMode() const; + void objcInObjcMode_data() const; + void objcInObjcMode() const; +#endif }; void tst_QDebug::assignment() const @@ -299,11 +319,17 @@ void tst_QDebug::debugNoQuotes() const MessageHandlerSetter mhs(myMessageHandler); { QDebug d = qDebug(); + QVERIFY(d.quoteStrings()); d << QStringLiteral("Hello"); + QVERIFY(d.quoteStrings()); d.noquote(); + QVERIFY(!d.quoteStrings()); d << QStringLiteral("Hello"); + QVERIFY(!d.quoteStrings()); d.quote(); + QVERIFY(d.quoteStrings()); d << QStringLiteral("Hello"); + QVERIFY(d.quoteStrings()); } QCOMPARE(s_msg, QString::fromLatin1("\"Hello\" Hello \"Hello\"")); @@ -312,7 +338,7 @@ void tst_QDebug::debugNoQuotes() const d << QChar('H'); d << QLatin1String("Hello"); d << QByteArray("Hello"); - d.noquote(); + d.setQuoteStrings(false); d << QChar('H'); d << QLatin1String("Hello"); d << QByteArray("Hello"); @@ -437,6 +463,25 @@ void tst_QDebug::qDebugQChar() const } +void tst_QDebug::qDebugQMetaType() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << QMetaType::fromType<int>() << QMetaType::fromType<QString>(); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 4; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, R"(QMetaType(int) QMetaType(QString))"_L1); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); +} + void tst_QDebug::qDebugQString() const { /* Use a basic string. */ @@ -555,6 +600,46 @@ void tst_QDebug::qDebugQStringView() const } } +void tst_QDebug::qDebugQUtf8StringView() const +{ + /* Use a utf8 string. */ + { + QLatin1String file, function; + int line = 0; + const QUtf8StringView inView = u8"\U0001F609 is ;-)"; + + MessageHandlerSetter mhs(myMessageHandler); + { qDebug() << inView; } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = QLatin1String(__FILE__); line = __LINE__ - 2; function = QLatin1String(Q_FUNC_INFO); +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromUtf8("\"\\xF0\\x9F\\x98\\x89 is ;-)\"")); + QCOMPARE(QLatin1String(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QLatin1String(s_function), function); + } + + /* Use a null QUtf8StringView. */ + { + QString file, function; + int line = 0; + + const QUtf8StringView inView; + + MessageHandlerSetter mhs(myMessageHandler); + { qDebug() << inView; } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QLatin1String("\"\"")); + QCOMPARE(QLatin1String(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QLatin1String(s_function), function); + } +} + void tst_QDebug::qDebugQLatin1String() const { QString file, function; @@ -593,6 +678,324 @@ void tst_QDebug::qDebugQLatin1String() const QCOMPARE(s_msg, QString("\"\\nSm\\u00F8rg\\u00E5sbord\\\\\"")); } +void tst_QDebug::qDebugStdString() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << pmr::string("foo") << std::string("") << std::string("barbaz", 3); + d.nospace().noquote() << std::string("baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::string string("\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString::fromStdString(string)); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString::fromStdString(string)); +} + +void tst_QDebug::qDebugStdStringView() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << std::string_view("foo") << std::string_view("") << std::string_view("barbaz", 3); + d.nospace().noquote() << std::string_view("baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::string_view string("\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString::fromStdString(std::string(string))); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString::fromStdString(std::string(string))); +} + +void tst_QDebug::qDebugStdWString() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << pmr::wstring(L"foo") << std::wstring(L"") << std::wstring(L"barbaz", 3); + d.nospace().noquote() << std::wstring(L"baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::wstring string(L"\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString::fromStdWString(string)); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString::fromStdWString(string)); +} + +void tst_QDebug::qDebugStdWStringView() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << std::wstring_view(L"foo") << std::wstring_view(L"") << std::wstring_view(L"barbaz", 3); + d.nospace().noquote() << std::wstring_view(L"baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::wstring_view string(L"\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString::fromStdWString(std::wstring(string))); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString::fromStdWString(std::wstring(string))); +} + +void tst_QDebug::qDebugStdU8String() const +{ +#ifndef __cpp_lib_char8_t + QSKIP("This test requires C++20 char8_t support enabled in the compiler."); +#else + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << pmr::u8string(u8"foo") << std::u8string(u8"") << std::u8string(u8"barbaz", 3); + d.nospace().noquote() << std::u8string(u8"baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::u8string string(u8"\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QUtf8StringView(string).toString()); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QUtf8StringView(string).toString()); +#endif // __cpp_lib_char8_t +} + +void tst_QDebug::qDebugStdU8StringView() const +{ +#ifndef __cpp_lib_char8_t + QSKIP("This test requires C++20 char8_t support enabled in the compiler."); +#else + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << std::u16string_view(u"foo") << std::u16string_view(u"") << std::u16string_view(u"barbaz", 3); + d.nospace().noquote() << std::u16string_view(u"baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::u16string_view string(u"\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString::fromStdU16String(std::u16string(string))); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString::fromStdU16String(std::u16string(string))); +#endif // __cpp_lib_char8_t +} + +void tst_QDebug::qDebugStdU16String() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << pmr::u16string(u"foo") << std::u16string(u"") << std::u16string(u"barbaz", 3); + d.nospace().noquote() << std::u16string(u"baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::u16string string(u"\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString::fromStdU16String(string)); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString::fromStdU16String(string)); +} + +void tst_QDebug::qDebugStdU16StringView() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << std::u16string_view(u"foo") << std::u16string_view(u"") << std::u16string_view(u"barbaz", 3); + d.nospace().noquote() << std::u16string_view(u"baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::u16string_view string(u"\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString::fromStdU16String(std::u16string(string))); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString::fromStdU16String(std::u16string(string))); +} + +void tst_QDebug::qDebugStdU32String() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << pmr::u32string(U"foo") << std::u32string(U"") << std::u32string(U"barbaz", 3); + d.nospace().noquote() << std::u32string(U"baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::u32string string(U"\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString::fromStdU32String(string)); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString::fromStdU32String(string)); +} + +void tst_QDebug::qDebugStdU32StringView() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << std::u32string_view(U"foo") << std::u32string_view(U"") << std::u32string_view(U"barbaz", 3); + d.nospace().noquote() << std::u32string_view(U"baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + std::u32string_view string(U"\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString::fromStdU32String(std::u32string(string))); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString::fromStdU32String(std::u32string(string))); +} + void tst_QDebug::qDebugQByteArray() const { QString file, function; @@ -635,6 +1038,48 @@ void tst_QDebug::qDebugQByteArray() const QCOMPARE(s_msg, QString("\"\\xFF\"\"FFFF\"")); } +void tst_QDebug::qDebugQByteArrayView() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << QByteArrayView("foo") << QByteArrayView("") << QByteArrayView("barbaz", 3); + d.nospace().noquote() << QByteArrayView("baz"); + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + QByteArrayView ba = "\"Hello\""; + qDebug() << ba; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << ba; + QCOMPARE(s_msg, QString::fromLatin1(ba)); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << ba; + QCOMPARE(s_msg, " " + QString::fromLatin1(ba)); + + ba = "\nSm\xC3\xB8rg\xC3\xA5sbord\\"; + qDebug().noquote().nospace() << ba; + QCOMPARE(s_msg, QString::fromUtf8(ba)); + + qDebug() << ba; + QCOMPARE(s_msg, QString("\"\\nSm\\xC3\\xB8rg\\xC3\\xA5sbord\\\\\"")); + + // ensure that it closes hex escape sequences correctly + qDebug() << QByteArrayView("\377FFFF"); + QCOMPARE(s_msg, QString("\"\\xFF\"\"FFFF\"")); +} + enum TestEnum { Flag1 = 0x1, Flag2 = 0x10 @@ -670,6 +1115,129 @@ void tst_QDebug::qDebugQFlags() const 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::qDebugStdOptional() const +{ + QString file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + { + std::optional<QByteArray> notSet = std::nullopt; + std::optional<QByteArray> set("foo"); + auto no = std::nullopt; + QDebug d = qDebug(); + d << notSet << set << no; + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 4; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("nullopt std::optional(\"foo\") nullopt")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); +} + void tst_QDebug::textStreamModifiers() const { QString file, function; @@ -749,7 +1317,7 @@ void tst_QDebug::threadSafety() const s_sema.release(numThreads); sync.waitForFinished(); QMutexLocker lock(&s_mutex); - QCOMPARE(s_messages.count(), numThreads); + QCOMPARE(s_messages.size(), numThreads); for (int i = 0; i < numThreads; ++i) { QCOMPARE(s_messages.at(i), QStringLiteral("doDebug")); } @@ -785,6 +1353,69 @@ void tst_QDebug::noQVariantEndlessRecursion() const qDebug() << var; } +#if defined(Q_OS_DARWIN) + +@interface MyObjcClass : NSObject +@end + +@implementation MyObjcClass : NSObject +- (NSString *)description +{ + return @"MyObjcClass is the best"; +} +@end + +void tst_QDebug::objcInCppMode_data() const +{ + QTest::addColumn<objc_object *>("object"); + QTest::addColumn<QString>("message"); + + QTest::newRow("nil") << static_cast<objc_object*>(nullptr) << QString::fromLatin1("(null)"); + + // Not an NSObject subclass + auto *nsproxy = reinterpret_cast<objc_object *>(class_createInstance(objc_getClass("NSProxy"), 0)); + QTest::newRow("NSProxy") << nsproxy << QString::fromLatin1("<NSProxy: 0x%1>").arg(uintptr_t(nsproxy), 1, 16); + + // Plain NSObject + auto *nsobject = reinterpret_cast<objc_object *>(class_createInstance(objc_getClass("NSObject"), 0)); + QTest::newRow("NSObject") << nsobject << QString::fromLatin1("<NSObject: 0x%1>").arg(uintptr_t(nsobject), 1, 16); + + auto str = QString::fromLatin1("foo"); + QTest::newRow("NSString") << reinterpret_cast<objc_object*>(str.toNSString()) << str; + + // Custom debug description + QTest::newRow("MyObjcClass") << reinterpret_cast<objc_object*>([[MyObjcClass alloc] init]) + << QString::fromLatin1("MyObjcClass is the best"); +} + +void tst_QDebug::objcInCppMode() const +{ + QFETCH(objc_object *, object); + QFETCH(QString, message); + + MessageHandlerSetter mhs(myMessageHandler); + { qDebug() << object; } + + QCOMPARE(s_msg, message); +} + +void tst_QDebug::objcInObjcMode_data() const +{ + objcInCppMode_data(); +} + +void tst_QDebug::objcInObjcMode() const +{ + QFETCH(objc_object *, object); + QFETCH(QString, message); + + MessageHandlerSetter mhs(myMessageHandler); + { qDebug() << static_cast<id>(object); } + + QCOMPARE(s_msg, message); +} +#endif + // Should compile: instentiation of unrelated operator<< should not cause cause compilation // error in QDebug operators (QTBUG-47375) class TestClassA {}; |