From be98fa32c7d56ea91359b647a329356fa44eca04 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 3 Feb 2012 09:35:22 +0100 Subject: Allow customization of qDebug output at runtime Check the QT_OUTPUT_PATTERN environment variable in the default message handler to customize the output of messages. Following place holders are right now supported: %{message}, %{type}, %{file}, %{line}, %{function} The original cleanupFuncinfo was written by Thiago Macieira. Change-Id: I6ad25baaa0e6a1c9f886105d2a93ef3310e512a9 Reviewed-by: Olivier Goffart Reviewed-by: David Faure --- qmake/Makefile.unix | 6 +- qmake/Makefile.win32 | 4 +- qmake/Makefile.win32-g++ | 5 +- qmake/Makefile.win32-g++-sh | 6 +- qmake/qmake.pri | 3 +- src/corelib/global/qglobal.cpp | 21 +- src/corelib/global/qlogging.cpp | 313 +++++++++- src/corelib/kernel/qcoreapplication_win.cpp | 24 +- tests/auto/corelib/global/global.pro | 2 +- tests/auto/corelib/global/qlogging/app/app.pro | 9 + tests/auto/corelib/global/qlogging/app/main.cpp | 55 ++ tests/auto/corelib/global/qlogging/qlogging.pro | 5 + .../auto/corelib/global/qlogging/tst_qlogging.cpp | 645 +++++++++++++++++++++ .../auto/corelib/global/qlogging/tst_qlogging.pro | 4 + .../global/qmessagehandler/qmessagehandler.pro | 4 - .../global/qmessagehandler/tst_qmessagehandler.cpp | 147 ----- tools/configure/configure.pro | 2 + 17 files changed, 1076 insertions(+), 179 deletions(-) create mode 100644 tests/auto/corelib/global/qlogging/app/app.pro create mode 100644 tests/auto/corelib/global/qlogging/app/main.cpp create mode 100644 tests/auto/corelib/global/qlogging/qlogging.pro create mode 100644 tests/auto/corelib/global/qlogging/tst_qlogging.cpp create mode 100644 tests/auto/corelib/global/qlogging/tst_qlogging.pro delete mode 100644 tests/auto/corelib/global/qmessagehandler/qmessagehandler.pro delete mode 100644 tests/auto/corelib/global/qmessagehandler/tst_qmessagehandler.cpp diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix index 286e2ebcbc..16af49311b 100644 --- a/qmake/Makefile.unix +++ b/qmake/Makefile.unix @@ -22,7 +22,7 @@ QOBJS=qtextcodec.o qutfcodec.o qstring.o qtextstream.o qiodevice.o qmalloc.o qgl qfileinfo.o qdatetime.o qstringlist.o qabstractfileengine.o qtemporaryfile.o \ qmap.o qmetatype.o qsettings.o qsystemerror.o qlibraryinfo.o qvariant.o qvsnprintf.o \ qlocale.o qlocale_tools.o qlocale_unix.o qlinkedlist.o qurl.o qnumeric.o qcryptographichash.o \ - qxmlstream.o qxmlutils.o \ + qxmlstream.o qxmlutils.o qlogging.o \ $(QTOBJS) @@ -66,6 +66,7 @@ DEPEND_SRC=project.cpp property.cpp meta.cpp main.cpp generators/makefile.cpp ge $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp \ $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp \ $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp \ + $(SOURCE_PATH)/src/corelib/global/qlogging.cpp \ $(QTSRCS) CPPFLAGS = -g -I. -Igenerators -Igenerators/unix -Igenerators/win32 \ @@ -316,6 +317,9 @@ qxmlstream.o: $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp qxmlutils.o: $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp +qlogging.o: $(SOURCE_PATH)/src/corelib/global/qlogging.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qlogging.cpp + #default rules .cpp.o: $(CXX) -c -o $@ $(CXXFLAGS) $< diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32 index e767786001..3efe6a67e0 100644 --- a/qmake/Makefile.win32 +++ b/qmake/Makefile.win32 @@ -118,8 +118,8 @@ QTOBJS= \ qmetatype.obj \ qxmlstream.obj \ qxmlutils.obj \ - qnumeric.obj - + qnumeric.obj \ + qlogging.obj first all: qmake.exe diff --git a/qmake/Makefile.win32-g++ b/qmake/Makefile.win32-g++ index 443dba390a..585061ed26 100644 --- a/qmake/Makefile.win32-g++ +++ b/qmake/Makefile.win32-g++ @@ -95,7 +95,8 @@ QTOBJS= \ qmetatype.o \ qxmlstream.o \ qxmlutils.o \ - qnumeric.o + qnumeric.o \ + qlogging.o qmake.exe: $(OBJS) $(QTOBJS) @@ -339,3 +340,5 @@ qxmlstream.o: $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp qxmlutils.o: $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp +qlogging.o: $(SOURCE_PATH)/src/corelib/global/qlogging.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qlogging.cpp diff --git a/qmake/Makefile.win32-g++-sh b/qmake/Makefile.win32-g++-sh index bc8356e178..6dfb486375 100644 --- a/qmake/Makefile.win32-g++-sh +++ b/qmake/Makefile.win32-g++-sh @@ -95,7 +95,8 @@ QTOBJS= \ qmetatype.o \ qxmlstream.o \ qxmlutils.o \ - qnumeric.o + qnumeric.o \ + qlogging.o qmake.exe: $(OBJS) $(QTOBJS) $(LINKQMAKE) @@ -337,3 +338,6 @@ qxmlstream.o: $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp qxmlutils.o: $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp + +qlogging.o: $(SOURCE_PATH)/src/corelib/global/qlogging.cpp + $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qlogging.cpp diff --git a/qmake/qmake.pri b/qmake/qmake.pri index 1f59531c42..ba6ab383c7 100644 --- a/qmake/qmake.pri +++ b/qmake/qmake.pri @@ -76,7 +76,8 @@ bootstrap { #Qt code qvector.cpp \ qvsnprintf.cpp \ qxmlstream.cpp \ - qxmlutils.cpp + qxmlutils.cpp \ + qlogging.cpp HEADERS+= \ qbitarray.h \ diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 01b3e2ec32..983116f1b3 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1862,27 +1862,32 @@ extern Q_CORE_EXPORT void qWinMessageHandler(QtMsgType t, const QMessageLogConte const char *str); #endif +// defined in qlogging.cpp +extern Q_CORE_EXPORT QByteArray qMessageFormatString(QtMsgType type, const QMessageLogContext &context, + const char *str); + /*! \internal */ -static void qDefaultMsgHandler(QtMsgType, const char *buf) +static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const char *buf) { + QByteArray logMessage = qMessageFormatString(type, context, buf); #if defined(Q_OS_WINCE) - QString fstr = QString::fromLatin1(buf); - fstr += QLatin1Char('\n'); - OutputDebugString(reinterpret_cast (fstr.utf16())); + QString fstr = QString::fromLocal8Bit(logMessage); + OutputDebugString(reinterpret_cast (fstr.utf16())); #else - fprintf(stderr, "%s\n", buf); - fflush(stderr); + fprintf(stderr, "%s", logMessage.constData()); + fflush(stderr); #endif } /*! \internal */ -static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &, const char *buf) +static void qDefaultMsgHandler(QtMsgType type, const char *buf) { - qDefaultMsgHandler(type, buf); + QMessageLogContext emptyContext; + qDefaultMessageHandler(type, emptyContext, buf); } QMessageHandler qInstallMessageHandler(QMessageHandler h) diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index bc26c9b6b7..39b3205571 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -39,7 +39,13 @@ ** ****************************************************************************/ -#include +#include "qlogging.h" +#include "qlist.h" +#include "qbytearray.h" +#include "qstring.h" +#include "qvarlengtharray.h" + +#include QT_BEGIN_NAMESPACE @@ -73,4 +79,309 @@ QT_BEGIN_NAMESPACE \sa QMessageLogContext, qDebug(), qWarning(), qCritical(), qFatal() */ +/*! + \internal +*/ +Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info) +{ + // Strip the function info down to the base function name + // note that this throws away the template definitions, + // the parameter types (overloads) and any const/volatile qualifiers. + + if (info.isEmpty()) + return info; + + int pos; + + // skip trailing [with XXX] for templates (gcc) + pos = info.size() - 1; + if (info.endsWith(']')) { + while (--pos) { + if (info.at(pos) == '[') + info.truncate(pos); + } + } + + // operator names with '(', ')', '<', '>' in it + static const char operator_call[] = "operator()"; + static const char operator_lessThan[] = "operator<"; + static const char operator_greaterThan[] = "operator>"; + static const char operator_lessThanEqual[] = "operator<="; + static const char operator_greaterThanEqual[] = "operator>="; + + // canonize operator names + info.replace("operator ", "operator"); + + // remove argument list + forever { + int parencount = 0; + pos = info.lastIndexOf(')'); + if (pos == -1) { + // Don't know how to parse this function name + return info; + } + + // find the beginning of the argument list + --pos; + ++parencount; + while (pos && parencount) { + if (info.at(pos) == ')') + ++parencount; + else if (info.at(pos) == '(') + --parencount; + --pos; + } + if (parencount != 0) + return info; + + info.truncate(++pos); + + if (info.at(pos - 1) == ')') { + if (info.indexOf(operator_call) == pos - (int)strlen(operator_call)) + break; + + // this function returns a pointer to a function + // and we matched the arguments of the return type's parameter list + // try again + info.remove(0, info.indexOf('(')); + info.chop(1); + continue; + } else { + break; + } + } + + // find the beginning of the function name + int parencount = 0; + int templatecount = 0; + --pos; + + // make sure special characters in operator names are kept + if (pos > -1) { + switch (info.at(pos)) { + case ')': + if (info.indexOf(operator_call) == pos - (int)strlen(operator_call) + 1) + pos -= 2; + break; + case '<': + if (info.indexOf(operator_lessThan) == pos - (int)strlen(operator_lessThan) + 1) + --pos; + break; + case '>': + if (info.indexOf(operator_greaterThan) == pos - (int)strlen(operator_greaterThan) + 1) + --pos; + break; + case '=': { + int operatorLength = (int)strlen(operator_lessThanEqual); + if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1) + pos -= 2; + else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1) + pos -= 2; + break; + } + default: + break; + } + } + + while (pos > -1) { + if (parencount < 0 || templatecount < 0) + return info; + + char c = info.at(pos); + if (c == ')') + ++parencount; + else if (c == '(') + --parencount; + else if (c == '>') + ++templatecount; + else if (c == '<') + --templatecount; + else if (c == ' ' && templatecount == 0 && parencount == 0) + break; + + --pos; + } + info = info.mid(pos + 1); + + // we have the full function name now. + // clean up the templates + while ((pos = info.lastIndexOf('>')) != -1) { + if (!info.contains('<')) + break; + + // find the matching close + int end = pos; + templatecount = 1; + --pos; + while (pos && templatecount) { + register char c = info.at(pos); + if (c == '>') + ++templatecount; + else if (c == '<') + --templatecount; + --pos; + } + ++pos; + info.remove(pos, end - pos + 1); + } + + return info; +} + +// tokens as recognized in QT_MESSAGE_PATTERN +static const char typeTokenC[] = "%{type}"; +static const char messageTokenC[] = "%{message}"; +static const char fileTokenC[] = "%{file}"; +static const char lineTokenC[] = "%{line}"; +static const char functionTokenC[] = "%{function}"; +static const char emptyTokenC[] = ""; + +struct QMessagePattern { + QMessagePattern(); + ~QMessagePattern(); + + // 0 terminated arrays of literal tokens / literal or placeholder tokens + const char **literals; + const char **tokens; +}; + +QMessagePattern::QMessagePattern() +{ + QString pattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN")); + if (pattern.isEmpty()) { + pattern = QLatin1String("%{message}"); + } + + // scanner + QList lexemes; + QString lexeme; + bool inPlaceholder = false; + for (int i = 0; i < pattern.size(); ++i) { + const QChar c = pattern.at(i); + if ((c == QLatin1Char('%')) + && !inPlaceholder) { + if ((i + 1 < pattern.size()) + && pattern.at(i + 1) == QLatin1Char('{')) { + // beginning of placeholder + if (!lexeme.isEmpty()) { + lexemes.append(lexeme); + lexeme.clear(); + } + inPlaceholder = true; + } + } + + lexeme.append(c); + + if ((c == QLatin1Char('}') && inPlaceholder)) { + // end of placeholder + lexemes.append(lexeme); + lexeme.clear(); + inPlaceholder = false; + } + } + if (!lexeme.isEmpty()) + lexemes.append(lexeme); + + // tokenizer + QVarLengthArray literalsVar; + tokens = new const char*[lexemes.size() + 1]; + tokens[lexemes.size()] = 0; + + for (int i = 0; i < lexemes.size(); ++i) { + const QString lexeme = lexemes.at(i); + if (lexeme.startsWith(QLatin1String("%{")) + && lexeme.endsWith(QLatin1Char('}'))) { + // placeholder + if (lexeme == QLatin1String(typeTokenC)) { + tokens[i] = typeTokenC; + } else if (lexeme == QLatin1String(messageTokenC)) + tokens[i] = messageTokenC; + else if (lexeme == QLatin1String(fileTokenC)) + tokens[i] = fileTokenC; + else if (lexeme == QLatin1String(lineTokenC)) + tokens[i] = lineTokenC; + else if (lexeme == QLatin1String(functionTokenC)) + tokens[i] = functionTokenC; + else { + fprintf(stderr, "%s\n", + QString::fromLatin1("QT_MESSAGE_PATTERN: Unknown placeholder %1\n" + ).arg(lexeme).toLocal8Bit().constData()); + fflush(stderr); + tokens[i] = emptyTokenC; + } + } else { + char *literal = new char[lexeme.size() + 1]; + strncpy(literal, lexeme.toLocal8Bit().constData(), lexeme.size()); + literal[lexeme.size()] = '\0'; + literalsVar.append(literal); + tokens[i] = literal; + } + } + literals = new const char*[literalsVar.size() + 1]; + literals[literalsVar.size()] = 0; + memcpy(literals, literalsVar.constData(), literalsVar.size() * sizeof(const char*)); +} + +QMessagePattern::~QMessagePattern() +{ + for (int i = 0; literals[i] != 0; ++i) + delete [] literals[i]; + delete [] literals; + literals = 0; + delete [] tokens; + tokens = 0; +} + +Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern) + +/*! + \internal +*/ +Q_CORE_EXPORT QByteArray qMessageFormatString(QtMsgType type, const QMessageLogContext &context, + const char *str) +{ + QByteArray message; + + QMessagePattern *pattern = qMessagePattern(); + if (!pattern) { + // after destruction of static QMessagePattern instance + message.append(str); + message.append('\n'); + return message; + } + + // we do not convert file, function, line literals to local encoding due to overhead + for (int i = 0; pattern->tokens[i] != 0; ++i) { + const char *token = pattern->tokens[i]; + if (token == messageTokenC) { + message.append(str); + } else if (token == typeTokenC) { + switch (type) { + case QtDebugMsg: message.append("debug"); break; + case QtWarningMsg: message.append("warning"); break; + case QtCriticalMsg:message.append("critical"); break; + case QtFatalMsg: message.append("fatal"); break; + } + } else if (token == fileTokenC) { + if (context.file) + message.append(context.file); + else + message.append("unknown"); + } else if (token == lineTokenC) { + message.append(QString::number(context.line).toLatin1().constData()); + } else if (token == functionTokenC) { + if (context.function) + message.append(qCleanupFuncinfo(context.function)); + else + message.append("unknown"); + } else { + message.append(token); + } + } + message.append('\n'); + return message; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index 9a45f28f16..c1f7c8ab25 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -140,30 +140,30 @@ public: { LeaveCriticalSection(&cs); } }; -Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char* str) -{ - Q_UNUSED(t); - // OutputDebugString is not threadsafe. +// defined in qlogging.cpp +extern Q_CORE_EXPORT QByteArray qMessageFormatString(QtMsgType type, + const QMessageLogContext &context, + const char *str); +Q_CORE_EXPORT void qWinMessageHandler(QtMsgType t, const QMessageLogContext &context, const char *str) +{ // cannot use QMutex here, because qWarning()s in the QMutex // implementation may cause this function to recurse static QWinMsgHandlerCriticalSection staticCriticalSection; - if (!str) - str = "(null)"; + QByteArray message = qMessageFormatString(t, context, str); + QString s(QString::fromLocal8Bit(message)); + // OutputDebugString is not threadsafe. staticCriticalSection.lock(); - - QString s(QString::fromLocal8Bit(str)); - s += QLatin1Char('\n'); OutputDebugString((wchar_t*)s.utf16()); - staticCriticalSection.unlock(); } -Q_CORE_EXPORT void qWinMessageHandler(QtMsgType t, const QMessageLogContext &, const char* str) +Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char *str) { - qWinMsgHandler(t, str); + QMessageLogContext emptyContext; + qWinMessageHandler(t, emptyContext, str); } /***************************************************************************** diff --git a/tests/auto/corelib/global/global.pro b/tests/auto/corelib/global/global.pro index a6c638f530..d4293a896c 100644 --- a/tests/auto/corelib/global/global.pro +++ b/tests/auto/corelib/global/global.pro @@ -6,4 +6,4 @@ SUBDIRS=\ qglobal \ qnumeric \ qrand \ - qmessagehandler + qlogging diff --git a/tests/auto/corelib/global/qlogging/app/app.pro b/tests/auto/corelib/global/qlogging/app/app.pro new file mode 100644 index 0000000000..a167cc45cd --- /dev/null +++ b/tests/auto/corelib/global/qlogging/app/app.pro @@ -0,0 +1,9 @@ +TEMPLATE = app + +TARGET = app +QT = core + +CONFIG -= debug_and_release app_bundle +CONFIG += debug console + +SOURCES += main.cpp diff --git a/tests/auto/corelib/global/qlogging/app/main.cpp b/tests/auto/corelib/global/qlogging/app/main.cpp new file mode 100644 index 0000000000..c26b29ea56 --- /dev/null +++ b/tests/auto/corelib/global/qlogging/app/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** 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 + +struct T { + T() { qDebug("static constructor"); } + ~T() { qDebug("static destructor"); } +} t; + +int main(int, char **) +{ + qDebug("qDebug"); + qWarning("qWarning"); + qCritical("qCritical"); + return 0; +} diff --git a/tests/auto/corelib/global/qlogging/qlogging.pro b/tests/auto/corelib/global/qlogging/qlogging.pro new file mode 100644 index 0000000000..449b7dfa5e --- /dev/null +++ b/tests/auto/corelib/global/qlogging/qlogging.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + tst_qlogging.pro \ + app \ No newline at end of file diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp new file mode 100644 index 0000000000..742a858961 --- /dev/null +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp @@ -0,0 +1,645 @@ +/**************************************************************************** +** +** 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" diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.pro b/tests/auto/corelib/global/qlogging/tst_qlogging.pro new file mode 100644 index 0000000000..60377e0fdc --- /dev/null +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.pro @@ -0,0 +1,4 @@ +CONFIG += testcase parallel_test +TARGET = tst_qlogging +QT = core testlib +SOURCES = tst_qlogging.cpp diff --git a/tests/auto/corelib/global/qmessagehandler/qmessagehandler.pro b/tests/auto/corelib/global/qmessagehandler/qmessagehandler.pro deleted file mode 100644 index 8bdba4bfc4..0000000000 --- a/tests/auto/corelib/global/qmessagehandler/qmessagehandler.pro +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG += testcase parallel_test -TARGET = tst_qmessagehandler -QT = core testlib -SOURCES = tst_qmessagehandler.cpp diff --git a/tests/auto/corelib/global/qmessagehandler/tst_qmessagehandler.cpp b/tests/auto/corelib/global/qmessagehandler/tst_qmessagehandler.cpp deleted file mode 100644 index 39bd0986a5..0000000000 --- a/tests/auto/corelib/global/qmessagehandler/tst_qmessagehandler.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/**************************************************************************** -** -** 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 - -class tst_qmessagehandler : public QObject -{ - Q_OBJECT -private slots: - void cleanup(); - - void defaultHandler(); - void installMessageHandler(); - void installMsgHandler(); - void installBothHandler(); -}; - -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); -} - -QTEST_MAIN(tst_qmessagehandler) -#include "tst_qmessagehandler.moc" diff --git a/tools/configure/configure.pro b/tools/configure/configure.pro index d39d9b45cc..f68e3c0e54 100644 --- a/tools/configure/configure.pro +++ b/tools/configure/configure.pro @@ -46,6 +46,7 @@ HEADERS = configureapp.h environment.h tools.h\ $$QT_SOURCE_TREE/src/corelib/codecs/qtextcodec.h \ $$QT_SOURCE_TREE/src/corelib/global/qglobal.h \ $$QT_SOURCE_TREE/src/corelib/global/qnumeric.h \ + $$QT_SOURCE_TREE/src/corelib/global/qlogging.h \ $$QT_SOURCE_TREE/src/corelib/io/qbuffer.h \ $$QT_SOURCE_TREE/src/corelib/io/qdatastream.h \ $$QT_SOURCE_TREE/src/corelib/io/qdir.h \ @@ -89,6 +90,7 @@ SOURCES = main.cpp configureapp.cpp environment.cpp tools.cpp \ $$QT_SOURCE_TREE/src/corelib/codecs/qtextcodec.cpp \ $$QT_SOURCE_TREE/src/corelib/global/qglobal.cpp \ $$QT_SOURCE_TREE/src/corelib/global/qnumeric.cpp \ + $$QT_SOURCE_TREE/src/corelib/global/qlogging.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qbuffer.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qdatastream.cpp \ $$QT_SOURCE_TREE/src/corelib/io/qdir.cpp \ -- cgit v1.2.3