4#include <QtTest/private/qjunittestlogger_p.h>
5#include <QtTest/private/qtestelement_p.h>
6#include <QtTest/private/qtestjunitstreamer_p.h>
7#include <QtTest/qtestcase.h>
8#include <QtTest/private/qtestresult_p.h>
9#include <QtTest/private/qbenchmark_p.h>
10#include <QtTest/private/qtestlog_p.h>
12#include <QtCore/qlibraryinfo.h>
20
21
22
23
24
25
26
27
30QJUnitTestLogger::QJUnitTestLogger(
const char *filename)
31 : QAbstractTestLogger(filename)
35QJUnitTestLogger::~QJUnitTestLogger()
37 Q_ASSERT(!currentTestSuite);
43Q_CONSTINIT
static QElapsedTimer elapsedTestcaseTime;
46 return elapsedTestcaseTime.nsecsElapsed() / 1e9;
51 return QByteArray::number(ms / 1000,
'f', 3);
54void QJUnitTestLogger::startLogging()
56 QAbstractTestLogger::startLogging();
58 logFormatter =
new QTestJUnitStreamer(
this);
60 Q_ASSERT(!currentTestSuite);
61 currentTestSuite =
new QTestElement(QTest::LET_TestSuite);
62 currentTestSuite->addAttribute(QTest::AI_Name, QTestResult::currentTestObjectName());
64 auto localTime = QDateTime::currentDateTime();
65 currentTestSuite->addAttribute(QTest::AI_Timestamp,
66 localTime.toString(Qt::ISODate).toUtf8().constData());
68 currentTestSuite->addAttribute(QTest::AI_Hostname,
69 QSysInfo::machineHostName().toUtf8().constData());
71 QTestElement *property;
72 QTestElement *properties =
new QTestElement(QTest::LET_Properties);
74 property =
new QTestElement(QTest::LET_Property);
75 property->addAttribute(QTest::AI_Name,
"QTestVersion");
76 property->addAttribute(QTest::AI_PropertyValue, QTEST_VERSION_STR);
77 properties->addChild(property);
79 property =
new QTestElement(QTest::LET_Property);
80 property->addAttribute(QTest::AI_Name,
"QtVersion");
81 property->addAttribute(QTest::AI_PropertyValue, qVersion());
82 properties->addChild(property);
84 property =
new QTestElement(QTest::LET_Property);
85 property->addAttribute(QTest::AI_Name,
"QtBuild");
86 property->addAttribute(QTest::AI_PropertyValue, QLibraryInfo::build());
87 properties->addChild(property);
89 currentTestSuite->addChild(properties);
91 elapsedTestcaseTime.start();
94void QJUnitTestLogger::stopLogging()
98 std::snprintf(buf,
sizeof(buf),
"%i", testCounter);
99 currentTestSuite->addAttribute(QTest::AI_Tests, buf);
101 std::snprintf(buf,
sizeof(buf),
"%i", failureCounter);
102 currentTestSuite->addAttribute(QTest::AI_Failures, buf);
104 std::snprintf(buf,
sizeof(buf),
"%i", errorCounter);
105 currentTestSuite->addAttribute(QTest::AI_Errors, buf);
107 std::snprintf(buf,
sizeof(buf),
"%i", QTestLog::skipCount());
108 currentTestSuite->addAttribute(QTest::AI_Skipped, buf);
110 currentTestSuite->addAttribute(QTest::AI_Time,
111 toSecondsFormat(QTestLog::msecsTotalTime()).constData());
113 for (
auto *testCase : listOfTestcases)
114 currentTestSuite->addChild(testCase);
115 listOfTestcases.clear();
117 logFormatter->output(currentTestSuite);
119 delete currentTestSuite;
120 currentTestSuite =
nullptr;
122 QAbstractTestLogger::stopLogging();
125void QJUnitTestLogger::enterTestFunction(
const char *function)
127 enterTestCase(function);
130void QJUnitTestLogger::enterTestCase(
const char *name)
132 currentTestCase =
new QTestElement(QTest::LET_TestCase);
133 currentTestCase->addAttribute(QTest::AI_Name, name);
134 currentTestCase->addAttribute(QTest::AI_Classname, QTestResult::currentTestObjectName());
135 listOfTestcases.push_back(currentTestCase);
137 Q_ASSERT(!systemOutputElement && !systemErrorElement);
138 systemOutputElement =
new QTestElement(QTest::LET_SystemOutput);
139 systemErrorElement =
new QTestElement(QTest::LET_SystemError);
145 elapsedTestcaseTime.restart();
148void QJUnitTestLogger::enterTestData(QTestData *)
150 QTestCharBuffer testIdentifier;
151 QTestPrivate::generateTestIdentifier(&testIdentifier,
152 QTestPrivate::TestFunction | QTestPrivate::TestDataTag);
154 static const char *lastTestFunction =
nullptr;
155 if (QTestResult::currentTestFunction() != lastTestFunction) {
157 auto *name =
const_cast<QTestElementAttribute*>(
158 currentTestCase->attribute(QTest::AI_Name));
159 name->setPair(QTest::AI_Name, testIdentifier.data());
160 lastTestFunction = QTestResult::currentTestFunction();
161 elapsedTestcaseTime.restart();
165 enterTestCase(testIdentifier.data());
169void QJUnitTestLogger::leaveTestFunction()
174void QJUnitTestLogger::leaveTestCase()
176 currentTestCase->addAttribute(QTest::AI_Time,
177 toSecondsFormat(elapsedTestCaseSeconds() * 1000).constData());
179 if (!systemOutputElement->childElements().empty())
180 currentTestCase->addChild(systemOutputElement);
182 delete systemOutputElement;
184 if (!systemErrorElement->childElements().empty())
185 currentTestCase->addChild(systemErrorElement);
187 delete systemErrorElement;
189 systemOutputElement =
nullptr;
190 systemErrorElement =
nullptr;
193void QJUnitTestLogger::addIncident(IncidentTypes type,
const char *description,
194 const char *file,
int line)
196 if (type == Fail || type == XPass) {
197 auto failureType = [&]() {
199 case QAbstractTestLogger::Fail:
return "fail";
200 case QAbstractTestLogger::XPass:
return "xpass";
201 default: Q_UNREACHABLE();
205 addFailure(QTest::LET_Failure, failureType, QString::fromUtf8(description));
206 }
else if (type == XFail) {
209 addMessage(Info, QString::fromUtf8(description), file, line);
210 }
else if (type == Skip) {
211 auto skippedElement =
new QTestElement(QTest::LET_Skipped);
212 skippedElement->addAttribute(QTest::AI_Message, description);
213 currentTestCase->addChild(skippedElement);
217void QJUnitTestLogger::addFailure(QTest::LogElementType elementType,
218 const char *failureType,
const QString &failureDescription)
220 if (elementType == QTest::LET_Failure) {
223 for (
auto *childElement : currentTestCase->childElements()) {
224 if (childElement->elementType() == QTest::LET_Error ||
225 childElement->elementType() == QTest::LET_Failure)
230 QTestElement *failureElement =
new QTestElement(elementType);
231 failureElement->addAttribute(QTest::AI_Type, failureType);
234 QString message = failureDescription.section(u'\n', 0, 0);
235 QString details = failureDescription.section(u'\n', 1);
237 failureElement->addAttribute(QTest::AI_Message, message.toUtf8().constData());
239 if (!details.isEmpty()) {
240 auto textNode =
new QTestElement(QTest::LET_Text);
241 textNode->addAttribute(QTest::AI_Value, details.toUtf8().constData());
242 failureElement->addChild(textNode);
245 currentTestCase->addChild(failureElement);
247 switch (elementType) {
248 case QTest::LET_Failure: ++failureCounter;
break;
249 case QTest::LET_Error: ++errorCounter;
break;
250 default: Q_UNREACHABLE();
254void QJUnitTestLogger::addMessage(MessageTypes type,
const QString &message,
const char *file,
int line)
259 if (type == QFatal) {
260 addFailure(QTest::LET_Error,
"qfatal", message);
264 auto systemLogElement = [&]() {
266 case QAbstractTestLogger::QDebug:
267 case QAbstractTestLogger::Info:
268 case QAbstractTestLogger::QInfo:
269 return systemOutputElement;
270 case QAbstractTestLogger::Warn:
271 case QAbstractTestLogger::QWarning:
272 case QAbstractTestLogger::QCritical:
273 return systemErrorElement;
279 if (!systemLogElement)
282 auto textNode =
new QTestElement(QTest::LET_Text);
283 textNode->addAttribute(QTest::AI_Value, message.toUtf8().constData());
284 systemLogElement->addChild(textNode);
static QByteArray toSecondsFormat(qreal ms)
static qreal elapsedTestCaseSeconds()