Qt 4.8
qxmltestlogger.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 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 
53 
54 namespace QTest {
55 
57  {
58  switch (type) {
60  return "warn";
62  return "system";
64  return "qdebug";
66  return "qwarn";
68  return "qfatal";
70  return "skip";
72  return "info";
73  }
74  return "??????";
75  }
76 
78  {
79  switch (type) {
81  return "pass";
83  return "xfail";
85  return "fail";
87  return "xpass";
88  }
89  return "??????";
90  }
91 
92 }
93 
94 
96  :xmlmode(mode), randomSeed(0), hasRandomSeed(false)
97 {
98 
99 }
100 
102 {
103 }
104 
106 {
108  QTestCharBuffer buf;
109 
111  QTestCharBuffer quotedTc;
113  QTest::qt_asprintf(&buf,
114  "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
115  "<TestCase name=\"%s\">\n", quotedTc.constData());
116  outputString(buf.constData());
117  }
118 
119  if (hasRandomSeed) {
120  QTest::qt_asprintf(&buf,
121  "<Environment>\n"
122  " <QtVersion>%s</QtVersion>\n"
123  " <QTestVersion>" QTEST_VERSION_STR "</QTestVersion>\n"
124  " <RandomSeed>%d</RandomSeed>\n"
125  "</Environment>\n", qVersion(), randomSeed);
126  } else {
127  QTest::qt_asprintf(&buf,
128  "<Environment>\n"
129  " <QtVersion>%s</QtVersion>\n"
130  " <QTestVersion>" QTEST_VERSION_STR "</QTestVersion>\n"
131  "</Environment>\n", qVersion());
132  }
133  outputString(buf.constData());
134 }
135 
137 {
139  outputString("</TestCase>\n");
140  }
141 
143 }
144 
145 void QXmlTestLogger::enterTestFunction(const char *function)
146 {
147  QTestCharBuffer buf;
148  QTestCharBuffer quotedFunction;
149  xmlQuote(&quotedFunction, function);
150  QTest::qt_asprintf(&buf, "<TestFunction name=\"%s\">\n", quotedFunction.constData());
151  outputString(buf.constData());
152 }
153 
155 {
156  outputString("</TestFunction>\n");
157 }
158 
159 namespace QTest
160 {
161 
162 inline static bool isEmpty(const char *str)
163 {
164  return !str || !str[0];
165 }
166 
167 static const char *incidentFormatString(bool noDescription, bool noTag)
168 {
169  if (noDescription) {
170  if (noTag)
171  return "<Incident type=\"%s\" file=\"%s\" line=\"%d\" />\n";
172  else
173  return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
174  " <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
175  "</Incident>\n";
176  } else {
177  if (noTag)
178  return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
179  " <Description><![CDATA[%s%s%s%s]]></Description>\n"
180  "</Incident>\n";
181  else
182  return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
183  " <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
184  " <Description><![CDATA[%s]]></Description>\n"
185  "</Incident>\n";
186  }
187 }
188 
189 static const char *benchmarkResultFormatString()
190 {
191  return "<BenchmarkResult metric=\"%s\" tag=\"%s\" value=\"%s\" iterations=\"%d\" />\n";
192 }
193 
194 static const char *messageFormatString(bool noDescription, bool noTag)
195 {
196  if (noDescription) {
197  if (noTag)
198  return "<Message type=\"%s\" file=\"%s\" line=\"%d\" />\n";
199  else
200  return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
201  " <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
202  "</Message>\n";
203  } else {
204  if (noTag)
205  return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
206  " <Description><![CDATA[%s%s%s%s]]></Description>\n"
207  "</Message>\n";
208  else
209  return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
210  " <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
211  " <Description><![CDATA[%s]]></Description>\n"
212  "</Message>\n";
213  }
214 }
215 
216 } // namespace
217 
218 void QXmlTestLogger::addIncident(IncidentTypes type, const char *description,
219  const char *file, int line)
220 {
221  QTestCharBuffer buf;
222  const char *tag = QTestResult::currentDataTag();
223  const char *gtag = QTestResult::currentGlobalDataTag();
224  const char *filler = (tag && gtag) ? ":" : "";
225  const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag);
226 
227  QTestCharBuffer quotedFile;
228  QTestCharBuffer cdataGtag;
229  QTestCharBuffer cdataTag;
230  QTestCharBuffer cdataDescription;
231 
232  xmlQuote(&quotedFile, file);
233  xmlCdata(&cdataGtag, gtag);
234  xmlCdata(&cdataTag, tag);
235  xmlCdata(&cdataDescription, description);
236 
237  QTest::qt_asprintf(&buf,
238  QTest::incidentFormatString(QTest::isEmpty(description), notag),
240  quotedFile.constData(), line,
241  cdataGtag.constData(),
242  filler,
243  cdataTag.constData(),
244  cdataDescription.constData());
245 
246  outputString(buf.constData());
247 }
248 
250 {
251  QTestCharBuffer buf;
252  QTestCharBuffer quotedMetric;
253  QTestCharBuffer quotedTag;
254 
255  xmlQuote(&quotedMetric,
256  benchmarkMetricName(result.metric));
257  xmlQuote(&quotedTag, result.context.tag.toAscii().constData());
258 
260  &buf,
262  quotedMetric.constData(),
263  quotedTag.constData(),
264  QByteArray::number(result.value).constData(), //no 64-bit qt_snprintf support
265  result.iterations);
266  outputString(buf.constData());
267 }
268 
269 void QXmlTestLogger::addMessage(MessageTypes type, const char *message,
270  const char *file, int line)
271 {
272  QTestCharBuffer buf;
273  const char *tag = QTestResult::currentDataTag();
274  const char *gtag = QTestResult::currentGlobalDataTag();
275  const char *filler = (tag && gtag) ? ":" : "";
276  const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag);
277 
278  QTestCharBuffer quotedFile;
279  QTestCharBuffer cdataGtag;
280  QTestCharBuffer cdataTag;
281  QTestCharBuffer cdataDescription;
282 
283  xmlQuote(&quotedFile, file);
284  xmlCdata(&cdataGtag, gtag);
285  xmlCdata(&cdataTag, tag);
286  xmlCdata(&cdataDescription, message);
287 
288  QTest::qt_asprintf(&buf,
291  quotedFile.constData(), line,
292  cdataGtag.constData(),
293  filler,
294  cdataTag.constData(),
295  cdataDescription.constData());
296 
297  outputString(buf.constData());
298 }
299 
300 /*
301  Copy up to n characters from the src string into dest, escaping any special
302  XML characters as necessary so that dest is suitable for use in an XML
303  quoted attribute string.
304 */
305 int QXmlTestLogger::xmlQuote(QTestCharBuffer* destBuf, char const* src, size_t n)
306 {
307  if (n == 0) return 0;
308 
309  char *dest = destBuf->data();
310  *dest = 0;
311  if (!src) return 0;
312 
313  char* begin = dest;
314  char* end = dest + n;
315 
316  while (dest < end) {
317  switch (*src) {
318 
319 #define MAP_ENTITY(chr, ent) \
320  case chr: \
321  if (dest + sizeof(ent) < end) { \
322  strcpy(dest, ent); \
323  dest += sizeof(ent) - 1; \
324  } \
325  else { \
326  *dest = 0; \
327  return (dest+sizeof(ent)-begin); \
328  } \
329  ++src; \
330  break;
331 
332  MAP_ENTITY('>', "&gt;");
333  MAP_ENTITY('<', "&lt;");
334  MAP_ENTITY('\'', "&apos;");
335  MAP_ENTITY('"', "&quot;");
336  MAP_ENTITY('&', "&amp;");
337 
338  // not strictly necessary, but allows handling of comments without
339  // having to explicitly look for `--'
340  MAP_ENTITY('-', "&#x002D;");
341 
342 #undef MAP_ENTITY
343 
344  case 0:
345  *dest = 0;
346  return (dest-begin);
347 
348  default:
349  *dest = *src;
350  ++dest;
351  ++src;
352  break;
353  }
354  }
355 
356  // If we get here, dest was completely filled (dest == end)
357  *(dest-1) = 0;
358  return (dest-begin);
359 }
360 
361 /*
362  Copy up to n characters from the src string into dest, escaping any
363  special strings such that dest is suitable for use in an XML CDATA section.
364 */
365 int QXmlTestLogger::xmlCdata(QTestCharBuffer *destBuf, char const* src, size_t n)
366 {
367  if (!n) return 0;
368 
369  char *dest = destBuf->data();
370 
371  if (!src || n == 1) {
372  *dest = 0;
373  return 0;
374  }
375 
376  static char const CDATA_END[] = "]]>";
377  static char const CDATA_END_ESCAPED[] = "]]]><![CDATA[]>";
378 
379  char* begin = dest;
380  char* end = dest + n;
381  while (dest < end) {
382  if (!*src) {
383  *dest = 0;
384  return (dest-begin);
385  }
386 
387  if (!strncmp(src, CDATA_END, sizeof(CDATA_END)-1)) {
388  if (dest + sizeof(CDATA_END_ESCAPED) < end) {
389  strcpy(dest, CDATA_END_ESCAPED);
390  src += sizeof(CDATA_END)-1;
391  dest += sizeof(CDATA_END_ESCAPED) - 1;
392  }
393  else {
394  *dest = 0;
395  return (dest+sizeof(CDATA_END_ESCAPED)-begin);
396  }
397  continue;
398  }
399 
400  *dest = *src;
401  ++src;
402  ++dest;
403  }
404 
405  // If we get here, dest was completely filled (dest == end)
406  *(dest-1) = 0;
407  return (dest-begin);
408 }
409 
410 typedef int (*StringFormatFunction)(QTestCharBuffer*,char const*,size_t);
411 
412 /*
413  A wrapper for string functions written to work with a fixed size buffer so they can be called
414  with a dynamically allocated buffer.
415 */
416 int allocateStringFn(QTestCharBuffer* str, char const* src, StringFormatFunction func)
417 {
418  static const int MAXSIZE = 1024*1024*2;
419 
420  int size = str->size();
421 
422  int res = 0;
423 
424  for (;;) {
425  res = func(str, src, size);
426  str->data()[size - 1] = '\0';
427  if (res < size) {
428  // We succeeded or fatally failed
429  break;
430  }
431  // buffer wasn't big enough, try again
432  size *= 2;
433  if (size > MAXSIZE) {
434  break;
435  }
436  if (!str->reset(size))
437  break; // ran out of memory - bye
438  }
439 
440  return res;
441 }
442 
443 int QXmlTestLogger::xmlQuote(QTestCharBuffer* str, char const* src)
444 {
445  return allocateStringFn(str, src, QXmlTestLogger::xmlQuote);
446 }
447 
448 int QXmlTestLogger::xmlCdata(QTestCharBuffer* str, char const* src)
449 {
450  return allocateStringFn(str, src, QXmlTestLogger::xmlCdata);
451 }
452 
454 {
455  randomSeed = seed;
456  hasRandomSeed = true;
457 }
458 
QTest::QBenchmarkMetric metric
Definition: qbenchmark_p.h:100
static const char * xmlIncidentType2String(QAbstractTestLogger::IncidentTypes type)
int type
Definition: qmetatype.cpp:239
static void outputString(const char *msg)
static const char * xmlMessageType2String(QAbstractTestLogger::MessageTypes type)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void registerRandomSeed(unsigned int seed)
void enterTestFunction(const char *function)
QXmlTestLogger(XmlMode mode=Complete)
int qt_asprintf(QTestCharBuffer *str, const char *format,...)
void addBenchmarkResult(const QBenchmarkResult &result)
static int xmlCdata(QTestCharBuffer *dest, char const *src)
int allocateStringFn(QTestCharBuffer *str, char const *src, StringFormatFunction func)
static const char * incidentFormatString(bool noDescription, bool noTag)
Q_CORE_EXPORT const char * qVersion()
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static const char * currentTestObjectName()
static bool isEmpty(const char *str)
void addIncident(IncidentTypes type, const char *description, const char *file=0, int line=0)
const char * constData() const
#define QTEST_VERSION_STR
Definition: qtest_global.h:78
void addMessage(MessageTypes type, const char *message, const char *file=0, int line=0)
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
static const char * currentGlobalDataTag()
int(* StringFormatFunction)(QTestCharBuffer *, char const *, size_t)
static const char * benchmarkResultFormatString()
static const char * messageFormatString(bool noDescription, bool noTag)
const char * benchmarkMetricName(QBenchmarkMetric metric)
static unsigned int seed
Definition: qtestcase.cpp:943
static int xmlQuote(QTestCharBuffer *dest, char const *src)
#define MAP_ENTITY(chr, ent)
QByteArray toAscii() const Q_REQUIRED_RESULT
Returns an 8-bit representation of the string as a QByteArray.
Definition: qstring.cpp:4014
static const char * currentDataTag()
bool reset(int newSize)
QBenchmarkContext context
Definition: qbenchmark_p.h:97
static const KeyPair *const end
static QByteArray number(int, int base=10)
Returns a byte array containing the string equivalent of the number n to base base (10 by default)...
The QTest namespace contains all the functions and declarations that are related to the QTestLib tool...
unsigned int randomSeed