Qt 4.8
qplaintestlogger.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 "QtTest/private/qtestresult_p.h"
43 #include "QtTest/qtestassert.h"
44 #include "QtTest/private/qtestlog_p.h"
45 #include "QtTest/private/qplaintestlogger_p.h"
46 #include "QtTest/private/qbenchmark_p.h"
47 #include "QtTest/private/qbenchmarkmetric_p.h"
48 
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 
54 #ifdef Q_OS_WIN
55 #include "windows.h"
56 #endif
57 
58 #if defined(Q_OS_SYMBIAN)
59 #include <e32debug.h>
60 #endif
61 
62 #ifdef Q_OS_WINCE
63 #include <QtCore/QString>
64 #endif
65 
66 #include <QtCore/QByteArray>
67 #include <QtCore/qmath.h>
68 
70 
71 namespace QTest {
72 
73 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
74 
75  static CRITICAL_SECTION outputCriticalSection;
76  static HANDLE hConsole = INVALID_HANDLE_VALUE;
77  static WORD consoleAttributes = 0;
78 
79  static const char *qWinColoredMsg(int prefix, int color, const char *msg)
80  {
81  if (!hConsole)
82  return msg;
83 
84  WORD attr = consoleAttributes & ~(FOREGROUND_GREEN | FOREGROUND_BLUE
85  | FOREGROUND_RED | FOREGROUND_INTENSITY);
86  if (prefix)
87  attr |= FOREGROUND_INTENSITY;
88  if (color == 32)
89  attr |= FOREGROUND_GREEN;
90  if (color == 36)
91  attr |= FOREGROUND_BLUE | FOREGROUND_GREEN;
92  if (color == 31)
93  attr |= FOREGROUND_RED | FOREGROUND_INTENSITY;
94  if (color == 37)
95  attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
96  if (color == 33)
97  attr |= FOREGROUND_RED | FOREGROUND_GREEN;
98  SetConsoleTextAttribute(hConsole, attr);
99  printf(msg);
100  SetConsoleTextAttribute(hConsole, consoleAttributes);
101  return "";
102  }
103 
104 # define COLORED_MSG(prefix, color, msg) colored ? qWinColoredMsg(prefix, color, msg) : msg
105 #else
106 # define COLORED_MSG(prefix, color, msg) colored && QAbstractTestLogger::isTtyOutput() ? "\033["#prefix";"#color"m" msg "\033[0m" : msg
107 #endif
108 
110  {
111  static bool colored = (!qgetenv("QTEST_COLORED").isEmpty());
112  switch (type) {
114  return COLORED_MSG(0, 32, "PASS "); //green
116  return COLORED_MSG(1, 32, "XFAIL "); //light green
118  return COLORED_MSG(0, 31, "FAIL! "); //red
120  return COLORED_MSG(0, 31, "XPASS "); //red, too
121  }
122  return "??????";
123  }
124 
125  static const char *benchmarkResult2String()
126  {
127  static bool colored = (!qgetenv("QTEST_COLORED").isEmpty());
128  return COLORED_MSG(0, 36, "RESULT "); // cyan
129  }
130 
132  {
133 #ifdef Q_OS_WIN
134  static bool colored = (!qgetenv("QTEST_COLORED").isEmpty());
135 #else
136  static bool colored = ::getenv("QTEST_COLORED");
137 #endif
138  switch (type) {
140  return COLORED_MSG(0, 37, "SKIP "); //white
142  return COLORED_MSG(0, 33, "WARNING"); // yellow
144  return COLORED_MSG(1, 33, "QWARN ");
146  return COLORED_MSG(1, 33, "QDEBUG ");
148  return COLORED_MSG(1, 33, "QSYSTEM");
150  return COLORED_MSG(0, 31, "QFATAL "); // red
152  return "INFO "; // no coloring
153  }
154  return "??????";
155  }
156 
157  static void outputMessage(const char *str)
158  {
159 #if defined(Q_OS_WINCE)
160  QString strUtf16 = QString::fromLatin1(str);
161  const int maxOutputLength = 255;
162  do {
163  QString tmp = strUtf16.left(maxOutputLength);
164  OutputDebugString((wchar_t*)tmp.utf16());
165  strUtf16.remove(0, maxOutputLength);
166  } while (!strUtf16.isEmpty());
168 #elif defined(Q_OS_WIN)
169  EnterCriticalSection(&outputCriticalSection);
170  // OutputDebugString is not threadsafe
171  OutputDebugStringA(str);
172  LeaveCriticalSection(&outputCriticalSection);
173 #elif defined(Q_OS_SYMBIAN)
174  // RDebug::Print has a cap of 256 characters so break it up
175  TPtrC8 ptr(reinterpret_cast<const TUint8*>(str));
176  _LIT(format, "[QTestLib] %S");
177  const int maxBlockSize = 256 - ((const TDesC &)format).Length();
178  HBufC* hbuffer = HBufC::New(maxBlockSize);
179  if(hbuffer) {
180  for (int i = 0; i < ptr.Length(); i += maxBlockSize) {
181  int size = Min(maxBlockSize, ptr.Length() - i);
182  hbuffer->Des().Copy(ptr.Mid(i, size));
183  RDebug::Print(format, hbuffer);
184  }
185  delete hbuffer;
186  }
187  else {
188  // fast, no allocations, but truncates silently
189  RDebug::RawPrint(format);
190  TPtrC8 ptr(reinterpret_cast<const TUint8*>(str));
191  RDebug::RawPrint(ptr);
192  RDebug::RawPrint(_L8("\n"));
193  }
194 #endif
196  }
197 
198  static void printMessage(const char *type, const char *msg, const char *file = 0, int line = 0)
199  {
200  QTEST_ASSERT(type);
201  QTEST_ASSERT(msg);
202 
203  QTestCharBuffer buf;
204 
206  : "UnknownTestFunc";
207  const char *tag = QTestResult::currentDataTag() ? QTestResult::currentDataTag() : "";
208  const char *gtag = QTestResult::currentGlobalDataTag()
210  : "";
211  const char *filler = (tag[0] && gtag[0]) ? ":" : "";
212  if (file) {
213  QTest::qt_asprintf(&buf, "%s: %s::%s(%s%s%s)%s%s\n"
214 #ifdef Q_OS_WIN
215  "%s(%d) : failure location\n"
216 #else
217  " Loc: [%s(%d)]\n"
218 #endif
219  , type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag,
220  msg[0] ? " " : "", msg, file, line);
221  } else {
222  QTest::qt_asprintf(&buf, "%s: %s::%s(%s%s%s)%s%s\n",
223  type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag,
224  msg[0] ? " " : "", msg);
225  }
226  // In colored mode, printf above stripped our nonprintable control characters.
227  // Put them back.
228  memcpy(buf.data(), type, strlen(type));
229  outputMessage(buf.data());
230  }
231 
232  template <typename T>
233  static int countSignificantDigits(T num)
234  {
235  if (num <= 0)
236  return 0;
237 
238  int digits = 0;
239  qreal divisor = 1;
240 
241  while (num / divisor >= 1) {
242  divisor *= 10;
243  ++digits;
244  }
245 
246  return digits;
247  }
248 
249  // Pretty-prints a benchmark result using the given number of digits.
250  template <typename T> QString formatResult(T number, int significantDigits)
251  {
252  if (number < T(0))
253  return QLatin1String("NAN");
254  if (number == T(0))
255  return QLatin1String("0");
256 
257  QString beforeDecimalPoint = QString::number(qint64(number), 'f', 0);
258  QString afterDecimalPoint = QString::number(number, 'f', 20);
259  afterDecimalPoint.remove(0, beforeDecimalPoint.count() + 1);
260 
261  int beforeUse = qMin(beforeDecimalPoint.count(), significantDigits);
262  int beforeRemove = beforeDecimalPoint.count() - beforeUse;
263 
264  // Replace insignificant digits before the decimal point with zeros.
265  beforeDecimalPoint.chop(beforeRemove);
266  for (int i = 0; i < beforeRemove; ++i) {
267  beforeDecimalPoint.append(QLatin1Char('0'));
268  }
269 
270  int afterUse = significantDigits - beforeUse;
271 
272  // leading zeroes after the decimal point does not count towards the digit use.
273  if (beforeDecimalPoint == QLatin1String("0") && afterDecimalPoint.isEmpty() == false) {
274  ++afterUse;
275 
276  int i = 0;
277  while (i < afterDecimalPoint.count() && afterDecimalPoint.at(i) == QLatin1Char('0')) {
278  ++i;
279  }
280 
281  afterUse += i;
282  }
283 
284  int afterRemove = afterDecimalPoint.count() - afterUse;
285  afterDecimalPoint.chop(afterRemove);
286 
287  QChar separator = QLatin1Char(',');
288  QChar decimalPoint = QLatin1Char('.');
289 
290  // insert thousands separators
291  int length = beforeDecimalPoint.length();
292  for (int i = beforeDecimalPoint.length() -1; i >= 1; --i) {
293  if ((length - i) % 3 == 0)
294  beforeDecimalPoint.insert(i, separator);
295  }
296 
297  QString print;
298  print = beforeDecimalPoint;
299  if (afterUse > 0)
300  print.append(decimalPoint);
301 
302  print += afterDecimalPoint;
303 
304 
305  return print;
306  }
307 
308  template <typename T>
309  int formatResult(char * buffer, int bufferSize, T number, int significantDigits)
310  {
311  QString result = formatResult(number, significantDigits);
312  qstrncpy(buffer, result.toAscii().constData(), bufferSize);
313  int size = result.count();
314  return size;
315  }
316 
317 // static void printBenchmarkResult(const char *bmtag, int value, int iterations)
318  static void printBenchmarkResult(const QBenchmarkResult &result)
319  {
320  const char *bmtag = QTest::benchmarkResult2String();
321 
322  char buf1[1024];
324  buf1, sizeof(buf1), "%s: %s::%s",
325  bmtag,
327  result.context.slotName.toAscii().data());
328 
329  char bufTag[1024];
330  bufTag[0] = 0;
331  QByteArray tag = result.context.tag.toAscii();
332  if (tag.isEmpty() == false) {
333  QTest::qt_snprintf(bufTag, sizeof(bufTag), ":\"%s\"", tag.data());
334  }
335 
336 
337  char fillFormat[8];
338  int fillLength = 5;
340  fillFormat, sizeof(fillFormat), ":\n%%%ds", fillLength);
341  char fill[1024];
342  QTest::qt_snprintf(fill, sizeof(fill), fillFormat, "");
343 
344  const char * unitText = QTest::benchmarkMetricUnit(result.metric);
345 
346  qreal valuePerIteration = qreal(result.value) / qreal(result.iterations);
347  char resultBuffer[100] = "";
348  formatResult(resultBuffer, 100, valuePerIteration, countSignificantDigits(result.value));
349 
350  char buf2[1024];
352  buf2, sizeof(buf2), "%s %s",
353  resultBuffer,
354  unitText);
355 
356  char buf2_[1024];
357  QByteArray iterationText = " per iteration";
358  Q_ASSERT(result.iterations > 0);
360  buf2_,
361  sizeof(buf2_), "%s",
362  iterationText.data());
363 
364  char buf3[1024];
365  Q_ASSERT(result.iterations > 0);
366  formatResult(resultBuffer, 100, result.value, countSignificantDigits(result.value));
368  buf3, sizeof(buf3), " (total: %s, iterations: %d)",
369  resultBuffer,
370  result.iterations);
371 
372  char buf[1024];
373 
374  if (result.setByMacro) {
376  buf, sizeof(buf), "%s%s%s%s%s%s\n", buf1, bufTag, fill, buf2, buf2_, buf3);
377  } else {
378  QTest::qt_snprintf(buf, sizeof(buf), "%s%s%s%s\n", buf1, bufTag, fill, buf2);
379  }
380 
381  memcpy(buf, bmtag, strlen(bmtag));
382  outputMessage(buf);
383  }
384 }
385 
387 : randomSeed(9), hasRandomSeed(false)
388 {
389 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
390  InitializeCriticalSection(&QTest::outputCriticalSection);
391  QTest::hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
392  if (QTest::hConsole != INVALID_HANDLE_VALUE) {
393  CONSOLE_SCREEN_BUFFER_INFO info;
394  if (GetConsoleScreenBufferInfo(QTest::hConsole, &info)) {
395  QTest::consoleAttributes = info.wAttributes;
396  } else {
397  QTest::hConsole = INVALID_HANDLE_VALUE;
398  }
399  }
400 #endif
401 }
402 
404 {
405 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
406  DeleteCriticalSection(&QTest::outputCriticalSection);
407 #endif
408 }
409 
411 {
413 
414  char buf[1024];
415  if (QTestLog::verboseLevel() < 0) {
416  QTest::qt_snprintf(buf, sizeof(buf), "Testing %s\n",
418  } else {
419  if (hasRandomSeed) {
420  QTest::qt_snprintf(buf, sizeof(buf),
421  "********* Start testing of %s *********\n"
422  "Config: Using QTest library " QTEST_VERSION_STR
423  ", Qt %s, Random seed %d\n", QTestResult::currentTestObjectName(), qVersion(), randomSeed);
424  } else {
425  QTest::qt_snprintf(buf, sizeof(buf),
426  "********* Start testing of %s *********\n"
427  "Config: Using QTest library " QTEST_VERSION_STR
428  ", Qt %s\n", QTestResult::currentTestObjectName(), qVersion());
429  }
430  }
432 }
433 
435 {
436  char buf[1024];
437  if (QTestLog::verboseLevel() < 0) {
438  QTest::qt_snprintf(buf, sizeof(buf), "Totals: %d passed, %d failed, %d skipped\n",
441  } else {
442  QTest::qt_snprintf(buf, sizeof(buf),
443  "Totals: %d passed, %d failed, %d skipped\n"
444  "********* Finished testing of %s *********\n",
447  }
449 
451 }
452 
453 
454 void QPlainTestLogger::enterTestFunction(const char * /*function*/)
455 {
456  if (QTestLog::verboseLevel() >= 1)
458 }
459 
461 {
462 }
463 
464 void QPlainTestLogger::addIncident(IncidentTypes type, const char *description,
465  const char *file, int line)
466 {
467  // suppress PASS in silent mode
469  return;
470 
471  QTest::printMessage(QTest::incidentType2String(type), description, file, line);
472 }
473 
475 {
476 // QTest::printBenchmarkResult(QTest::benchmarkResult2String(), value, iterations);
478 }
479 
481  const char *file, int line)
482 {
483  // suppress PASS in silent mode
485  && QTestLog::verboseLevel() < 0)
486  return;
487 
488  QTest::printMessage(QTest::messageType2String(type), message, file, line);
489 }
490 
492 {
493  randomSeed = seed;
494  hasRandomSeed = true;
495 }
496 
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qstring.cpp:6448
QTest::QBenchmarkMetric metric
Definition: qbenchmark_p.h:100
static const char * currentTestFunction()
static int verboseLevel()
Definition: qtestlog.cpp:363
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
static int countSignificantDigits(T num)
int type
Definition: qmetatype.cpp:239
double qreal
Definition: qglobal.h:1193
static void outputString(const char *msg)
static mach_timebase_info_data_t info
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
const char * benchmarkMetricUnit(QBenchmarkMetric metric)
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
const QChar at(int i) const
Returns the character at the given index position in the string.
Definition: qstring.h:698
static const char * incidentType2String(QAbstractTestLogger::IncidentTypes type)
static int failCount()
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
void chop(int n)
Removes n characters from the end of the string.
Definition: qstring.cpp:4623
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
int qt_asprintf(QTestCharBuffer *str, const char *format,...)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
void addIncident(IncidentTypes type, const char *description, const char *file=0, int line=0)
static const char * outputFileName()
Definition: qtestlog.cpp:389
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
unsigned int randomSeed
void registerRandomSeed(unsigned int seed)
Q_CORE_EXPORT const char * qVersion()
static const char * benchmarkResult2String()
QString formatResult(T number, int significantDigits)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static const char * currentTestObjectName()
static int skipCount()
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
static const char * messageType2String(QAbstractTestLogger::MessageTypes type)
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
void enterTestFunction(const char *function)
const T * ptr(const T &t)
__int64 qint64
Definition: qglobal.h:942
void * HANDLE
Definition: qnamespace.h:1671
int count() const
Definition: qstring.h:103
static void outputMessage(const char *str)
#define QTEST_VERSION_STR
Definition: qtest_global.h:78
void addBenchmarkResult(const QBenchmarkResult &result)
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
int Q_TESTLIB_EXPORT qt_snprintf(char *str, int size, const char *format,...)
Definition: qtestcase.cpp:961
static const char * currentGlobalDataTag()
QString & append(QChar c)
Definition: qstring.cpp:1777
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
static void printMessage(const char *type, const char *msg, const char *file=0, int line=0)
void addMessage(MessageTypes type, const char *message, const char *file=0, int line=0)
static unsigned int seed
Definition: qtestcase.cpp:943
#define QTEST_ASSERT(cond)
Definition: qtestassert.h:53
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()
#define Q_OS_WIN
Definition: qglobal.h:270
static void printBenchmarkResult(const QBenchmarkResult &result)
static int passCount()
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
QString & remove(int i, int len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition: qstring.cpp:1867
QBenchmarkContext context
Definition: qbenchmark_p.h:97
QString & insert(int i, QChar c)
Definition: qstring.cpp:1671
The QTest namespace contains all the functions and declarations that are related to the QTestLib tool...
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
Q_CORE_EXPORT char * qstrncpy(char *dst, const char *src, uint len)
#define COLORED_MSG(prefix, color, msg)
const ushort * utf16() const
Returns the QString as a &#39;\0\&#39;-terminated array of unsigned shorts.
Definition: qstring.cpp:5290