diff -r 000000000000 -r 1918ee327afb src/testlib/qxmltestlogger.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testlib/qxmltestlogger.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,443 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtTest module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "QtTest/private/qxmltestlogger_p.h" +#include "QtTest/private/qtestresult_p.h" +#include "QtTest/private/qbenchmark_p.h" +#include "QtTest/qtestcase.h" + +QT_BEGIN_NAMESPACE + +namespace QTest { + + static const char* xmlMessageType2String(QAbstractTestLogger::MessageTypes type) + { + switch (type) { + case QAbstractTestLogger::Warn: + return "warn"; + case QAbstractTestLogger::QSystem: + return "system"; + case QAbstractTestLogger::QDebug: + return "qdebug"; + case QAbstractTestLogger::QWarning: + return "qwarn"; + case QAbstractTestLogger::QFatal: + return "qfatal"; + case QAbstractTestLogger::Skip: + return "skip"; + case QAbstractTestLogger::Info: + return "info"; + } + return "??????"; + } + + static const char* xmlIncidentType2String(QAbstractTestLogger::IncidentTypes type) + { + switch (type) { + case QAbstractTestLogger::Pass: + return "pass"; + case QAbstractTestLogger::XFail: + return "xfail"; + case QAbstractTestLogger::Fail: + return "fail"; + case QAbstractTestLogger::XPass: + return "xpass"; + } + return "??????"; + } + +} + + +QXmlTestLogger::QXmlTestLogger(XmlMode mode ) + :xmlmode(mode) +{ + +} + +QXmlTestLogger::~QXmlTestLogger() +{ +} + +void QXmlTestLogger::startLogging() +{ + QAbstractTestLogger::startLogging(); + QTestCharBuffer buf; + + if (xmlmode == QXmlTestLogger::Complete) { + QTestCharBuffer quotedTc; + xmlQuote("edTc, QTestResult::currentTestObjectName()); + QTest::qt_asprintf(&buf, + "\n" + "\n", quotedTc.constData()); + outputString(buf.constData()); + } + + QTest::qt_asprintf(&buf, + "\n" + " %s\n" + " "QTEST_VERSION_STR"\n" + "\n", qVersion()); + outputString(buf.constData()); +} + +void QXmlTestLogger::stopLogging() +{ + if (xmlmode == QXmlTestLogger::Complete) { + outputString("\n"); + } + + QAbstractTestLogger::stopLogging(); +} + +void QXmlTestLogger::enterTestFunction(const char *function) +{ + QTestCharBuffer buf; + QTestCharBuffer quotedFunction; + xmlQuote("edFunction, function); + QTest::qt_asprintf(&buf, "\n", quotedFunction.constData()); + outputString(buf.constData()); +} + +void QXmlTestLogger::leaveTestFunction() +{ + outputString("\n"); +} + +namespace QTest +{ + +inline static bool isEmpty(const char *str) +{ + return !str || !str[0]; +} + +static const char *incidentFormatString(bool noDescription, bool noTag) +{ + if (noDescription) { + if (noTag) + return "\n"; + else + return "\n" + " \n" + "\n"; + } else { + if (noTag) + return "\n" + " \n" + "\n"; + else + return "\n" + " \n" + " \n" + "\n"; + } +} + +static const char *benchmarkResultFormatString() +{ + return "\n"; +} + +static const char *messageFormatString(bool noDescription, bool noTag) +{ + if (noDescription) { + if (noTag) + return "\n"; + else + return "\n" + " \n" + "\n"; + } else { + if (noTag) + return "\n" + " \n" + "\n"; + else + return "\n" + " \n" + " \n" + "\n"; + } +} + +} // namespace + +void QXmlTestLogger::addIncident(IncidentTypes type, const char *description, + const char *file, int line) +{ + QTestCharBuffer buf; + const char *tag = QTestResult::currentDataTag(); + const char *gtag = QTestResult::currentGlobalDataTag(); + const char *filler = (tag && gtag) ? ":" : ""; + const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag); + + QTestCharBuffer quotedFile; + QTestCharBuffer cdataGtag; + QTestCharBuffer cdataTag; + QTestCharBuffer cdataDescription; + + xmlQuote("edFile, file); + xmlCdata(&cdataGtag, gtag); + xmlCdata(&cdataTag, tag); + xmlCdata(&cdataDescription, description); + + QTest::qt_asprintf(&buf, + QTest::incidentFormatString(QTest::isEmpty(description), notag), + QTest::xmlIncidentType2String(type), + quotedFile.constData(), line, + cdataGtag.constData(), + filler, + cdataTag.constData(), + cdataDescription.constData()); + + outputString(buf.constData()); +} + +void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result) +{ + QTestCharBuffer buf; + QTestCharBuffer quotedMetric; + QTestCharBuffer quotedTag; + + xmlQuote("edMetric, + QBenchmarkGlobalData::current->measurer->metricText().toAscii().constData()); + xmlQuote("edTag, result.context.tag.toAscii().constData()); + + QTest::qt_asprintf( + &buf, + QTest::benchmarkResultFormatString(), + quotedMetric.constData(), + quotedTag.constData(), + QByteArray::number(result.value).constData(), //no 64-bit qt_snprintf support + result.iterations); + outputString(buf.constData()); +} + +void QXmlTestLogger::addMessage(MessageTypes type, const char *message, + const char *file, int line) +{ + QTestCharBuffer buf; + const char *tag = QTestResult::currentDataTag(); + const char *gtag = QTestResult::currentGlobalDataTag(); + const char *filler = (tag && gtag) ? ":" : ""; + const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag); + + QTestCharBuffer quotedFile; + QTestCharBuffer cdataGtag; + QTestCharBuffer cdataTag; + QTestCharBuffer cdataDescription; + + xmlQuote("edFile, file); + xmlCdata(&cdataGtag, gtag); + xmlCdata(&cdataTag, tag); + xmlCdata(&cdataDescription, message); + + QTest::qt_asprintf(&buf, + QTest::messageFormatString(QTest::isEmpty(message), notag), + QTest::xmlMessageType2String(type), + quotedFile.constData(), line, + cdataGtag.constData(), + filler, + cdataTag.constData(), + cdataDescription.constData()); + + outputString(buf.constData()); +} + +/* + Copy up to n characters from the src string into dest, escaping any special + XML characters as necessary so that dest is suitable for use in an XML + quoted attribute string. +*/ +int QXmlTestLogger::xmlQuote(QTestCharBuffer* destBuf, char const* src, size_t n) +{ + if (n == 0) return 0; + + char *dest = destBuf->data(); + *dest = 0; + if (!src) return 0; + + char* begin = dest; + char* end = dest + n; + + while (dest < end) { + switch (*src) { + +#define MAP_ENTITY(chr, ent) \ + case chr: \ + if (dest + sizeof(ent) < end) { \ + strcpy(dest, ent); \ + dest += sizeof(ent) - 1; \ + } \ + else { \ + *dest = 0; \ + return (dest+sizeof(ent)-begin); \ + } \ + ++src; \ + break; + + MAP_ENTITY('>', ">"); + MAP_ENTITY('<', "<"); + MAP_ENTITY('\'', "'"); + MAP_ENTITY('"', """); + MAP_ENTITY('&', "&"); + + // not strictly necessary, but allows handling of comments without + // having to explicitly look for `--' + MAP_ENTITY('-', "-"); + +#undef MAP_ENTITY + + case 0: + *dest = 0; + return (dest-begin); + + default: + *dest = *src; + ++dest; + ++src; + break; + } + } + + // If we get here, dest was completely filled (dest == end) + *(dest-1) = 0; + return (dest-begin); +} + +/* + Copy up to n characters from the src string into dest, escaping any + special strings such that dest is suitable for use in an XML CDATA section. +*/ +int QXmlTestLogger::xmlCdata(QTestCharBuffer *destBuf, char const* src, size_t n) +{ + if (!n) return 0; + + char *dest = destBuf->data(); + + if (!src || n == 1) { + *dest = 0; + return 0; + } + + static char const CDATA_END[] = "]]>"; + static char const CDATA_END_ESCAPED[] = "]]]>"; + + char* begin = dest; + char* end = dest + n; + while (dest < end) { + if (!*src) { + *dest = 0; + return (dest-begin); + } + + if (!strncmp(src, CDATA_END, sizeof(CDATA_END)-1)) { + if (dest + sizeof(CDATA_END_ESCAPED) < end) { + strcpy(dest, CDATA_END_ESCAPED); + src += sizeof(CDATA_END)-1; + dest += sizeof(CDATA_END_ESCAPED) - 1; + } + else { + *dest = 0; + return (dest+sizeof(CDATA_END_ESCAPED)-begin); + } + continue; + } + + *dest = *src; + ++src; + ++dest; + } + + // If we get here, dest was completely filled (dest == end) + *(dest-1) = 0; + return (dest-begin); +} + +typedef int (*StringFormatFunction)(QTestCharBuffer*,char const*,size_t); + +/* + A wrapper for string functions written to work with a fixed size buffer so they can be called + with a dynamically allocated buffer. +*/ +int allocateStringFn(QTestCharBuffer* str, char const* src, StringFormatFunction func) +{ + static const int MAXSIZE = 1024*1024*2; + + int size = str->size(); + + int res = 0; + + for (;;) { + res = func(str, src, size); + str->data()[size - 1] = '\0'; + if (res < size) { + // We succeeded or fatally failed + break; + } + // buffer wasn't big enough, try again + size *= 2; + if (size > MAXSIZE) { + break; + } + if (!str->reset(size)) + break; // ran out of memory - bye + } + + return res; +} + +int QXmlTestLogger::xmlQuote(QTestCharBuffer* str, char const* src) +{ + return allocateStringFn(str, src, QXmlTestLogger::xmlQuote); +} + +int QXmlTestLogger::xmlCdata(QTestCharBuffer* str, char const* src) +{ + return allocateStringFn(str, src, QXmlTestLogger::xmlCdata); +} + +QT_END_NAMESPACE