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
qtestlog.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtTest/qtestassert.h>
5
6#include <QtTest/private/qtestlog_p.h>
7#include <QtTest/private/qtestresult_p.h>
8#include <QtTest/private/qabstracttestlogger_p.h>
9#include <QtTest/private/qplaintestlogger_p.h>
10#include <QtTest/private/qcsvbenchmarklogger_p.h>
11#include <QtTest/private/qjunittestlogger_p.h>
12#include <QtTest/private/qxmltestlogger_p.h>
13#include <QtTest/private/qteamcitylogger_p.h>
14#include <QtTest/private/qtaptestlogger_p.h>
15#if defined(HAVE_XCTEST)
16#include <QtTest/private/qxctestlogger_p.h>
17#endif
18
19#if defined(Q_OS_DARWIN)
20#include <QtTest/private/qappletestlogger_p.h>
21#endif
22
23#include <QtCore/qatomic.h>
24#include <QtCore/qbytearray.h>
25#include <QtCore/qelapsedtimer.h>
26#include <QtCore/qlist.h>
27#include <QtCore/qmutex.h>
28#include <QtCore/qvariant.h>
29#if QT_CONFIG(regularexpression)
30#include <QtCore/QRegularExpression>
31#endif
32
33#include <stdlib.h>
34#include <string.h>
35#include <limits.h>
36#include <vector>
37
38#include <vector>
39#include <memory>
40
42
43using namespace Qt::StringLiterals;
44
45static void saveCoverageTool(const char * appname, bool testfailed, bool installedTestCoverage)
46{
47#ifdef __COVERAGESCANNER__
48# if QT_CONFIG(testlib_selfcover)
49 __coveragescanner_teststate(QTestLog::failCount() > 0 ? "FAILED" :
50 QTestLog::passCount() > 0 ? "PASSED" : "SKIPPED");
51# else
52 if (!installedTestCoverage)
53 return;
54 // install again to make sure the filename is correct.
55 // without this, a plugin or similar may have changed the filename.
56 __coveragescanner_install(appname);
57 __coveragescanner_teststate(testfailed ? "FAILED" : "PASSED");
58 __coveragescanner_save();
59 __coveragescanner_testname("");
60 __coveragescanner_clear();
61 unsetenv("QT_TESTCOCOON_ACTIVE");
62# endif // testlib_selfcover
63#else
64 Q_UNUSED(appname);
65 Q_UNUSED(testfailed);
66 Q_UNUSED(installedTestCoverage);
67#endif
68}
69
72
73#define FOREACH_TEST_LOGGER for (const auto &logger : std::as_const(*QTest::loggers()))
74
75namespace QTest {
76
77 int fails = 0;
78 int passes = 0;
79 int skips = 0;
80 int blacklists = 0;
82
84 {
85 inline IgnoreResultList(QtMsgType tp, const QVariant &patternIn)
86 : type(tp), pattern(patternIn) {}
87
88 static inline void clearList(IgnoreResultList *&list)
89 {
90 while (list) {
91 IgnoreResultList *current = list;
92 list = list->next;
93 delete current;
94 }
95 }
96
97 static void append(IgnoreResultList *&list, QtMsgType type, const QVariant &patternIn)
98 {
100
101 if (!list) {
102 list = item;
103 return;
104 }
105 IgnoreResultList *last = list;
106 for ( ; last->next; last = last->next) ;
107 last->next = item;
108 }
109
110 static bool stringsMatch(const QString &expected, const QString &actual)
111 {
112 if (expected == actual)
113 return true;
114
115 // ignore an optional whitespace at the end of str
116 // (the space was added automatically by ~QDebug() until Qt 5.3,
117 // so autotests still might expect it)
118 if (expected.endsWith(u' '))
119 return actual == QStringView{expected}.left(expected.size() - 1);
120
121 return false;
122 }
123
124 inline bool matches(QtMsgType tp, const QString &message) const
125 {
126 return tp == type
127 && (pattern.userType() == QMetaType::QString ?
128 stringsMatch(pattern.toString(), message) :
129#if QT_CONFIG(regularexpression)
130 pattern.toRegularExpression().match(message).hasMatch());
131#else
132 false);
133#endif
134 }
135
139 };
140
142 Q_CONSTINIT static QBasicMutex mutex;
143
144 static std::vector<QVariant> failOnWarningList;
145
146 Q_GLOBAL_STATIC(std::vector<std::unique_ptr<QAbstractTestLogger>>, loggers)
147
148 static int verbosity = 0;
149 static int maxWarnings = 2002;
150 static bool installedTestCoverage = true;
151
153
155 {
156 const QMutexLocker mutexLocker(&QTest::mutex);
157
158 if (!ignoreResultList)
159 return false;
160 IgnoreResultList *last = nullptr;
162 while (list) {
163 if (list->matches(type, message)) {
164 // remove the item from the list
165 if (last)
166 last->next = list->next;
167 else
168 ignoreResultList = list->next;
169
170 delete list;
171 return true;
172 }
173
174 last = list;
175 list = list->next;
176 }
177 return false;
178 }
179
181 {
182 // failOnWarning can be called multiple times per test function, so let
183 // each call cause a failure if required.
184 for (const auto &pattern : failOnWarningList) {
185 if (pattern.metaType() == QMetaType::fromType<QString>()) {
186 if (message != pattern.toString())
187 continue;
188 }
189#if QT_CONFIG(regularexpression)
190 else if (pattern.metaType() == QMetaType::fromType<QRegularExpression>()) {
191 if (!message.contains(pattern.toRegularExpression()))
192 continue;
193 }
194#endif
195
196 const size_t maxMsgLen = 1024;
197 char msg[maxMsgLen] = {'\0'};
198 qsnprintf(msg, maxMsgLen, "Received a warning that resulted in a failure:\n%s",
200 QTestResult::addFailure(msg, context.file, context.line);
201 return true;
202 }
203 return false;
204 }
205
207 {
209
210 if (!QTestLog::hasLoggers()) {
211 // if this goes wrong, something is seriously broken.
214 }
215
217 // the message is expected, so just swallow it.
218 return;
219 }
220
222 return;
223
224 if (type != QtFatalMsg) {
225 if (counter.loadRelaxed() <= 0)
226 return;
227
228 if (!counter.deref()) {
230 logger->addMessage(QAbstractTestLogger::Warn,
231 QStringLiteral("Maximum amount of warnings exceeded. Use -maxwarnings to override."));
232 }
233 return;
234 }
235 }
236
238 logger->addMessage(type, context, message);
239
240 if (type == QtFatalMsg) {
241 /* Right now, we're inside the custom message handler and we're
242 * being qt_message_output in qglobal.cpp. After we return from
243 * this function, it will proceed with calling exit() and abort()
244 * and hence crash. Therefore, we call these logging functions such
245 * that we wrap up nicely, and in particular produce well-formed XML. */
246 QTestResult::addFailure("Received a fatal error.", context.file, context.line);
249 }
250 }
251}
252
253void QTestLog::enterTestFunction(const char* function)
254{
255 elapsedFunctionTime.restart();
256 if (printAvailableTags)
257 return;
258
259 QTEST_ASSERT(function);
260
262 logger->enterTestFunction(function);
263}
264
266{
268
270 logger->enterTestData(data);
271}
272
274{
275 const QMutexLocker mutexLocker(&QTest::mutex);
276 int i = 0;
278 while (list) {
279 ++i;
280 list = list->next;
281 }
282 return i;
283}
284
286{
287 if (printAvailableTags)
288 return;
289
291 logger->leaveTestFunction();
292}
293
295{
296 const QMutexLocker mutexLocker(&QTest::mutex);
299 while (list) {
300 if (list->pattern.userType() == QMetaType::QString) {
301 message = "Did not receive message: \"%1\""_L1.arg(list->pattern.toString());
302 } else {
303#if QT_CONFIG(regularexpression)
304 message = "Did not receive any message matching: \"%1\""_L1.arg(
305 list->pattern.toRegularExpression().pattern());
306#endif
307 }
309 logger->addMessage(QAbstractTestLogger::Info, message);
310
311 list = list->next;
312 }
313}
314
320
325
332
333void QTestLog::addPass(const char *msg)
334{
335 if (printAvailableTags)
336 return;
337
338 QTEST_ASSERT(msg);
340
343
345 logger->addIncident(QAbstractTestLogger::Pass, msg);
346}
347
348void QTestLog::addFail(const char *msg, const char *file, int line)
349{
350 QTEST_ASSERT(msg);
351
353 ++QTest::fails;
354 } else {
355 // After an XPASS/Continue, or fail or skip in a function the test
356 // calls, we can subsequently fail.
359 }
360 // It is up to particular loggers to decide whether to report such
361 // subsequent failures; they may carry useful information.
362
365 logger->addIncident(QAbstractTestLogger::Fail, msg, file, line);
366}
367
368void QTestLog::addXFail(const char *msg, const char *file, int line)
369{
370 QTEST_ASSERT(msg);
371
372 // Will be counted in addPass() if we get there.
373
375 logger->addIncident(QAbstractTestLogger::XFail, msg, file, line);
376}
377
378void QTestLog::addXPass(const char *msg, const char *file, int line)
379{
380 QTEST_ASSERT(msg);
381
383 ++QTest::fails;
384 } else {
385 // After an XPASS/Continue, we can subsequently XPASS again.
386 // Likewise after a fail or skip in a function called by the test.
389 }
390
393 logger->addIncident(QAbstractTestLogger::XPass, msg, file, line);
394}
395
396void QTestLog::addBPass(const char *msg)
397{
398 QTEST_ASSERT(msg);
400
401 ++QTest::blacklists; // Not passes ?
403
405 logger->addIncident(QAbstractTestLogger::BlacklistedPass, msg);
406}
407
408void QTestLog::addBFail(const char *msg, const char *file, int line)
409{
410 QTEST_ASSERT(msg);
411
414 } else {
415 // After a BXPASS/Continue, we can subsequently fail.
416 // Likewise after a fail or skip in a function called by a test.
419 }
420
423 logger->addIncident(QAbstractTestLogger::BlacklistedFail, msg, file, line);
424}
425
426void QTestLog::addBXPass(const char *msg, const char *file, int line)
427{
428 QTEST_ASSERT(msg);
429
432 } else {
433 // After a BXPASS/Continue, we may BXPASS again.
434 // Likewise after a fail or skip in a function called by a test.
437 }
438
441 logger->addIncident(QAbstractTestLogger::BlacklistedXPass, msg, file, line);
442}
443
444void QTestLog::addBXFail(const char *msg, const char *file, int line)
445{
446 QTEST_ASSERT(msg);
447
448 // Will be counted in addBPass() if we get there.
449
451 logger->addIncident(QAbstractTestLogger::BlacklistedXFail, msg, file, line);
452}
453
454void QTestLog::addSkip(const char *msg, const char *file, int line)
455{
456 QTEST_ASSERT(msg);
457
459 ++QTest::skips;
461 } else {
462 // After an B?XPASS/Continue, we might subsequently skip.
463 // Likewise after a skip in a function called by a test.
467 }
468 // It is up to particular loggers to decide whether to report such
469 // subsequent skips; they may carry useful information.
470
472 logger->addIncident(QAbstractTestLogger::Skip, msg, file, line);
473}
474
475void QTestLog::addBenchmarkResults(const QList<QBenchmarkResult> &results)
476{
478 logger->addBenchmarkResults(results);
479}
480
489
491{
494 logger->stopLogging();
495 }
496 QTest::loggers()->clear();
498}
499
500void QTestLog::addLogger(LogMode mode, const char *filename)
501{
502 if (filename && strcmp(filename, "-") == 0)
503 filename = nullptr;
504
505 QAbstractTestLogger *logger = nullptr;
506 switch (mode) {
507 case QTestLog::Plain:
508 logger = new QPlainTestLogger(filename);
509 break;
510 case QTestLog::CSV:
511 logger = new QCsvBenchmarkLogger(filename);
512 break;
513 case QTestLog::XML:
514 logger = new QXmlTestLogger(QXmlTestLogger::Complete, filename);
515 break;
517 logger = new QXmlTestLogger(QXmlTestLogger::Light, filename);
518 break;
520 logger = new QJUnitTestLogger(filename);
521 break;
523 logger = new QTeamCityLogger(filename);
524 break;
525 case QTestLog::TAP:
526 logger = new QTapTestLogger(filename);
527 break;
528#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
529 case QTestLog::Apple:
530 logger = new QAppleTestLogger;
531 break;
532#endif
533#if defined(HAVE_XCTEST)
534 case QTestLog::XCTest:
535 logger = new QXcodeTestLogger;
536 break;
537#endif
538 }
539
540 QTEST_ASSERT(logger);
541 addLogger(logger);
542}
543
553{
554 QTEST_ASSERT(logger);
555 QTest::loggers()->emplace_back(logger);
556}
557
559{
560 return !QTest::loggers()->empty();
561}
562
569{
571 if (!logger->isRepeatSupported())
572 return false;
573 }
574
575 return true;
576}
577
579{
581 if (logger->isLoggingToStdout())
582 return true;
583 }
584
585 return false;
586}
587
588void QTestLog::warn(const char *msg, const char *file, int line)
589{
590 QTEST_ASSERT(msg);
591
593 logger->addMessage(QAbstractTestLogger::Warn, QString::fromUtf8(msg), file, line);
594}
595
596void QTestLog::info(const char *msg, const char *file, int line)
597{
598 QTEST_ASSERT(msg);
599
601 logger->addMessage(QAbstractTestLogger::Info, QString::fromUtf8(msg), file, line);
602}
603
608
610{
611 return QTest::verbosity;
612}
613
621
622#if QT_CONFIG(regularexpression)
624{
625 QTEST_ASSERT(expression.isValid());
626
627 const QMutexLocker mutexLocker(&QTest::mutex);
629}
630#endif // QT_CONFIG(regularexpression)
631
633{
634 QTest::failOnWarningList.push_back({});
635}
636
637void QTestLog::failOnWarning(const char *msg)
638{
640}
641
642#if QT_CONFIG(regularexpression)
643void QTestLog::failOnWarning(const QRegularExpression &expression)
644{
645 QTEST_ASSERT(expression.isValid());
646
647 QTest::failOnWarningList.push_back(QVariant::fromValue(expression));
648}
649#endif // QT_CONFIG(regularexpression)
650
652{
653 QTest::maxWarnings = m <= 0 ? INT_MAX : m + 2;
654}
655
656bool QTestLog::printAvailableTags = false;
657
659{
660 printAvailableTags = true;
661}
662
664{
665 return QTest::passes;
666}
667
669{
670 return QTest::fails;
671}
672
674{
675 return QTest::skips;
676}
677
679{
680 return QTest::blacklists;
681}
682
684{
685 return passCount() + failCount() + skipCount() + blacklistCount();
686}
687
689{
690 QTest::passes = 0;
691 QTest::fails = 0;
692 QTest::skips = 0;
693}
694
696{
698}
699
704
706{
707 return elapsedTotalTime.nsecsElapsed();
708}
709
711{
712 return elapsedFunctionTime.nsecsElapsed();
713}
714
716
717#include "moc_qtestlog_p.cpp"
Base class for test loggers.
\inmodule QtCore
\inmodule QtCore
Definition qlogging.h:42
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
\inmodule QtCore \reentrant
bool isValid() const
Returns true if the regular expression is a valid regular expression (that is, it contains no syntax ...
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
static void clearCurrentTestState()
Definition qtestlog.cpp:326
static void addPass(const char *msg)
Definition qtestlog.cpp:333
static int verboseLevel()
Definition qtestlog.cpp:609
static int totalCount()
Definition qtestlog.cpp:683
static int passCount()
Definition qtestlog.cpp:663
static void addSkip(const char *msg, const char *file, int line)
Definition qtestlog.cpp:454
static int failCount()
Definition qtestlog.cpp:668
static int blacklistCount()
Definition qtestlog.cpp:678
static void addFail(const char *msg, const char *file, int line)
Definition qtestlog.cpp:348
static void startLogging()
Definition qtestlog.cpp:481
static void enterTestData(QTestData *data)
Definition qtestlog.cpp:265
static void clearFailOnWarnings()
Definition qtestlog.cpp:321
static void enterTestFunction(const char *function)
Definition qtestlog.cpp:253
static void setInstalledTestCoverage(bool installed)
Definition qtestlog.cpp:695
static void setVerboseLevel(int level)
Definition qtestlog.cpp:604
static bool hasLoggers()
Definition qtestlog.cpp:558
static void addXPass(const char *msg, const char *file, int line)
Definition qtestlog.cpp:378
static void addXFail(const char *msg, const char *file, int line)
Definition qtestlog.cpp:368
static void addBPass(const char *msg)
Definition qtestlog.cpp:396
static int unhandledIgnoreMessages()
Definition qtestlog.cpp:273
static void addBFail(const char *msg, const char *file, int line)
Definition qtestlog.cpp:408
static void clearIgnoreMessages()
Definition qtestlog.cpp:315
static bool loggerUsingStdout()
Definition qtestlog.cpp:578
static void setMaxWarnings(int max)
Definition qtestlog.cpp:651
static bool installedTestCoverage()
Definition qtestlog.cpp:700
static void addBXFail(const char *msg, const char *file, int line)
Definition qtestlog.cpp:444
static void info(const char *msg, const char *file, int line)
Definition qtestlog.cpp:596
static void setPrintAvailableTagsMode()
Definition qtestlog.cpp:658
static qint64 nsecsTotalTime()
Definition qtestlog.cpp:705
static void addBenchmarkResults(const QList< QBenchmarkResult > &result)
Definition qtestlog.cpp:475
static qint64 nsecsFunctionTime()
Definition qtestlog.cpp:710
static bool isRepeatSupported()
Definition qtestlog.cpp:568
static void stopLogging()
Definition qtestlog.cpp:490
static void leaveTestFunction()
Definition qtestlog.cpp:285
static int skipCount()
Definition qtestlog.cpp:673
static void failOnWarning()
Definition qtestlog.cpp:632
static void warn(const char *msg, const char *file, int line)
Definition qtestlog.cpp:588
static void addLogger(LogMode mode, const char *filename)
Definition qtestlog.cpp:500
static void printUnhandledIgnoreMessages()
Definition qtestlog.cpp:294
static void addBXPass(const char *msg, const char *file, int line)
Definition qtestlog.cpp:426
static void ignoreMessage(QtMsgType type, const char *msg)
Definition qtestlog.cpp:614
static void resetCounters()
Definition qtestlog.cpp:688
static const char * currentAppName()
static void addFailure(const char *message, const char *file=nullptr, int line=0)
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
QJSValue expected
Definition qjsengine.cpp:12
static Q_CONSTINIT QBasicAtomicPointer< void(QtMsgType, const QMessageLogContext &, const QString &) messageHandler)
QtMessageHandler qInstallMessageHandler(QtMessageHandler h)
Combined button and popup list for selecting options.
static bool handleIgnoredMessage(QtMsgType type, const QString &message)
Definition qtestlog.cpp:154
static bool handleFailOnWarning(const QMessageLogContext &context, const QString &message)
Definition qtestlog.cpp:180
@ Failed
Definition qtestlog.cpp:81
@ Passed
Definition qtestlog.cpp:81
@ Unresolved
Definition qtestlog.cpp:81
@ Suppressed
Definition qtestlog.cpp:81
@ Skipped
Definition qtestlog.cpp:81
enum QTest::@478 currentTestState
static Q_CONSTINIT QBasicMutex mutex
Definition qtestlog.cpp:142
int fails
Definition qtestlog.cpp:77
static int verbosity
Definition qtestlog.cpp:148
static IgnoreResultList * ignoreResultList
Definition qtestlog.cpp:141
int passes
Definition qtestlog.cpp:78
static int maxWarnings
Definition qtestlog.cpp:149
static bool installedTestCoverage
Definition qtestlog.cpp:150
static std::vector< QVariant > failOnWarningList
Definition qtestlog.cpp:144
int skips
Definition qtestlog.cpp:79
static QtMessageHandler oldMessageHandler
Definition qtestlog.cpp:152
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
Definition qtestlog.cpp:206
int blacklists
Definition qtestlog.cpp:80
static void * context
#define Q_BASIC_ATOMIC_INITIALIZER(a)
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt,...)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
QtMsgType
Definition qlogging.h:29
@ QtWarningMsg
Definition qlogging.h:31
@ QtFatalMsg
Definition qlogging.h:33
void(* QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &)
Definition qlogging.h:191
GLenum mode
const GLfloat * m
GLenum GLuint GLint level
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLuint GLsizei const GLchar * message
GLuint counter
GLubyte * pattern
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
#define QTEST_ASSERT(cond)
Definition qtestassert.h:11
static void saveCoverageTool(const char *appname, bool testfailed, bool installedTestCoverage)
Definition qtestlog.cpp:45
static Q_CONSTINIT QElapsedTimer elapsedFunctionTime
Definition qtestlog.cpp:70
#define FOREACH_TEST_LOGGER
Definition qtestlog.cpp:73
static Q_CONSTINIT QElapsedTimer elapsedTotalTime
Definition qtestlog.cpp:71
static constexpr size_t maxMsgLen
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:60
QList< int > list
[14]
QFile file
[0]
QGraphicsItem * item
IgnoreResultList(QtMsgType tp, const QVariant &patternIn)
Definition qtestlog.cpp:85
static void clearList(IgnoreResultList *&list)
Definition qtestlog.cpp:88
bool matches(QtMsgType tp, const QString &message) const
Definition qtestlog.cpp:124
static bool stringsMatch(const QString &expected, const QString &actual)
Definition qtestlog.cpp:110
static void append(IgnoreResultList *&list, QtMsgType type, const QVariant &patternIn)
Definition qtestlog.cpp:97
IgnoreResultList * next
Definition qtestlog.cpp:138