/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include class tst_qmessagehandler : public QObject { Q_OBJECT private slots: void cleanup(); void defaultHandler(); void installMessageHandler(); void installMsgHandler(); void installBothHandler(); void cleanupFuncinfo_data(); void cleanupFuncinfo(); void qMessagePattern(); }; static QtMsgType s_type; const char *s_file; int s_line; const char *s_function; static QString s_message; void customMessageHandler(QtMsgType type, const QMessageLogContext &context, const char *msg) { s_type = type; s_file = context.file; s_line = context.line; s_function = context.function; s_message = QString::fromLocal8Bit(msg); } void customMsgHandler(QtMsgType type, const char *msg) { s_type = type; s_file = 0; s_line = 0; s_function = 0; s_message = QString::fromLocal8Bit(msg); } void tst_qmessagehandler::cleanup() { qInstallMsgHandler(0); qInstallMessageHandler(0); s_type = QtFatalMsg; s_file = 0; s_line = 0; s_function = 0; } void tst_qmessagehandler::defaultHandler() { // check that the default works QTest::ignoreMessage(QtDebugMsg, "defaultHandler"); qDebug("defaultHandler"); } void tst_qmessagehandler::installMessageHandler() { QMessageHandler oldHandler = qInstallMessageHandler(customMessageHandler); qDebug("installMessageHandler"); int line = __LINE__; QCOMPARE(s_type, QtDebugMsg); QCOMPARE(s_message, QString::fromLocal8Bit("installMessageHandler")); QCOMPARE(s_file, __FILE__); QCOMPARE(s_function, Q_FUNC_INFO); QCOMPARE(s_line, line); QMessageHandler myHandler = qInstallMessageHandler(oldHandler); QCOMPARE((void*)myHandler, (void*)customMessageHandler); } void tst_qmessagehandler::installMsgHandler() { QtMsgHandler oldHandler = qInstallMsgHandler(customMsgHandler); qDebug("installMsgHandler"); QCOMPARE(s_type, QtDebugMsg); QCOMPARE(s_message, QString::fromLocal8Bit("installMsgHandler")); QCOMPARE(s_file, (const char*)0); QCOMPARE(s_function, (const char*)0); QCOMPARE(s_line, 0); QtMsgHandler myHandler = qInstallMsgHandler(oldHandler); QCOMPARE((void*)myHandler, (void*)customMsgHandler); } void tst_qmessagehandler::installBothHandler() { qInstallMessageHandler(customMessageHandler); qInstallMsgHandler(customMsgHandler); qDebug("installBothHandler"); int line = __LINE__; QCOMPARE(s_type, QtDebugMsg); QCOMPARE(s_message, QString::fromLocal8Bit("installBothHandler")); QCOMPARE(s_file, __FILE__); QCOMPARE(s_function, Q_FUNC_INFO); QCOMPARE(s_line, line); } # define ADD(x) QTest::newRow(x) << Q_FUNC_INFO << x; class TestClass1 { public: enum Something { foo }; void func_void() { ADD("TestClass1::func_void"); } int func_int() { ADD("TestClass1::func_int"); return 0; } unsigned func_unsigned() { ADD("TestClass1::func_unsigned"); return 0; } long func_long() { ADD("TestClass1::func_long"); return 0; } long long func_ll() { ADD("TestClass1::func_ll"); return 0; } unsigned long long func_ull() { ADD("TestClass1::func_ull"); return 0; } char func_char() { ADD("TestClass1::func_char"); return 0; } signed char func_schar() { ADD("TestClass1::func_schar"); return 0; } unsigned char func_uchar() { ADD("TestClass1::func_uchar"); return 0; } char *func_Pchar() { ADD("TestClass1::func_Pchar"); return 0; } const char *func_KPchar() { ADD("TestClass1::func_KPchar"); return 0; } const volatile char *func_VKPchar() { ADD("TestClass1::func_VKPchar"); return 0; } const volatile unsigned long long * const volatile func_KVPKVull() { ADD("TestClass1::func_KVPKVull"); return 0; } const void * const volatile *func_KPKVvoid() { ADD("TestClass1::func_KPKVvoid"); return 0; } QList func_ai() { ADD("TestClass1::func_ai"); return QList(); } QList func_aptr() { ADD("TestClass1::func_aptr"); return QList(); } QList func_aenum() { ADD("TestClass1::func_aenum"); return QList(); } QList > func_aaptr() { ADD("TestClass1::func_aaptr"); return QList >(); } QMap func_ienummap() { ADD("TestClass1::func_ienummap"); return QMap(); } template T* func_template1() { ADD("TestClass1::func_template1"); return 0; } template long func_template2() { ADD("TestClass1::func_template2"); return long(val); } typedef unsigned long long * ( *fptr)(); typedef unsigned long long * (TestClass1::* pmf)(); typedef fptr (TestClass1::* uglypmf)(); fptr func_fptr() { ADD("TestClass1::func_fptr"); return 0; } pmf func_pmf() { ADD("TestClass1::func_pmf"); return 0; } uglypmf func_uglypmf(uglypmf = 0) { ADD("TestClass1::func_uglypmf"); return 0; } QMap func_uglypmf2() { ADD("TestClass1::func_uglypmf2"); return QMap(); } void operator()() { ADD("TestClass1::operator()"); } int operator<(int) { ADD("TestClass1::operator<"); return 0; } int operator>(int) { ADD("TestClass1::operator>"); return 0; } int operator<=(int) { ADD("TestClass1::operator<="); return 0; } int operator>=(int) { ADD("TestClass1::operator>="); return 0; } int operator=(int) { ADD("TestClass1::operator="); return 0; } int operator+(int) { ADD("TestClass1::operator+"); return 0; } int operator-(int) { ADD("TestClass1::operator-"); return 0; } int operator*(int) { ADD("TestClass1::operator*"); return 0; } int operator/(int) { ADD("TestClass1::operator/"); return 0; } 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; } public: TestClass1() { // instantiate func_void(); func_int(); func_unsigned(); func_long(); func_ll(); func_ull(); func_char(); func_schar(); func_uchar(); func_Pchar(); func_KPchar(); func_VKPchar(); func_KVPKVull(); func_KPKVvoid(); func_ai(); func_aptr(); func_aenum(); func_aaptr(); func_ienummap(); func_template1(); func_template2(); func_fptr(); func_pmf(); func_uglypmf(); func_uglypmf2(); operator()(); operator<(0); operator>(0); operator<=(0); operator>=(0); operator=(0); operator+(0); operator-(0); operator*(0); operator/(0); operator%(0); operator++(); operator++(0); operator--(); operator--(0); } }; template class TestClass2 { long func_long() { ADD("TestClass2::func_long"); return 0; } template T* func_template1() { ADD("TestClass2::func_template1"); return 0; } template long func_template2() { ADD("TestClass2::func_template2"); return long(val); } public: TestClass2() { func_long(); func_template1(); func_template2(); } }; template class TestClass3 { long func_long() { ADD("TestClass3::func_long"); return 0; } template S* func_template1() { ADD("TestClass3::func_template1"); return 0; } template long func_template2() { ADD("TestClass3::func_template2"); return long(val); } public: struct Foo { TestClass3 foo; }; TestClass3() { func_long(); func_template1 >(); func_template2(); } }; class TestClass4 { TestClass1 c1; TestClass2 > func2() { ADD("TestClass4::func2"); return TestClass2 >(); } TestClass3, const void *>, TestClass1::foo>::Foo func3() { ADD("TestClass4::func3"); return TestClass3, const void *>, TestClass1::foo>::Foo(); } public: TestClass4() { func2(); func3(); ADD("TestClass4::TestClass4"); } ~TestClass4() { ADD("TestClass4::~TestClass4"); } }; void tst_qmessagehandler::cleanupFuncinfo_data() { #ifndef QT_BUILD_INTERNAL QSKIP("Requires -developer-build"); #endif QTest::addColumn("funcinfo"); QTest::addColumn("expected"); TestClass4 c4; QTest::newRow("msvc_01") << "void __thiscall TestClass1::func_void(void)" << "TestClass1::func_void"; QTest::newRow("gcc_01") << "void TestClass1::func_void()" << "TestClass1::func_void"; QTest::newRow("msvc_02") << "int __thiscall TestClass1::func_int(void)" << "TestClass1::func_int"; QTest::newRow("gcc_02") << "int TestClass1::func_int()" << "TestClass1::func_int"; QTest::newRow("msvc_03") << "unsigned int __thiscall TestClass1::func_unsigned(void)" << "TestClass1::func_unsigned"; QTest::newRow("gcc_03") << "unsigned int TestClass1::func_unsigned()" << "TestClass1::func_unsigned"; QTest::newRow("msvc_04") << "long __thiscall TestClass1::func_long(void)" << "TestClass1::func_long"; QTest::newRow("gcc_04") << "long int TestClass1::func_long()" << "TestClass1::func_long"; QTest::newRow("msvc_05") << "__int64 __thiscall TestClass1::func_ll(void)" << "TestClass1::func_ll"; QTest::newRow("gcc_05") << "long long int TestClass1::func_ll()" << "TestClass1::func_ll"; QTest::newRow("msvc_06") << "unsigned __int64 __thiscall TestClass1::func_ull(void)" << "TestClass1::func_ull"; QTest::newRow("gcc_06") << "long long unsigned int TestClass1::func_ull()" << "TestClass1::func_ull"; QTest::newRow("msvc_07") << "char __thiscall TestClass1::func_char(void)" << "TestClass1::func_char"; QTest::newRow("gcc_07") << "char TestClass1::func_char()" << "TestClass1::func_char"; QTest::newRow("msvc_08") << "signed char __thiscall TestClass1::func_schar(void)" << "TestClass1::func_schar"; QTest::newRow("gcc_08") << "signed char TestClass1::func_schar()" << "TestClass1::func_schar"; QTest::newRow("msvc_09") << "unsigned char __thiscall TestClass1::func_uchar(void)" << "TestClass1::func_uchar"; QTest::newRow("gcc_09") << "unsigned char TestClass1::func_uchar()" << "TestClass1::func_uchar"; QTest::newRow("msvc_10") << "char *__thiscall TestClass1::func_Pchar(void)" << "TestClass1::func_Pchar"; QTest::newRow("gcc_10") << "char* TestClass1::func_Pchar()" << "TestClass1::func_Pchar"; QTest::newRow("msvc_11") << "const char *__thiscall TestClass1::func_KPchar(void)" << "TestClass1::func_KPchar"; QTest::newRow("gcc_11") << "const char* TestClass1::func_KPchar()" << "TestClass1::func_KPchar"; QTest::newRow("msvc_12") << "volatile const char *__thiscall TestClass1::func_VKPchar(void)" << "TestClass1::func_VKPchar"; QTest::newRow("gcc_12") << "const volatile char* TestClass1::func_VKPchar()" << "TestClass1::func_VKPchar"; QTest::newRow("msvc_13") << "volatile const unsigned __int64 *volatile const __thiscall TestClass1::func_KVPKVull(void)" << "TestClass1::func_KVPKVull"; QTest::newRow("gcc_13") << "const volatile long long unsigned int* const volatile TestClass1::func_KVPKVull()" << "TestClass1::func_KVPKVull"; QTest::newRow("msvc_14") << "const void *volatile const *__thiscall TestClass1::func_KPKVvoid(void)" << "TestClass1::func_KPKVvoid"; QTest::newRow("gcc_14") << "const void* const volatile* TestClass1::func_KPKVvoid()" << "TestClass1::func_KPKVvoid"; QTest::newRow("msvc_15") << "class QList __thiscall TestClass1::func_ai(void)" << "TestClass1::func_ai"; QTest::newRow("gcc_15") << "QList TestClass1::func_ai()" << "TestClass1::func_ai"; QTest::newRow("msvc_16") << "class QList __thiscall TestClass1::func_aptr(void)" << "TestClass1::func_aptr"; QTest::newRow("gcc_16") << "QList TestClass1::func_aptr()" << "TestClass1::func_aptr"; QTest::newRow("msvc_17") << "class QList __thiscall TestClass1::func_aenum(void)" << "TestClass1::func_aenum"; QTest::newRow("gcc_17") << "QList TestClass1::func_aenum()" << "TestClass1::func_aenum"; QTest::newRow("msvc_18") << "class QList > __thiscall TestClass1::func_aaptr(void)" << "TestClass1::func_aaptr"; QTest::newRow("gcc_18") << "QList > TestClass1::func_aaptr()" << "TestClass1::func_aaptr"; QTest::newRow("msvc_19") << "class QMap __thiscall TestClass1::func_ienummap(void)" << "TestClass1::func_ienummap"; QTest::newRow("gcc_19") << "QMap TestClass1::func_ienummap()" << "TestClass1::func_ienummap"; QTest::newRow("msvc_20") << "class TestClass1 *__thiscall TestClass1::func_template1(void)" << "TestClass1::func_template1"; QTest::newRow("gcc_20") << "T* TestClass1::func_template1() [with T = TestClass1]" << "TestClass1::func_template1"; QTest::newRow("msvc_21") << "long __thiscall TestClass1::func_template2(void)" << "TestClass1::func_template2"; QTest::newRow("gcc_21") << "long int TestClass1::func_template2() [with TestClass1::Something val = foo]" << "TestClass1::func_template2"; QTest::newRow("msvc_22") << "unsigned __int64 *(__cdecl *__thiscall TestClass1::func_fptr(void))(void)" << "TestClass1::func_fptr"; QTest::newRow("gcc_22") << "long long unsigned int* (* TestClass1::func_fptr())()" << "TestClass1::func_fptr"; QTest::newRow("msvc_23") << "unsigned __int64 *(__thiscall TestClass1::* __thiscall TestClass1::func_pmf(void))(void)" << "TestClass1::func_pmf"; QTest::newRow("gcc_23") << "long long unsigned int* (TestClass1::* TestClass1::func_pmf())()" << "TestClass1::func_pmf"; QTest::newRow("msvc_24") << "unsigned __int64 *(__cdecl *(__thiscall TestClass1::* __thiscall TestClass1::func_uglypmf(unsigned __int64 *(__cdecl *(__thiscall TestClass1::* )(void))(void)))(void))(void)" << "TestClass1::func_uglypmf"; QTest::newRow("gcc_24") << "long long unsigned int* (* (TestClass1::* TestClass1::func_uglypmf(long long unsigned int* (* (TestClass1::*)())()))())()" << "TestClass1::func_uglypmf"; QTest::newRow("msvc_25") << "class QMap __thiscall TestClass1::func_uglypmf2(void)" << "TestClass1::func_uglypmf2"; QTest::newRow("gcc_25") << "QMap TestClass1::func_uglypmf2()" << "TestClass1::func_uglypmf2"; QTest::newRow("msvc_26") << "class TestClass2,class std::allocator > > > __thiscall TestClass4::func2(void)" << "TestClass4::func2"; QTest::newRow("gcc_26") << "TestClass2, std::allocator > > > TestClass4::func2()" << "TestClass4::func2"; QTest::newRow("msvc_27") << "long __thiscall TestClass2,class std::allocator > > >::func_long(void)" << "TestClass2::func_long"; QTest::newRow("gcc_27") << "long int TestClass2::func_long() [with T = std::map, std::allocator > >]" << "TestClass2::func_long"; QTest::newRow("msvc_28") << "class std::map,class std::allocator > > *__thiscall TestClass2,class std::allocator > > >::func_template1,class std::allocator > > >>(void)" << "TestClass2::func_template1"; QTest::newRow("gcc_21") << "T* TestClass2::func_template1() [with S = TestClass2, std::allocator > > >, T = std::map, std::allocator > >]" << "TestClass2::func_template1"; QTest::newRow("msvc_29") << "long __thiscall TestClass2,class std::allocator > > >::func_template2(void)" << "TestClass2::func_template2"; QTest::newRow("gcc_29") << "long int TestClass2::func_template2() [with TestClass1::Something val = foo, T = std::map, std::allocator > >]" << "TestClass2::func_template2"; QTest::newRow("msvc_30") << "struct TestClass3 >,void const *,struct std::less > >,class std::allocator > const ,void const *> > >,0>::Foo __thiscall TestClass4::func3(void)" << "TestClass4::func3"; QTest::newRow("gcc_30") << "TestClass3 >, const void*, std::less > >, std::allocator >, const void*> > >, foo>::Foo TestClass4::func3()" << "TestClass4::func3"; QTest::newRow("msvc_31") << "long __thiscall TestClass3 >,void const *,struct std::less > >,class std::allocator > const ,void const *> > >,0>::func_long(void)" << "TestClass3::func_long"; QTest::newRow("gcc_31") << "long int TestClass3::func_long() [with T = std::map >, const void*, std::less > >, std::allocator >, const void*> > >, TestClass1::Something v = foo]" << "TestClass3::func_long"; QTest::newRow("msvc_32") << "class TestClass2 >,void const *,struct std::less > >,class std::allocator > const ,void const *> > > > *__thiscall TestClass3 >,void const *,struct std::less > >,class std::allocator > const ,void const *> > >,0>::func_template1 >,void const *,struct std::less > >,class std::allocator > const ,void const *> > > >>(void)" << "TestClass3::func_template1"; QTest::newRow("gcc_32") << "S* TestClass3::func_template1() [with S = TestClass2 >, const void*, std::less > >, std::allocator >, const void*> > > >, T = std::map >, const void*, std::less > >, std::allocator >, const void*> > >, TestClass1::Something v = foo]" << "TestClass3::func_template1"; QTest::newRow("msvc_33") << "long __thiscall TestClass3 >,void const *,struct std::less > >,class std::allocator > const ,void const *> > >,0>::func_template2(void)" << "TestClass3::func_template2"; QTest::newRow("gcc_33") << "long int TestClass3::func_template2() [with TestClass1::Something val = foo, T = std::map >, const void*, std::less > >, std::allocator >, const void*> > >, TestClass1::Something v = foo]" << "TestClass3::func_template2"; QTest::newRow("msvc_34") << "__thiscall TestClass4::TestClass4(void)" << "TestClass4::TestClass4"; QTest::newRow("gcc_34") << "TestClass4::TestClass4()" << "TestClass4::TestClass4"; QTest::newRow("msvc_35") << "__thiscall TestClass4::~TestClass4(void)" << "TestClass4::~TestClass4"; QTest::newRow("gcc_35") << "TestClass4::~TestClass4()" << "TestClass4::~TestClass4"; QTest::newRow("gcc_36") << "void TestClass1::operator()()" << "TestClass1::operator()"; QTest::newRow("gcc_37") << "long int TestClass1::func_template2() [with TestClass1::Something val = (TestClass1::Something)0u]" << "TestClass1::func_template2"; QTest::newRow("gcc_38") << "int TestClass1::operator<(int)" << "TestClass1::operator<"; QTest::newRow("gcc_39") << "int TestClass1::operator>(int)" << "TestClass1::operator>";} #ifdef QT_BUILD_INTERNAL QT_BEGIN_NAMESPACE extern QByteArray qCleanupFuncinfo(QByteArray); QT_END_NAMESPACE #endif void tst_qmessagehandler::cleanupFuncinfo() { #ifdef QT_BUILD_INTERNAL QFETCH(QString, funcinfo); QByteArray result = qCleanupFuncinfo(funcinfo.toLatin1()); QTEST(QString::fromLatin1(result), "expected"); #endif } void tst_qmessagehandler::qMessagePattern() { QProcess process; QStringList environment = QProcess::systemEnvironment(); // %{file} is tricky because of shadow builds environment.prepend("QT_MESSAGE_PATTERN=\"%{type} %{line} %{function} %{message}\""); process.setEnvironment(environment); #ifdef Q_OS_WIN process.start("app/app.exe"); #else process.start("app/app"); #endif process.waitForFinished(); QByteArray output = process.readAllStandardError(); // qDebug() << output; QVERIFY(!output.isEmpty()); QVERIFY(output.contains("debug 45 T::T static constructor")); // we can't be sure whether the QT_MESSAGE_PATTERN is already destructed QVERIFY(output.contains("static destructor")); QVERIFY(output.contains("debug 51 main qDebug")); QVERIFY(output.contains("warning 52 main qWarning")); QVERIFY(output.contains("critical 53 main qCritical")); environment = QProcess::systemEnvironment(); environment.prepend("QT_MESSAGE_PATTERN=\"PREFIX: %{unknown} %{message}\""); process.setEnvironment(environment); #ifdef Q_OS_WIN process.start("app/app.exe"); #else process.start("app/app"); #endif process.waitForFinished(); output = process.readAllStandardError(); // qDebug() << output; QVERIFY(!output.isEmpty()); QVERIFY(output.contains("QT_MESSAGE_PATTERN: Unknown placeholder %{unknown}")); QVERIFY(output.contains("PREFIX: qDebug")); } QTEST_MAIN(tst_qmessagehandler) #include "tst_qlogging.moc"