1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtTest module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
44 #include <QtCore/qglobal.h>
46 #include <QtTest/private/qxmltestlogger_p.h>
47 #include <QtTest/private/qtestresult_p.h>
48 #include <QtTest/private/qbenchmark_p.h>
49 #include <QtTest/private/qbenchmarkmetric_p.h>
50 #include <QtTest/qtestcase.h>
56 static const char* xmlMessageType2String(QAbstractTestLogger::MessageTypes type)
59 case QAbstractTestLogger::Warn:
61 case QAbstractTestLogger::QSystem:
63 case QAbstractTestLogger::QDebug:
65 case QAbstractTestLogger::QWarning:
67 case QAbstractTestLogger::QFatal:
69 case QAbstractTestLogger::Skip:
71 case QAbstractTestLogger::Info:
77 static const char* xmlIncidentType2String(QAbstractTestLogger::IncidentTypes type)
80 case QAbstractTestLogger::Pass:
82 case QAbstractTestLogger::XFail:
84 case QAbstractTestLogger::Fail:
86 case QAbstractTestLogger::XPass:
95 QXmlTestLogger::QXmlTestLogger(XmlMode mode, const char *filename)
96 : QAbstractTestLogger(filename), xmlmode(mode)
100 QXmlTestLogger::~QXmlTestLogger()
104 void QXmlTestLogger::startLogging()
106 QAbstractTestLogger::startLogging();
109 if (xmlmode == QXmlTestLogger::Complete) {
110 QTestCharBuffer quotedTc;
111 xmlQuote("edTc, QTestResult::currentTestObjectName());
112 QTest::qt_asprintf(&buf,
113 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
114 "<TestCase name=\"%s\">\n", quotedTc.constData());
115 outputString(buf.constData());
118 QTest::qt_asprintf(&buf,
120 " <QtVersion>%s</QtVersion>\n"
121 " <QTestVersion>" QTEST_VERSION_STR "</QTestVersion>\n"
122 "</Environment>\n", qVersion());
123 outputString(buf.constData());
126 void QXmlTestLogger::stopLogging()
128 if (xmlmode == QXmlTestLogger::Complete) {
129 outputString("</TestCase>\n");
132 QAbstractTestLogger::stopLogging();
135 void QXmlTestLogger::enterTestFunction(const char *function)
138 QTestCharBuffer quotedFunction;
139 xmlQuote("edFunction, function);
140 QTest::qt_asprintf(&buf, "<TestFunction name=\"%s\">\n", quotedFunction.constData());
141 outputString(buf.constData());
144 void QXmlTestLogger::leaveTestFunction()
146 outputString("</TestFunction>\n");
152 inline static bool isEmpty(const char *str)
154 return !str || !str[0];
157 static const char *incidentFormatString(bool noDescription, bool noTag)
161 return "<Incident type=\"%s\" file=\"%s\" line=\"%d\" />\n";
163 return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
164 " <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
168 return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
169 " <Description><![CDATA[%s%s%s%s]]></Description>\n"
172 return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
173 " <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
174 " <Description><![CDATA[%s]]></Description>\n"
179 static const char *benchmarkResultFormatString()
181 return "<BenchmarkResult metric=\"%s\" tag=\"%s\" value=\"%s\" iterations=\"%d\" />\n";
184 static const char *messageFormatString(bool noDescription, bool noTag)
188 return "<Message type=\"%s\" file=\"%s\" line=\"%d\" />\n";
190 return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
191 " <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
195 return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
196 " <Description><![CDATA[%s%s%s%s]]></Description>\n"
199 return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
200 " <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
201 " <Description><![CDATA[%s]]></Description>\n"
208 void QXmlTestLogger::addIncident(IncidentTypes type, const char *description,
209 const char *file, int line)
212 const char *tag = QTestResult::currentDataTag();
213 const char *gtag = QTestResult::currentGlobalDataTag();
214 const char *filler = (tag && gtag) ? ":" : "";
215 const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag);
217 QTestCharBuffer quotedFile;
218 QTestCharBuffer cdataGtag;
219 QTestCharBuffer cdataTag;
220 QTestCharBuffer cdataDescription;
222 xmlQuote("edFile, file);
223 xmlCdata(&cdataGtag, gtag);
224 xmlCdata(&cdataTag, tag);
225 xmlCdata(&cdataDescription, description);
227 QTest::qt_asprintf(&buf,
228 QTest::incidentFormatString(QTest::isEmpty(description), notag),
229 QTest::xmlIncidentType2String(type),
230 quotedFile.constData(), line,
231 cdataGtag.constData(),
233 cdataTag.constData(),
234 cdataDescription.constData());
236 outputString(buf.constData());
239 void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result)
242 QTestCharBuffer quotedMetric;
243 QTestCharBuffer quotedTag;
245 xmlQuote("edMetric,
246 benchmarkMetricName(result.metric));
247 xmlQuote("edTag, result.context.tag.toUtf8().constData());
251 QTest::benchmarkResultFormatString(),
252 quotedMetric.constData(),
253 quotedTag.constData(),
254 QByteArray::number(result.value).constData(), //no 64-bit qsnprintf support
256 outputString(buf.constData());
259 void QXmlTestLogger::addMessage(MessageTypes type, const char *message,
260 const char *file, int line)
263 const char *tag = QTestResult::currentDataTag();
264 const char *gtag = QTestResult::currentGlobalDataTag();
265 const char *filler = (tag && gtag) ? ":" : "";
266 const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag);
268 QTestCharBuffer quotedFile;
269 QTestCharBuffer cdataGtag;
270 QTestCharBuffer cdataTag;
271 QTestCharBuffer cdataDescription;
273 xmlQuote("edFile, file);
274 xmlCdata(&cdataGtag, gtag);
275 xmlCdata(&cdataTag, tag);
276 xmlCdata(&cdataDescription, message);
278 QTest::qt_asprintf(&buf,
279 QTest::messageFormatString(QTest::isEmpty(message), notag),
280 QTest::xmlMessageType2String(type),
281 quotedFile.constData(), line,
282 cdataGtag.constData(),
284 cdataTag.constData(),
285 cdataDescription.constData());
287 outputString(buf.constData());
291 Copy up to n characters from the src string into dest, escaping any special
292 XML characters as necessary so that dest is suitable for use in an XML
293 quoted attribute string.
295 int QXmlTestLogger::xmlQuote(QTestCharBuffer* destBuf, char const* src, size_t n)
297 if (n == 0) return 0;
299 char *dest = destBuf->data();
304 char* end = dest + n;
309 #define MAP_ENTITY(chr, ent) \
311 if (dest + sizeof(ent) < end) { \
313 dest += sizeof(ent) - 1; \
317 return (dest+sizeof(ent)-begin); \
322 MAP_ENTITY('>', ">");
323 MAP_ENTITY('<', "<");
324 MAP_ENTITY('\'', "'");
325 MAP_ENTITY('"', """);
326 MAP_ENTITY('&', "&");
328 // not strictly necessary, but allows handling of comments without
329 // having to explicitly look for `--'
330 MAP_ENTITY('-', "-");
346 // If we get here, dest was completely filled (dest == end)
352 Copy up to n characters from the src string into dest, escaping any
353 special strings such that dest is suitable for use in an XML CDATA section.
355 int QXmlTestLogger::xmlCdata(QTestCharBuffer *destBuf, char const* src, size_t n)
359 char *dest = destBuf->data();
361 if (!src || n == 1) {
366 static char const CDATA_END[] = "]]>";
367 static char const CDATA_END_ESCAPED[] = "]]]><![CDATA[]>";
370 char* end = dest + n;
377 if (!strncmp(src, CDATA_END, sizeof(CDATA_END)-1)) {
378 if (dest + sizeof(CDATA_END_ESCAPED) < end) {
379 strcpy(dest, CDATA_END_ESCAPED);
380 src += sizeof(CDATA_END)-1;
381 dest += sizeof(CDATA_END_ESCAPED) - 1;
385 return (dest+sizeof(CDATA_END_ESCAPED)-begin);
395 // If we get here, dest was completely filled (dest == end)
400 typedef int (*StringFormatFunction)(QTestCharBuffer*,char const*,size_t);
403 A wrapper for string functions written to work with a fixed size buffer so they can be called
404 with a dynamically allocated buffer.
406 int allocateStringFn(QTestCharBuffer* str, char const* src, StringFormatFunction func)
408 static const int MAXSIZE = 1024*1024*2;
410 int size = str->size();
415 res = func(str, src, size);
416 str->data()[size - 1] = '\0';
418 // We succeeded or fatally failed
421 // buffer wasn't big enough, try again
423 if (size > MAXSIZE) {
426 if (!str->reset(size))
427 break; // ran out of memory - bye
433 int QXmlTestLogger::xmlQuote(QTestCharBuffer* str, char const* src)
435 return allocateStringFn(str, src, QXmlTestLogger::xmlQuote);
438 int QXmlTestLogger::xmlCdata(QTestCharBuffer* str, char const* src)
440 return allocateStringFn(str, src, QXmlTestLogger::xmlCdata);