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 char msg[maxMsgLen] = {'\0'};
276 std::snprintf(msg, maxMsgLen, "Received a warning that resulted in a failure:\n%s",
277 qPrintable(message));
278 QTestResult::addFailure(msg, context.file, context.line);
279 return true;
280 }
281 return false;
282 }
283
284 static constexpr bool isWarnOrWorse(QtMsgType type)
285 {
286 // ## TODO Inline this once we get to Qt 7 !
287#if QT_VERSION_MAJOR == 7 || defined(QT_BOOTSTRAPPED) // To match QtMsgType decl
288 return type >= QtWarningMsg;
289#else
290 // Until Qt 6, Info was > Fatal :-(
291 switch (type) {
292 case QtWarningMsg:
293 case QtCriticalMsg:
294 case QtFatalMsg:
295 return true;
296 case QtDebugMsg:
297 case QtInfoMsg:
298 return false;
299 }
300 Q_UNREACHABLE_RETURN(false);
301#endif
302 }
303
304 static void messageHandler(QtMsgType type, const QMessageLogContext & context, const QString &message)
305 {
306 static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(QTest::maxWarnings);
307
308 auto loggerCapture = loggers->allLoggers();
309
310 if (loggerCapture.isEmpty()) {
311 // the message handler may be called from a worker thread, after the main thread stopped
312 // logging. Forwarding to original message handler to avoid swallowing the message
313 Q_ASSERT(oldMessageHandler);
314 oldMessageHandler(type, context, message);
315 return;
316 }
317
318 if (handleIgnoredMessage(type, message)) {
319 // the message is expected, so just swallow it.
320 return;
321 }
322
323 if (isWarnOrWorse(type) && handleFailOnWarning(context, message)) {
324 if (type == QtFatalMsg)
326 return;
327 }
328
329 if (type != QtFatalMsg) {
330 if (counter.loadRelaxed() <= 0)
331 return;
332
333 if (!counter.deref()) {
334 for (auto &logger : loggerCapture)
335 logger->addMessage(QAbstractTestLogger::Warn,
336 QStringLiteral("Maximum amount of warnings exceeded. Use "
337 "-maxwarnings to override."));
338
339 return;
340 }
341 }
342
343 for (auto &logger : loggerCapture)
344 logger->addMessage(type, context, message);
345
346 if (type == QtFatalMsg) {
347 QTestResult::addFailure("Received a fatal error.", context.file, context.line);
349 }
350 }
351}
352
353void QTestLog::enterTestFunction(const char* function)
354{
355 {
356 QMutexLocker locker(&elapsedTimersMutex);
357 elapsedFunctionTime.start();
358 }
359 if (printAvailableTags)
360 return;
361
362 QTEST_ASSERT(function);
363
364 for (auto &logger : QTest::loggers->allLoggers())
365 logger->enterTestFunction(function);
366}
367
368void QTestLog::enterTestData(QTestData *data)
369{
370 QTEST_ASSERT(data);
371
372 for (auto &logger : QTest::loggers->allLoggers())
373 logger->enterTestData(data);
374}
375
376int QTestLog::unhandledIgnoreMessages()
377{
378 const QMutexLocker mutexLocker(&QTest::mutex);
379 int i = 0;
380 QTest::IgnoreResultList *list = QTest::ignoreResultList;
381 while (list) {
382 ++i;
383 list = list->next;
384 }
385 return i;
386}
387
388void QTestLog::leaveTestFunction()
389{
390 if (printAvailableTags)
391 return;
392
393 for (auto &logger : QTest::loggers->allLoggers())
394 logger->leaveTestFunction();
395}
396
397void QTestLog::printUnhandledIgnoreMessages()
398{
399 const QMutexLocker mutexLocker(&QTest::mutex);
400 QString message;
401 QTest::IgnoreResultList *list = QTest::ignoreResultList;
402 while (list) {
403 if (const auto *text = get_if<QString>(&list->pattern)) {
404 message = "Did not receive message: \"%1\""_L1.arg(*text);
405#if QT_CONFIG(regularexpression)
406 } else if (const auto *regex = get_if<QRegularExpression>(&list->pattern)) {
407 message = "Did not receive any message matching: \"%1\""_L1.arg(regex->pattern());
408#endif
409 } else {
410 Q_UNREACHABLE();
411 message = "Missing message of unrecognized pattern type: \"%1\""_L1.arg(
412 list->pattern.metaType().name());
413 }
414 for (auto &logger : QTest::loggers->allLoggers())
415 logger->addMessage(QAbstractTestLogger::Info, message);
416
417 list = list->next;
418 }
419}
420
421void QTestLog::clearIgnoreMessages()
422{
423 const QMutexLocker mutexLocker(&QTest::mutex);
424 QTest::IgnoreResultList::clearList(QTest::ignoreResultList);
425}
426
427void QTestLog::clearFailOnWarnings()
428{
429 QTest::failOnWarningList.clear();
430}
431
432void QTestLog::clearCurrentTestState()
433{
434 clearIgnoreMessages();
435 clearFailOnWarnings();
436 QTest::currentTestState = QTest::Unresolved;
437}
438
439void QTestLog::addPass(const char *msg)
440{
441 if (printAvailableTags)
442 return;
443
444 QTEST_ASSERT(msg);
445 Q_ASSERT(QTest::currentTestState == QTest::Unresolved);
446
447 ++QTest::passes;
448 QTest::currentTestState = QTest::Passed;
449
450 for (auto &logger : QTest::loggers->allLoggers())
451 logger->addIncident(QAbstractTestLogger::Pass, msg);
452}
453
454void QTestLog::addFail(const char *msg, const char *file, int line)
455{
456 QTEST_ASSERT(msg);
457
458 if (QTest::currentTestState == QTest::Unresolved) {
459 ++QTest::fails;
460 } else {
461 // After an XPASS/Continue, or fail or skip in a function the test
462 // calls, we can subsequently fail.
463 Q_ASSERT(QTest::currentTestState == QTest::Failed
464 || QTest::currentTestState == QTest::Skipped);
465 }
466 // It is up to particular loggers to decide whether to report such
467 // subsequent failures; they may carry useful information.
468
469 QTest::currentTestState = QTest::Failed;
470 for (auto &logger : QTest::loggers->allLoggers())
471 logger->addIncident(QAbstractTestLogger::Fail, msg, file, line);
472}
473
474void QTestLog::addXFail(const char *msg, const char *file, int line)
475{
476 QTEST_ASSERT(msg);
477
478 // Will be counted in addPass() if we get there.
479
480 for (auto &logger : QTest::loggers->allLoggers())
481 logger->addIncident(QAbstractTestLogger::XFail, msg, file, line);
482}
483
484void QTestLog::addXPass(const char *msg, const char *file, int line)
485{
486 QTEST_ASSERT(msg);
487
488 if (QTest::currentTestState == QTest::Unresolved) {
489 ++QTest::fails;
490 } else {
491 // After an XPASS/Continue, we can subsequently XPASS again.
492 // Likewise after a fail or skip in a function called by the test.
493 Q_ASSERT(QTest::currentTestState == QTest::Failed
494 || QTest::currentTestState == QTest::Skipped);
495 }
496
497 QTest::currentTestState = QTest::Failed;
498 for (auto &logger : QTest::loggers->allLoggers())
499 logger->addIncident(QAbstractTestLogger::XPass, msg, file, line);
500}
501
502void QTestLog::addBPass(const char *msg)
503{
504 QTEST_ASSERT(msg);
505 Q_ASSERT(QTest::currentTestState == QTest::Unresolved);
506
507 ++QTest::blacklists; // Not passes ?
508 QTest::currentTestState = QTest::Suppressed;
509
510 for (auto &logger : QTest::loggers->allLoggers())
511 logger->addIncident(QAbstractTestLogger::BlacklistedPass, msg);
512}
513
514void QTestLog::addBFail(const char *msg, const char *file, int line)
515{
516 QTEST_ASSERT(msg);
517
518 if (QTest::currentTestState == QTest::Unresolved) {
519 ++QTest::blacklists;
520 } else {
521 // After a BXPASS/Continue, we can subsequently fail.
522 // Likewise after a fail or skip in a function called by a test.
523 Q_ASSERT(QTest::currentTestState == QTest::Suppressed
524 || QTest::currentTestState == QTest::Skipped);
525 }
526
527 QTest::currentTestState = QTest::Suppressed;
528 for (auto &logger : QTest::loggers->allLoggers())
529 logger->addIncident(QAbstractTestLogger::BlacklistedFail, msg, file, line);
530}
531
532void QTestLog::addBXPass(const char *msg, const char *file, int line)
533{
534 QTEST_ASSERT(msg);
535
536 if (QTest::currentTestState == QTest::Unresolved) {
537 ++QTest::blacklists;
538 } else {
539 // After a BXPASS/Continue, we may BXPASS again.
540 // Likewise after a fail or skip in a function called by a test.
541 Q_ASSERT(QTest::currentTestState == QTest::Suppressed
542 || QTest::currentTestState == QTest::Skipped);
543 }
544
545 QTest::currentTestState = QTest::Suppressed;
546 for (auto &logger : QTest::loggers->allLoggers())
547 logger->addIncident(QAbstractTestLogger::BlacklistedXPass, msg, file, line);
548}
549
550void QTestLog::addBXFail(const char *msg, const char *file, int line)
551{
552 QTEST_ASSERT(msg);
553
554 // Will be counted in addBPass() if we get there.
555
556 for (auto &logger : QTest::loggers->allLoggers())
557 logger->addIncident(QAbstractTestLogger::BlacklistedXFail, msg, file, line);
558}
559
560void QTestLog::addSkip(const char *msg, const char *file, int line)
561{
562 QTEST_ASSERT(msg);
563
564 if (QTest::currentTestState == QTest::Unresolved) {
565 ++QTest::skips;
566 QTest::currentTestState = QTest::Skipped;
567 } else {
568 // After an B?XPASS/Continue, we might subsequently skip.
569 // Likewise after a skip in a function called by a test.
570 Q_ASSERT(QTest::currentTestState == QTest::Suppressed
571 || QTest::currentTestState == QTest::Failed
572 || QTest::currentTestState == QTest::Skipped);
573 }
574 // It is up to particular loggers to decide whether to report such
575 // subsequent skips; they may carry useful information.
576
577 for (auto &logger : QTest::loggers->allLoggers())
578 logger->addIncident(QAbstractTestLogger::Skip, msg, file, line);
579}
580
581void QTestLog::addBenchmarkResults(const QList<QBenchmarkResult> &results)
582{
583 for (auto &logger : QTest::loggers->allLoggers())
584 logger->addBenchmarkResults(results);
585}
586
587void QTestLog::startLogging()
588{
589 {
590 QMutexLocker locker(&elapsedTimersMutex);
591 elapsedTotalTime.start();
592 elapsedFunctionTime.start();
593 }
594 for (auto &logger : QTest::loggers->allLoggers())
595 logger->startLogging();
596 QTest::oldMessageHandler = qInstallMessageHandler(QTest::messageHandler);
597}
598
599void QTestLog::stopLogging()
600{
601 qInstallMessageHandler(QTest::oldMessageHandler);
602 for (auto &logger : QTest::loggers->allLoggers())
603 logger->stopLogging();
604
605 QTest::loggers->clear();
606 saveCoverageTool(QTestResult::currentAppName(), failCount() != 0, QTestLog::installedTestCoverage());
607}
608
609void QTestLog::addLogger(LogMode mode, const char *filename)
610{
611 if (filename && strcmp(filename, "-") == 0)
612 filename = nullptr;
613
614 QAbstractTestLogger *logger = nullptr;
615 switch (mode) {
616 case QTestLog::Plain:
617 logger = new QPlainTestLogger(filename);
618 break;
619 case QTestLog::CSV:
620 logger = new QCsvBenchmarkLogger(filename);
621 break;
622 case QTestLog::XML:
623 logger = new QXmlTestLogger(QXmlTestLogger::Complete, filename);
624 break;
625 case QTestLog::LightXML:
626 logger = new QXmlTestLogger(QXmlTestLogger::Light, filename);
627 break;
628 case QTestLog::JUnitXML:
629 logger = new QJUnitTestLogger(filename);
630 break;
631 case QTestLog::TeamCity:
632 logger = new QTeamCityLogger(filename);
633 break;
634 case QTestLog::TAP:
635 logger = new QTapTestLogger(filename);
636 break;
637#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
638 case QTestLog::Apple:
639 logger = new QAppleTestLogger;
640 break;
641#endif
642#if defined(HAVE_XCTEST)
643 case QTestLog::XCTest:
644 logger = new QXcodeTestLogger;
645 break;
646#endif
647 }
648
649 QTEST_ASSERT(logger);
650 addLogger(std::unique_ptr<QAbstractTestLogger>{ logger });
651}
652
653/*!
654 \internal
655
656 Adds a new logger to the set of loggers that will be used
657 to report incidents and messages during testing.
658*/
659void QTestLog::addLogger(std::unique_ptr<QAbstractTestLogger> logger)
660{
661 QTEST_ASSERT(logger);
662 QTest::loggers()->addLogger(std::move(logger));
663}
664
665bool QTestLog::hasLoggers()
666{
667 return !QTest::loggers()->allLoggers().isEmpty();
668}
669
670/*!
671 \internal
672
673 Returns true if all loggers support repeated test runs
674*/
675bool QTestLog::isRepeatSupported()
676{
677 for (auto &logger : QTest::loggers->allLoggers())
678 if (!logger->isRepeatSupported())
679 return false;
680
681 return true;
682}
683
684bool QTestLog::loggerUsingStdout()
685{
686 auto loggersCapture = QTest::loggers->allLoggers();
687 return q20::ranges::any_of(loggersCapture.begin(), loggersCapture.end(), [](auto &logger) {
688 return logger->isLoggingToStdout();
689 });
690}
691
692void QTestLog::warn(const char *msg, const char *file, int line)
693{
694 QTEST_ASSERT(msg);
695
696 for (auto &logger : QTest::loggers->allLoggers())
697 logger->addMessage(QAbstractTestLogger::Warn, QString::fromUtf8(msg), file, line);
698}
699
700void QTestLog::info(const char *msg, const char *file, int line)
701{
702 QTEST_ASSERT(msg);
703
704 for (auto &logger : QTest::loggers->allLoggers())
705 logger->addMessage(QAbstractTestLogger::Info, QString::fromUtf8(msg), file, line);
706}
707
708void QTestLog::setVerboseLevel(int level)
709{
710 QTest::verbosity = level;
711}
712
713int QTestLog::verboseLevel()
714{
715 return QTest::verbosity;
716}
717
718void QTestLog::ignoreMessage(QtMsgType type, const char *msg)
719{
720 QTEST_ASSERT(msg);
721
722 const QMutexLocker mutexLocker(&QTest::mutex);
723 QTest::IgnoreResultList::append(QTest::ignoreResultList, type, QString::fromUtf8(msg));
724}
725
726#if QT_CONFIG(regularexpression)
727void QTestLog::ignoreMessage(QtMsgType type, const QRegularExpression &expression)
728{
729 QTEST_ASSERT(expression.isValid());
730
731 const QMutexLocker mutexLocker(&QTest::mutex);
732 QTest::IgnoreResultList::append(QTest::ignoreResultList, type, QVariant(expression));
733}
734#endif // QT_CONFIG(regularexpression)
735
736void QTestLog::failOnWarning()
737{
738 QTest::failOnWarningList.push_back({});
739}
740
741void QTestLog::failOnWarning(const char *msg)
742{
743 QTest::failOnWarningList.push_back(QString::fromUtf8(msg));
744}
745
746#if QT_CONFIG(regularexpression)
747void QTestLog::failOnWarning(const QRegularExpression &expression)
748{
749 QTEST_ASSERT(expression.isValid());
750
751 QTest::failOnWarningList.push_back(QVariant::fromValue(expression));
752}
753#endif // QT_CONFIG(regularexpression)
754
755void QTestLog::setMaxWarnings(int m)
756{
757 QTest::maxWarnings = m <= 0 ? INT_MAX : m + 2;
758}
759
760bool QTestLog::printAvailableTags = false;
761
762void QTestLog::setPrintAvailableTagsMode()
763{
764 printAvailableTags = true;
765}
766
767int QTestLog::passCount()
768{
769 return QTest::passes;
770}
771
772int QTestLog::failCount()
773{
774 return QTest::fails;
775}
776
777int QTestLog::skipCount()
778{
779 return QTest::skips;
780}
781
782int QTestLog::blacklistCount()
783{
784 return QTest::blacklists;
785}
786
787int QTestLog::totalCount()
788{
789 return passCount() + failCount() + skipCount() + blacklistCount();
790}
791
792void QTestLog::resetCounters()
793{
794 QTest::passes = 0;
795 QTest::fails = 0;
796 QTest::skips = 0;
797}
798
799void QTestLog::setInstalledTestCoverage(bool installed)
800{
801 QTest::installedTestCoverage = installed;
802}
803
804bool QTestLog::installedTestCoverage()
805{
806 return QTest::installedTestCoverage;
807}
808
809qint64 QTestLog::nsecsTotalTime()
810{
811 QMutexLocker locker(&elapsedTimersMutex);
812 return elapsedTotalTime.nsecsElapsed();
813}
814
815qint64 QTestLog::nsecsFunctionTime()
816{
817 QMutexLocker locker(&elapsedTimersMutex);
818 return elapsedFunctionTime.nsecsElapsed();
819}
820
821QT_END_NAMESPACE
822
823#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:284
static int verbosity
Definition qtestlog.cpp:212
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
Definition qtestlog.cpp:304
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