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 <ogoffart@woboq.com> Reviewed-by: David Faure <faure@kde.org>
This commit is contained in:
parent
e7e8799304
commit
be98fa32c7
@ -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) $<
|
||||
|
@ -118,8 +118,8 @@ QTOBJS= \
|
||||
qmetatype.obj \
|
||||
qxmlstream.obj \
|
||||
qxmlutils.obj \
|
||||
qnumeric.obj
|
||||
|
||||
qnumeric.obj \
|
||||
qlogging.obj
|
||||
|
||||
first all: qmake.exe
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -76,7 +76,8 @@ bootstrap { #Qt code
|
||||
qvector.cpp \
|
||||
qvsnprintf.cpp \
|
||||
qxmlstream.cpp \
|
||||
qxmlutils.cpp
|
||||
qxmlutils.cpp \
|
||||
qlogging.cpp
|
||||
|
||||
HEADERS+= \
|
||||
qbitarray.h \
|
||||
|
@ -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<const wchar_t *> (fstr.utf16()));
|
||||
QString fstr = QString::fromLocal8Bit(logMessage);
|
||||
OutputDebugString(reinterpret_cast<const wchar_t *> (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)
|
||||
|
@ -39,7 +39,13 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <qlogging.h>
|
||||
#include "qlogging.h"
|
||||
#include "qlist.h"
|
||||
#include "qbytearray.h"
|
||||
#include "qstring.h"
|
||||
#include "qvarlengtharray.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
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<QString> 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<const char*> 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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -6,4 +6,4 @@ SUBDIRS=\
|
||||
qglobal \
|
||||
qnumeric \
|
||||
qrand \
|
||||
qmessagehandler
|
||||
qlogging
|
||||
|
9
tests/auto/corelib/global/qlogging/app/app.pro
Normal file
9
tests/auto/corelib/global/qlogging/app/app.pro
Normal file
@ -0,0 +1,9 @@
|
||||
TEMPLATE = app
|
||||
|
||||
TARGET = app
|
||||
QT = core
|
||||
|
||||
CONFIG -= debug_and_release app_bundle
|
||||
CONFIG += debug console
|
||||
|
||||
SOURCES += main.cpp
|
55
tests/auto/corelib/global/qlogging/app/main.cpp
Normal file
55
tests/auto/corelib/global/qlogging/app/main.cpp
Normal file
@ -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 <qglobal.h>
|
||||
|
||||
struct T {
|
||||
T() { qDebug("static constructor"); }
|
||||
~T() { qDebug("static destructor"); }
|
||||
} t;
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
qDebug("qDebug");
|
||||
qWarning("qWarning");
|
||||
qCritical("qCritical");
|
||||
return 0;
|
||||
}
|
5
tests/auto/corelib/global/qlogging/qlogging.pro
Normal file
5
tests/auto/corelib/global/qlogging/qlogging.pro
Normal file
@ -0,0 +1,5 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += \
|
||||
tst_qlogging.pro \
|
||||
app
|
645
tests/auto/corelib/global/qlogging/tst_qlogging.cpp
Normal file
645
tests/auto/corelib/global/qlogging/tst_qlogging.cpp
Normal file
@ -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 <qdebug.h>
|
||||
#include <qglobal.h>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
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<int> func_ai() { ADD("TestClass1::func_ai"); return QList<int>(); }
|
||||
QList<unsigned long long const volatile*> func_aptr() { ADD("TestClass1::func_aptr"); return QList<unsigned long long const volatile*>(); }
|
||||
|
||||
QList<Something> func_aenum() { ADD("TestClass1::func_aenum"); return QList<Something>(); }
|
||||
QList<QList<const void *> > func_aaptr() { ADD("TestClass1::func_aaptr"); return QList<QList<const void *> >(); }
|
||||
|
||||
QMap<int, Something> func_ienummap() { ADD("TestClass1::func_ienummap"); return QMap<int, Something>(); }
|
||||
|
||||
template<typename T>
|
||||
T* func_template1() { ADD("TestClass1::func_template1"); return 0; }
|
||||
template<Something val>
|
||||
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<QString, uglypmf> func_uglypmf2() { ADD("TestClass1::func_uglypmf2"); return QMap<QString, uglypmf>(); }
|
||||
|
||||
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<TestClass1>();
|
||||
func_template2<foo>();
|
||||
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<typename T> class TestClass2
|
||||
{
|
||||
long func_long() { ADD("TestClass2::func_long"); return 0; }
|
||||
template<typename S>
|
||||
T* func_template1() { ADD("TestClass2::func_template1"); return 0; }
|
||||
template<TestClass1::Something val>
|
||||
long func_template2() { ADD("TestClass2::func_template2"); return long(val); }
|
||||
public:
|
||||
TestClass2()
|
||||
{
|
||||
func_long();
|
||||
func_template1<TestClass2>();
|
||||
func_template2<TestClass1::foo>();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, TestClass1::Something v> class TestClass3
|
||||
{
|
||||
long func_long() { ADD("TestClass3::func_long"); return 0; }
|
||||
template<typename S>
|
||||
S* func_template1() { ADD("TestClass3::func_template1"); return 0; }
|
||||
template<TestClass1::Something val>
|
||||
long func_template2() { ADD("TestClass3::func_template2"); return long(val); }
|
||||
public:
|
||||
struct Foo { TestClass3 foo; };
|
||||
TestClass3()
|
||||
{
|
||||
func_long();
|
||||
func_template1<TestClass2<T> >();
|
||||
func_template2<TestClass1::foo>();
|
||||
}
|
||||
};
|
||||
|
||||
class TestClass4
|
||||
{
|
||||
TestClass1 c1;
|
||||
|
||||
TestClass2<std::map<long, const void *> > func2()
|
||||
{ ADD("TestClass4::func2"); return TestClass2<std::map<long, const void *> >(); }
|
||||
TestClass3<std::map<std::list<int>, const void *>, TestClass1::foo>::Foo func3()
|
||||
{ ADD("TestClass4::func3"); return TestClass3<std::map<std::list<int>, 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<QString>("funcinfo");
|
||||
QTest::addColumn<QString>("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<int> __thiscall TestClass1::func_ai(void)"
|
||||
<< "TestClass1::func_ai";
|
||||
QTest::newRow("gcc_15")
|
||||
<< "QList<int> TestClass1::func_ai()"
|
||||
<< "TestClass1::func_ai";
|
||||
|
||||
QTest::newRow("msvc_16")
|
||||
<< "class QList<unsigned __int64 const volatile *> __thiscall TestClass1::func_aptr(void)"
|
||||
<< "TestClass1::func_aptr";
|
||||
QTest::newRow("gcc_16")
|
||||
<< "QList<const volatile long long unsigned int*> TestClass1::func_aptr()"
|
||||
<< "TestClass1::func_aptr";
|
||||
|
||||
QTest::newRow("msvc_17")
|
||||
<< "class QList<enum TestClass1::Something> __thiscall TestClass1::func_aenum(void)"
|
||||
<< "TestClass1::func_aenum";
|
||||
QTest::newRow("gcc_17")
|
||||
<< "QList<TestClass1::Something> TestClass1::func_aenum()"
|
||||
<< "TestClass1::func_aenum";
|
||||
|
||||
QTest::newRow("msvc_18")
|
||||
<< "class QList<class QList<void const *> > __thiscall TestClass1::func_aaptr(void)"
|
||||
<< "TestClass1::func_aaptr";
|
||||
QTest::newRow("gcc_18")
|
||||
<< "QList<QList<const void*> > TestClass1::func_aaptr()"
|
||||
<< "TestClass1::func_aaptr";
|
||||
|
||||
QTest::newRow("msvc_19")
|
||||
<< "class QMap<int,enum TestClass1::Something> __thiscall TestClass1::func_ienummap(void)"
|
||||
<< "TestClass1::func_ienummap";
|
||||
QTest::newRow("gcc_19")
|
||||
<< "QMap<int, TestClass1::Something> TestClass1::func_ienummap()"
|
||||
<< "TestClass1::func_ienummap";
|
||||
|
||||
QTest::newRow("msvc_20")
|
||||
<< "class TestClass1 *__thiscall TestClass1::func_template1<class TestClass1>(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<foo>(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<class QString,unsigned __int64 * (__cdecl*(__thiscall TestClass1::*)(void))(void)> __thiscall TestClass1::func_uglypmf2(void)"
|
||||
<< "TestClass1::func_uglypmf2";
|
||||
QTest::newRow("gcc_25")
|
||||
<< "QMap<QString, long long unsigned int* (* (TestClass1::*)())()> TestClass1::func_uglypmf2()"
|
||||
<< "TestClass1::func_uglypmf2";
|
||||
|
||||
QTest::newRow("msvc_26")
|
||||
<< "class TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > > __thiscall TestClass4::func2(void)"
|
||||
<< "TestClass4::func2";
|
||||
QTest::newRow("gcc_26")
|
||||
<< "TestClass2<std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > > > TestClass4::func2()"
|
||||
<< "TestClass4::func2";
|
||||
|
||||
QTest::newRow("msvc_27")
|
||||
<< "long __thiscall TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > >::func_long(void)"
|
||||
<< "TestClass2::func_long";
|
||||
QTest::newRow("gcc_27")
|
||||
<< "long int TestClass2<T>::func_long() [with T = std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > >]"
|
||||
<< "TestClass2::func_long";
|
||||
|
||||
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")
|
||||
<< "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";
|
||||
|
||||
QTest::newRow("msvc_29")
|
||||
<< "long __thiscall TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > >::func_template2<foo>(void)"
|
||||
<< "TestClass2::func_template2";
|
||||
QTest::newRow("gcc_29")
|
||||
<< "long int TestClass2<T>::func_template2() [with TestClass1::Something val = foo, T = std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > >]"
|
||||
<< "TestClass2::func_template2";
|
||||
|
||||
QTest::newRow("msvc_30")
|
||||
<< "struct TestClass3<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > >,0>::Foo __thiscall TestClass4::func3(void)"
|
||||
<< "TestClass4::func3";
|
||||
QTest::newRow("gcc_30")
|
||||
<< "TestClass3<std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, const void*> > >, foo>::Foo TestClass4::func3()"
|
||||
<< "TestClass4::func3";
|
||||
|
||||
QTest::newRow("msvc_31")
|
||||
<< "long __thiscall TestClass3<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > >,0>::func_long(void)"
|
||||
<< "TestClass3::func_long";
|
||||
QTest::newRow("gcc_31")
|
||||
<< "long int TestClass3<T, v>::func_long() [with T = std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, const void*> > >, TestClass1::Something v = foo]"
|
||||
<< "TestClass3::func_long";
|
||||
|
||||
QTest::newRow("msvc_32")
|
||||
<< "class TestClass2<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > > > *__thiscall TestClass3<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > >,0>::func_template1<class TestClass2<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > > >>(void)"
|
||||
<< "TestClass3::func_template1";
|
||||
QTest::newRow("gcc_32")
|
||||
<< "S* TestClass3<T, v>::func_template1() [with S = TestClass2<std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, const void*> > > >, T = std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, const void*> > >, TestClass1::Something v = foo]"
|
||||
<< "TestClass3::func_template1";
|
||||
|
||||
QTest::newRow("msvc_33")
|
||||
<< "long __thiscall TestClass3<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > >,0>::func_template2<foo>(void)"
|
||||
<< "TestClass3::func_template2";
|
||||
QTest::newRow("gcc_33")
|
||||
<< "long int TestClass3<T, v>::func_template2() [with TestClass1::Something val = foo, T = std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, 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"
|
4
tests/auto/corelib/global/qlogging/tst_qlogging.pro
Normal file
4
tests/auto/corelib/global/qlogging/tst_qlogging.pro
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG += testcase parallel_test
|
||||
TARGET = tst_qlogging
|
||||
QT = core testlib
|
||||
SOURCES = tst_qlogging.cpp
|
@ -1,4 +0,0 @@
|
||||
CONFIG += testcase parallel_test
|
||||
TARGET = tst_qmessagehandler
|
||||
QT = core testlib
|
||||
SOURCES = tst_qmessagehandler.cpp
|
@ -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 <qdebug.h>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
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"
|
@ -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 \
|
||||
|
Loading…
x
Reference in New Issue
Block a user