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