Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qteamcitylogger.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2017 Borgar Ovsthus
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <QtTest/private/qtestresult_p.h>
6#include <QtTest/qtestassert.h>
7#include <QtTest/private/qtestlog_p.h>
8#include <QtTest/private/qteamcitylogger_p.h>
9#include <QtCore/qbytearray.h>
10#include <private/qlocale_p.h>
11
12#include <limits.h>
13#include <stdarg.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17
19
20using namespace Qt::StringLiterals;
21
22namespace QTest {
23
25 {
26 switch (type) {
28 return "SKIP";
30 return "PASS";
32 return "XFAIL";
34 return "FAIL!";
36 return "XPASS";
38 return "BPASS";
40 return "BFAIL";
42 return "BXPASS";
44 return "BXFAIL";
45 }
46 return "??????";
47 }
48
50 {
51 switch (type) {
53 return "QDEBUG";
55 return "QINFO";
57 return "QWARN";
59 return "QCRITICAL";
61 return "QFATAL";
63 return "INFO";
65 return "WARNING";
66 }
67 return "??????";
68 }
69}
70
79 : QAbstractTestLogger(filename)
80{
81}
82
84
86{
88
89 tcEscapedString(&flowID, QTestResult::currentTestObjectName());
90
92 QTest::qt_asprintf(&buf, "##teamcity[testSuiteStarted name='%s' flowId='%s']\n",
93 flowID.constData(), flowID.constData());
94 outputString(buf.constData());
95}
96
98{
100 QTest::qt_asprintf(&buf, "##teamcity[testSuiteFinished name='%s' flowId='%s']\n",
101 flowID.constData(), flowID.constData());
102 outputString(buf.constData());
103
105}
106
107void QTeamCityLogger::enterTestFunction(const char * /*function*/)
108{
109 // don't print anything
110}
111
113{
114 // don't print anything
115}
116
117void QTeamCityLogger::addIncident(IncidentTypes type, const char *description,
118 const char *file, int line)
119{
120 // suppress B?PASS and B?XFAIL in silent mode
122 return;
123
125 QTestCharBuffer tmpFuncName;
126 escapedTestFuncName(&tmpFuncName);
127
128 if (qstrcmp(tmpFuncName.constData(), currTestFuncName.constData()) != 0) {
129 QTest::qt_asprintf(&buf, "##teamcity[testStarted name='%s' flowId='%s']\n",
130 tmpFuncName.constData(), flowID.constData());
131 outputString(buf.constData());
132
133 currTestFuncName.clear();
134 QTestPrivate::appendCharBuffer(&currTestFuncName, tmpFuncName);
135 }
136
138 addPendingMessage(QTest::tcIncidentType2String(type), description, file, line);
139 return;
140 }
141
142 QTestCharBuffer detailedText;
143 tcEscapedString(&detailedText, description);
144
145 // Test failed
146 if (type == Fail || type == XPass) {
147 QTestCharBuffer messageText;
148 if (file)
149 QTest::qt_asprintf(&messageText, "Failure! |[Loc: %s(%d)|]", file, line);
150 else
151 QTest::qt_asprintf(&messageText, "Failure!");
152
153 QTest::qt_asprintf(&buf, "##teamcity[testFailed name='%s' message='%s' details='%s'"
154 " flowId='%s']\n", tmpFuncName.constData(), messageText.constData(),
155 detailedText.constData(), flowID.constData());
156
157 outputString(buf.constData());
158 } else if (type == Skip) {
159 if (file) {
161 QTest::qt_asprintf(&detail, " |[Loc: %s(%d)|]", file, line);
163 }
164
165 QTest::qt_asprintf(&buf, "##teamcity[testIgnored name='%s' message='%s' flowId='%s']\n",
166 currTestFuncName.constData(), detailedText.constData(),
167 flowID.constData());
168
169 outputString(buf.constData());
170 }
171
172 if (!pendingMessages.isEmpty()) {
173 QTest::qt_asprintf(&buf, "##teamcity[testStdOut name='%s' out='%s' flowId='%s']\n",
174 tmpFuncName.constData(), pendingMessages.constData(),
175 flowID.constData());
176
177 outputString(buf.constData());
178 pendingMessages.clear();
179 }
180
181 QTest::qt_asprintf(&buf, "##teamcity[testFinished name='%s' flowId='%s']\n",
182 tmpFuncName.constData(), flowID.constData());
183 outputString(buf.constData());
184}
185
187{
188 // don't print anything
189}
190
192 const char *file, int line)
193{
194 // suppress non-fatal messages in silent mode
195 if (type != QFatal && QTestLog::verboseLevel() < 0)
196 return;
197
198 QTestCharBuffer escapedMessage;
199 tcEscapedString(&escapedMessage, qUtf8Printable(message));
200 addPendingMessage(QTest::tcMessageType2String(type), escapedMessage.constData(), file, line);
201}
202
203void QTeamCityLogger::tcEscapedString(QTestCharBuffer *buf, const char *str) const
204{
205 {
206 size_t size = qstrlen(str) + 1;
207 for (const char *p = str; *p; ++p) {
208 if (strchr("\n\r|[]'", *p))
209 ++size;
210 }
211 Q_ASSERT(size <= size_t(INT_MAX));
212 buf->resize(int(size));
213 }
214
215 bool swallowSpace = true;
216 char *p = buf->data();
217 for (; *str; ++str) {
218 char ch = *str;
219 switch (ch) {
220 case '\n':
221 p++[0] = '|';
222 ch = 'n';
223 swallowSpace = false;
224 break;
225 case '\r':
226 p++[0] = '|';
227 ch = 'r';
228 swallowSpace = false;
229 break;
230 case '|':
231 case '[':
232 case ']':
233 case '\'':
234 p++[0] = '|';
235 swallowSpace = false;
236 break;
237 default:
238 if (ascii_isspace(ch)) {
239 if (swallowSpace)
240 continue;
241 swallowSpace = true;
242 ch = ' ';
243 } else {
244 swallowSpace = false;
245 }
246 break;
247 }
248 p++[0] = ch;
249 }
250 Q_ASSERT(p < buf->data() + buf->size());
251 if (swallowSpace && p > buf->data()) {
252 Q_ASSERT(p[-1] == ' ');
253 --p;
254 }
255 Q_ASSERT(p == buf->data() || !ascii_isspace(p[-1]));
256 *p = '\0';
257}
258
259void QTeamCityLogger::escapedTestFuncName(QTestCharBuffer *buf) const
260{
263}
264
265void QTeamCityLogger::addPendingMessage(const char *type, const char *msg,
266 const char *file, int line)
267{
268 const char *pad = pendingMessages.isEmpty() ? "" : "|n";
269
270 QTestCharBuffer newMessage;
271 if (file)
272 QTest::qt_asprintf(&newMessage, "%s%s |[Loc: %s(%d)|]: %s", pad, type, file, line, msg);
273 else
274 QTest::qt_asprintf(&newMessage, "%s%s: %s", pad, type, msg);
275
276 QTestPrivate::appendCharBuffer(&pendingMessages, newMessage);
277}
278
Base class for test loggers.
void outputString(const char *msg)
Convenience method to write msg to the output stream.
IncidentTypes
\value Pass The test ran to completion successfully.
virtual void startLogging()
Called before the start of a test run.
MessageTypes
The members whose names begin with Q describe messages that originate in calls, by the test or code u...
virtual void stopLogging()
Called after the end of a test run.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void addIncident(IncidentTypes type, const char *description, const char *file=nullptr, int line=0) override
This virtual method is called when an event occurs that relates to the resolution of the test.
QTeamCityLogger(const char *filename)
void startLogging() override
Called before the start of a test run.
void stopLogging() override
Called after the end of a test run.
void addBenchmarkResult(const QBenchmarkResult &result) override
This virtual method is called after a benchmark has been run enough times to produce usable data.
void leaveTestFunction() override
This virtual method is called after a test function has completed, to match \l enterTestFunction().
void enterTestFunction(const char *function) override
This virtual method is called before each test function is invoked.
void addMessage(MessageTypes type, const QString &message, const char *file=nullptr, int line=0) override
This is an overloaded member function, provided for convenience. It differs from the above function o...
static int verboseLevel()
Definition qtestlog.cpp:609
static const char * currentTestObjectName()
QString str
[2]
Combined button and popup list for selecting options.
void generateTestIdentifier(QTestCharBuffer *identifier, int parts)
bool appendCharBuffer(QTestCharBuffer *accumulator, const QTestCharBuffer &more)
static const char * tcIncidentType2String(QAbstractTestLogger::IncidentTypes type)
static const char * tcMessageType2String(QAbstractTestLogger::MessageTypes type)
int qt_asprintf(QTestCharBuffer *str, const char *format,...)
size_t qstrlen(const char *str)
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
constexpr bool ascii_isspace(uchar c)
Definition qlocale_p.h:556
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLuint GLsizei const GLchar * message
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qUtf8Printable(string)
Definition qstring.h:1535
QFile file
[0]
const char * constData() const