Qt 6.x
The Qt SDK
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{
256 if (printAvailableTags)
257 return;
258
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
316{
317 const QMutexLocker mutexLocker(&QTest::mutex);
319}
320
321
323{
325}
326
328{
330}
331
332void QTestLog::addPass(const char *msg)
333{
334 if (printAvailableTags)
335 return;
336
337 QTEST_ASSERT(msg);
339
342
344 logger->addIncident(QAbstractTestLogger::Pass, msg);
345}
346
347void QTestLog::addFail(const char *msg, const char *file, int line)
348{
349 QTEST_ASSERT(msg);
350
352 ++QTest::fails;
353 } else {
354 // After an XPASS/Continue, or fail or skip in a function the test
355 // calls, we can subsequently fail.
358 }
359 // It is up to particular loggers to decide whether to report such
360 // subsequent failures; they may carry useful information.
361
364 logger->addIncident(QAbstractTestLogger::Fail, msg, file, line);
365}
366
367void QTestLog::addXFail(const char *msg, const char *file, int line)
368{
369 QTEST_ASSERT(msg);
370
371 // Will be counted in addPass() if we get there.
372
374 logger->addIncident(QAbstractTestLogger::XFail, msg, file, line);
375}
376
377void QTestLog::addXPass(const char *msg, const char *file, int line)
378{
379 QTEST_ASSERT(msg);
380
382 ++QTest::fails;
383 } else {
384 // After an XPASS/Continue, we can subsequently XPASS again.
385 // Likewise after a fail or skip in a function called by the test.
388 }
389
392 logger->addIncident(QAbstractTestLogger::XPass, msg, file, line);
393}
394
395void QTestLog::addBPass(const char *msg)
396{
397 QTEST_ASSERT(msg);
399
400 ++QTest::blacklists; // Not passes ?
402
404 logger->addIncident(QAbstractTestLogger::BlacklistedPass, msg);
405}
406
407void QTestLog::addBFail(const char *msg, const char *file, int line)
408{
409 QTEST_ASSERT(msg);
410
413 } else {
414 // After a BXPASS/Continue, we can subsequently fail.
415 // Likewise after a fail or skip in a function called by a test.
418 }
419
422 logger->addIncident(QAbstractTestLogger::BlacklistedFail, msg, file, line);
423}
424
425void QTestLog::addBXPass(const char *msg, const char *file, int line)
426{
427 QTEST_ASSERT(msg);
428
431 } else {
432 // After a BXPASS/Continue, we may BXPASS again.
433 // Likewise after a fail or skip in a function called by a test.
436 }
437
440 logger->addIncident(QAbstractTestLogger::BlacklistedXPass, msg, file, line);
441}
442
443void QTestLog::addBXFail(const char *msg, const char *file, int line)
444{
445 QTEST_ASSERT(msg);
446
447 // Will be counted in addBPass() if we get there.
448
450 logger->addIncident(QAbstractTestLogger::BlacklistedXFail, msg, file, line);
451}
452
453void QTestLog::addSkip(const char *msg, const char *file, int line)
454{
455 QTEST_ASSERT(msg);
456
458 ++QTest::skips;
460 } else {
461 // After an B?XPASS/Continue, we might subsequently skip.
462 // Likewise after a skip in a function called by a test.
466 }
467 // It is up to particular loggers to decide whether to report such
468 // subsequent skips; they may carry useful information.
469
471 logger->addIncident(QAbstractTestLogger::Skip, msg, file, line);
472}
473
475{
477 logger->addBenchmarkResults(results);
478}
479
481{
485 logger->startLogging();
487}
488
490{
493 logger->stopLogging();
494 }
495 QTest::loggers()->clear();
497}
498
499void QTestLog::addLogger(LogMode mode, const char *filename)
500{
501 if (filename && strcmp(filename, "-") == 0)
502 filename = nullptr;
503
504 QAbstractTestLogger *logger = nullptr;
505 switch (mode) {
506 case QTestLog::Plain:
507 logger = new QPlainTestLogger(filename);
508 break;
509 case QTestLog::CSV:
510 logger = new QCsvBenchmarkLogger(filename);
511 break;
512 case QTestLog::XML:
513 logger = new QXmlTestLogger(QXmlTestLogger::Complete, filename);
514 break;
516 logger = new QXmlTestLogger(QXmlTestLogger::Light, filename);
517 break;
519 logger = new QJUnitTestLogger(filename);
520 break;
522 logger = new QTeamCityLogger(filename);
523 break;
524 case QTestLog::TAP:
525 logger = new QTapTestLogger(filename);
526 break;
527#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
528 case QTestLog::Apple:
529 logger = new QAppleTestLogger;
530 break;
531#endif
532#if defined(HAVE_XCTEST)
533 case QTestLog::XCTest:
534 logger = new QXcodeTestLogger;
535 break;
536#endif
537 }
538
539 QTEST_ASSERT(logger);
540 addLogger(logger);
541}
542
552{
553 QTEST_ASSERT(logger);
554 QTest::loggers()->emplace_back(logger);
555}
556
558{
559 return !QTest::loggers()->empty();
560}
561
563{
565 if (logger->isLoggingToStdout())
566 return true;
567 }
568
569 return false;
570}
571
572void QTestLog::warn(const char *msg, const char *file, int line)
573{
574 QTEST_ASSERT(msg);
575
577 logger->addMessage(QAbstractTestLogger::Warn, QString::fromUtf8(msg), file, line);
578}
579
580void QTestLog::info(const char *msg, const char *file, int line)
581{
582 QTEST_ASSERT(msg);
583
585 logger->addMessage(QAbstractTestLogger::Info, QString::fromUtf8(msg), file, line);
586}
587
589{
591}
592
594{
595 return QTest::verbosity;
596}
597
599{
600 QTEST_ASSERT(msg);
601
602 const QMutexLocker mutexLocker(&QTest::mutex);
604}
605
606#if QT_CONFIG(regularexpression)
608{
609 QTEST_ASSERT(expression.isValid());
610
611 const QMutexLocker mutexLocker(&QTest::mutex);
613}
614#endif // QT_CONFIG(regularexpression)
615
616void QTestLog::failOnWarning(const char *msg)
617{
619}
620
621#if QT_CONFIG(regularexpression)
622void QTestLog::failOnWarning(const QRegularExpression &expression)
623{
624 QTEST_ASSERT(expression.isValid());
625
626 QTest::failOnWarningList.push_back(QVariant::fromValue(expression));
627}
628#endif // QT_CONFIG(regularexpression)
629
631{
632 QTest::maxWarnings = m <= 0 ? INT_MAX : m + 2;
633}
634
635bool QTestLog::printAvailableTags = false;
636
638{
639 printAvailableTags = true;
640}
641
643{
644 return QTest::passes;
645}
646
648{
649 return QTest::fails;
650}
651
653{
654 return QTest::skips;
655}
656
658{
659 return QTest::blacklists;
660}
661
663{
664 return passCount() + failCount() + skipCount() + blacklistCount();
665}
666
668{
669 QTest::passes = 0;
670 QTest::fails = 0;
671 QTest::skips = 0;
672}
673
675{
677}
678
680{
682}
683
685{
687}
688
690{
692}
693
695
696#include "moc_qtestlog_p.cpp"
Base class for test loggers.
\inmodule QtCore
qint64 restart() noexcept
Restarts the timer and returns the number of milliseconds elapsed since the previous start.
void start() noexcept
Starts this timer.
qint64 nsecsElapsed() const noexcept
Definition qlist.h:74
\inmodule QtCore
Definition qlogging.h:39
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
\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:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
static void clearCurrentTestState()
Definition qtestlog.cpp:327
static void addPass(const char *msg)
Definition qtestlog.cpp:332
static int verboseLevel()
Definition qtestlog.cpp:593
static int totalCount()
Definition qtestlog.cpp:662
static int passCount()
Definition qtestlog.cpp:642
static void addSkip(const char *msg, const char *file, int line)
Definition qtestlog.cpp:453
static int failCount()
Definition qtestlog.cpp:647
static int blacklistCount()
Definition qtestlog.cpp:657
static void addFail(const char *msg, const char *file, int line)
Definition qtestlog.cpp:347
static void startLogging()
Definition qtestlog.cpp:480
static void enterTestData(QTestData *data)
Definition qtestlog.cpp:265
static void clearFailOnWarnings()
Definition qtestlog.cpp:322
static void enterTestFunction(const char *function)
Definition qtestlog.cpp:253
static void setInstalledTestCoverage(bool installed)
Definition qtestlog.cpp:674
static void setVerboseLevel(int level)
Definition qtestlog.cpp:588
static bool hasLoggers()
Definition qtestlog.cpp:557
static void addXPass(const char *msg, const char *file, int line)
Definition qtestlog.cpp:377
static void addXFail(const char *msg, const char *file, int line)
Definition qtestlog.cpp:367
static void addBPass(const char *msg)
Definition qtestlog.cpp:395
static int unhandledIgnoreMessages()
Definition qtestlog.cpp:273
static void addBFail(const char *msg, const char *file, int line)
Definition qtestlog.cpp:407
static void clearIgnoreMessages()
Definition qtestlog.cpp:315
static bool loggerUsingStdout()
Definition qtestlog.cpp:562
static void setMaxWarnings(int max)
Definition qtestlog.cpp:630
static bool installedTestCoverage()
Definition qtestlog.cpp:679
static void addBXFail(const char *msg, const char *file, int line)
Definition qtestlog.cpp:443
static void info(const char *msg, const char *file, int line)
Definition qtestlog.cpp:580
static void setPrintAvailableTagsMode()
Definition qtestlog.cpp:637
static qint64 nsecsTotalTime()
Definition qtestlog.cpp:684
static void addBenchmarkResults(const QList< QBenchmarkResult > &result)
Definition qtestlog.cpp:474
static qint64 nsecsFunctionTime()
Definition qtestlog.cpp:689
static void stopLogging()
Definition qtestlog.cpp:489
static void leaveTestFunction()
Definition qtestlog.cpp:285
static int skipCount()
Definition qtestlog.cpp:652
static void warn(const char *msg, const char *file, int line)
Definition qtestlog.cpp:572
static void addLogger(LogMode mode, const char *filename)
Definition qtestlog.cpp:499
static void printUnhandledIgnoreMessages()
Definition qtestlog.cpp:294
static void addBXPass(const char *msg, const char *file, int line)
Definition qtestlog.cpp:425
static void ignoreMessage(QtMsgType type, const char *msg)
Definition qtestlog.cpp:598
static void resetCounters()
Definition qtestlog.cpp:667
static const char * currentAppName()
static void addFailure(const char *message, const char *file=nullptr, int line=0)
\inmodule QtCore
Definition qvariant.h:64
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:531
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
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
@ 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
int passes
Definition qtestlog.cpp:78
static int maxWarnings
Definition qtestlog.cpp:149
enum QTest::@481 currentTestState
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,...)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
#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:187
GLenum mode
const GLfloat * m
GLenum GLuint GLint level
GLenum type
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint counter
GLubyte * pattern
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1391
#define QStringLiteral(str)
#define QTEST_ASSERT(cond)
Definition qtestassert.h:12
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
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:55
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