Fix binary incompatibility between openssl versions
[profile/ivi/qtbase.git] / src / testlib / qxmltestlogger.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 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.
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 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.
24 **
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.
28 **
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.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <QtCore/qglobal.h>
45
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>
51
52 QT_BEGIN_NAMESPACE
53
54 namespace QTest {
55
56     static const char* xmlMessageType2String(QAbstractTestLogger::MessageTypes type)
57     {
58         switch (type) {
59         case QAbstractTestLogger::Warn:
60             return "warn";
61         case QAbstractTestLogger::QSystem:
62             return "system";
63         case QAbstractTestLogger::QDebug:
64             return "qdebug";
65         case QAbstractTestLogger::QWarning:
66             return "qwarn";
67         case QAbstractTestLogger::QFatal:
68             return "qfatal";
69         case QAbstractTestLogger::Skip:
70             return "skip";
71         case QAbstractTestLogger::Info:
72             return "info";
73         }
74         return "??????";
75     }
76
77     static const char* xmlIncidentType2String(QAbstractTestLogger::IncidentTypes type)
78     {
79         switch (type) {
80         case QAbstractTestLogger::Pass:
81             return "pass";
82         case QAbstractTestLogger::XFail:
83             return "xfail";
84         case QAbstractTestLogger::Fail:
85             return "fail";
86         case QAbstractTestLogger::XPass:
87             return "xpass";
88         }
89         return "??????";
90     }
91
92 }
93
94
95 QXmlTestLogger::QXmlTestLogger(XmlMode mode, const char *filename)
96     : QAbstractTestLogger(filename), xmlmode(mode)
97 {
98 }
99
100 QXmlTestLogger::~QXmlTestLogger()
101 {
102 }
103
104 void QXmlTestLogger::startLogging()
105 {
106     QAbstractTestLogger::startLogging();
107     QTestCharBuffer buf;
108
109     if (xmlmode == QXmlTestLogger::Complete) {
110         QTestCharBuffer quotedTc;
111         xmlQuote(&quotedTc, 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());
116     }
117
118     QTest::qt_asprintf(&buf,
119                 "<Environment>\n"
120                 "    <QtVersion>%s</QtVersion>\n"
121                 "    <QTestVersion>" QTEST_VERSION_STR "</QTestVersion>\n"
122                 "</Environment>\n", qVersion());
123     outputString(buf.constData());
124 }
125
126 void QXmlTestLogger::stopLogging()
127 {
128     if (xmlmode == QXmlTestLogger::Complete) {
129         outputString("</TestCase>\n");
130     }
131
132     QAbstractTestLogger::stopLogging();
133 }
134
135 void QXmlTestLogger::enterTestFunction(const char *function)
136 {
137     QTestCharBuffer buf;
138     QTestCharBuffer quotedFunction;
139     xmlQuote(&quotedFunction, function);
140     QTest::qt_asprintf(&buf, "<TestFunction name=\"%s\">\n", quotedFunction.constData());
141     outputString(buf.constData());
142 }
143
144 void QXmlTestLogger::leaveTestFunction()
145 {
146     outputString("</TestFunction>\n");
147 }
148
149 namespace QTest
150 {
151
152 inline static bool isEmpty(const char *str)
153 {
154     return !str || !str[0];
155 }
156
157 static const char *incidentFormatString(bool noDescription, bool noTag)
158 {
159     if (noDescription) {
160         if (noTag)
161             return "<Incident type=\"%s\" file=\"%s\" line=\"%d\" />\n";
162         else
163             return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
164                 "    <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
165                 "</Incident>\n";
166     } else {
167         if (noTag)
168             return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
169                 "    <Description><![CDATA[%s%s%s%s]]></Description>\n"
170                 "</Incident>\n";
171         else
172             return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
173                 "    <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
174                 "    <Description><![CDATA[%s]]></Description>\n"
175                 "</Incident>\n";
176     }
177 }
178
179 static const char *benchmarkResultFormatString()
180 {
181     return "<BenchmarkResult metric=\"%s\" tag=\"%s\" value=\"%s\" iterations=\"%d\" />\n";
182 }
183
184 static const char *messageFormatString(bool noDescription, bool noTag)
185 {
186     if (noDescription) {
187         if (noTag)
188             return "<Message type=\"%s\" file=\"%s\" line=\"%d\" />\n";
189         else
190             return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
191                 "    <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
192                 "</Message>\n";
193     } else {
194         if (noTag)
195             return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
196                 "    <Description><![CDATA[%s%s%s%s]]></Description>\n"
197                 "</Message>\n";
198         else
199             return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
200                 "    <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
201                 "    <Description><![CDATA[%s]]></Description>\n"
202                 "</Message>\n";
203     }
204 }
205
206 } // namespace
207
208 void QXmlTestLogger::addIncident(IncidentTypes type, const char *description,
209                                 const char *file, int line)
210 {
211     QTestCharBuffer buf;
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);
216
217     QTestCharBuffer quotedFile;
218     QTestCharBuffer cdataGtag;
219     QTestCharBuffer cdataTag;
220     QTestCharBuffer cdataDescription;
221
222     xmlQuote(&quotedFile, file);
223     xmlCdata(&cdataGtag, gtag);
224     xmlCdata(&cdataTag, tag);
225     xmlCdata(&cdataDescription, description);
226
227     QTest::qt_asprintf(&buf,
228             QTest::incidentFormatString(QTest::isEmpty(description), notag),
229             QTest::xmlIncidentType2String(type),
230             quotedFile.constData(), line,
231             cdataGtag.constData(),
232             filler,
233             cdataTag.constData(),
234             cdataDescription.constData());
235
236     outputString(buf.constData());
237 }
238
239 void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result)
240 {
241     QTestCharBuffer buf;
242     QTestCharBuffer quotedMetric;
243     QTestCharBuffer quotedTag;
244
245     xmlQuote(&quotedMetric,
246         benchmarkMetricName(result.metric));
247     xmlQuote(&quotedTag, result.context.tag.toUtf8().constData());
248
249     QTest::qt_asprintf(
250         &buf,
251         QTest::benchmarkResultFormatString(),
252         quotedMetric.constData(),
253         quotedTag.constData(),
254         QByteArray::number(result.value).constData(),  //no 64-bit qsnprintf support
255         result.iterations);
256     outputString(buf.constData());
257 }
258
259 void QXmlTestLogger::addMessage(MessageTypes type, const char *message,
260                                 const char *file, int line)
261 {
262     QTestCharBuffer buf;
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);
267
268     QTestCharBuffer quotedFile;
269     QTestCharBuffer cdataGtag;
270     QTestCharBuffer cdataTag;
271     QTestCharBuffer cdataDescription;
272
273     xmlQuote(&quotedFile, file);
274     xmlCdata(&cdataGtag, gtag);
275     xmlCdata(&cdataTag, tag);
276     xmlCdata(&cdataDescription, message);
277
278     QTest::qt_asprintf(&buf,
279             QTest::messageFormatString(QTest::isEmpty(message), notag),
280             QTest::xmlMessageType2String(type),
281             quotedFile.constData(), line,
282             cdataGtag.constData(),
283             filler,
284             cdataTag.constData(),
285             cdataDescription.constData());
286
287     outputString(buf.constData());
288 }
289
290 /*
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.
294 */
295 int QXmlTestLogger::xmlQuote(QTestCharBuffer* destBuf, char const* src, size_t n)
296 {
297     if (n == 0) return 0;
298
299     char *dest = destBuf->data();
300     *dest = 0;
301     if (!src) return 0;
302
303     char* begin = dest;
304     char* end = dest + n;
305
306     while (dest < end) {
307         switch (*src) {
308
309 #define MAP_ENTITY(chr, ent) \
310             case chr:                                   \
311                 if (dest + sizeof(ent) < end) {         \
312                     strcpy(dest, ent);                  \
313                     dest += sizeof(ent) - 1;            \
314                 }                                       \
315                 else {                                  \
316                     *dest = 0;                          \
317                     return (dest+sizeof(ent)-begin);    \
318                 }                                       \
319                 ++src;                                  \
320                 break;
321
322             MAP_ENTITY('>', "&gt;");
323             MAP_ENTITY('<', "&lt;");
324             MAP_ENTITY('\'', "&apos;");
325             MAP_ENTITY('"', "&quot;");
326             MAP_ENTITY('&', "&amp;");
327
328             // not strictly necessary, but allows handling of comments without
329             // having to explicitly look for `--'
330             MAP_ENTITY('-', "&#x002D;");
331
332 #undef MAP_ENTITY
333
334             case 0:
335                 *dest = 0;
336                 return (dest-begin);
337
338             default:
339                 *dest = *src;
340                 ++dest;
341                 ++src;
342                 break;
343         }
344     }
345
346     // If we get here, dest was completely filled (dest == end)
347     *(dest-1) = 0;
348     return (dest-begin);
349 }
350
351 /*
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.
354 */
355 int QXmlTestLogger::xmlCdata(QTestCharBuffer *destBuf, char const* src, size_t n)
356 {
357     if (!n) return 0;
358
359     char *dest = destBuf->data();
360
361     if (!src || n == 1) {
362         *dest = 0;
363         return 0;
364     }
365
366     static char const CDATA_END[] = "]]>";
367     static char const CDATA_END_ESCAPED[] = "]]]><![CDATA[]>";
368
369     char* begin = dest;
370     char* end = dest + n;
371     while (dest < end) {
372         if (!*src) {
373             *dest = 0;
374             return (dest-begin);
375         }
376
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;
382             }
383             else {
384                 *dest = 0;
385                 return (dest+sizeof(CDATA_END_ESCAPED)-begin);
386             }
387             continue;
388         }
389
390         *dest = *src;
391         ++src;
392         ++dest;
393     }
394
395     // If we get here, dest was completely filled (dest == end)
396     *(dest-1) = 0;
397     return (dest-begin);
398 }
399
400 typedef int (*StringFormatFunction)(QTestCharBuffer*,char const*,size_t);
401
402 /*
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.
405 */
406 int allocateStringFn(QTestCharBuffer* str, char const* src, StringFormatFunction func)
407 {
408     static const int MAXSIZE = 1024*1024*2;
409
410     int size = str->size();
411
412     int res = 0;
413
414     for (;;) {
415         res = func(str, src, size);
416         str->data()[size - 1] = '\0';
417         if (res < size) {
418             // We succeeded or fatally failed
419             break;
420         }
421         // buffer wasn't big enough, try again
422         size *= 2;
423         if (size > MAXSIZE) {
424             break;
425         }
426         if (!str->reset(size))
427             break; // ran out of memory - bye
428     }
429
430     return res;
431 }
432
433 int QXmlTestLogger::xmlQuote(QTestCharBuffer* str, char const* src)
434 {
435     return allocateStringFn(str, src, QXmlTestLogger::xmlQuote);
436 }
437
438 int QXmlTestLogger::xmlCdata(QTestCharBuffer* str, char const* src)
439 {
440     return allocateStringFn(str, src, QXmlTestLogger::xmlCdata);
441 }
442
443 QT_END_NAMESPACE