1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtTest module of the Qt Toolkit.
7 **
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include <QtTest/private/qtestjunitstreamer_p.h>
41 #include <QtTest/private/qjunittestlogger_p.h>
42 #include <QtTest/private/qtestelement_p.h>
43 #include <QtTest/private/qtestelementattribute_p.h>
44 #include <QtTest/qtestassert.h>
45 #include <QtTest/private/qtestlog_p.h>
46 #include <QtTest/private/qtestresult_p.h>
47 #include <QtTest/private/qxmltestlogger_p.h>
48
49 QT_BEGIN_NAMESPACE
50
QTestJUnitStreamer(QJUnitTestLogger * logger)51 QTestJUnitStreamer::QTestJUnitStreamer(QJUnitTestLogger *logger)
52 : testLogger(logger)
53 {
54 QTEST_ASSERT(testLogger);
55 }
56
57 QTestJUnitStreamer::~QTestJUnitStreamer() = default;
58
indentForElement(const QTestElement * element,char * buf,int size)59 void QTestJUnitStreamer::indentForElement(const QTestElement* element, char* buf, int size)
60 {
61 if (size == 0) return;
62
63 buf[0] = 0;
64
65 if (!element) return;
66
67 char* endbuf = buf + size;
68 element = element->parentElement();
69 while (element && buf+2 < endbuf) {
70 *(buf++) = ' ';
71 *(buf++) = ' ';
72 *buf = 0;
73 element = element->parentElement();
74 }
75 }
76
formatStart(const QTestElement * element,QTestCharBuffer * formatted) const77 void QTestJUnitStreamer::formatStart(const QTestElement *element, QTestCharBuffer *formatted) const
78 {
79 if (!element || !formatted )
80 return;
81
82 char indent[20];
83 indentForElement(element, indent, sizeof(indent));
84
85 // Errors are written as CDATA within system-err, comments elsewhere
86 if (element->elementType() == QTest::LET_Error) {
87 if (element->parentElement()->elementType() == QTest::LET_SystemError) {
88 QTest::qt_asprintf(formatted, "<![CDATA[");
89 } else {
90 QTest::qt_asprintf(formatted, "%s<!--", indent);
91 }
92 return;
93 }
94
95 QTest::qt_asprintf(formatted, "%s<%s", indent, element->elementName());
96 }
97
formatEnd(const QTestElement * element,QTestCharBuffer * formatted) const98 void QTestJUnitStreamer::formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const
99 {
100 if (!element || !formatted )
101 return;
102
103 if (!element->childElements()) {
104 formatted->data()[0] = '\0';
105 return;
106 }
107
108 char indent[20];
109 indentForElement(element, indent, sizeof(indent));
110
111 QTest::qt_asprintf(formatted, "%s</%s>\n", indent, element->elementName());
112 }
113
formatAttributes(const QTestElement * element,const QTestElementAttribute * attribute,QTestCharBuffer * formatted) const114 void QTestJUnitStreamer::formatAttributes(const QTestElement* element, const QTestElementAttribute *attribute, QTestCharBuffer *formatted) const
115 {
116 if (!attribute || !formatted )
117 return;
118
119 QTest::AttributeIndex attrindex = attribute->index();
120
121 // For errors within system-err, we only want to output `message'
122 if (element && element->elementType() == QTest::LET_Error
123 && element->parentElement()->elementType() == QTest::LET_SystemError) {
124
125 if (attrindex != QTest::AI_Description) return;
126
127 QXmlTestLogger::xmlCdata(formatted, attribute->value());
128 return;
129 }
130
131 char const* key = nullptr;
132 if (attrindex == QTest::AI_Description)
133 key = "message";
134 else if (attrindex != QTest::AI_File && attrindex != QTest::AI_Line)
135 key = attribute->name();
136
137 if (key) {
138 QTestCharBuffer quotedValue;
139 QXmlTestLogger::xmlQuote("edValue, attribute->value());
140 QTest::qt_asprintf(formatted, " %s=\"%s\"", key, quotedValue.constData());
141 } else {
142 formatted->data()[0] = '\0';
143 }
144 }
145
formatAfterAttributes(const QTestElement * element,QTestCharBuffer * formatted) const146 void QTestJUnitStreamer::formatAfterAttributes(const QTestElement *element, QTestCharBuffer *formatted) const
147 {
148 if (!element || !formatted )
149 return;
150
151 // Errors are written as CDATA within system-err, comments elsewhere
152 if (element->elementType() == QTest::LET_Error) {
153 if (element->parentElement()->elementType() == QTest::LET_SystemError) {
154 QTest::qt_asprintf(formatted, "]]>\n");
155 } else {
156 QTest::qt_asprintf(formatted, " -->\n");
157 }
158 return;
159 }
160
161 if (!element->childElements())
162 QTest::qt_asprintf(formatted, "/>\n");
163 else
164 QTest::qt_asprintf(formatted, ">\n");
165 }
166
output(QTestElement * element) const167 void QTestJUnitStreamer::output(QTestElement *element) const
168 {
169 QTEST_ASSERT(element);
170
171 outputString("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
172 outputElements(element);
173 }
174
outputElements(QTestElement * element,bool) const175 void QTestJUnitStreamer::outputElements(QTestElement *element, bool) const
176 {
177 QTestCharBuffer buf;
178 bool hasChildren;
179 /*
180 Elements are in reverse order of occurrence, so start from the end and work
181 our way backwards.
182 */
183 while (element && element->nextElement()) {
184 element = element->nextElement();
185 }
186 while (element) {
187 hasChildren = element->childElements();
188
189 if (element->elementType() != QTest::LET_Benchmark) {
190 formatStart(element, &buf);
191 outputString(buf.data());
192
193 outputElementAttributes(element, element->attributes());
194
195 formatAfterAttributes(element, &buf);
196 outputString(buf.data());
197
198 if (hasChildren)
199 outputElements(element->childElements(), true);
200
201 formatEnd(element, &buf);
202 outputString(buf.data());
203 }
204 element = element->previousElement();
205 }
206 }
207
outputElementAttributes(const QTestElement * element,QTestElementAttribute * attribute) const208 void QTestJUnitStreamer::outputElementAttributes(const QTestElement* element, QTestElementAttribute *attribute) const
209 {
210 QTestCharBuffer buf;
211 while (attribute) {
212 formatAttributes(element, attribute, &buf);
213 outputString(buf.data());
214 attribute = attribute->nextElement();
215 }
216 }
217
outputString(const char * msg) const218 void QTestJUnitStreamer::outputString(const char *msg) const
219 {
220 testLogger->outputString(msg);
221 }
222
223 QT_END_NAMESPACE
224