diff options
Diffstat (limited to 'tests/auto/corelib/global/qlogging')
-rw-r--r-- | tests/auto/corelib/global/qlogging/.prev_CMakeLists.txt | 4 | ||||
-rw-r--r-- | tests/auto/corelib/global/qlogging/BLACKLIST | 10 | ||||
-rw-r--r-- | tests/auto/corelib/global/qlogging/CMakeLists.txt | 29 | ||||
-rw-r--r-- | tests/auto/corelib/global/qlogging/app/app.pro | 25 | ||||
-rw-r--r-- | tests/auto/corelib/global/qlogging/app/main.cpp | 29 | ||||
-rw-r--r-- | tests/auto/corelib/global/qlogging/qlogging.pro | 6 | ||||
-rw-r--r-- | tests/auto/corelib/global/qlogging/test/test.pro | 22 | ||||
-rw-r--r-- | tests/auto/corelib/global/qlogging/tst_qlogging.cpp | 240 | ||||
-rw-r--r-- | tests/auto/corelib/global/qlogging/tst_qmessagelogger.cpp | 334 |
9 files changed, 512 insertions, 187 deletions
diff --git a/tests/auto/corelib/global/qlogging/.prev_CMakeLists.txt b/tests/auto/corelib/global/qlogging/.prev_CMakeLists.txt deleted file mode 100644 index c95195c71e..0000000000 --- a/tests/auto/corelib/global/qlogging/.prev_CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Generated from qlogging.pro. - -add_subdirectory(app) -add_subdirectory(test) diff --git a/tests/auto/corelib/global/qlogging/BLACKLIST b/tests/auto/corelib/global/qlogging/BLACKLIST index e2d930e37b..6cd7fc045d 100644 --- a/tests/auto/corelib/global/qlogging/BLACKLIST +++ b/tests/auto/corelib/global/qlogging/BLACKLIST @@ -1,9 +1,7 @@ [qMessagePattern:backtrace] -# QTBUG-63915 -b2qt 64bit +# QTBUG-121389 +b2qt 32bit [qMessagePattern:backtrace depth,separator] -# QTBUG-63915 -b2qt 64bit -# QTBUG-85364 -b2qt cmake +# QTBUG-121389 +b2qt 32bit diff --git a/tests/auto/corelib/global/qlogging/CMakeLists.txt b/tests/auto/corelib/global/qlogging/CMakeLists.txt index e47f62776d..f35c9c4192 100644 --- a/tests/auto/corelib/global/qlogging/CMakeLists.txt +++ b/tests/auto/corelib/global/qlogging/CMakeLists.txt @@ -1,26 +1,33 @@ -# Generated from qlogging.pro. -# This file is almost completely custom written # special case +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause -qt_add_executable(qlogging_helper - NO_INSTALL # special case - OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} # special case +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qlogging LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_executable(qlogging_helper + NO_INSTALL + OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} SOURCES app/main.cpp DEFINES QT_MESSAGELOGCONTEXT LIBRARIES Qt::Core) -# special case begin # Fixes required for the backtrace stack to be correct if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND NOT MINGW) target_link_options(qlogging_helper PRIVATE -rdynamic) endif() set_target_properties(qlogging_helper PROPERTIES CXX_VISIBILITY_PRESET default) -# special case end -qt_add_test(tst_qlogging SOURCES tst_qlogging.cpp +qt_internal_add_test(tst_qlogging SOURCES tst_qlogging.cpp DEFINES QT_MESSAGELOGCONTEXT - QT_DISABLE_DEPRECATED_BEFORE=0 - HELPER_BINARY="${CMAKE_CURRENT_BINARY_DIR}/qlogging_helper" # special case ) -target_compile_definitions(tst_qlogging PRIVATE QT_CMAKE_BUILD) # special case # to fix the binary name +add_dependencies(tst_qlogging qlogging_helper) + +qt_internal_add_test(tst_qmessagelogger SOURCES tst_qmessagelogger.cpp + DEFINES + QT_MESSAGELOGCONTEXT +) diff --git a/tests/auto/corelib/global/qlogging/app/app.pro b/tests/auto/corelib/global/qlogging/app/app.pro deleted file mode 100644 index 3ada382ff4..0000000000 --- a/tests/auto/corelib/global/qlogging/app/app.pro +++ /dev/null @@ -1,25 +0,0 @@ -TEMPLATE = app - -debug_and_release { - CONFIG(debug, debug|release) { - TARGET = ../debug/helper - } else { - TARGET = ../release/helper - } -} else { - TARGET = ../helper -} - -QT = core - -DESTDIR = ./ - -CONFIG += cmdline - -SOURCES += main.cpp -DEFINES += QT_MESSAGELOGCONTEXT - -gcc:!mingw:!haiku { - QMAKE_LFLAGS += -rdynamic - contains(QT_ARCH, arm): QMAKE_CXXFLAGS += -funwind-tables -fno-inline -} diff --git a/tests/auto/corelib/global/qlogging/app/main.cpp b/tests/auto/corelib/global/qlogging/app/main.cpp index 4c26bb85e3..e5b669e14f 100644 --- a/tests/auto/corelib/global/qlogging/app/main.cpp +++ b/tests/auto/corelib/global/qlogging/app/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** 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. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QCoreApplication> #include <QLoggingCategory> diff --git a/tests/auto/corelib/global/qlogging/qlogging.pro b/tests/auto/corelib/global/qlogging/qlogging.pro deleted file mode 100644 index c81e257a2d..0000000000 --- a/tests/auto/corelib/global/qlogging/qlogging.pro +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLATE = subdirs - -test.depends = app -SUBDIRS += app - -SUBDIRS += test diff --git a/tests/auto/corelib/global/qlogging/test/test.pro b/tests/auto/corelib/global/qlogging/test/test.pro deleted file mode 100644 index c6c5950ff1..0000000000 --- a/tests/auto/corelib/global/qlogging/test/test.pro +++ /dev/null @@ -1,22 +0,0 @@ -CONFIG += testcase -qtConfig(c++11): CONFIG += c++11 -qtConfig(c++14): CONFIG += c++14 -debug_and_release { - CONFIG(debug, debug|release) { - TARGET = ../../debug/tst_qlogging - !android: TEST_HELPER_INSTALLS = ../debug/helper - } else { - TARGET = ../../release/tst_qlogging - !android: TEST_HELPER_INSTALLS = ../release/helper - } -} else { - TARGET = ../tst_qlogging - !android: TEST_HELPER_INSTALLS = ../helper -} - -QT = core testlib -SOURCES = ../tst_qlogging.cpp - -DEFINES += QT_MESSAGELOGCONTEXT -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 -DEFINES += HELPER_BINARY=\\\"helper\\\" diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp index 82bdfdb28a..defe3ac421 100644 --- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp @@ -1,31 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com> -** 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) 2022 The Qt Company Ltd. +// Copyright (C) 2022 Intel Corporation. +// Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qdebug.h> #include <qglobal.h> @@ -33,6 +9,8 @@ # include <QtCore/QProcess> #endif #include <QtTest/QTest> +#include <QList> +#include <QMap> class tst_qmessagehandler : public QObject { @@ -52,6 +30,8 @@ private slots: #ifdef QT_BUILD_INTERNAL void cleanupFuncinfo_data(); void cleanupFuncinfo(); + void cleanupFuncinfoBad_data(); + void cleanupFuncinfoBad(); #endif void qMessagePattern_data(); @@ -62,7 +42,10 @@ private slots: void formatLogMessage(); private: - QStringList m_baseEnvironment; + QString backtraceHelperPath(); +#if QT_CONFIG(process) + QProcessEnvironment m_baseEnvironment; +#endif }; static QtMsgType s_type; @@ -89,13 +72,9 @@ tst_qmessagehandler::tst_qmessagehandler() void tst_qmessagehandler::initTestCase() { #if QT_CONFIG(process) - m_baseEnvironment = QProcess::systemEnvironment(); - for (int i = 0; i < m_baseEnvironment.count(); ++i) { - if (m_baseEnvironment.at(i).startsWith("QT_MESSAGE_PATTERN=")) { - m_baseEnvironment.removeAt(i); - break; - } - } + m_baseEnvironment = QProcessEnvironment::systemEnvironment(); + m_baseEnvironment.remove("QT_MESSAGE_PATTERN"); + m_baseEnvironment.insert("QT_FORCE_STDERR_LOGGING", "1"); #endif // QT_CONFIG(process) } @@ -189,9 +168,13 @@ public: int operator%(int) { ADD("TestClass1::operator%"); return 0; } int x; int &operator++() { ADD("TestClass1::operator++"); return x; } - int operator++(int) { ADD("TestClass1::operator++"); return 0; } int &operator--() { ADD("TestClass1::operator--"); return x; } - int operator--(int) { ADD("TestClass1::operator--"); return 0; } + + // slightly different to avoid duplicate test rows +#define ADD2(x) QTest::newRow(x ".postfix") << Q_FUNC_INFO << x; + int operator++(int) { ADD2("TestClass1::operator++"); return 0; } + int operator--(int) { ADD2("TestClass1::operator--"); return 0; } +#undef ADD2 int nested_struct() { @@ -553,7 +536,7 @@ void tst_qmessagehandler::cleanupFuncinfo_data() QTest::newRow("msvc_28") << "class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > *__thiscall TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > >::func_template1<class TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > >>(void)" << "TestClass2::func_template1"; - QTest::newRow("gcc_21") + QTest::newRow("gcc_28") << "T* TestClass2<T>::func_template1() [with S = TestClass2<std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > > >, T = std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > >]" << "TestClass2::func_template1"; @@ -622,6 +605,34 @@ void tst_qmessagehandler::cleanupFuncinfo_data() << "int TestClass1::operator>(int)" << "TestClass1::operator>"; + QTest::newRow("gcc_40") + << "Polymorphic<void (*)(int)>::~Polymorphic()" + << "Polymorphic::~Polymorphic"; + + QTest::newRow("gcc_41") + << "function<void (int*)>()::S::f()" + << "function()::S::f"; + + QTest::newRow("msvc_41") + << "void `void function<void __cdecl(int *)>(void)'::`2'::S::f(void)" + << "function(void)'::`2'::S::f"; + + QTest::newRow("gcc_42") + << "function<Polymorphic<void (int*)> >()::S::f(Polymorphic<void (int*)>*)" + << "function()::S::f"; + + QTest::newRow("msvc_42") + << "void `void function<Polymorphic<void __cdecl(int *)> >(void)'::`2'::S::f(Polymorphic<void __cdecl(int *)> *)" + << "function(void)'::`2'::S::f"; + + QTest::newRow("gcc_lambda_1") << "main(int, char**)::<lambda()>" + << "main(int, char**)::<lambda()>"; + + QTest::newRow("gcc_lambda_with_auto_1") + << "SomeClass::someMethod(const QString&, const QString&)::<lambda(auto:57)> [with " + "auto:57 = QNetworkReply::NetworkError]" + << "SomeClass::someMethod(const QString&, const QString&)::<lambda(auto:57)>"; + QTest::newRow("objc_1") << "-[SomeClass someMethod:withArguments:]" << "-[SomeClass someMethod:withArguments:]"; @@ -637,6 +648,14 @@ void tst_qmessagehandler::cleanupFuncinfo_data() QTest::newRow("objc_4") << "__31-[SomeClass someMethodSchedulingBlock]_block_invoke" << "__31-[SomeClass someMethodSchedulingBlock]_block_invoke"; + + QTest::newRow("thunk-1") + << "non-virtual thunk to QFutureWatcherBasePrivate::postCallOutEvent(QFutureCallOutEvent const&)" + << "QFutureWatcherBasePrivate::postCallOutEvent"; + + QTest::newRow("thunk-2") + << "virtual thunk to std::basic_iostream<char, std::char_traits<char> >::~basic_iostream()" + << "std::basic_iostream::~basic_iostream"; } #endif @@ -657,6 +676,41 @@ void tst_qmessagehandler::cleanupFuncinfo() QEXPECT_FAIL("TestClass1::nested_struct_const", "Nested function processing is broken", Continue); QTEST(QString::fromLatin1(result), "expected"); } + +void tst_qmessagehandler::cleanupFuncinfoBad_data() +{ + QTest::addColumn<QByteArray>("funcinfo"); + + auto addBadFrame = [i = 0](const char *symbol) mutable { + QTest::addRow("%d", ++i) << QByteArray(symbol); + }; + addBadFrame("typeinfo for QEventLoop"); + addBadFrame("typeinfo name for QtPrivate::ResultStoreBase"); + addBadFrame("typeinfo name for ._anon_476"); + addBadFrame("typeinfo name for std::__1::__function::__base<bool (void*, void*)>"); + addBadFrame("vtable for BezierEase"); + addBadFrame("vtable for Polymorphic<void ()>"); + addBadFrame("vtable for Polymorphic<void (*)(int)>"); + addBadFrame("TLS wrapper function for (anonymous namespace)::jitStacks"); + addBadFrame("lcCheckIndex()::category"); + addBadFrame("guard variable for lcEPDetach()::category"); + addBadFrame("guard variable for QImageReader::read(QImage*)::disableNxImageLoading"); + addBadFrame("VTT for std::__1::ostrstream"); + addBadFrame("qIsRelocatable<(anonymous namespace)::Data>"); + addBadFrame("qt_incomplete_metaTypeArray<(anonymous namespace)::qt_meta_stringdata_CLASSQNonContiguousByteDeviceIoDeviceImplENDCLASS_t, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, true> > >"); + addBadFrame("f()::i"); +} + +void tst_qmessagehandler::cleanupFuncinfoBad() +{ + QFETCH(QByteArray, funcinfo); + + // A corrupted stack trace may find non-sensical symbols that aren't + // functions. The result doesn't matter, so long as we don't crash or hang. + + QByteArray result = qCleanupFuncinfo(funcinfo); + qDebug() << "Decode of" << funcinfo << "produced" << result; +} #endif void tst_qmessagehandler::qMessagePattern_data() @@ -667,16 +721,16 @@ void tst_qmessagehandler::qMessagePattern_data() // %{file} is tricky because of shadow builds QTest::newRow("basic") << "%{type} %{appname} %{line} %{function} %{message}" << true << (QList<QByteArray>() - << "debug 39 T::T static constructor" + << "debug 14 T::T static constructor" // we can't be sure whether the QT_MESSAGE_PATTERN is already destructed << "static destructor" - << "debug tst_qlogging 60 MyClass::myFunction from_a_function 34" - << "debug tst_qlogging 70 main qDebug" - << "info tst_qlogging 71 main qInfo" - << "warning tst_qlogging 72 main qWarning" - << "critical tst_qlogging 73 main qCritical" - << "warning tst_qlogging 76 main qDebug with category" - << "debug tst_qlogging 80 main qDebug2"); + << "debug tst_qlogging 35 MyClass::myFunction from_a_function 34" + << "debug tst_qlogging 45 main qDebug" + << "info tst_qlogging 46 main qInfo" + << "warning tst_qlogging 47 main qWarning" + << "critical tst_qlogging 48 main qCritical" + << "warning tst_qlogging 51 main qDebug with category" + << "debug tst_qlogging 55 main qDebug2"); QTest::newRow("invalid") << "PREFIX: %{unknown} %{message}" << false << (QList<QByteArray>() @@ -737,30 +791,44 @@ void tst_qmessagehandler::qMessagePattern_data() QTest::newRow("time-process") << "<%{time process}>%{message}" << true << (QList<QByteArray>() << "< "); -#ifdef QT_CMAKE_BUILD #define BACKTRACE_HELPER_NAME "qlogging_helper" -#else -#define BACKTRACE_HELPER_NAME "helper" -#endif -#ifdef __GLIBC__ #ifdef QT_NAMESPACE #define QT_NAMESPACE_STR QT_STRINGIFY(QT_NAMESPACE::) #else #define QT_NAMESPACE_STR "" #endif -#ifndef QT_NO_DEBUG - QTest::newRow("backtrace") << "[%{backtrace}] %{message}" << true << (QList<QByteArray>() - // MyClass::qt_static_metacall is explicitly marked as hidden in the Q_OBJECT macro - << "[MyClass::myFunction|MyClass::mySlot1|?" BACKTRACE_HELPER_NAME "?|" QT_NAMESPACE_STR "QMetaMethod::invoke|" QT_NAMESPACE_STR "QMetaObject::invokeMethod] from_a_function 34"); -#endif +#ifdef __GLIBC__ +# if QT_CONFIG(static) + // These test cases don't work with static Qt builds +# elif !defined(Q_PROCESSOR_X86) + // On most RISC platforms, call frames do not have to be stored to the + // stack (the return pointer may be saved in any callee-saved register), so + // this test isn't reliable. +# elif defined(QT_ASAN_ENABLED) + // These tests produce far more call frames under ASan +# else +# ifndef QT_NO_DEBUG + QList<QByteArray> expectedBacktrace = { + // MyClass::qt_static_metacall is explicitly marked as hidden in the + // Q_OBJECT macro hence the ?helper? frame + "[MyClass::myFunction|MyClass::mySlot1|?" BACKTRACE_HELPER_NAME "?|", + + // QMetaObject::invokeMethodImpl calls internal function + // (QMetaMethodPrivate::invokeImpl, at the time of this writing), which + // will usually show only as ?libQt6Core.so? or equivalent, so we skip + + "|" QT_NAMESPACE_STR "QMetaObject::invokeMethodImpl] from_a_function 34" + }; + QTest::newRow("backtrace") << "[%{backtrace}] %{message}" << true << expectedBacktrace; +# endif QTest::newRow("backtrace depth,separator") << "[%{backtrace depth=2 separator=\"\n\"}] %{message}" << true << (QList<QByteArray>() << "[MyClass::myFunction\nMyClass::mySlot1] from_a_function 34" << "[T::T\n"); -#endif - +# endif // #if !QT_CONFIG(static) +#endif // #ifdef __GLIBC__ } @@ -777,18 +845,14 @@ void tst_qmessagehandler::qMessagePattern() QFETCH(QList<QByteArray>, expected); QProcess process; -#ifndef Q_OS_ANDROID - const QString appExe(QLatin1String(HELPER_BINARY)); -#else - const QString appExe(QCoreApplication::applicationDirPath() + QLatin1String("/lib" BACKTRACE_HELPER_NAME ".so")); -#endif + const QString appExe(backtraceHelperPath()); // // test QT_MESSAGE_PATTERN // - QStringList environment = m_baseEnvironment; - environment.prepend("QT_MESSAGE_PATTERN=\"" + pattern + QLatin1Char('"')); - process.setEnvironment(environment); + QProcessEnvironment environment = m_baseEnvironment; + environment.insert("QT_MESSAGE_PATTERN", pattern); + process.setProcessEnvironment(environment); process.start(appExe); QVERIFY2(process.waitForStarted(), qPrintable( @@ -801,15 +865,16 @@ void tst_qmessagehandler::qMessagePattern() QVERIFY(!output.isEmpty()); QCOMPARE(!output.contains("QT_MESSAGE_PATTERN"), valid); - for (const QByteArray &e : qAsConst(expected)) { + for (const QByteArray &e : std::as_const(expected)) { if (!output.contains(e)) { - qDebug() << output; - qDebug() << "expected: " << e; - QVERIFY(output.contains(e)); + // use QDebug so we get proper string escaping for the newlines + QString buf; + QDebug(&buf) << "Got:" << output << "; Expected:" << e; + QVERIFY2(output.contains(e), qPrintable(buf)); } } if (pattern.startsWith("%{pid}")) - QVERIFY2(output.startsWith('"' + pid), "PID: " + pid + "\noutput:\n" + output); + QVERIFY2(output.startsWith(pid), "PID: " + pid + "\noutput:\n" + output); #endif } @@ -827,22 +892,10 @@ void tst_qmessagehandler::setMessagePattern() // QProcess process; -#ifndef Q_OS_ANDROID - const QString appExe(QLatin1String(HELPER_BINARY)); -#else - const QString appExe(QCoreApplication::applicationDirPath() + QLatin1String("/libhelper.so")); -#endif + const QString appExe(backtraceHelperPath()); // make sure there is no QT_MESSAGE_PATTERN in the environment - QStringList environment; - environment.reserve(m_baseEnvironment.size()); - const auto doesNotStartWith = [](QLatin1String s) { - return [s](const QString &str) { return !str.startsWith(s); }; - }; - std::copy_if(m_baseEnvironment.cbegin(), m_baseEnvironment.cend(), - std::back_inserter(environment), - doesNotStartWith(QLatin1String("QT_MESSAGE_PATTERN"))); - process.setEnvironment(environment); + process.setProcessEnvironment(m_baseEnvironment); process.start(appExe); QVERIFY2(process.waitForStarted(), qPrintable( @@ -902,7 +955,11 @@ void tst_qmessagehandler::formatLogMessage_data() << format << "[F] msg" << QtFatalMsg << BA("") << 0 << BA("func") << QByteArray() << "msg"; QTest::newRow("if_cat") +#ifndef Q_OS_ANDROID << format << "[F] cat: msg" +#else + << format << "[F] : msg" +#endif << QtFatalMsg << BA("") << 0 << BA("func") << BA("cat") << "msg"; } @@ -924,6 +981,17 @@ void tst_qmessagehandler::formatLogMessage() QCOMPARE(r, result); } +QString tst_qmessagehandler::backtraceHelperPath() +{ +#ifdef Q_OS_ANDROID + QString appExe(QCoreApplication::applicationDirPath() + + QLatin1String("/lib" BACKTRACE_HELPER_NAME ".so")); +#else + QString appExe(QCoreApplication::applicationDirPath() + + QLatin1String("/" BACKTRACE_HELPER_NAME)); +#endif + return appExe; +} QTEST_MAIN(tst_qmessagehandler) #include "tst_qlogging.moc" diff --git a/tests/auto/corelib/global/qlogging/tst_qmessagelogger.cpp b/tests/auto/corelib/global/qlogging/tst_qmessagelogger.cpp new file mode 100644 index 0000000000..9c6b9e275d --- /dev/null +++ b/tests/auto/corelib/global/qlogging/tst_qmessagelogger.cpp @@ -0,0 +1,334 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <qlogging.h> +#include <qloggingcategory.h> +#include <QtTest/QTest> + +Q_LOGGING_CATEGORY(debugTestCategory, "debug", QtDebugMsg) +Q_LOGGING_CATEGORY(infoTestCategory, "info", QtInfoMsg) +Q_LOGGING_CATEGORY(warningTestCategory, "warning", QtWarningMsg) +Q_LOGGING_CATEGORY(criticalTestCategory, "critical", QtCriticalMsg) + +struct LoggerMessageInfo +{ + QtMsgType messageType { QtFatalMsg }; + QString message; + const char *file { nullptr }; + int line { 0 }; + const char *function { nullptr }; + const char *category { nullptr }; +}; + +LoggerMessageInfo messageInfo; + +static void customMessageHandler(QtMsgType type, const QMessageLogContext &context, + const QString &message) +{ + messageInfo.messageType = type; + messageInfo.message = message; + messageInfo.file = context.file; + messageInfo.line = context.line; + messageInfo.function = context.function; + messageInfo.category = context.category; +} + +class tst_QMessageLogger : public QObject +{ + Q_OBJECT +private slots: + void initTestCase_data(); + + void init(); + void cleanup(); + + void logMessage(); + void logMessageWithLoggingCategory(); + void logMessageWithLoggingCategoryDisabled(); + void logMessageWithCategoryFunction(); + void logMessageWithNoDebug(); + +private: + void logWithLoggingCategoryHelper(bool messageTypeEnabled); +}; + +void tst_QMessageLogger::initTestCase_data() +{ + QTest::addColumn<QtMsgType>("messageType"); + QTest::addColumn<QByteArray>("categoryName"); + QTest::addColumn<QByteArray>("messageText"); + QTest::addColumn<bool>("useDebugStream"); + + // not testing QtFatalMsg, as it terminates the application + QTest::newRow("debug") << QtDebugMsg << QByteArray("categoryDebug") + << QByteArray("debug message") << false; + QTest::newRow("info") << QtInfoMsg << QByteArray("categoryInfo") << QByteArray("info message") + << false; + QTest::newRow("warning") << QtWarningMsg << QByteArray("categoryWarning") + << QByteArray("warning message") << false; + QTest::newRow("critical") << QtCriticalMsg << QByteArray("categoryCritical") + << QByteArray("critical message") << false; + +#ifndef QT_NO_DEBUG_STREAM + QTest::newRow("stream debug") << QtDebugMsg << QByteArray("categoryDebug") + << QByteArray("debug message") << true; + QTest::newRow("stream info") << QtInfoMsg << QByteArray("categoryInfo") + << QByteArray("info message") << true; + QTest::newRow("stream warning") << QtWarningMsg << QByteArray("categoryWarning") + << QByteArray("warning message") << true; + QTest::newRow("stream critical") << QtCriticalMsg << QByteArray("categoryCritical") + << QByteArray("critical message") << true; +#endif +} + +void tst_QMessageLogger::init() +{ + qInstallMessageHandler(customMessageHandler); +} + +void tst_QMessageLogger::cleanup() +{ + qInstallMessageHandler((QtMessageHandler)0); + messageInfo.messageType = QtFatalMsg; + messageInfo.message.clear(); + messageInfo.file = nullptr; + messageInfo.line = 0; + messageInfo.function = nullptr; + messageInfo.category = nullptr; +} + +void tst_QMessageLogger::logMessage() +{ + const int line = QT_MESSAGELOG_LINE; + QMessageLogger logger(QT_MESSAGELOG_FILE, line, QT_MESSAGELOG_FUNC); + + QFETCH_GLOBAL(QtMsgType, messageType); + QFETCH_GLOBAL(QByteArray, messageText); + QFETCH_GLOBAL(bool, useDebugStream); + if (useDebugStream) { +#ifndef QT_NO_DEBUG_STREAM + switch (messageType) { + case QtDebugMsg: + logger.debug().noquote() << messageText; + break; + case QtInfoMsg: + logger.info().noquote() << messageText; + break; + case QtWarningMsg: + logger.warning().noquote() << messageText; + break; + case QtCriticalMsg: + logger.critical().noquote() << messageText; + break; + default: + QFAIL("Invalid message type"); + break; + } +#else + QSKIP("Qt debug stream disabled"); +#endif + } else { + switch (messageType) { + case QtDebugMsg: + logger.debug("%s", messageText.constData()); + break; + case QtInfoMsg: + logger.info("%s", messageText.constData()); + break; + case QtWarningMsg: + logger.warning("%s", messageText.constData()); + break; + case QtCriticalMsg: + logger.critical("%s", messageText.constData()); + break; + default: + QFAIL("Invalid message type"); + break; + } + } + + QCOMPARE(messageInfo.messageType, messageType); + QCOMPARE(messageInfo.message, messageText); + QCOMPARE(messageInfo.file, __FILE__); + QCOMPARE(messageInfo.line, line); + QCOMPARE(messageInfo.function, Q_FUNC_INFO); +} + +void tst_QMessageLogger::logMessageWithLoggingCategory() +{ + logWithLoggingCategoryHelper(true); +} + +void tst_QMessageLogger::logMessageWithLoggingCategoryDisabled() +{ + logWithLoggingCategoryHelper(false); +} + +void tst_QMessageLogger::logMessageWithCategoryFunction() +{ + const int line = QT_MESSAGELOG_LINE; + QMessageLogger logger(QT_MESSAGELOG_FILE, line, QT_MESSAGELOG_FUNC); + + const QLoggingCategory *category = nullptr; + QFETCH_GLOBAL(QtMsgType, messageType); + QFETCH_GLOBAL(QByteArray, messageText); + QFETCH_GLOBAL(bool, useDebugStream); + if (useDebugStream) { +#ifndef QT_NO_DEBUG_STREAM + switch (messageType) { + case QtDebugMsg: + logger.debug(debugTestCategory()).noquote() << messageText; + category = &debugTestCategory(); + break; + case QtInfoMsg: + logger.info(infoTestCategory()).noquote() << messageText; + category = &infoTestCategory(); + break; + case QtWarningMsg: + logger.warning(warningTestCategory()).noquote() << messageText; + category = &warningTestCategory(); + break; + case QtCriticalMsg: + logger.critical(criticalTestCategory()).noquote() << messageText; + category = &criticalTestCategory(); + break; + default: + QFAIL("Invalid message type"); + break; + } +#else + QSKIP("Qt debug stream disabled"); +#endif + } else { + switch (messageType) { + case QtDebugMsg: + logger.debug(debugTestCategory(), "%s", messageText.constData()); + category = &debugTestCategory(); + break; + case QtInfoMsg: + logger.info(infoTestCategory(), "%s", messageText.constData()); + category = &infoTestCategory(); + break; + case QtWarningMsg: + logger.warning(warningTestCategory(), "%s", messageText.constData()); + category = &warningTestCategory(); + break; + case QtCriticalMsg: + logger.critical(criticalTestCategory(), "%s", messageText.constData()); + category = &criticalTestCategory(); + break; + default: + QFAIL("Invalid message type"); + break; + } + } + + QCOMPARE(messageInfo.messageType, messageType); + QCOMPARE(messageInfo.message, messageText); + QCOMPARE(messageInfo.file, __FILE__); + QCOMPARE(messageInfo.line, line); + QCOMPARE(messageInfo.function, Q_FUNC_INFO); + QCOMPARE(messageInfo.category, category->categoryName()); +} + +void tst_QMessageLogger::logMessageWithNoDebug() +{ + const int line = QT_MESSAGELOG_LINE; + QMessageLogger logger(QT_MESSAGELOG_FILE, line, QT_MESSAGELOG_FUNC); + + QFETCH_GLOBAL(QByteArray, messageText); + QFETCH_GLOBAL(bool, useDebugStream); + if (useDebugStream) { +#ifndef QT_NO_DEBUG_STREAM + logger.noDebug().noquote() << messageText; +#else + QSKIP("Qt debug stream disabled"); +#endif + } else { + logger.noDebug("%s", messageText.constData()); + } + + // the callback was not called + QVERIFY(messageInfo.messageType == QtFatalMsg); + QVERIFY(messageInfo.message.isEmpty()); + QVERIFY(messageInfo.file == nullptr); + QVERIFY(messageInfo.line == 0); + QVERIFY(messageInfo.function == nullptr); + QVERIFY(messageInfo.category == nullptr); +} + +void tst_QMessageLogger::logWithLoggingCategoryHelper(bool messageTypeEnabled) +{ + QFETCH_GLOBAL(QtMsgType, messageType); + QFETCH_GLOBAL(QByteArray, categoryName); + QLoggingCategory category(categoryName.constData(), messageType); + if (!messageTypeEnabled) + category.setEnabled(messageType, false); + + const int line = QT_MESSAGELOG_LINE; + QMessageLogger logger(QT_MESSAGELOG_FILE, line, QT_MESSAGELOG_FUNC); + + QFETCH_GLOBAL(QByteArray, messageText); + QFETCH_GLOBAL(bool, useDebugStream); + if (useDebugStream) { +#ifndef QT_NO_DEBUG_STREAM + switch (messageType) { + case QtDebugMsg: + logger.debug(category).noquote() << messageText; + break; + case QtInfoMsg: + logger.info(category).noquote() << messageText; + break; + case QtWarningMsg: + logger.warning(category).noquote() << messageText; + break; + case QtCriticalMsg: + logger.critical(category).noquote() << messageText; + break; + default: + QFAIL("Invalid message type"); + break; + } +#else + QSKIP("Qt debug stream disabled"); +#endif + } else { + switch (messageType) { + case QtDebugMsg: + logger.debug(category, "%s", messageText.constData()); + break; + case QtInfoMsg: + logger.info(category, "%s", messageText.constData()); + break; + case QtWarningMsg: + logger.warning(category, "%s", messageText.constData()); + break; + case QtCriticalMsg: + logger.critical(category, "%s", messageText.constData()); + break; + default: + QFAIL("Invalid message type"); + break; + } + } + + if (messageTypeEnabled) { + QCOMPARE(messageInfo.messageType, messageType); + QCOMPARE(messageInfo.message, messageText); + QCOMPARE(messageInfo.file, __FILE__); + QCOMPARE(messageInfo.line, line); + QCOMPARE(messageInfo.function, Q_FUNC_INFO); + QCOMPARE(messageInfo.category, categoryName); + } else { + // the callback was not called + QVERIFY(messageInfo.messageType == QtFatalMsg); + QVERIFY(messageInfo.message.isEmpty()); + QVERIFY(messageInfo.file == nullptr); + QVERIFY(messageInfo.line == 0); + QVERIFY(messageInfo.function == nullptr); + QVERIFY(messageInfo.category == nullptr); + } +} + +QTEST_MAIN(tst_QMessageLogger) +#include "tst_qmessagelogger.moc" |