summaryrefslogtreecommitdiffstats
path: root/src/testlib/qxmltestlogger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/testlib/qxmltestlogger.cpp')
-rw-r--r--src/testlib/qxmltestlogger.cpp285
1 files changed, 141 insertions, 144 deletions
diff --git a/src/testlib/qxmltestlogger.cpp b/src/testlib/qxmltestlogger.cpp
index 89c4cbb765..27da73ba52 100644
--- a/src/testlib/qxmltestlogger.cpp
+++ b/src/testlib/qxmltestlogger.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtTest module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <stdio.h>
#include <string.h>
@@ -56,22 +20,20 @@ namespace QTest {
static const char *xmlMessageType2String(QAbstractTestLogger::MessageTypes type)
{
switch (type) {
- case QAbstractTestLogger::Warn:
- return "warn";
- case QAbstractTestLogger::QCritical:
- return "qcritical";
case QAbstractTestLogger::QDebug:
return "qdebug";
case QAbstractTestLogger::QInfo:
return "qinfo";
case QAbstractTestLogger::QWarning:
return "qwarn";
+ case QAbstractTestLogger::QCritical:
+ return "qcritical";
case QAbstractTestLogger::QFatal:
return "qfatal";
- case QAbstractTestLogger::Skip:
- return "skip";
case QAbstractTestLogger::Info:
return "info";
+ case QAbstractTestLogger::Warn:
+ return "warn";
}
return "??????";
}
@@ -79,6 +41,8 @@ namespace QTest {
static const char *xmlIncidentType2String(QAbstractTestLogger::IncidentTypes type)
{
switch (type) {
+ case QAbstractTestLogger::Skip:
+ return "skip";
case QAbstractTestLogger::Pass:
return "pass";
case QAbstractTestLogger::XFail:
@@ -101,6 +65,26 @@ namespace QTest {
}
+/*! \internal
+ \class QXmlTestLogger
+ \inmodule QtTest
+
+ QXmlTestLogger implements two XML formats specific to Qt.
+
+ The two formats are distinguished by the XmlMode enum.
+*/
+/*! \internal
+ \enum QXmlTestLogger::XmlMode
+
+ This enumerated type selects the type of XML output to produce.
+
+ \value Complete A full self-contained XML document
+ \value Light XML content suitable for embedding in an XML document
+
+ The Complete form wraps the Light form in a <TestCase> element whose name
+ attribute identifies the test class whose private slots are to be run. It
+ also includes the usual <?xml ...> preamble.
+*/
QXmlTestLogger::QXmlTestLogger(XmlMode mode, const char *filename)
: QAbstractTestLogger(filename), xmlmode(mode)
@@ -116,46 +100,55 @@ void QXmlTestLogger::startLogging()
if (xmlmode == QXmlTestLogger::Complete) {
QTestCharBuffer quotedTc;
- xmlQuote(&quotedTc, QTestResult::currentTestObjectName());
- QTest::qt_asprintf(&buf,
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<TestCase name=\"%s\">\n", quotedTc.constData());
+ QTest::qt_asprintf(&buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
outputString(buf.constData());
+ if (xmlQuote(&quotedTc, QTestResult::currentTestObjectName())) {
+ QTest::qt_asprintf(&buf, "<TestCase name=\"%s\">\n", quotedTc.constData());
+ outputString(buf.constData());
+ } else {
+ // Unconditional end-tag => omitting the start tag is bad.
+ Q_ASSERT_X(false, "QXmlTestLogger::startLogging",
+ "Insanely long test-case name or OOM issue");
+ }
}
QTestCharBuffer quotedBuild;
- xmlQuote(&quotedBuild, QLibraryInfo::build());
-
- QTest::qt_asprintf(&buf,
- "<Environment>\n"
- " <QtVersion>%s</QtVersion>\n"
- " <QtBuild>%s</QtBuild>\n"
- " <QTestVersion>" QTEST_VERSION_STR "</QTestVersion>\n"
- "</Environment>\n", qVersion(), quotedBuild.constData());
- outputString(buf.constData());
+ if (!QLibraryInfo::build() || xmlQuote(&quotedBuild, QLibraryInfo::build())) {
+ QTest::qt_asprintf(&buf,
+ " <Environment>\n"
+ " <QtVersion>%s</QtVersion>\n"
+ " <QtBuild>%s</QtBuild>\n"
+ " <QTestVersion>" QTEST_VERSION_STR "</QTestVersion>\n"
+ " </Environment>\n", qVersion(), quotedBuild.constData());
+ outputString(buf.constData());
+ }
}
void QXmlTestLogger::stopLogging()
{
QTestCharBuffer buf;
- QTest::qt_asprintf(&buf, "<Duration msecs=\"%s\"/>\n",
+ QTest::qt_asprintf(&buf, " <Duration msecs=\"%s\"/>\n",
QString::number(QTestLog::msecsTotalTime()).toUtf8().constData());
outputString(buf.constData());
- if (xmlmode == QXmlTestLogger::Complete) {
+ if (xmlmode == QXmlTestLogger::Complete)
outputString("</TestCase>\n");
- }
QAbstractTestLogger::stopLogging();
}
void QXmlTestLogger::enterTestFunction(const char *function)
{
- QTestCharBuffer buf;
QTestCharBuffer quotedFunction;
- xmlQuote(&quotedFunction, function);
- QTest::qt_asprintf(&buf, "<TestFunction name=\"%s\">\n", quotedFunction.constData());
- outputString(buf.constData());
+ if (xmlQuote(&quotedFunction, function)) {
+ QTestCharBuffer buf;
+ QTest::qt_asprintf(&buf, " <TestFunction name=\"%s\">\n", quotedFunction.constData());
+ outputString(buf.constData());
+ } else {
+ // Unconditional end-tag => omitting the start tag is bad.
+ Q_ASSERT_X(false, "QXmlTestLogger::enterTestFunction",
+ "Insanely long test-function name or OOM issue");
+ }
}
void QXmlTestLogger::leaveTestFunction()
@@ -163,7 +156,7 @@ void QXmlTestLogger::leaveTestFunction()
QTestCharBuffer buf;
QTest::qt_asprintf(&buf,
" <Duration msecs=\"%s\"/>\n"
- "</TestFunction>\n",
+ " </TestFunction>\n",
QString::number(QTestLog::msecsFunctionTime()).toUtf8().constData());
outputString(buf.constData());
@@ -181,45 +174,45 @@ static const char *incidentFormatString(bool noDescription, bool noTag)
{
if (noDescription) {
return noTag
- ? "<Incident type=\"%s\" file=\"%s\" line=\"%d\" />\n"
- : "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
- " <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
- "</Incident>\n";
+ ? " <Incident type=\"%s\" file=\"%s\" line=\"%d\" />\n"
+ : " <Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
+ " </Incident>\n";
}
return noTag
- ? "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
- " <Description><![CDATA[%s%s%s%s]]></Description>\n"
- "</Incident>\n"
- : "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
- " <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
- " <Description><![CDATA[%s]]></Description>\n"
- "</Incident>\n";
+ ? " <Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <Description><![CDATA[%s%s%s%s]]></Description>\n"
+ " </Incident>\n"
+ : " <Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
+ " <Description><![CDATA[%s]]></Description>\n"
+ " </Incident>\n";
}
static const char *benchmarkResultFormatString()
{
- return "<BenchmarkResult metric=\"%s\" tag=\"%s\" value=\"%.6g\" iterations=\"%d\" />\n";
+ return " <BenchmarkResult metric=\"%s\" tag=\"%s\" value=\"%.6g\" iterations=\"%d\" />\n";
}
static const char *messageFormatString(bool noDescription, bool noTag)
{
if (noDescription) {
if (noTag)
- return "<Message type=\"%s\" file=\"%s\" line=\"%d\" />\n";
+ return " <Message type=\"%s\" file=\"%s\" line=\"%d\" />\n";
else
- return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ return " <Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
" <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
- "</Message>\n";
+ " </Message>\n";
} else {
if (noTag)
- return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ return " <Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
" <Description><![CDATA[%s%s%s%s]]></Description>\n"
- "</Message>\n";
+ " </Message>\n";
else
- return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ return " <Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
" <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
" <Description><![CDATA[%s]]></Description>\n"
- "</Message>\n";
+ " </Message>\n";
}
}
@@ -239,41 +232,40 @@ void QXmlTestLogger::addIncident(IncidentTypes type, const char *description,
QTestCharBuffer cdataTag;
QTestCharBuffer cdataDescription;
- xmlQuote(&quotedFile, file);
- xmlCdata(&cdataGtag, gtag);
- xmlCdata(&cdataTag, tag);
- xmlCdata(&cdataDescription, description);
+ if (xmlQuote(&quotedFile, 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());
+ 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());
+ outputString(buf.constData());
+ }
}
void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result)
{
- QTestCharBuffer buf;
QTestCharBuffer quotedMetric;
QTestCharBuffer quotedTag;
- xmlQuote(&quotedMetric,
- benchmarkMetricName(result.metric));
- xmlQuote(&quotedTag, result.context.tag.toUtf8().constData());
-
- QTest::qt_asprintf(
- &buf,
- QTest::benchmarkResultFormatString(),
- quotedMetric.constData(),
- quotedTag.constData(),
- result.value / double(result.iterations),
- result.iterations);
- outputString(buf.constData());
+ if (xmlQuote(&quotedMetric, benchmarkMetricName(result.measurement.metric))
+ && xmlQuote(&quotedTag, result.context.tag.toUtf8().constData())) {
+ QTestCharBuffer buf;
+ QTest::qt_asprintf(&buf,
+ QTest::benchmarkResultFormatString(),
+ quotedMetric.constData(),
+ quotedTag.constData(),
+ result.measurement.value / double(result.iterations),
+ result.iterations);
+ outputString(buf.constData());
+ }
}
void QXmlTestLogger::addMessage(MessageTypes type, const QString &message,
@@ -290,30 +282,32 @@ void QXmlTestLogger::addMessage(MessageTypes type, const QString &message,
QTestCharBuffer cdataTag;
QTestCharBuffer cdataDescription;
- xmlQuote(&quotedFile, file);
- xmlCdata(&cdataGtag, gtag);
- xmlCdata(&cdataTag, tag);
- xmlCdata(&cdataDescription, message.toUtf8().constData());
-
- QTest::qt_asprintf(&buf,
- QTest::messageFormatString(message.isEmpty(), notag),
- QTest::xmlMessageType2String(type),
- quotedFile.constData(), line,
- cdataGtag.constData(),
- filler,
- cdataTag.constData(),
- cdataDescription.constData());
+ if (xmlQuote(&quotedFile, file)
+ && xmlCdata(&cdataGtag, gtag)
+ && xmlCdata(&cdataTag, tag)
+ && xmlCdata(&cdataDescription, message.toUtf8().constData())) {
+ QTest::qt_asprintf(&buf,
+ QTest::messageFormatString(message.isEmpty(), notag),
+ QTest::xmlMessageType2String(type),
+ quotedFile.constData(), line,
+ cdataGtag.constData(),
+ filler,
+ cdataTag.constData(),
+ cdataDescription.constData());
- outputString(buf.constData());
+ outputString(buf.constData());
+ }
}
int QXmlTestLogger::xmlQuote(QTestCharBuffer *destBuf, char const *src, qsizetype n)
{
- Q_ASSERT(n > 0 && destBuf->size() >= n);
-
+ // QTestCharBuffer initially has size 512, with '\0' at the start of its
+ // data; and we only grow it.
+ Q_ASSERT(n >= 512 && destBuf->size() == n);
char *dest = destBuf->data();
- if (!src || n == 1) {
- *dest = '\0';
+
+ if (!src || !*src) {
+ Q_ASSERT(!dest[0]);
return 0;
}
@@ -359,19 +353,19 @@ int QXmlTestLogger::xmlQuote(QTestCharBuffer *destBuf, char const *src, qsizetyp
}
}
- // If we get here, dest was completely filled (dest == end)
- dest[-1] = '\0';
- return dest - begin;
+ // If we get here, dest was completely filled:
+ Q_ASSERT(dest == end && end > begin);
+ dest[-1] = '\0'; // hygiene, but it'll be ignored
+ return n;
}
int QXmlTestLogger::xmlCdata(QTestCharBuffer *destBuf, char const *src, qsizetype n)
{
- Q_ASSERT(n > 0 && destBuf->size() >= n);
-
+ Q_ASSERT(n >= 512 && destBuf->size() == n);
char *dest = destBuf->data();
- if (!src || n == 1) {
- *dest = '\0';
+ if (!src || !*src) {
+ Q_ASSERT(!dest[0]);
return 0;
}
@@ -404,10 +398,10 @@ int QXmlTestLogger::xmlCdata(QTestCharBuffer *destBuf, char const *src, qsizetyp
++dest;
}
- // If we get here, dest was completely filled:
+ // If we get here, dest was completely filled; caller shall grow and retry:
Q_ASSERT(dest == end && end > begin);
- dest[-1] = '\0';
- return dest - begin;
+ dest[-1] = '\0'; // hygiene, but it'll be ignored
+ return n;
}
typedef int (*StringFormatFunction)(QTestCharBuffer *, char const *, qsizetype);
@@ -416,21 +410,24 @@ typedef int (*StringFormatFunction)(QTestCharBuffer *, char const *, qsizetype);
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 bool allocateStringFn(QTestCharBuffer *str, char const *src, StringFormatFunction func)
{
constexpr int MAXSIZE = 1024 * 1024 * 2;
int size = str->size();
+ Q_ASSERT(size >= 512 && !str->data()[0]);
do {
const int res = func(str, src, size);
- if (res < size) // Success or fatal failure
- return res;
+ if (res < size) { // Success
+ Q_ASSERT(res > 0 || (!res && (!src || !src[0])));
+ return true;
+ }
// Buffer wasn't big enough, try again, if not too big:
size *= 2;
} while (size <= MAXSIZE && str->reset(size));
- return 0;
+ return false;
}
/*
@@ -442,7 +439,7 @@ int allocateStringFn(QTestCharBuffer *str, char const *src, StringFormatFunction
Returns 0 on invalid or empty input, the actual length written on success.
*/
-int QXmlTestLogger::xmlQuote(QTestCharBuffer *str, char const *src)
+bool QXmlTestLogger::xmlQuote(QTestCharBuffer *str, char const *src)
{
return allocateStringFn(str, src, QXmlTestLogger::xmlQuote);
}
@@ -455,7 +452,7 @@ int QXmlTestLogger::xmlQuote(QTestCharBuffer *str, char const *src)
Returns 0 on invalid or empty input, the actual length written on success.
*/
-int QXmlTestLogger::xmlCdata(QTestCharBuffer *str, char const *src)
+bool QXmlTestLogger::xmlCdata(QTestCharBuffer *str, char const *src)
{
return allocateStringFn(str, src, QXmlTestLogger::xmlCdata);
}