diff options
-rw-r--r-- | src/corelib/io/qdebug.cpp | 103 | ||||
-rw-r--r-- | src/corelib/io/qdebug.h | 5 | ||||
-rw-r--r-- | src/corelib/io/qtextstream.cpp | 4 | ||||
-rw-r--r-- | src/corelib/io/qtextstream.h | 1 | ||||
-rw-r--r-- | src/testlib/qtestcase.cpp | 2 | ||||
-rw-r--r-- | tests/auto/corelib/io/qdebug/tst_qdebug.cpp | 67 | ||||
-rw-r--r-- | tests/auto/testlib/selftests/expected_badxml.lightxml | 2 | ||||
-rw-r--r-- | tests/auto/testlib/selftests/expected_badxml.xml | 2 | ||||
-rw-r--r-- | tests/auto/testlib/selftests/expected_badxml.xunitxml | 4 |
9 files changed, 182 insertions, 8 deletions
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index 050a48bd65..d8b77dd603 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Intel Corporation. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -40,9 +41,12 @@ #include "qdebug.h" #include <private/qtextstream_p.h> +#include <private/qtools_p.h> QT_BEGIN_NAMESPACE +using QtMiscUtils::toHexUpper; + // This file is needed to force compilation of QDebug into the kernel library. /*! @@ -168,6 +172,105 @@ void QDebug::putUcs4(uint ucs4) maybeQuote('\''); } +template <typename Char> +static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, int length) +{ + QChar quote(QLatin1Char('"')); + d->write("e, 1); + + const Char *end = begin + length; + for (const Char *p = begin; p != end; ++p) { + if (sizeof(Char) == sizeof(QChar)) { + int runLength = 0; + while (p + runLength != end && + p[runLength] < 0x7f && p[runLength] >= 0x20 && p[runLength] != '\\' && p[runLength] != '"') + ++runLength; + if (runLength) { + d->write(reinterpret_cast<const QChar *>(p), runLength); + p += runLength - 1; + continue; + } + } + + // print as an escape sequence + int buflen = 2; + ushort buf[sizeof "\\U12345678" - 1]; + buf[0] = '\\'; + + switch (*p) { + case '"': + case '\\': + buf[1] = *p; + break; + case '\b': + buf[1] = 'b'; + break; + case '\f': + buf[1] = 'f'; + break; + case '\n': + buf[1] = 'n'; + break; + case '\r': + buf[1] = 'r'; + break; + case '\t': + buf[1] = 't'; + break; + default: + if (QChar::isHighSurrogate(*p)) { + if ((p + 1) != end && QChar::isLowSurrogate(p[1])) { + // properly-paired surrogates + uint ucs4 = QChar::surrogateToUcs4(*p, p[1]); + ++p; + buf[1] = 'U'; + buf[2] = '0'; // toHexUpper(ucs4 >> 32); + buf[3] = '0'; // toHexUpper(ucs4 >> 28); + buf[4] = toHexUpper(ucs4 >> 20); + buf[5] = toHexUpper(ucs4 >> 16); + buf[6] = toHexUpper(ucs4 >> 12); + buf[7] = toHexUpper(ucs4 >> 8); + buf[8] = toHexUpper(ucs4 >> 4); + buf[9] = toHexUpper(ucs4); + buflen = 10; + break; + } + // improperly-paired surrogates, fall through + } + buf[1] = 'u'; + if (sizeof(Char) == 1) { + buf[2] = buf[3] = '0'; + } else { + buf[2] = toHexUpper(*p >> 12); + buf[3] = toHexUpper(*p >> 8); + } + buf[4] = toHexUpper(*p >> 4); + buf[5] = toHexUpper(*p); + buflen = 6; + } + d->write(reinterpret_cast<QChar *>(buf), buflen); + } + + d->write("e, 1); +} + +/*! + \internal + Duplicated from QtTest::toPrettyUnicode(). +*/ +void QDebug::putString(const QChar *begin, size_t length) +{ + if (stream->testFlag(Stream::NoQuotes)) { + // no quotes, write the string directly too (no pretty-printing) + // this respects the QTextStream state, though + stream->ts.d_ptr->putString(begin, length); + } else { + // we'll reset the QTextStream formatting mechanisms, so save the state + QDebugStateSaver saver(*this); + stream->ts.d_ptr->params.reset(); + putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const ushort *>(begin), length); + } +} /*! \fn QDebug::swap(QDebug &other) diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 99c2909aa0..a2d6598bce 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -78,6 +78,7 @@ class Q_CORE_EXPORT QDebug } *stream; void putUcs4(uint ucs4); + void putString(const QChar *begin, size_t length); public: inline QDebug(QIODevice *device) : stream(new Stream(device)) {} inline QDebug(QString *string) : stream(new Stream(string)) {} @@ -118,8 +119,8 @@ public: inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); } - inline QDebug &operator<<(const QString & t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); } - inline QDebug &operator<<(const QStringRef & t) { return operator<<(t.toString()); } + inline QDebug &operator<<(const QString & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); } + inline QDebug &operator<<(const QStringRef & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); } inline QDebug &operator<<(QLatin1String t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); } inline QDebug &operator<<(const QByteArray & t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); } inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); } diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 5f3177e58f..771067fa14 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -806,7 +806,7 @@ inline void QTextStreamPrivate::restoreToSavedConverterState() /*! \internal */ -inline void QTextStreamPrivate::write(const QChar *data, int len) +void QTextStreamPrivate::write(const QChar *data, int len) { if (string) { // ### What about seek()?? @@ -885,7 +885,7 @@ inline void QTextStreamPrivate::putChar(QChar ch) /*! \internal */ -inline void QTextStreamPrivate::putString(const QChar *data, int len, bool number) +void QTextStreamPrivate::putString(const QChar *data, int len, bool number) { QString pad; int padLeft = 0, padRight = 0; diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h index 5c75a006af..b15e7772e2 100644 --- a/src/corelib/io/qtextstream.h +++ b/src/corelib/io/qtextstream.h @@ -185,6 +185,7 @@ public: private: Q_DISABLE_COPY(QTextStream) friend class QDebugStateSaverPrivate; + friend class QDebug; QScopedPointer<QTextStreamPrivate> d_ptr; }; diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index a2e4b66ebf..4e7ab18e9b 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -2146,6 +2146,8 @@ char *toHexRepresentation(const char *ba, int length) \internal Returns the same QString but with only the ASCII characters still shown; everything else is replaced with \c {\uXXXX}. + + Similar to QDebug::putString(). */ char *toPrettyUnicode(const ushort *p, int length) { diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp index 015a13775d..63de953437 100644 --- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp +++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp @@ -52,6 +52,7 @@ private slots: void stateSaver() const; void veryLongWarningMessage() const; void qDebugQChar() const; + void qDebugQString() const; void qDebugQStringRef() const; void qDebugQLatin1String() const; void qDebugQByteArray() const; @@ -344,6 +345,54 @@ void tst_QDebug::qDebugQChar() const } +void tst_QDebug::qDebugQString() const +{ + /* Use a basic string. */ + { + QString file, function; + int line = 0; + const QString in(QLatin1String("input")); + const QStringRef inRef(&in); + + MessageHandlerSetter mhs(myMessageHandler); + { qDebug() << inRef; } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, QString::fromLatin1("\"input\"")); + QCOMPARE(QString::fromLatin1(s_file), file); + QCOMPARE(s_line, line); + QCOMPARE(QString::fromLatin1(s_function), function); + } + + /* simpler tests from now on */ + MessageHandlerSetter mhs(myMessageHandler); + + QString string = "Hello"; + qDebug() << string; + QCOMPARE(s_msg, QString("\"Hello\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, string); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + string); + + string = QLatin1String("\nSm\xF8rg\xE5sbord\\"); + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, string); + + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\nSm\\u00F8rg\\u00E5sbord\\\\\"")); + + // surrogate pairs (including broken pairings) + ushort utf16[] = { 0xDC00, 0xD800, 0xDC00, 'x', 0xD800, 0xDC00, 0xD800, 0 }; + string = QString::fromUtf16(utf16); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\uDC00\\U00010000x\\U00010000\\uD800\"")); +} + void tst_QDebug::qDebugQStringRef() const { /* Use a basic string. */ @@ -403,6 +452,24 @@ void tst_QDebug::qDebugQLatin1String() const QCOMPARE(QString::fromLatin1(s_file), file); QCOMPARE(s_line, line); QCOMPARE(QString::fromLatin1(s_function), function); + + /* simpler tests from now on */ + QLatin1String string("\"Hello\""); + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\"")); + + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString(string)); + + qDebug().noquote().nospace() << qSetFieldWidth(8) << string; + QCOMPARE(s_msg, " " + QString(string)); + + string = QLatin1String("\nSm\xF8rg\xE5sbord\\"); + qDebug().noquote().nospace() << string; + QCOMPARE(s_msg, QString(string)); + + qDebug() << string; + QCOMPARE(s_msg, QString("\"\\nSm\\u00F8rg\\u00E5sbord\\\\\"")); } void tst_QDebug::qDebugQByteArray() const diff --git a/tests/auto/testlib/selftests/expected_badxml.lightxml b/tests/auto/testlib/selftests/expected_badxml.lightxml index 94f479a79a..e0de44f0be 100644 --- a/tests/auto/testlib/selftests/expected_badxml.lightxml +++ b/tests/auto/testlib/selftests/expected_badxml.lightxml @@ -113,7 +113,7 @@ </TestFunction> <TestFunction name="encoding"> <Message type="qdebug" file="" line="0"> - <Description><![CDATA["Ülrich Ümläut"]]></Description> + <Description><![CDATA["\u00DClrich \u00DCml\u00E4ut"]]></Description> </Message> <Incident type="pass" file="" line="0" /> <Duration msecs="0"/> diff --git a/tests/auto/testlib/selftests/expected_badxml.xml b/tests/auto/testlib/selftests/expected_badxml.xml index c1266bfeed..8667c2d9cd 100644 --- a/tests/auto/testlib/selftests/expected_badxml.xml +++ b/tests/auto/testlib/selftests/expected_badxml.xml @@ -115,7 +115,7 @@ </TestFunction> <TestFunction name="encoding"> <Message type="qdebug" file="" line="0"> - <Description><![CDATA["Ülrich Ümläut"]]></Description> + <Description><![CDATA["\u00DClrich \u00DCml\u00E4ut"]]></Description> </Message> <Incident type="pass" file="" line="0" /> <Duration msecs="0"/> diff --git a/tests/auto/testlib/selftests/expected_badxml.xunitxml b/tests/auto/testlib/selftests/expected_badxml.xunitxml index 49048fdad6..46f4be4391 100644 --- a/tests/auto/testlib/selftests/expected_badxml.xunitxml +++ b/tests/auto/testlib/selftests/expected_badxml.xunitxml @@ -30,7 +30,7 @@ <failure message="failure message" result="fail"/> </testcase> <testcase result="pass" name="encoding"> - <!-- message=""Ülrich Ümläut"" type="qdebug" --> + <!-- message=""\u00DClrich \u00DCml\u00E4ut"" type="qdebug" --> </testcase> <testcase result="pass" name="cleanupTestCase"/> <system-err> @@ -46,6 +46,6 @@ <![CDATA[quotes " text" more text]]> <![CDATA[xml close > open < tags < text]]> <![CDATA[all > " mixed ]]]><![CDATA[]> up > " in < the ]]]><![CDATA[]> hopes < of triggering "< ]]]><![CDATA[]> bugs]]> -<![CDATA["Ülrich Ümläut"]]> +<![CDATA["\u00DClrich \u00DCml\u00E4ut"]]> </system-err> </testsuite> |