Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
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
37#include <QtCore/q20algorithm.h>
38#include <atomic>
39#include <cstdio>
40#include <memory>
41#include <vector>
42
43QT_BEGIN_NAMESPACE
44
45using namespace Qt::StringLiterals;
46
47static void saveCoverageTool(const char * appname, bool testfailed, bool installedTestCoverage)
48{
49#ifdef __COVERAGESCANNER__
50# if QT_CONFIG(testlib_selfcover)
51 __coveragescanner_teststate(QTestLog::failCount() > 0 ? "FAILED" :
52 QTestLog::passCount() > 0 ? "PASSED" : "SKIPPED");
53# else
54 if (!installedTestCoverage)
55 return;
56 // install again to make sure the filename is correct.
57 // without this, a plugin or similar may have changed the filename.
58 __coveragescanner_install(appname);
59 __coveragescanner_teststate(testfailed ? "FAILED" : "PASSED");
60 __coveragescanner_save();
61 __coveragescanner_testname("");
62 __coveragescanner_clear();
63 unsetenv("QT_TESTCOCOON_ACTIVE");
64# endif // testlib_selfcover
65#else
66 Q_UNUSED(appname);
67 Q_UNUSED(testfailed);
68 Q_UNUSED(installedTestCoverage);
69#endif
70}
71
72Q_CONSTINIT static QBasicMutex elapsedTimersMutex; // due to the WatchDog thread
73Q_CONSTINIT static QElapsedTimer elapsedFunctionTime;
74Q_CONSTINIT static QElapsedTimer elapsedTotalTime;
75
76namespace {
77class LoggerRegistry
78{
79 using LoggersContainer = std::vector<std::shared_ptr<QAbstractTestLogger>>;
80 using SharedLoggersContainer = std::shared_ptr<const LoggersContainer>;
81
82public:
83 void addLogger(std::unique_ptr<QAbstractTestLogger> logger)
84 {
85 // read/update/clone
86 const SharedLoggersContainer currentLoggers = load();
87 auto newLoggers = currentLoggers
88 ? std::make_shared<LoggersContainer>(*currentLoggers)
89 : std::make_shared<LoggersContainer>();
90 newLoggers->emplace_back(std::move(logger));
91 store(std::move(newLoggers));
92 }
93
94 void clear() { store(SharedLoggersContainer{}); }
95
96 auto allLoggers() const
97 {
98 struct LoggersRange
99 {
100 const SharedLoggersContainer loggers;
101
102 auto begin() const
103 {
104 return loggers ? loggers->cbegin() : LoggersContainer::const_iterator{};
105 }
106 auto end() const
107 {
108 return loggers ? loggers->cend() : LoggersContainer::const_iterator{};
109 }
110 bool isEmpty() const { return loggers ? loggers->empty() : true; }
111 };
112
113 return LoggersRange{ load() };
114 }
115
116private:
117#ifdef __cpp_lib_atomic_shared_ptr
118 SharedLoggersContainer load() const { return loggers.load(std::memory_order_acquire); }
119 void store(SharedLoggersContainer newLoggers)
120 {
121 loggers.store(std::move(newLoggers), std::memory_order_release);
122 }
123 std::atomic<SharedLoggersContainer> loggers = nullptr;
124#else
125 SharedLoggersContainer load() const
126 {
127 return std::atomic_load_explicit(&loggers, std::memory_order_acquire);
128 }
129 void store(SharedLoggersContainer newLoggers)
130 {
131 std::atomic_store_explicit(&loggers, std::move(newLoggers), std::memory_order_release);
132 }
133 SharedLoggersContainer loggers;
134#endif
135};
136
137} // namespace
138
139namespace QTest {
140
141 int fails = 0;
142 int passes = 0;
143 int skips = 0;
144 int blacklists = 0;
145 enum { Unresolved, Passed, Skipped, Suppressed, Failed } currentTestState;
146
148 {
149 inline IgnoreResultList(QtMsgType tp, const QVariant &patternIn)
150 : type(tp), pattern(patternIn) {}
151
152 static inline void clearList(IgnoreResultList *&list)
153 {
154 while (list) {
155 IgnoreResultList *current = list;
156 list = list->next;
157 delete current;
158 }
159 }
160
161 static void append(IgnoreResultList *&list, QtMsgType type, const QVariant &patternIn)
162 {
163 QTest::IgnoreResultList *item = new QTest::IgnoreResultList(type, patternIn);
164
165 if (!list) {
166 list = item;
167 return;
168 }
169 IgnoreResultList *last = list;
170 for ( ; last->next; last = last->next) ;
171 last->next = item;
172 }
173
174 static bool stringsMatch(const QString &expected, const QString &actual)
175 {
176 if (expected == actual)
177 return true;
178
179 // ignore an optional whitespace at the end of str
180 // (the space was added automatically by ~QDebug() until Qt 5.3,
181 // so autotests still might expect it)
182 if (expected.endsWith(u' '))
183 return actual == QStringView{expected}.left(expected.size() - 1);
184
185 return false;
186 }
187
188 inline bool matches(QtMsgType tp, const QString &message) const
189 {
190 if (tp != type)
191 return false;
192#if QT_CONFIG(regularexpression)
193 if (const auto *regex = get_if<QRegularExpression>(&pattern))
194 return regex->match(message).hasMatch();
195#endif
196 Q_ASSERT(pattern.metaType() == QMetaType::fromType<QString>());
197 return stringsMatch(pattern.toString(), message);
198 }
199
203 };
204
206 Q_CONSTINIT static QBasicMutex mutex;
207
209
210 Q_GLOBAL_STATIC(LoggerRegistry, loggers)
211
212 static int verbosity = 0;
213 static int maxWarnings = 2002;
214 static bool installedTestCoverage = true;
215
217
218 static bool handleIgnoredMessage(QtMsgType type, const QString &message)
219 {
220 const QMutexLocker mutexLocker(&QTest::mutex);
221
222 if (!ignoreResultList)
223 return false;
224 IgnoreResultList *last = nullptr;
226 while (list) {
227 if (list->matches(type, message)) {
228 // remove the item from the list
229 if (last)
230 last->next = list->next;
231 else
233
234 delete list;
235 return true;
236 }
237
238 last = list;
239 list = list->next;
240 }
241 return false;
242 }
243
244 static void handleFatal()
245 {
246 /* Right now, we're inside the custom message handler and we're
247 being qt_message_output in qglobal.cpp. After we return from this
248 function, it will proceed with calling exit() and abort() and
249 hence crash. Therefore, we call these logging functions such that
250 we wrap up nicely, and in particular produce well-formed XML.
251 */
252 QTestLog::leaveTestFunction();
253 QTestLog::stopLogging();
254 }
255
256 static bool handleFailOnWarning(const QMessageLogContext &context, const QString &message)
257 {
258 // failOnWarning can be called multiple times per test function, so let
259 // each call cause a failure if required.
260 for (const auto &pattern : failOnWarningList) {
261 if (const auto *text = get_if<QString>(&pattern)) {
262 if (message != *text)
263 continue;
264#if QT_CONFIG(regularexpression)
265 } else if (const auto *regex = get_if<QRegularExpression>(&pattern)) {
266 if (!message.contains(*regex))
267 continue;
268#endif
269 } else {
270 // The no-arg clearFailOnWarnings()'s null pattern matches all messages.
271 Q_ASSERT(pattern.isNull());
272 }
273
274 const size_t maxMsgLen = 1024;
275 Q_DECL_UNINITIALIZED char msg[maxMsgLen];
276 msg[0] = '\0';
277 std::snprintf(msg, maxMsgLen, "Received a warning that resulted in a failure:\n%s",
278 qPrintable(message));
279 QTestResult::addFailure(msg, context.file, context.line);
280 return true;
281 }
282 return false;
283 }
284
285 static constexpr bool isWarnOrWorse(QtMsgType type)
286 {
287 // ## TODO Inline this once we get to Qt 7 !
288#if QT_VERSION_MAJOR == 7 || defined(QT_BOOTSTRAPPED) // To match QtMsgType decl
289 return type >= QtWarningMsg;
290#else
291 // Until Qt 6, Info was > Fatal :-(
292 switch (type) {
293 case QtWarningMsg:
294 case QtCriticalMsg:
295 case QtFatalMsg:
296 return true;
297 case QtDebugMsg:
298 case QtInfoMsg:
299 return false;
300 }
301 Q_UNREACHABLE_RETURN(false);
302#endif
303 }
304
305 static void messageHandler(QtMsgType type, const QMessageLogContext & context, const QString &message)
306 {
307 static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(QTest::maxWarnings);
308
309 if (loggers.isDestroyed() || loggers->allLoggers().isEmpty()) {
310 // the message handler may be called from a worker thread, after the main thread stopped
311 // logging. Forwarding to original message handler to avoid swallowing the message
312 Q_ASSERT(oldMessageHandler);
313 oldMessageHandler(type, context, message);
314 return;
315 }
316
317 if (handleIgnoredMessage(type, message)) {
318 // the message is expected, so just swallow it.
319 return;
320 }
321
322 if (isWarnOrWorse(type) && handleFailOnWarning(context, message)) {
323 if (type == QtFatalMsg)
325 return;
326 }
327
328 auto loggerCapture = loggers->allLoggers();
329
330 if (type != QtFatalMsg) {
331 if (counter.loadRelaxed() <= 0)
332 return;
333
334 if (!counter.deref()) {
335 for (auto &logger : loggerCapture)
336 logger->addMessage(QAbstractTestLogger::Warn,
337 QStringLiteral("Maximum amount of warnings exceeded. Use "
338 "-maxwarnings to override."));
339
340 return;
341 }
342 }
343
344 for (auto &logger : loggerCapture)
345 logger->addMessage(type, context, message);
346
347 if (type == QtFatalMsg) {
348 QTestResult::addFailure("Received a fatal error.", context.file, context.line);
350 }
351 }
352}
353
354void QTestLog::enterTestFunction(const char* function)
355{
356 {
357 QMutexLocker locker(&elapsedTimersMutex);
358 elapsedFunctionTime.start();
359 }
360 if (printAvailableTags)
361 return;
362
363 QTEST_ASSERT(function);
364
365 for (auto &logger : QTest::loggers->allLoggers())
366 logger->enterTestFunction(function);
367}
368
369void QTestLog::enterTestData(QTestData *data)
370{
371 QTEST_ASSERT(data);
372
373 for (auto &logger : QTest::loggers->allLoggers())
374 logger->enterTestData(data);
375}
376
377int QTestLog::unhandledIgnoreMessages()
378{
379 const QMutexLocker mutexLocker(&QTest::mutex);
380 int i = 0;
381 QTest::IgnoreResultList *list = QTest::ignoreResultList;
382 while (list) {
383 ++i;
384 list = list->next;
385 }
386 return i;
387}
388
389void QTestLog::leaveTestFunction()
390{
391 if (printAvailableTags)
392 return;
393
394 for (auto &logger : QTest::loggers->allLoggers())
395 logger->leaveTestFunction();
396}
397
398void QTestLog::printUnhandledIgnoreMessages()
399{
400 const QMutexLocker mutexLocker(&QTest::mutex);
401 QString message;
402 QTest::IgnoreResultList *list = QTest::ignoreResultList;
403 while (list) {
404 if (const auto *text = get_if<QString>(&list->pattern)) {
405 message = "Did not receive message: \"%1\""_L1.arg(*text);
406#if QT_CONFIG(regularexpression)
407 } else if (const auto *regex = get_if<QRegularExpression>(&list->pattern)) {
408 message = "Did not receive any message matching: \"%1\""_L1.arg(regex->pattern());
409#endif
410 } else {
411 Q_UNREACHABLE();
412 message = "Missing message of unrecognized pattern type: \"%1\""_L1.arg(
413 list->pattern.metaType().name());
414 }
415 for (auto &logger : QTest::loggers->allLoggers())
416 logger->addMessage(QAbstractTestLogger::Info, message);
417
418 list = list->next;
419 }
420}
421
422void QTestLog::clearIgnoreMessages()
423{
424 const QMutexLocker mutexLocker(&QTest::mutex);
425 QTest::IgnoreResultList::clearList(QTest::ignoreResultList);
426}
427
428void QTestLog::clearFailOnWarnings()
429{
430 QTest::failOnWarningList.clear();
431}
432
433void QTestLog::clearCurrentTestState()
434{
435 clearIgnoreMessages();
436 clearFailOnWarnings();
437 QTest::currentTestState = QTest::Unresolved;
438}
439
440void QTestLog::addPass(const char *msg)
441{
442 if (printAvailableTags)
443 return;
444
445 QTEST_ASSERT(msg);
446 Q_ASSERT(QTest::currentTestState == QTest::Unresolved);
447
448 ++QTest::passes;
449 QTest::currentTestState = QTest::Passed;
450
451 for (auto &logger : QTest::loggers->allLoggers())
452 logger->addIncident(QAbstractTestLogger::Pass, msg);
453}
454
455void QTestLog::addFail(const char *msg, const char *file, int line)
456{
457 QTEST_ASSERT(msg);
458
459 if (QTest::currentTestState == QTest::Unresolved) {
460 ++QTest::fails;
461 } else {
462 // After an XPASS/Continue, or fail or skip in a function the test
463 // calls, we can subsequently fail.
464 Q_ASSERT(QTest::currentTestState == QTest::Failed
465 || QTest::currentTestState == QTest::Skipped);
466 }
467 // It is up to particular loggers to decide whether to report such
468 // subsequent failures; they may carry useful information.
469
470 QTest::currentTestState = QTest::Failed;
471 for (auto &logger : QTest::loggers->allLoggers())
472 logger->addIncident(QAbstractTestLogger::Fail, msg, file, line);
473}
474
475void QTestLog::addXFail(const char *msg, const char *file, int line)
476{
477 QTEST_ASSERT(msg);
478
479 // Will be counted in addPass() if we get there.
480
481 for (auto &logger : QTest::loggers->allLoggers())
482 logger->addIncident(QAbstractTestLogger::XFail, msg, file, line);
483}
484
485void QTestLog::addXPass(const char *msg, const char *file, int line)
486{
487 QTEST_ASSERT(msg);
488
489 if (QTest::currentTestState == QTest::Unresolved) {
490 ++QTest::fails;
491 } else {
492 // After an XPASS/Continue, we can subsequently XPASS again.
493 // Likewise after a fail or skip in a function called by the test.
494 Q_ASSERT(QTest::currentTestState == QTest::Failed
495 || QTest::currentTestState == QTest::Skipped);
496 }
497
498 QTest::currentTestState = QTest::Failed;
499 for (auto &logger : QTest::loggers->allLoggers())
500 logger->addIncident(QAbstractTestLogger::XPass, msg, file, line);
501}
502
503void QTestLog::addBPass(const char *msg)
504{
505 QTEST_ASSERT(msg);
506 Q_ASSERT(QTest::currentTestState == QTest::Unresolved);
507
508 ++QTest::blacklists; // Not passes ?
509 QTest::currentTestState = QTest::Suppressed;
510
511 for (auto &logger : QTest::loggers->allLoggers())
512 logger->addIncident(QAbstractTestLogger::BlacklistedPass, msg);
513}
514
515void QTestLog::addBFail(const char *msg, const char *file, int line)
516{
517 QTEST_ASSERT(msg);
518
519 if (QTest::currentTestState == QTest::Unresolved) {
520 ++QTest::blacklists;
521 } else {
522 // After a BXPASS/Continue, we can subsequently fail.
523 // Likewise after a fail or skip in a function called by a test.
524 Q_ASSERT(QTest::currentTestState == QTest::Suppressed
525 || QTest::currentTestState == QTest::Skipped);
526 }
527
528 QTest::currentTestState = QTest::Suppressed;
529 for (auto &logger : QTest::loggers->allLoggers())
530 logger->addIncident(QAbstractTestLogger::BlacklistedFail, msg, file, line);
531}
532
533void QTestLog::addBXPass(const char *msg, const char *file, int line)
534{
535 QTEST_ASSERT(msg);
536
537 if (QTest::currentTestState == QTest::Unresolved) {
538 ++QTest::blacklists;
539 } else {
540 // After a BXPASS/Continue, we may BXPASS again.
541 // Likewise after a fail or skip in a function called by a test.
542 Q_ASSERT(QTest::currentTestState == QTest::Suppressed
543 || QTest::currentTestState == QTest::Skipped);
544 }
545
546 QTest::currentTestState = QTest::Suppressed;
547 for (auto &logger : QTest::loggers->allLoggers())
548 logger->addIncident(QAbstractTestLogger::BlacklistedXPass, msg, file, line);
549}
550
551void QTestLog::addBXFail(const char *msg, const char *file, int line)
552{
553 QTEST_ASSERT(msg);
554
555 // Will be counted in addBPass() if we get there.
556
557 for (auto &logger : QTest::loggers->allLoggers())
558 logger->addIncident(QAbstractTestLogger::BlacklistedXFail, msg, file, line);
559}
560
561void QTestLog::addSkip(const char *msg, const char *file, int line)
562{
563 QTEST_ASSERT(msg);
564
565 if (QTest::currentTestState == QTest::Unresolved) {
566 ++QTest::skips;
567 QTest::currentTestState = QTest::Skipped;
568 } else {
569 // After an B?XPASS/Continue, we might subsequently skip.
570 // Likewise after a skip in a function called by a test.
571 Q_ASSERT(QTest::currentTestState == QTest::Suppressed
572 || QTest::currentTestState == QTest::Failed
573 || QTest::currentTestState == QTest::Skipped);
574 }
575 // It is up to particular loggers to decide whether to report such
576 // subsequent skips; they may carry useful information.
577
578 for (auto &logger : QTest::loggers->allLoggers())
579 logger->addIncident(QAbstractTestLogger::Skip, msg, file, line);
580}
581
582void QTestLog::addBenchmarkResults(const QList<QBenchmarkResult> &results)
583{
584 for (auto &logger : QTest::loggers->allLoggers())
585 logger->addBenchmarkResults(results);
586}
587
588void QTestLog::startLogging()
589{
590 {
591 QMutexLocker locker(&elapsedTimersMutex);
592 elapsedTotalTime.start();
593 elapsedFunctionTime.start();
594 }
595 for (auto &logger : QTest::loggers->allLoggers())
596 logger->startLogging();
597 QTest::oldMessageHandler = qInstallMessageHandler(QTest::messageHandler);
598}
599
600void QTestLog::stopLogging()
601{
602 qInstallMessageHandler(QTest::oldMessageHandler);
603 for (auto &logger : QTest::loggers->allLoggers())
604 logger->stopLogging();
605
606 QTest::loggers->clear();
607 saveCoverageTool(QTestResult::currentAppName(), failCount() != 0, QTestLog::installedTestCoverage());
608}
609
610void QTestLog::addLogger(LogMode mode, const char *filename)
611{
612 if (filename && strcmp(filename, "-") == 0)
613 filename = nullptr;
614
615 QAbstractTestLogger *logger = nullptr;
616 switch (mode) {
617 case QTestLog::Plain:
618 logger = new QPlainTestLogger(filename);
619 break;
620 case QTestLog::CSV:
621 logger = new QCsvBenchmarkLogger(filename);
622 break;
623 case QTestLog::XML:
624 logger = new QXmlTestLogger(QXmlTestLogger::Complete, filename);
625 break;
626 case QTestLog::LightXML:
627 logger = new QXmlTestLogger(QXmlTestLogger::Light, filename);
628 break;
629 case QTestLog::JUnitXML:
630 logger = new QJUnitTestLogger(filename);
631 break;
632 case QTestLog::TeamCity:
633 logger = new QTeamCityLogger(filename);
634 break;
635 case QTestLog::TAP:
636 logger = new QTapTestLogger(filename);
637 break;
638#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
639 case QTestLog::Apple:
640 logger = new QAppleTestLogger;
641 break;
642#endif
643#if defined(HAVE_XCTEST)
644 case QTestLog::XCTest:
645 logger = new QXcodeTestLogger;
646 break;
647#endif
648 }
649
650 QTEST_ASSERT(logger);
651 addLogger(std::unique_ptr<QAbstractTestLogger>{ logger });
652}
653
654/*!
655 \internal
656
657 Adds a new logger to the set of loggers that will be used
658 to report incidents and messages during testing.
659*/
660void QTestLog::addLogger(std::unique_ptr<QAbstractTestLogger> logger)
661{
662 QTEST_ASSERT(logger);
663 QTest::loggers()->addLogger(std::move(logger));
664}
665
666bool QTestLog::hasLoggers()
667{
668 return !QTest::loggers()->allLoggers().isEmpty();
669}
670
671/*!
672 \internal
673
674 Returns true if all loggers support repeated test runs
675*/
676bool QTestLog::isRepeatSupported()
677{
678 for (auto &logger : QTest::loggers->allLoggers())
679 if (!logger->isRepeatSupported())
680 return false;
681
682 return true;
683}
684
685bool QTestLog::loggerUsingStdout()
686{
687 auto loggersCapture = QTest::loggers->allLoggers();
688 return q20::ranges::any_of(loggersCapture.begin(), loggersCapture.end(), [](auto &logger) {
689 return logger->isLoggingToStdout();
690 });
691}
692
693void QTestLog::warn(const char *msg, const char *file, int line)
694{
695 QTEST_ASSERT(msg);
696
697 for (auto &logger : QTest::loggers->allLoggers())
698 logger->addMessage(QAbstractTestLogger::Warn, QString::fromUtf8(msg), file, line);
699}
700
701void QTestLog::info(const char *msg, const char *file, int line)
702{
703 QTEST_ASSERT(msg);
704
705 for (auto &logger : QTest::loggers->allLoggers())
706 logger->addMessage(QAbstractTestLogger::Info, QString::fromUtf8(msg), file, line);
707}
708
709void QTestLog::setVerboseLevel(int level)
710{
711 QTest::verbosity = level;
712}
713
714int QTestLog::verboseLevel()
715{
716 return QTest::verbosity;
717}
718
719void QTestLog::ignoreMessage(QtMsgType type, const char *msg)
720{
721 QTEST_ASSERT(msg);
722
723 const QMutexLocker mutexLocker(&QTest::mutex);
724 QTest::IgnoreResultList::append(QTest::ignoreResultList, type, QString::fromUtf8(msg));
725}
726
727#if QT_CONFIG(regularexpression)
728void QTestLog::ignoreMessage(QtMsgType type, const QRegularExpression &expression)
729{
730 QTEST_ASSERT(expression.isValid());
731
732 const QMutexLocker mutexLocker(&QTest::mutex);
733 QTest::IgnoreResultList::append(QTest::ignoreResultList, type, QVariant(expression));
734}
735#endif // QT_CONFIG(regularexpression)
736
737void QTestLog::failOnWarning()
738{
739 QTest::failOnWarningList.push_back({});
740}
741
742void QTestLog::failOnWarning(const char *msg)
743{
744 QTest::failOnWarningList.push_back(QString::fromUtf8(msg));
745}
746
747#if QT_CONFIG(regularexpression)
748void QTestLog::failOnWarning(const QRegularExpression &expression)
749{
750 QTEST_ASSERT(expression.isValid());
751
752 QTest::failOnWarningList.push_back(QVariant::fromValue(expression));
753}
754#endif // QT_CONFIG(regularexpression)
755
756void QTestLog::setMaxWarnings(int m)
757{
758 QTest::maxWarnings = m <= 0 ? INT_MAX : m + 2;
759}
760
761bool QTestLog::printAvailableTags = false;
762
763void QTestLog::setPrintAvailableTagsMode()
764{
765 printAvailableTags = true;
766}
767
768int QTestLog::passCount()
769{
770 return QTest::passes;
771}
772
773int QTestLog::failCount()
774{
775 return QTest::fails;
776}
777
778int QTestLog::skipCount()
779{
780 return QTest::skips;
781}
782
783int QTestLog::blacklistCount()
784{
785 return QTest::blacklists;
786}
787
788int QTestLog::totalCount()
789{
790 return passCount() + failCount() + skipCount() + blacklistCount();
791}
792
793void QTestLog::resetCounters()
794{
795 QTest::passes = 0;
796 QTest::fails = 0;
797 QTest::skips = 0;
798}
799
800void QTestLog::setInstalledTestCoverage(bool installed)
801{
802 QTest::installedTestCoverage = installed;
803}
804
805bool QTestLog::installedTestCoverage()
806{
807 return QTest::installedTestCoverage;
808}
809
810qint64 QTestLog::nsecsTotalTime()
811{
812 QMutexLocker locker(&elapsedTimersMutex);
813 return elapsedTotalTime.nsecsElapsed();
814}
815
816qint64 QTestLog::nsecsFunctionTime()
817{
818 QMutexLocker locker(&elapsedTimersMutex);
819 return elapsedFunctionTime.nsecsElapsed();
820}
821
822QT_END_NAMESPACE
823
824#include "moc_qtestlog_p.cpp"
static bool handleIgnoredMessage(QtMsgType type, const QString &message)
Definition qtestlog.cpp:218
static bool handleFailOnWarning(const QMessageLogContext &context, const QString &message)
Definition qtestlog.cpp:256
static void handleFatal()
Definition qtestlog.cpp:244
static IgnoreResultList * ignoreResultList
Definition qtestlog.cpp:205
int fails
Definition qtestlog.cpp:141
int passes
Definition qtestlog.cpp:142
static int maxWarnings
Definition qtestlog.cpp:213
static bool installedTestCoverage
Definition qtestlog.cpp:214
static QtMessageHandler oldMessageHandler
Definition qtestlog.cpp:216
@ Skipped
Definition qtestlog.cpp:145
@ Suppressed
Definition qtestlog.cpp:145
@ Unresolved
Definition qtestlog.cpp:145
int skips
Definition qtestlog.cpp:143
static constexpr bool isWarnOrWorse(QtMsgType type)
Definition qtestlog.cpp:285
static int verbosity
Definition qtestlog.cpp:212
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
Definition qtestlog.cpp:305
static std::vector< QVariant > failOnWarningList
Definition qtestlog.cpp:208
int blacklists
Definition qtestlog.cpp:144
static void saveCoverageTool(const char *appname, bool testfailed, bool installedTestCoverage)
Definition qtestlog.cpp:47
IgnoreResultList(QtMsgType tp, const QVariant &patternIn)
Definition qtestlog.cpp:149
static void clearList(IgnoreResultList *&list)
Definition qtestlog.cpp:152
IgnoreResultList * next
Definition qtestlog.cpp:202
bool matches(QtMsgType tp, const QString &message) const
Definition qtestlog.cpp:188
static bool stringsMatch(const QString &expected, const QString &actual)
Definition qtestlog.cpp:174
static void append(IgnoreResultList *&list, QtMsgType type, const QVariant &patternIn)
Definition qtestlog.cpp:161