Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtestcase.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2022 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <QtTest/qtestcase.h>
6#include <QtTest/private/qtestcase_p.h>
7#include <QtTest/qtestassert.h>
8
9#include <QtCore/qbytearray.h>
10#include <QtCore/qcoreapplication.h>
11#include <QtCore/qdebug.h>
12#include <QtCore/qdir.h>
13#include <QtCore/qdirlisting.h>
14#include <QtCore/qfile.h>
15#include <QtCore/qfileinfo.h>
16#include <QtCore/qfloat16.h>
17#include <QtCore/qlibraryinfo.h>
18#include <QtCore/qlist.h>
19#include <QtCore/qmetaobject.h>
20#include <QtCore/qobject.h>
21#include <QtCore/qstringlist.h>
22#include <QtCore/qtemporarydir.h>
23#include <QtCore/qthread.h>
24#include <QtCore/qvarlengtharray.h>
25#include <QtCore/private/qlocking_p.h>
26#include <QtCore/private/qtools_p.h>
27#include <QtCore/private/qwaitcondition_p.h>
28
29#include <QtCore/qtestsupport_core.h>
30
31#include <QtTest/private/qtestlog_p.h>
32#include <QtTest/private/qtesttable_p.h>
33#include <QtTest/qtestdata.h>
34#include <QtTest/private/qtestresult_p.h>
35#include <QtTest/private/qsignaldumper_p.h>
36#include <QtTest/private/qbenchmark_p.h>
37#if QT_CONFIG(batch_test_support)
38#include <QtTest/private/qtestregistry_p.h>
39#endif // QT_CONFIG(batch_test_support)
40#include <QtTest/private/cycle_p.h>
41#include <QtTest/private/qtestblacklist_p.h>
42#include <QtTest/private/qtestcrashhandler_p.h>
43#if defined(HAVE_XCTEST)
44#include <QtTest/private/qxctestlogger_p.h>
45#endif
46#if defined Q_OS_MACOS
47#include <QtTest/private/qtestutil_macos_p.h>
48#endif
49
50#if defined(Q_OS_DARWIN)
51#include <QtTest/private/qappletestlogger_p.h>
52#endif
53
54#include <algorithm>
55#include <array>
56#if !defined(Q_OS_INTEGRITY) || __GHS_VERSION_NUMBER > 202014
57# include <charconv>
58#else
59// Broken implementation, causes link failures just by #include'ing!
60# undef __cpp_lib_to_chars // in case <version> was included
61#endif
62#include <chrono>
63#include <cmath>
64#include <limits>
65#include <memory>
66#include <mutex>
67#include <numeric>
68#include <optional>
69
70#include <stdarg.h>
71#include <stdio.h>
72#include <stdlib.h>
73
74#if defined(Q_OS_LINUX)
75#include <sys/types.h>
76#include <fcntl.h>
77#endif
78
79#ifdef Q_OS_WIN
80# include <iostream>
81# if !defined(Q_CC_MINGW) || (defined(Q_CC_MINGW) && defined(__MINGW64_VERSION_MAJOR))
82# include <crtdbg.h>
83# endif
84#include <qt_windows.h> // for Sleep
85#endif
86#ifdef Q_OS_UNIX
87#include <QtCore/private/qcore_unix_p.h>
88
89#include <errno.h>
90#if __has_include(<paths.h>)
91# include <paths.h>
92#endif
93#include <signal.h>
94#include <time.h>
95#include <sys/mman.h>
96#include <sys/uio.h>
97#include <sys/wait.h>
98#include <unistd.h>
99# if !defined(Q_OS_INTEGRITY)
100# include <sys/resource.h>
101# endif
102# ifndef _PATH_DEFPATH
103# define _PATH_DEFPATH "/usr/bin:/bin"
104# endif
105# ifndef SIGSTKSZ
106# define SIGSTKSZ 0 /* we have code to set the minimum */
107# endif
108# ifndef SA_RESETHAND
109# define SA_RESETHAND 0
110# endif
111#endif
112
113#if defined(Q_OS_MACOS)
114#include <IOKit/pwr_mgt/IOPMLib.h>
115#include <mach/task.h>
116#include <mach/mach_init.h>
117#include <CoreFoundation/CFPreferences.h>
118#endif
119
120#if defined(Q_OS_WASM)
121#include <emscripten.h>
122#endif
123
124#include <vector>
125
127
128using namespace Qt::StringLiterals;
129
132
133static bool installCoverageTool(const char * appname, const char * testname)
134{
135#if defined(__COVERAGESCANNER__) && !QT_CONFIG(testlib_selfcover)
136 if (!qEnvironmentVariableIsEmpty("QT_TESTCOCOON_ACTIVE"))
137 return false;
138 // Set environment variable QT_TESTCOCOON_ACTIVE to prevent an eventual subtest from
139 // being considered as a stand-alone test regarding the coverage analysis.
140 qputenv("QT_TESTCOCOON_ACTIVE", "1");
141
142 // Install Coverage Tool
143 __coveragescanner_install(appname);
144 __coveragescanner_testname(testname);
145 __coveragescanner_clear();
146 return true;
147#else
148 Q_UNUSED(appname);
149 Q_UNUSED(testname);
150 return false;
151#endif
152}
153
154static bool isValidSlot(const QMetaMethod &sl)
155{
156 if (sl.access() != QMetaMethod::Private || sl.parameterCount() != 0
157 || sl.returnType() != QMetaType::Void || sl.methodType() != QMetaMethod::Slot)
158 return false;
159 const QByteArray name = sl.name();
160 return !(name.isEmpty() || name.endsWith("_data")
161 || name == "initTestCase" || name == "cleanupTestCase"
162 || name == "init" || name == "cleanup");
163}
164
165namespace QTestPrivate
166{
167 Q_TESTLIB_EXPORT Qt::MouseButtons qtestMouseButtons = Qt::NoButton;
168}
169
170namespace {
171
172class TestFailedException : public std::exception // clazy:exclude=copyable-polymorphic
173{
174public:
175 TestFailedException() = default;
176 ~TestFailedException() override = default;
177
178 const char *what() const noexcept override { return "QtTest: test failed"; }
179};
180
181class TestSkippedException : public std::exception // clazy:exclude=copyable-polymorphic
182{
183public:
184 TestSkippedException() = default;
185 ~TestSkippedException() override = default;
186
187 const char *what() const noexcept override { return "QtTest: test was skipped"; }
188};
189
190} // unnamed namespace
191
192namespace QTest
193{
194
195void Internal::throwOnFail() { throw TestFailedException(); }
196void Internal::throwOnSkip() { throw TestSkippedException(); }
197
200
202{
203 if (g_throwOnFail.loadRelaxed() > 0)
205}
206
208{
209 if (g_throwOnSkip.loadRelaxed() > 0)
211}
212
325void setThrowOnFail(bool enable) noexcept
326{
327 g_throwOnFail.fetchAndAddRelaxed(enable ? 1 : -1);
328}
329
352void setThrowOnSkip(bool enable) noexcept
353{
354 g_throwOnSkip.fetchAndAddRelaxed(enable ? 1 : -1);
355}
356
357QString Internal::formatTryTimeoutDebugMessage(q_no_char8_t::QUtf8StringView expr, int timeout, int actual)
358{
359 return "QTestLib: This test case check (\"%1\") failed because the requested timeout (%2 ms) "
360 "was too short, %3 ms would have been sufficient this time."_L1
361 // ### Qt 7: remove the toString() (or earlier, when arg() can handle QUtf8StringView), passing the view directly
362 .arg(expr.toString(), QString::number(timeout), QString::number(actual));
363}
364
365extern Q_TESTLIB_EXPORT int lastMouseTimestamp;
366
367class WatchDog;
368
369static QObject *currentTestObject = nullptr;
371static bool inTestFunction = false;
372
373#if defined(Q_OS_MACOS)
374static IOPMAssertionID macPowerSavingDisabled = 0;
375#endif
376
378public:
379 Q_DISABLE_COPY_MOVE(TestMethods)
380
382
384
385 void invokeTests(QObject *testObject) const;
386
387 static QMetaMethod findMethod(const QObject *obj, const char *signature);
388
389private:
390 bool invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const;
391 void invokeTestOnData(int index) const;
392
393 QMetaMethod m_initTestCaseMethod; // might not exist, check isValid().
394 QMetaMethod m_initTestCaseDataMethod;
395 QMetaMethod m_cleanupTestCaseMethod;
396 QMetaMethod m_initMethod;
397 QMetaMethod m_cleanupMethod;
398
399 MetaMethods m_methods;
400};
401
403 : m_initTestCaseMethod(TestMethods::findMethod(o, "initTestCase()"))
404 , m_initTestCaseDataMethod(TestMethods::findMethod(o, "initTestCase_data()"))
405 , m_cleanupTestCaseMethod(TestMethods::findMethod(o, "cleanupTestCase()"))
406 , m_initMethod(TestMethods::findMethod(o, "init()"))
407 , m_cleanupMethod(TestMethods::findMethod(o, "cleanup()"))
408 , m_methods(std::move(m))
409{
410 if (m_methods.empty()) {
411 const QMetaObject *metaObject = o->metaObject();
412 const int count = metaObject->methodCount();
413 m_methods.reserve(count);
414 for (int i = 0; i < count; ++i) {
415 const QMetaMethod me = metaObject->method(i);
416 if (isValidSlot(me))
417 m_methods.push_back(me);
418 }
419 }
420}
421
422QMetaMethod TestMethods::findMethod(const QObject *obj, const char *signature)
423{
424 const QMetaObject *metaObject = obj->metaObject();
425 const int funcIndex = metaObject->indexOfMethod(signature);
426 return funcIndex >= 0 ? metaObject->method(funcIndex) : QMetaMethod();
427}
428
429static int keyDelay = -1;
430static int mouseDelay = -1;
431static int eventDelay = -1;
432#if QT_CONFIG(thread)
433static int timeout = -1;
434#endif
435static int repetitions = 1;
436static bool repeatForever = false;
437static bool skipBlacklisted = false;
438
439namespace Internal {
440bool noCrashHandler = false;
441}
442
444{
445 if (!m.isValid())
446 return false;
447 bool ok = true;
448 try { ok = m.invoke(obj, Qt ::DirectConnection); }
449 catch (const TestFailedException &) {} // ignore (used for control flow)
450 catch (const TestSkippedException &) {} // ditto
451 // every other exception is someone else's problem
452 return ok;
453}
454
456{
457 const QMetaObject *metaObject = obj->metaObject();
458 int funcIndex = metaObject->indexOfMethod(methodName);
459 // doesn't generate a warning if it doesn't exist:
460 invokeTestMethodIfValid(metaObject->method(funcIndex), obj);
461}
462
464{
465 if (eventDelay == -1) {
466 const QByteArray env = qgetenv("QTEST_EVENT_DELAY");
467 if (!env.isEmpty())
468 eventDelay = atoi(env.constData());
469 else
470 eventDelay = 0;
471 }
472 return eventDelay;
473}
474
475int Q_TESTLIB_EXPORT defaultMouseDelay()
476{
477 if (mouseDelay == -1) {
478 const QByteArray env = qgetenv("QTEST_MOUSEEVENT_DELAY");
479 if (!env.isEmpty())
480 mouseDelay = atoi(env.constData());
481 else
483 }
484 return mouseDelay;
485}
486
487int Q_TESTLIB_EXPORT defaultKeyDelay()
488{
489 if (keyDelay == -1) {
490 const QByteArray env = qgetenv("QTEST_KEYEVENT_DELAY");
491 if (!env.isEmpty())
492 keyDelay = atoi(env.constData());
493 else
495 }
496 return keyDelay;
497}
498#if QT_CONFIG(thread)
499static std::chrono::milliseconds defaultTimeout()
500{
501 if (timeout == -1) {
502 bool ok = false;
503 timeout = qEnvironmentVariableIntValue("QTEST_FUNCTION_TIMEOUT", &ok);
504
505 if (!ok || timeout <= 0)
506 timeout = 5*60*1000;
507 }
508 return std::chrono::milliseconds{timeout};
509}
510#endif
511
512Q_TESTLIB_EXPORT bool printAvailableFunctions = false;
513Q_TESTLIB_EXPORT QStringList testFunctions;
514Q_TESTLIB_EXPORT QStringList testTags;
515
516static bool qPrintTestSlots(FILE *stream, const char *filter = nullptr, const char *preamble = "")
517{
518 const auto matches = [filter](const QByteArray &s) {
521 };
522 bool matched = false;
523 for (int i = 0; i < QTest::currentTestObject->metaObject()->methodCount(); ++i) {
524 QMetaMethod sl = QTest::currentTestObject->metaObject()->method(i);
525 if (isValidSlot(sl)) {
526 const QByteArray signature = sl.methodSignature();
527 if (matches(signature)) {
528 fprintf(stream, "%s%s\n", preamble, signature.constData());
529 preamble = "";
530 matched = true;
531 }
532 }
533 }
534 return matched;
535}
536
537static void qPrintDataTags(FILE *stream)
538{
539 // Avoid invoking the actual test functions, and also avoid printing irrelevant output:
541
542 // Get global data tags:
544 invokeTestMethodIfExists("initTestCase_data()");
545 const QTestTable *gTable = QTestTable::globalTestTable();
546
547 const QMetaObject *currTestMetaObj = QTest::currentTestObject->metaObject();
548
549 // Process test functions:
550 for (int i = 0; i < currTestMetaObj->methodCount(); ++i) {
551 QMetaMethod tf = currTestMetaObj->method(i);
552
553 if (isValidSlot(tf)) {
554
555 // Retrieve local tags:
556 QStringList localTags;
558 char *slot = qstrdup(tf.methodSignature().constData());
559 slot[strlen(slot) - 2] = '\0';
560 QByteArray member;
561 member.resize(qstrlen(slot) + qstrlen("_data()") + 1);
562 qsnprintf(member.data(), member.size(), "%s_data()", slot);
564 const int dataCount = table.dataCount();
565 localTags.reserve(dataCount);
566 for (int j = 0; j < dataCount; ++j)
567 localTags << QLatin1StringView(table.testData(j)->dataTag());
568
569 // Print all tag combinations:
570 if (gTable->dataCount() == 0) {
571 if (localTags.size() == 0) {
572 // No tags at all, so just print the test function:
573 fprintf(stream, "%s %s\n", currTestMetaObj->className(), slot);
574 } else {
575 // Only local tags, so print each of them:
576 for (int k = 0; k < localTags.size(); ++k)
577 fprintf(
578 stream, "%s %s %s\n",
579 currTestMetaObj->className(), slot, localTags.at(k).toLatin1().data());
580 }
581 } else {
582 for (int j = 0; j < gTable->dataCount(); ++j) {
583 if (localTags.size() == 0) {
584 // Only global tags, so print the current one:
585 fprintf(
586 stream, "%s %s __global__ %s\n",
587 currTestMetaObj->className(), slot, gTable->testData(j)->dataTag());
588 } else {
589 // Local and global tags, so print each of the local ones and
590 // the current global one:
591 for (int k = 0; k < localTags.size(); ++k)
592 fprintf(
593 stream, "%s %s %s __global__ %s\n", currTestMetaObj->className(), slot,
594 localTags.at(k).toLatin1().data(), gTable->testData(j)->dataTag());
595 }
596 }
597 }
598
599 delete[] slot;
600 }
601 }
602}
603
604static int qToInt(const char *str)
605{
606 char *pEnd;
607 int l = static_cast<int>(strtol(str, &pEnd, 10));
608 if (*pEnd != 0) {
609 fprintf(stderr, "Invalid numeric parameter: '%s'\n", str);
610 exit(1);
611 }
612 return l;
613}
614
615Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool qml)
616{
617 int logFormat = -1; // Not set
618 const char *logFilename = nullptr;
619
620 repetitions = 1;
621 repeatForever = false;
622
623 QTest::testFunctions.clear();
624 QTest::testTags.clear();
625
626 if (qEnvironmentVariableIsSet("QTEST_THROW_ON_FAIL"))
628 if (qEnvironmentVariableIsSet("QTEST_THROW_ON_SKIP"))
630
631#if defined(Q_OS_DARWIN) && defined(HAVE_XCTEST)
633 logFormat = QTestLog::XCTest;
634#endif
635
636 const char *testOptions =
637 " New-style logging options:\n"
638 " -o filename,format : Output results to file in the specified format\n"
639 " Use - to output to stdout\n"
640 " Valid formats are:\n"
641 " txt : Plain text\n"
642 " csv : CSV format (suitable for benchmarks)\n"
643 " junitxml : XML JUnit document\n"
644 " xml : XML document\n"
645 " lightxml : A stream of XML tags\n"
646 " teamcity : TeamCity format\n"
647 " tap : Test Anything Protocol\n"
648 "\n"
649 " *** Multiple loggers can be specified, but at most one can log to stdout.\n"
650 "\n"
651 " Old-style logging options:\n"
652 " -o filename : Write the output into file\n"
653 " -txt : Output results in Plain Text\n"
654 " -csv : Output results in a CSV format (suitable for benchmarks)\n"
655 " -junitxml : Output results as XML JUnit document\n"
656 " -xml : Output results as XML document\n"
657 " -lightxml : Output results as stream of XML tags\n"
658 " -teamcity : Output results in TeamCity format\n"
659 " -tap : Output results in Test Anything Protocol format\n"
660 "\n"
661 " *** If no output file is specified, stdout is assumed.\n"
662 " *** If no output format is specified, -txt is assumed.\n"
663 "\n"
664 " Test log detail options:\n"
665 " -silent : Log failures and fatal errors only\n"
666 " -v1 : Log the start of each testfunction\n"
667 " -v2 : Log each QVERIFY/QCOMPARE/QTEST (implies -v1)\n"
668 " -vs : Log every signal emission and resulting slot invocations\n"
669 "\n"
670 " *** The -silent and -v1 options only affect plain text output.\n"
671 "\n"
672 " Testing options:\n"
673 " -functions : Returns a list of current testfunctions\n"
674 " -datatags : Returns a list of current data tags.\n"
675 " A global data tag is preceded by ' __global__ '.\n"
676 " -eventdelay ms : Set default delay for mouse and keyboard simulation to ms milliseconds\n"
677 " -keydelay ms : Set default delay for keyboard simulation to ms milliseconds\n"
678 " -mousedelay ms : Set default delay for mouse simulation to ms milliseconds\n"
679 " -maxwarnings n : Sets the maximum amount of messages to output.\n"
680 " 0 means unlimited, default: 2000\n"
681 " -nocrashhandler : Disables the crash handler. Useful for debugging crashes.\n"
682 " -repeat n : Run the testsuite n times or until the test fails.\n"
683 " Useful for finding flaky tests. If negative, the tests are\n"
684 " repeated forever. This is intended as a developer tool, and\n"
685 " is only supported with the plain text logger.\n"
686 " -skipblacklisted : Skip blacklisted tests. Useful for measuring test coverage.\n"
687 " -[no]throwonfail : Enables/disables throwing on QCOMPARE()/QVERIFY()/etc.\n"
688 " Default: off, unless QTEST_THROW_ON_FAIL is set."
689 " -[no]throwonskip : Enables/disables throwing on QSKIP().\n"
690 " Default: off, unless QTEST_THROW_ON_SKIP is set."
691 "\n"
692 " Benchmarking options:\n"
693#if QT_CONFIG(valgrind)
694 " -callgrind : Use callgrind to time benchmarks\n"
695#endif
696#ifdef QTESTLIB_USE_PERF_EVENTS
697 " -perf : Use Linux perf events to time benchmarks\n"
698 " -perfcounter name : Use the counter named 'name'\n"
699 " -perfcounterlist : Lists the counters available\n"
700#endif
701#ifdef HAVE_TICK_COUNTER
702 " -tickcounter : Use CPU tick counters to time benchmarks\n"
703#endif
704 " -eventcounter : Counts events received during benchmarks\n"
705 " -minimumvalue n : Sets the minimum acceptable measurement value\n"
706 " -minimumtotal n : Sets the minimum acceptable total for repeated executions of a test function\n"
707 " -iterations n : Sets the number of accumulation iterations.\n"
708 " -median n : Sets the number of median iterations.\n"
709 " -vb : Print out verbose benchmarking information.\n";
710
711 for (int i = 1; i < argc; ++i) {
712 if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "--help") == 0
713 || strcmp(argv[i], "/?") == 0) {
714 printf(" Usage: %s [options] [testfunction[:testdata]]...\n"
715 " By default, all testfunctions will be run.\n\n"
716 "%s", argv[0], testOptions);
717
718 if (qml) {
719 printf("\n"
720 " QmlTest options:\n"
721 " -import dir : Specify an import directory.\n"
722 " -plugins dir : Specify a directory where to search for plugins.\n"
723 " -input dir/file : Specify the root directory for test cases or a single test case file.\n"
724 " -translation file : Specify the translation file.\n"
725 " -file-selector dir : Specify a file selector for the QML engine.\n"
726 );
727 }
728
729 printf("\n"
730 " -help : This help\n");
731 exit(0);
732 } else if (strcmp(argv[i], "-functions") == 0) {
733 if (qml) {
735 } else {
736 qPrintTestSlots(stdout);
737 exit(0);
738 }
739 } else if (strcmp(argv[i], "-datatags") == 0) {
740 if (!qml) {
741 qPrintDataTags(stdout);
742 exit(0);
743 }
744 } else if (strcmp(argv[i], "-txt") == 0) {
745 logFormat = QTestLog::Plain;
746 } else if (strcmp(argv[i], "-csv") == 0) {
747 logFormat = QTestLog::CSV;
748 } else if (strcmp(argv[i], "-junitxml") == 0) {
749 logFormat = QTestLog::JUnitXML;
750 } else if (strcmp(argv[i], "-xunitxml") == 0) {
751 fprintf(stderr, "WARNING: xunitxml is deprecated. Please use junitxml.\n");
752 logFormat = QTestLog::JUnitXML;
753 } else if (strcmp(argv[i], "-xml") == 0) {
754 logFormat = QTestLog::XML;
755 } else if (strcmp(argv[i], "-lightxml") == 0) {
756 logFormat = QTestLog::LightXML;
757 } else if (strcmp(argv[i], "-teamcity") == 0) {
758 logFormat = QTestLog::TeamCity;
759 } else if (strcmp(argv[i], "-tap") == 0) {
760 logFormat = QTestLog::TAP;
761 } else if (strcmp(argv[i], "-silent") == 0) {
763 } else if (strcmp(argv[i], "-v1") == 0) {
765 } else if (strcmp(argv[i], "-v2") == 0) {
767 } else if (strcmp(argv[i], "-vs") == 0) {
769 } else if (strcmp(argv[i], "-o") == 0) {
770 if (i + 1 >= argc) {
771 fprintf(stderr, "-o needs an extra parameter specifying the filename and optional format\n");
772 exit(1);
773 }
774 ++i;
775 // Do we have the old or new style -o option?
776 char *filename = new char[strlen(argv[i])+1];
777 char *format = new char[strlen(argv[i])+1];
778 if (sscanf(argv[i], "%[^,],%s", filename, format) == 1) {
779 // Old-style
780 logFilename = argv[i];
781 } else {
782 // New-style
783 if (strcmp(format, "txt") == 0)
784 logFormat = QTestLog::Plain;
785 else if (strcmp(format, "csv") == 0)
786 logFormat = QTestLog::CSV;
787 else if (strcmp(format, "lightxml") == 0)
788 logFormat = QTestLog::LightXML;
789 else if (strcmp(format, "xml") == 0)
790 logFormat = QTestLog::XML;
791 else if (strcmp(format, "junitxml") == 0)
792 logFormat = QTestLog::JUnitXML;
793 else if (strcmp(format, "xunitxml") == 0) {
794 fprintf(stderr, "WARNING: xunitxml is deprecated. Please use junitxml.\n");
795 logFormat = QTestLog::JUnitXML;
796 } else if (strcmp(format, "teamcity") == 0)
797 logFormat = QTestLog::TeamCity;
798 else if (strcmp(format, "tap") == 0)
799 logFormat = QTestLog::TAP;
800 else {
801 fprintf(stderr, "output format must be one of txt, csv, lightxml, xml, tap, teamcity or junitxml\n");
802 exit(1);
803 }
804 if (strcmp(filename, "-") == 0 && QTestLog::loggerUsingStdout()) {
805 fprintf(stderr, "only one logger can log to stdout\n");
806 exit(1);
807 }
808 QTestLog::addLogger(QTestLog::LogMode(logFormat), filename);
809 }
810 delete [] filename;
811 delete [] format;
812 } else if (strcmp(argv[i], "-eventdelay") == 0) {
813 if (i + 1 >= argc) {
814 fprintf(stderr, "-eventdelay needs an extra parameter to indicate the delay(ms)\n");
815 exit(1);
816 } else {
817 QTest::eventDelay = qToInt(argv[++i]);
818 }
819 } else if (strcmp(argv[i], "-keydelay") == 0) {
820 if (i + 1 >= argc) {
821 fprintf(stderr, "-keydelay needs an extra parameter to indicate the delay(ms)\n");
822 exit(1);
823 } else {
824 QTest::keyDelay = qToInt(argv[++i]);
825 }
826 } else if (strcmp(argv[i], "-mousedelay") == 0) {
827 if (i + 1 >= argc) {
828 fprintf(stderr, "-mousedelay needs an extra parameter to indicate the delay(ms)\n");
829 exit(1);
830 } else {
831 QTest::mouseDelay = qToInt(argv[++i]);
832 }
833 } else if (strcmp(argv[i], "-maxwarnings") == 0) {
834 if (i + 1 >= argc) {
835 fprintf(stderr, "-maxwarnings needs an extra parameter with the amount of warnings\n");
836 exit(1);
837 } else {
839 }
840 } else if (strcmp(argv[i], "-repeat") == 0) {
841 if (i + 1 >= argc) {
842 fprintf(stderr, "-repeat needs an extra parameter for the number of repetitions\n");
843 exit(1);
844 } else {
845 repetitions = qToInt(argv[++i]);
847 }
848 } else if (strcmp(argv[i], "-nocrashhandler") == 0) {
850 } else if (strcmp(argv[i], "-skipblacklisted") == 0) {
852 } else if (strcmp(argv[i], "-throwonfail") == 0) {
854 } else if (strcmp(argv[i], "-nothrowonfail") == 0) {
856 } else if (strcmp(argv[i], "-throwonskip") == 0) {
858 } else if (strcmp(argv[i], "-nothrowonskip") == 0) {
860#if QT_CONFIG(valgrind)
861 } else if (strcmp(argv[i], "-callgrind") == 0) {
863 fprintf(stderr,
864 "WARNING: Valgrind not found or too old. "
865 "Make sure it is installed and in your path. "
866 "Using the walltime measurer.\n");
867 } else if (QFileInfo(QDir::currentPath()).isWritable()) {
870 } else {
871 fprintf(stderr,
872 "WARNING: Current directory not writable. "
873 "Using the walltime measurer.\n");
874 }
875 } else if (strcmp(argv[i], "-callgrindchild") == 0) { // "private" option
877 QBenchmarkGlobalData::current->callgrindOutFileBase =
879#endif
880#ifdef QTESTLIB_USE_PERF_EVENTS
881 } else if (strcmp(argv[i], "-perf") == 0) {
883 // perf available
885 } else {
886 fprintf(stderr, "WARNING: Linux perf events not available. Using the walltime measurer.\n");
887 }
888 } else if (strcmp(argv[i], "-perfcounter") == 0) {
889 if (i + 1 >= argc) {
890 fprintf(stderr, "-perfcounter needs an extra parameter with the name of the counter\n");
891 exit(1);
892 } else {
894 }
895 } else if (strcmp(argv[i], "-perfcounterlist") == 0) {
897 exit(0);
898#endif
899#ifdef HAVE_TICK_COUNTER
900 } else if (strcmp(argv[i], "-tickcounter") == 0) {
902#endif
903 } else if (strcmp(argv[i], "-eventcounter") == 0) {
905 } else if (strcmp(argv[i], "-minimumvalue") == 0) {
906 if (i + 1 >= argc) {
907 fprintf(stderr, "-minimumvalue needs an extra parameter to indicate the minimum time(ms)\n");
908 exit(1);
909 } else {
910 QBenchmarkGlobalData::current->walltimeMinimum = qToInt(argv[++i]);
911 }
912 } else if (strcmp(argv[i], "-minimumtotal") == 0) {
913 if (i + 1 >= argc) {
914 fprintf(stderr, "-minimumtotal needs an extra parameter to indicate the minimum total measurement\n");
915 exit(1);
916 } else {
917 QBenchmarkGlobalData::current->minimumTotal = qToInt(argv[++i]);
918 }
919 } else if (strcmp(argv[i], "-iterations") == 0) {
920 if (i + 1 >= argc) {
921 fprintf(stderr, "-iterations needs an extra parameter to indicate the number of iterations\n");
922 exit(1);
923 } else {
924 QBenchmarkGlobalData::current->iterationCount = qToInt(argv[++i]);
925 }
926 } else if (strcmp(argv[i], "-median") == 0) {
927 if (i + 1 >= argc) {
928 fprintf(stderr, "-median needs an extra parameter to indicate the number of median iterations\n");
929 exit(1);
930 } else {
931 QBenchmarkGlobalData::current->medianIterationCount = qToInt(argv[++i]);
932 }
933
934 } else if (strcmp(argv[i], "-vb") == 0) {
935 QBenchmarkGlobalData::current->verboseOutput = true;
936#if defined(Q_OS_DARWIN)
937 } else if (strncmp(argv[i], "-Apple", 6) == 0) {
938 i += 1; // Skip Apple-specific user preferences
939 continue;
940# if defined(HAVE_XCTEST)
941 } else if (int skip = QXcodeTestLogger::parseCommandLineArgument(argv[i])) {
942 i += (skip - 1); // Eating argv[i] with a continue counts towards skips
943 continue;
944# endif
945#endif
946 } else if (argv[i][0] == '-') {
947 fprintf(stderr, "Unknown option: '%s'\n\n%s", argv[i], testOptions);
948 if (qml) {
949 fprintf(stderr, "\nqmltest related options:\n"
950 " -import : Specify an import directory.\n"
951 " -plugins : Specify a directory where to search for plugins.\n"
952 " -input : Specify the root directory for test cases.\n"
953 );
954 }
955
956 fprintf(stderr, "\n"
957 " -help : This help\n");
958 exit(1);
959 } else {
960 // We can't check the availability of test functions until
961 // we load the QML files. So just store the data for now.
962 int colon = -1;
963 int offset;
964 for (offset = 0; argv[i][offset]; ++offset) {
965 if (argv[i][offset] == ':') {
966 if (argv[i][offset + 1] == ':') {
967 // "::" is used as a test name separator.
968 // e.g. "ClickTests::test_click:row1".
969 ++offset;
970 } else {
971 colon = offset;
972 break;
973 }
974 }
975 }
976 if (colon == -1) {
979 } else {
981 QString::fromLatin1(argv[i], colon);
983 QString::fromLatin1(argv[i] + colon + 1);
984 }
985 }
986 }
987
990
991 // If no loggers were created by the long version of the -o command-line
992 // option, but a logger was requested via the old-style option, add it.
993 const bool explicitLoggerRequested = logFormat != -1;
994 if (!QTestLog::hasLoggers() && explicitLoggerRequested)
995 QTestLog::addLogger(QTestLog::LogMode(logFormat), logFilename);
996
997 bool addFallbackLogger = !explicitLoggerRequested;
998
999#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
1000 // Any explicitly requested loggers will be added by now, so we can check if they use stdout
1001 const bool safeToAddAppleLogger = !AppleUnifiedLogger::preventsStderrLogging() || !QTestLog::loggerUsingStdout();
1002 if (safeToAddAppleLogger && QAppleTestLogger::debugLoggingEnabled()) {
1003 QTestLog::addLogger(QTestLog::Apple, nullptr);
1004 if (AppleUnifiedLogger::preventsStderrLogging() && !logFilename)
1005 addFallbackLogger = false; // Prevent plain test logger fallback below
1006 }
1007#endif
1008
1009 if (addFallbackLogger)
1011
1013 fprintf(stderr, "-repeat is only supported with plain text logger\n");
1014 exit(1);
1015 }
1016}
1017
1018// Temporary, backwards compatibility, until qtdeclarative's use of it is converted
1019Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) {
1020 qtest_qParseArgs(argc, const_cast<const char *const *>(argv), qml);
1021}
1022
1023static QList<QBenchmarkResult> qMedian(const QList<QList<QBenchmarkResult>> &container)
1024{
1025 const int count = container.size();
1026 if (count == 0)
1027 return {};
1028
1029 if (count == 1)
1030 return container.front();
1031
1032 QList<QList<QBenchmarkResult>> containerCopy = container;
1033 std::sort(containerCopy.begin(), containerCopy.end(),
1034 [](const QList<QBenchmarkResult> &a, const QList<QBenchmarkResult> &b) {
1035 return a.first() < b.first();
1036 });
1037
1038 const int middle = count / 2;
1039
1040 // ### handle even-sized containers here by doing an arithmetic mean of the two middle items.
1041 return containerCopy.at(middle);
1042}
1043
1055
1056void TestMethods::invokeTestOnData(int index) const
1057{
1058 /* Benchmarking: for each median iteration*/
1059
1060 bool isBenchmark = false;
1061 int i = (QBenchmarkGlobalData::current->measurer->needsWarmupIteration()) ? -1 : 0;
1062
1063 QList<QList<QBenchmarkResult>> resultsList;
1064 bool minimumTotalReached = false;
1065 do {
1066 QBenchmarkTestMethodData::current->beginDataRun();
1067 if (i < 0)
1068 QBenchmarkTestMethodData::current->iterationCount = 1;
1069
1070 /* Benchmarking: for each accumulation iteration*/
1071 bool invokeOk;
1072 do {
1073 QTest::inTestFunction = true;
1074 invokeTestMethodIfValid(m_initMethod);
1075
1076 const bool initQuit =
1078 if (!initQuit) {
1079 QBenchmarkTestMethodData::current->results.clear();
1080 QBenchmarkTestMethodData::current->resultAccepted = false;
1081 QBenchmarkTestMethodData::current->valid = false;
1082
1085
1086 invokeOk = invokeTestMethodIfValid(m_methods[index]);
1087 if (!invokeOk)
1088 QTestResult::addFailure("Unable to execute slot", __FILE__, __LINE__);
1089
1090 isBenchmark = QBenchmarkTestMethodData::current->isBenchmark();
1091 } else {
1092 invokeOk = false;
1093 }
1094
1095 QTest::inTestFunction = false;
1097
1098 if (!initQuit) {
1099 invokeTestMethodIfValid(m_cleanupMethod);
1100
1101 // Process any deleteLater(), used by event-loop-based apps.
1102 // Fixes memleak reports.
1105 }
1106 // If the test isn't a benchmark, finalize the result after
1107 // cleanup() has finished (or init has lead us to skip the test).
1108 if (!isBenchmark)
1110
1111 // If this test method has a benchmark, repeat until all measurements are
1112 // acceptable.
1113 // The QBENCHMARK macro increases the number of iterations for each run until
1114 // this happens.
1115 } while (invokeOk && isBenchmark
1116 && QBenchmarkTestMethodData::current->resultsAccepted() == false
1118
1121 if (i > -1) // iteration -1 is the warmup iteration.
1122 resultsList.append(QBenchmarkTestMethodData::current->results);
1123
1124 if (isBenchmark && QBenchmarkGlobalData::current->verboseOutput &&
1126 // we only print the first result
1127 const QBenchmarkResult &first = QBenchmarkTestMethodData::current->results.constFirst();
1128 QString pattern = i < 0 ? "warmup stage result : %1"_L1
1129 : "accumulation stage result: %1"_L1;
1130 QTestLog::info(qPrintable(pattern.arg(first.measurement.value)), nullptr, 0);
1131 }
1132 }
1133
1134 // Verify if the minimum total measurement (for the first measurement)
1135 // was reached, if it was specified:
1136 if (QBenchmarkGlobalData::current->minimumTotal == -1) {
1137 minimumTotalReached = true;
1138 } else {
1139 auto addResult = [](qreal current, const QList<QBenchmarkResult> &r) {
1140 if (!r.isEmpty())
1141 current += r.first().measurement.value;
1142 return current;
1143 };
1144 const qreal total = std::accumulate(resultsList.begin(), resultsList.end(), 0.0, addResult);
1145 minimumTotalReached = (total >= QBenchmarkGlobalData::current->minimumTotal);
1146 }
1147 } while (isBenchmark
1148 && ((++i < QBenchmarkGlobalData::current->adjustMedianIterationCount()) || !minimumTotalReached)
1150
1151 // If the test is a benchmark, finalize the result after all iterations have finished.
1152 if (isBenchmark) {
1155 // Only report benchmark figures if the test passed
1156 if (testPassed && QBenchmarkTestMethodData::current->resultsAccepted())
1158 }
1159}
1160
1161#if QT_CONFIG(thread)
1162
1163class WatchDog : public QThread
1164{
1165 enum Expectation : std::size_t {
1166 // bits 0..1: state
1167 ThreadStart,
1168 TestFunctionStart,
1169 TestFunctionEnd,
1170 ThreadEnd,
1171
1172 // bits 2..: generation
1173 };
1174 static constexpr auto ExpectationMask = Expectation{ThreadStart | TestFunctionStart | TestFunctionEnd | ThreadEnd};
1175 static_assert(size_t(ExpectationMask) == 0x3);
1176 static constexpr size_t GenerationShift = 2;
1177
1178 static constexpr Expectation state(Expectation e) noexcept
1179 { return Expectation{e & ExpectationMask}; }
1180 static constexpr size_t generation(Expectation e) noexcept
1181 { return e >> GenerationShift; }
1182 static constexpr Expectation combine(Expectation e, size_t gen) noexcept
1183 { return Expectation{e | (gen << GenerationShift)}; }
1184
1185 bool waitFor(std::unique_lock<std::mutex> &m, Expectation e)
1186 {
1187 auto expectationChanged = [this, e] { return expecting.load(std::memory_order_relaxed) != e; };
1188 switch (state(e)) {
1189 case TestFunctionEnd:
1190 return waitCondition.wait_for(m, defaultTimeout(), expectationChanged);
1191 case ThreadStart:
1192 case ThreadEnd:
1193 case TestFunctionStart:
1194 waitCondition.wait(m, expectationChanged);
1195 return true;
1196 }
1197 Q_UNREACHABLE_RETURN(false);
1198 }
1199
1200 void setExpectation(Expectation e)
1201 {
1202 Q_ASSERT(generation(e) == 0); // no embedded generation allowed
1203 const auto locker = qt_scoped_lock(mutex);
1204 auto cur = expecting.load(std::memory_order_relaxed);
1205 auto gen = generation(cur);
1206 if (e == TestFunctionStart)
1207 ++gen;
1208 e = combine(e, gen);
1209 expecting.store(e, std::memory_order_relaxed);
1210 waitCondition.notify_all();
1211 }
1212
1213public:
1214 WatchDog()
1215 {
1216 setObjectName("QtTest Watchdog"_L1);
1217 auto locker = qt_unique_lock(mutex);
1218 expecting.store(ThreadStart, std::memory_order_relaxed);
1219 start();
1220 waitFor(locker, ThreadStart);
1221 }
1222
1223 ~WatchDog()
1224 {
1225 setExpectation(ThreadEnd);
1226 wait();
1227 }
1228
1229 void beginTest()
1230 {
1231 setExpectation(TestFunctionEnd);
1232 }
1233
1234 void testFinished()
1235 {
1236 setExpectation(TestFunctionStart);
1237 }
1238
1239 void run() override
1240 {
1242 auto locker = qt_unique_lock(mutex);
1243 expecting.store(TestFunctionStart, std::memory_order_release);
1244 waitCondition.notify_all();
1245 while (true) {
1246 Expectation e = expecting.load(std::memory_order_acquire);
1247 switch (state(e)) {
1248 case ThreadEnd:
1249 return;
1250 case ThreadStart:
1251 Q_UNREACHABLE();
1252 case TestFunctionStart:
1253 case TestFunctionEnd:
1254 if (Q_UNLIKELY(!waitFor(locker, e))) {
1255 fflush(stderr);
1258 qFatal("Test function timed out");
1259 }
1260 }
1261 }
1262 }
1263
1264private:
1265 std::mutex mutex;
1266 std::condition_variable waitCondition;
1267 std::atomic<Expectation> expecting;
1268};
1269
1270#else // !QT_CONFIG(thread)
1271
1272class WatchDog : public QObject
1273{
1274public:
1275 void beginTest() {};
1276 void testFinished() {};
1277};
1278
1279#endif // QT_CONFIG(thread)
1280
1281
1283 const QTestTable &lTable, const QTestTable &gTable)
1284{
1285 fprintf(stderr, "Unknown testdata for function %s(): '%s'\n", name.constData(), tag.data());
1286 const int localDataCount = lTable.dataCount();
1287 if (localDataCount) {
1288 fputs("Available test-specific data tags:\n", stderr);
1289 for (int i = 0; i < localDataCount; ++i)
1290 fprintf(stderr, "\t%s\n", lTable.testData(i)->dataTag());
1291 }
1292 const int globalDataCount = gTable.dataCount();
1293 if (globalDataCount) {
1294 fputs("Available global data tags:\n", stderr);
1295 for (int i = 0; i < globalDataCount; ++i)
1296 fprintf(stderr, "\t%s\n", gTable.testData(i)->dataTag());
1297 }
1298 if (localDataCount == 0 && globalDataCount == 0)
1299 fputs("Function has no data tags\n", stderr);
1300}
1301
1311bool TestMethods::invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const
1312{
1313 QBenchmarkTestMethodData benchmarkData;
1314 QBenchmarkTestMethodData::current = &benchmarkData;
1315
1316 const QByteArray &name = m_methods[index].name();
1317 QBenchmarkGlobalData::current->context.slotName = QLatin1StringView(name) + "()"_L1;
1318
1319 char member[512];
1321
1323
1324 const QTestTable *gTable = QTestTable::globalTestTable();
1325 const int globalDataCount = gTable->dataCount();
1326 int curGlobalDataIndex = 0;
1327 const auto globalDataTag = [gTable, globalDataCount](int index) {
1328 return globalDataCount ? gTable->testData(index)->dataTag() : nullptr;
1329 };
1330
1331 const auto dataTagMatches = [](QLatin1StringView tag, QLatin1StringView local,
1333 if (tag.isEmpty()) // No tag specified => run all data sets for this function
1334 return true;
1335 if (tag == local || tag == global) // Equal to either => run it
1336 return true;
1337 // Also allow global:local as a match:
1338 return tag.startsWith(global) && tag.endsWith(local) &&
1339 tag.size() == global.size() + 1 + local.size() &&
1340 tag[global.size()] == ':';
1341 };
1342 bool foundFunction = false;
1343 bool blacklisted = false;
1344
1345 /* For each entry in the global data table, do: */
1346 do {
1347 if (!gTable->isEmpty())
1348 QTestResult::setCurrentGlobalTestData(gTable->testData(curGlobalDataIndex));
1349
1350 if (curGlobalDataIndex == 0) {
1351 qsnprintf(member, 512, "%s_data()", name.constData());
1354 break;
1355 }
1356
1357 int curDataIndex = 0;
1358 const int dataCount = table.dataCount();
1359 const auto dataTag = [&table, dataCount](int index) {
1360 return dataCount ? table.testData(index)->dataTag() : nullptr;
1361 };
1362
1363 /* For each entry in this test's data table, do: */
1364 do {
1367 if (dataTagMatches(tag, QLatin1StringView(dataTag(curDataIndex)),
1368 QLatin1StringView(globalDataTag(curGlobalDataIndex)))) {
1369 foundFunction = true;
1370 blacklisted = QTestPrivate::checkBlackLists(name.constData(), dataTag(curDataIndex),
1371 globalDataTag(curGlobalDataIndex));
1372 if (blacklisted)
1374
1375 if (blacklisted && skipBlacklisted) {
1376 QTest::qSkip("Skipping blacklisted test since -skipblacklisted option is set.",
1377 NULL, 0);
1380 } else {
1381 QTestDataSetter s(
1382 curDataIndex >= dataCount ? nullptr : table.testData(curDataIndex));
1383
1385 if (watchDog)
1386 watchDog->beginTest();
1387 QTest::lastMouseTimestamp += 500; // Maintain at least 500ms mouse event timestamps between each test function call
1388 invokeTestOnData(index);
1389 if (watchDog)
1390 watchDog->testFinished();
1391 }
1392
1393 if (!tag.isEmpty() && !globalDataCount)
1394 break;
1395 }
1396 ++curDataIndex;
1397 } while (curDataIndex < dataCount);
1398
1400 ++curGlobalDataIndex;
1401 } while (curGlobalDataIndex < globalDataCount);
1402
1403 if (!tag.isEmpty() && !foundFunction) {
1405 QTestResult::addFailure(qPrintable("Data tag not found: %1"_L1.arg(tag)));
1406 }
1410
1411 return true;
1412}
1413
1414void *fetchData(QTestData *data, const char *tagName, int typeId)
1415{
1416 QTEST_ASSERT(typeId);
1417 QTEST_ASSERT_X(data, "QTest::fetchData()", "Test data requested, but no testdata available.");
1418 QTEST_ASSERT(data->parent());
1419
1420 int idx = data->parent()->indexOf(tagName);
1421
1422 if (Q_UNLIKELY(idx == -1 || idx >= data->dataCount())) {
1423 qFatal("QFETCH: Requested testdata '%s' not available, check your _data function.",
1424 tagName);
1425 }
1426
1427 if (Q_UNLIKELY(typeId != data->parent()->elementTypeId(idx))) {
1428 qFatal("Requested type '%s' does not match available type '%s'.",
1429 QMetaType(typeId).name(),
1430 QMetaType(data->parent()->elementTypeId(idx)).name());
1431 }
1432
1433 return data->data(idx);
1434}
1435
1439char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...)
1440{
1441 va_list ap;
1442 va_start(ap, numArguments);
1443
1445 arguments += prefix;
1446
1447 if (numArguments > 0) {
1448 arguments += va_arg(ap, const char *);
1449
1450 for (size_t i = 1; i < numArguments; ++i) {
1451 arguments += ", ";
1452 arguments += va_arg(ap, const char *);
1453 }
1454 }
1455
1456 va_end(ap);
1457 arguments += suffix;
1458 return qstrdup(arguments.constData());
1459}
1460
1472{
1473 if (length == 0)
1474 return qstrdup("");
1475
1476 /* We output at maximum about maxLen characters in order to avoid
1477 * running out of memory and flooding things when the byte array
1478 * is large.
1479 *
1480 * maxLen can't be for example 200 because Qt Test is sprinkled with fixed
1481 * size char arrays.
1482 * */
1483 const qsizetype maxLen = 50;
1484 const qsizetype len = qMin(maxLen, length);
1485 char *result = nullptr;
1486
1487 if (length > maxLen) {
1488 const qsizetype size = len * 3 + 4;
1489 result = new char[size];
1490
1491 char *const forElipsis = result + size - 5;
1492 forElipsis[0] = ' ';
1493 forElipsis[1] = '.';
1494 forElipsis[2] = '.';
1495 forElipsis[3] = '.';
1496 result[size - 1] = '\0';
1497 }
1498 else {
1499 const qsizetype size = len * 3;
1500 result = new char[size];
1501 result[size - 1] = '\0';
1502 }
1503
1504 qsizetype i = 0;
1505 qsizetype o = 0;
1506
1507 while (true) {
1508 const char at = ba[i];
1509
1510 result[o] = toHexUpper(at >> 4);
1511 ++o;
1512 result[o] = toHexUpper(at);
1513
1514 ++i;
1515 ++o;
1516 if (i == len)
1517 break;
1518 result[o] = ' ';
1519 ++o;
1520 }
1521
1522 return result;
1523}
1524
1531{
1532 bool trimmed = false;
1533 auto buffer = std::make_unique<char[]>(256);
1534 const char *end = p + length;
1535 char *dst = buffer.get();
1536
1537 bool lastWasHexEscape = false;
1538 *dst++ = '"';
1539 for ( ; p != end; ++p) {
1540 // we can add:
1541 // 1 byte: a single character
1542 // 2 bytes: a simple escape sequence (\n)
1543 // 3 bytes: "" and a character
1544 // 4 bytes: an hex escape sequence (\xHH)
1545 if (dst - buffer.get() > 246) {
1546 // plus the quote, the three dots and NUL, it's 255 in the worst case
1547 trimmed = true;
1548 break;
1549 }
1550
1551 // check if we need to insert "" to break an hex escape sequence
1552 if (Q_UNLIKELY(lastWasHexEscape)) {
1553 if (fromHex(*p) != -1) {
1554 // yes, insert it
1555 *dst++ = '"';
1556 *dst++ = '"';
1557 }
1558 lastWasHexEscape = false;
1559 }
1560
1561 if (*p < 0x7f && *p >= 0x20 && *p != '\\' && *p != '"') {
1562 *dst++ = *p;
1563 continue;
1564 }
1565
1566 // write as an escape sequence
1567 // this means we may advance dst to buffer.data() + 247 or 250
1568 *dst++ = '\\';
1569 switch (*p) {
1570 case 0x5c:
1571 case 0x22:
1572 *dst++ = uchar(*p);
1573 break;
1574 case 0x8:
1575 *dst++ = 'b';
1576 break;
1577 case 0xc:
1578 *dst++ = 'f';
1579 break;
1580 case 0xa:
1581 *dst++ = 'n';
1582 break;
1583 case 0xd:
1584 *dst++ = 'r';
1585 break;
1586 case 0x9:
1587 *dst++ = 't';
1588 break;
1589 default:
1590 // print as hex escape
1591 *dst++ = 'x';
1592 *dst++ = toHexUpper(uchar(*p) >> 4);
1593 *dst++ = toHexUpper(uchar(*p));
1594 lastWasHexEscape = true;
1595 break;
1596 }
1597 }
1598
1599 *dst++ = '"';
1600 if (trimmed) {
1601 *dst++ = '.';
1602 *dst++ = '.';
1603 *dst++ = '.';
1604 }
1605 *dst++ = '\0';
1606 return buffer.release();
1607}
1608
1619// escape sequence, closing quote, the three dots and NUL
1620constexpr qsizetype PrettyUnicodeMaxIncrement = sizeof(R"(\uXXXX"...)"); // includes NUL
1621
1622static char *writePrettyUnicodeChar(char16_t ch, char * const buffer)
1623{
1624 auto dst = buffer;
1625 auto first = [&](int n) { Q_ASSERT(dst - buffer == n); return dst; };
1626 if (ch < 0x7f && ch >= 0x20 && ch != '\\' && ch != '"') {
1627 *dst++ = ch;
1628 return first(1);
1629 }
1630
1631 // write as an escape sequence
1632 *dst++ = '\\';
1633 switch (ch) {
1634 case 0x22:
1635 case 0x5c:
1636 *dst++ = uchar(ch);
1637 break;
1638 case 0x8:
1639 *dst++ = 'b';
1640 break;
1641 case 0xc:
1642 *dst++ = 'f';
1643 break;
1644 case 0xa:
1645 *dst++ = 'n';
1646 break;
1647 case 0xd:
1648 *dst++ = 'r';
1649 break;
1650 case 0x9:
1651 *dst++ = 't';
1652 break;
1653 default:
1654 *dst++ = 'u';
1655 *dst++ = toHexUpper(ch >> 12);
1656 *dst++ = toHexUpper(ch >> 8);
1657 *dst++ = toHexUpper(ch >> 4);
1658 *dst++ = toHexUpper(ch);
1659 return first(6);
1660 }
1661 return first(2);
1662}
1663
1665{
1666 auto p = string.utf16();
1667 auto length = string.size();
1668 // keep it simple for the vast majority of cases
1669 bool trimmed = false;
1670 auto buffer = std::make_unique<char[]>(PrettyUnicodeMaxOutputSize);
1671 const auto end = p + length;
1672 char *dst = buffer.get();
1673
1674 *dst++ = '"';
1675 for ( ; p != end; ++p) {
1677 trimmed = true;
1678 break;
1679 }
1680 dst = writePrettyUnicodeChar(*p, dst);
1681 }
1682
1683 *dst++ = '"';
1684 if (trimmed) {
1685 *dst++ = '.';
1686 *dst++ = '.';
1687 *dst++ = '.';
1688 }
1689 *dst++ = '\0';
1690 return buffer.release();
1691}
1692
1694{
1695 const QMetaObject *metaObject = testObject->metaObject();
1698 invokeTestMethodIfValid(m_initTestCaseDataMethod, testObject);
1699
1700 std::optional<WatchDog> watchDog = std::nullopt;
1702#if QT_CONFIG(valgrind)
1704#endif
1705 ) {
1706 watchDog.emplace();
1707 }
1708
1710
1712 invokeTestMethodIfValid(m_initTestCaseMethod, testObject);
1713
1714 // finishedCurrentTestDataCleanup() resets QTestResult::currentTestFailed(), so use a local copy.
1715 const bool previousFailed = QTestResult::currentTestFailed();
1719
1720 if (!QTestResult::skipCurrentTest() && !previousFailed) {
1721 for (int i = 0, count = int(m_methods.size()); i < count; ++i) {
1722 const char *data = nullptr;
1723 if (i < QTest::testTags.size() && !QTest::testTags.at(i).isEmpty())
1724 data = qstrdup(QTest::testTags.at(i).toLatin1().constData());
1725 const bool ok = invokeTest(i, QLatin1StringView(data), watchDog);
1726 delete [] data;
1727 if (!ok)
1728 break;
1729 }
1730 }
1731
1732 const bool wasSkipped = QTestResult::skipCurrentTest();
1735 QTestResult::setCurrentTestFunction("cleanupTestCase");
1736 invokeTestMethodIfValid(m_cleanupTestCaseMethod, testObject);
1738 // Restore skip state as it affects decision on whether we passed:
1741 }
1744
1746}
1747
1748#if QT_DEPRECATED_SINCE(6, 8)
1749static const char *functionRefFormatter(const void *f)
1750{
1751 auto formatter = static_cast<const qxp::function_ref<const char *()> *>(f);
1752 return (*formatter)();
1753};
1754
1755bool reportResult(bool success, qxp::function_ref<const char *()> lhs,
1756 qxp::function_ref<const char *()> rhs,
1757 const char *lhsExpr, const char *rhsExpr,
1758 ComparisonOperation op, const char *file, int line)
1759{
1760 return QTestResult::reportResult(success, &lhs, &rhs,
1761 functionRefFormatter, functionRefFormatter,
1762 lhsExpr, rhsExpr, op, file, line);
1763}
1764#endif // QT_DEPRECATED_SINCE(6, 8)
1765
1766bool reportResult(bool success, const void *lhs, const void *rhs,
1767 const char *(*lhsFormatter)(const void*),
1768 const char *(*rhsFormatter)(const void*),
1769 const char *lhsExpr, const char *rhsExpr,
1770 ComparisonOperation op, const char *file, int line)
1771{
1772 return QTestResult::reportResult(success, lhs, rhs, lhsFormatter, rhsFormatter,
1773 lhsExpr, rhsExpr, op, file, line);
1774}
1775} // namespace QTest
1776
1777static void initEnvironment()
1778{
1779 qputenv("QT_QTESTLIB_RUNNING", "1");
1780}
1781
1820int QTest::qExec(QObject *testObject, int argc, char **argv)
1821{
1822 // NB: QtQuick's testing recombines qInit(), qRun() and qCleanup() to
1823 // provide a replacement for qExec() that calls qRun() once for each
1824 // built-in style. So think twice about moving parts between these three
1825 // functions, as doing so may mess up QtQuick's testing.
1826 qInit(testObject, argc, argv);
1827 int ret = qRun();
1828 qCleanup();
1829
1830#if defined(Q_OS_WASM)
1831 EM_ASM({
1832 if (typeof Module != "undefined" && typeof Module.notifyTestFinished != "undefined")
1833 Module.notifyTestFinished($0);
1834 }, ret);
1835#endif // Q_OS_WASM
1836
1837 return ret;
1838}
1839
1842void QTest::qInit(QObject *testObject, int argc, char **argv)
1843{
1845 CrashHandler::maybeDisableCoreDump();
1847
1848#if defined(Q_OS_MACOS)
1849 // Don't restore saved window state for auto tests
1851
1852 // Disable App Nap which may cause tests to stall
1853 QTestPrivate::AppNapDisabler appNapDisabler;
1854
1855 if (qApp && (qstrcmp(qApp->metaObject()->className(), "QApplication") == 0)) {
1856 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
1857 kIOPMAssertionLevelOn, CFSTR("QtTest running tests"),
1858 &macPowerSavingDisabled);
1859 }
1860#endif
1861
1864
1868
1869 const QMetaObject *metaObject = testObject->metaObject();
1871
1873 if (argc > 0)
1875
1876 qtest_qParseArgs(argc, argv, false);
1877
1878#if QT_CONFIG(valgrind)
1880#endif
1882}
1883
1887{
1889
1890#if QT_CONFIG(valgrind)
1891 int callgrindChildExitCode = 0;
1892#endif
1893
1894#ifndef QT_NO_EXCEPTIONS
1895 try {
1896#endif
1897
1898#if QT_CONFIG(valgrind)
1900 if (Q_UNLIKELY(!qApp))
1901 qFatal("QtTest: -callgrind option is not available with QTEST_APPLESS_MAIN");
1902
1903 const QStringList origAppArgs(QCoreApplication::arguments());
1904 if (!QBenchmarkValgrindUtils::rerunThroughCallgrind(origAppArgs, callgrindChildExitCode))
1905 return -1;
1906
1908
1909 } else
1910#endif
1911 {
1912 std::optional<CrashHandler::FatalSignalHandler> handler;
1913 CrashHandler::prepareStackTrace();
1914 if (!Internal::noCrashHandler)
1915 handler.emplace();
1916
1917 bool seenBad = false;
1918 TestMethods::MetaMethods commandLineMethods;
1919 commandLineMethods.reserve(static_cast<size_t>(QTest::testFunctions.size()));
1920 for (const QString &tf : std::as_const(QTest::testFunctions)) {
1921 const QByteArray tfB = tf.toLatin1();
1922 const QByteArray signature = tfB + QByteArrayLiteral("()");
1923 QMetaMethod m = TestMethods::findMethod(currentTestObject, signature.constData());
1924 if (m.isValid() && isValidSlot(m)) {
1925 commandLineMethods.push_back(m);
1926 } else {
1927 fprintf(stderr, "Unknown test function: '%s'.", tfB.constData());
1928 if (!qPrintTestSlots(stderr, tfB.constData(), " Possible matches:\n"))
1929 fputc('\n', stderr);
1930 QTestResult::setCurrentTestFunction(tfB.constData());
1931 QTestResult::addFailure(qPrintable("Function not found: %1"_L1.arg(tf)));
1933 // Ditch the tag that came with tf as test function:
1934 QTest::testTags.remove(commandLineMethods.size());
1935 seenBad = true;
1936 }
1937 }
1938 if (seenBad) {
1939 // Provide relevant help to do better next time:
1940 fprintf(stderr, "\n%s -functions\nlists all available test functions.\n\n",
1942 if (commandLineMethods.empty()) // All requested functions missing.
1943 return 1;
1944 }
1945 TestMethods test(currentTestObject, std::move(commandLineMethods));
1946
1947 while (QTestLog::failCount() == 0 && (repeatForever || repetitions-- > 0)) {
1951 }
1952 }
1953
1954#ifndef QT_NO_EXCEPTIONS
1955 } catch (...) {
1956 QTestResult::addFailure("Caught unhandled exception", __FILE__, __LINE__);
1960 }
1961
1962 qCleanup();
1963
1964 // Re-throw exception to make debugging easier
1965 throw;
1966 return 1;
1967 }
1968#endif
1969
1970#if QT_CONFIG(valgrind)
1972 return callgrindChildExitCode;
1973#endif
1974 // make sure our exit code is never going above 127
1975 // since that could wrap and indicate 0 test fails
1976 return qMin(QTestLog::failCount(), 127);
1977}
1978
1982{
1983 currentTestObject = nullptr;
1984
1985#if QT_CONFIG(valgrind)
1987#endif
1989
1992
1993#if defined(Q_OS_MACOS)
1994 IOPMAssertionRelease(macPowerSavingDisabled);
1995#endif
1996}
1997
1998#if QT_CONFIG(batch_test_support) || defined(Q_QDOC)
2009void QTest::qRegisterTestCase(const QString &name, TestEntryFunction entryFunction)
2010{
2011 QTest::TestRegistry::instance()->registerTest(name, entryFunction);
2012}
2013
2014QList<QString> QTest::qGetTestCaseNames()
2015{
2016 return QTest::TestRegistry::instance()->getAllTestNames();
2017}
2018
2019QTest::TestEntryFunction QTest::qGetTestCaseEntryFunction(const QString& name)
2020{
2021 return QTest::TestRegistry::instance()->getTestEntryFunction(name);
2022}
2023
2024#endif // QT_CONFIG(batch_test_support)
2025
2034{
2035 const int argc = arguments.size();
2036 QVarLengthArray<char *> argv(argc);
2037
2038 QList<QByteArray> args;
2039 args.reserve(argc);
2040
2041 for (int i = 0; i < argc; ++i)
2042 {
2043 args.append(arguments.at(i).toLocal8Bit().constData());
2044 argv[i] = args.last().data();
2045 }
2046
2047 return qExec(testObject, argc, argv.data());
2048}
2049
2052void QTest::qFail(const char *message, const char *file, int line)
2053{
2055}
2056
2059bool QTest::qVerify(bool statement, const char *statementStr, const char *description,
2060 const char *file, int line)
2061{
2062 return QTestResult::verify(statement, statementStr, description, file, line);
2063}
2064
2068void QTest::qSkip(const char *message, const char *file, int line)
2069{
2072}
2073
2077bool QTest::qExpectFail(const char *dataIndex, const char *comment,
2078 QTest::TestFailMode mode, const char *file, int line)
2079{
2080 return QTestResult::expectFail(dataIndex, qstrdup(comment), mode, file, line);
2081}
2082
2099void QTest::qCaught(const char *expected, const char *what, const char *file, int line)
2100{
2101 auto message = [&] {
2102 const auto exType = what ? "std::" : "unknown ";
2103 const auto ofType = expected ? " of type " : "";
2104 const auto no = expected ? "an" : "no";
2105 const auto withMsg = what ? " with message " : "";
2106 const auto protect = [](const char *s) { return s ? s : ""; };
2107
2108 return QString::asprintf("Expected %s exception%s%s to be thrown, "
2109 "but caught %sexception%s%s",
2110 no, ofType, protect(expected),
2111 exType, withMsg, protect(what));
2112 };
2113 qFail(message().toUtf8().constData(), file, line);
2114}
2115
2135void QTest::qCaught(const char *expected, const char *file, int line)
2136{
2137 try {
2138 // let's see what the cat brought us:
2139 std::rethrow_exception(std::current_exception());
2140 } catch (const std::exception &e) {
2141 qCaught(expected, e.what(), file, line);
2142 } catch (...) {
2143 qCaught(expected, nullptr, file, line);
2144 throw;
2145 }
2146 // caller shall invoke `QTEST_FAIL_ACTION` if control reached here
2147}
2148
2149
2150#if QT_DEPRECATED_SINCE(6, 3)
2155void QTest::qWarn(const char *message, const char *file, int line)
2156{
2158}
2159#endif
2160
2181
2182#if QT_CONFIG(regularexpression)
2198void QTest::ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern)
2199{
2200 QTestLog::ignoreMessage(type, messagePattern);
2201}
2202#endif // QT_CONFIG(regularexpression)
2203
2213{
2214 return QTestLog::failOnWarning();
2215}
2216
2226{
2228}
2229
2230#if QT_CONFIG(regularexpression)
2283void QTest::failOnWarning(const QRegularExpression &messagePattern)
2284{
2285 QTestLog::failOnWarning(messagePattern);
2286}
2287#endif // QT_CONFIG(regularexpression)
2288
2292#ifdef Q_OS_WIN
2293static inline bool isWindowsBuildDirectory(const QString &dirName)
2294{
2295 return dirName.compare("Debug"_L1, Qt::CaseInsensitive) == 0
2296 || dirName.compare("Release"_L1, Qt::CaseInsensitive) == 0;
2297}
2298#endif
2299
2300#if QT_CONFIG(temporaryfile)
2311QSharedPointer<QTemporaryDir> QTest::qExtractTestData(const QString &dirName)
2312{
2313 QSharedPointer<QTemporaryDir> result; // null until success, then == tempDir
2314
2315 QSharedPointer<QTemporaryDir> tempDir = QSharedPointer<QTemporaryDir>::create();
2316
2317 tempDir->setAutoRemove(true);
2318
2319 if (!tempDir->isValid())
2320 return result;
2321
2322 const QString dataPath = tempDir->path();
2323 const QString resourcePath = u':' + dirName;
2324 const QFileInfo fileInfo(resourcePath);
2325
2326 if (!fileInfo.isDir()) {
2327 qWarning("Resource path '%s' is not a directory.", qPrintable(resourcePath));
2328 return result;
2329 }
2330
2331 bool isResourceDirEmpty = true;
2332 for (const auto &dirEntry : QDirListing(resourcePath, QDirListing::IteratorFlag::Recursive)) {
2333 isResourceDirEmpty = false;
2334 if (!dirEntry.isDir()) {
2335 const QString &filePath = dirEntry.filePath();
2336 const QString destination =
2337 dataPath + u'/' + QStringView{filePath}.sliced(resourcePath.size());
2338 QFileInfo destinationFileInfo(destination);
2339 QDir().mkpath(destinationFileInfo.path());
2340 QFile file(filePath);
2341 if (!file.copy(destination)) {
2342 qWarning("Failed to copy '%ls': %ls.", qUtf16Printable(filePath),
2344 return result;
2345 }
2346
2349 qWarning("Failed to set permissions on '%ls': %ls.", qUtf16Printable(destination),
2351 return result;
2352 }
2353 }
2354 }
2355
2356 if (isResourceDirEmpty) {
2357 qWarning("Resource directory '%s' is empty.", qPrintable(resourcePath));
2358 return result;
2359 }
2360
2361 result = std::move(tempDir);
2362
2363 return result;
2364}
2365#endif // QT_CONFIG(temporaryfile)
2366
2370QString QTest::qFindTestData(const QString& base, const char *file, int line, const char *builddir,
2371 const char *sourcedir)
2372{
2373 QString found;
2374
2375 // Testdata priorities:
2376
2377 // 1. relative to test binary.
2378 if (qApp) {
2380 if (binDirectory.exists(base)) {
2381 found = binDirectory.absoluteFilePath(base);
2382 }
2383#ifdef Q_OS_WIN
2384 // Windows: The executable is typically located in one of the
2385 // 'Release' or 'Debug' directories.
2386 else if (isWindowsBuildDirectory(binDirectory.dirName())
2387 && binDirectory.cdUp() && binDirectory.exists(base)) {
2388 found = binDirectory.absoluteFilePath(base);
2389 }
2390#endif // Q_OS_WIN
2391 else if (QTestLog::verboseLevel() >= 2) {
2393 QTestLog::info(qPrintable("testdata %1 not found relative to test binary [%2]; "
2394 "checking next location"_L1.arg(base, candidate)),
2395 file, line);
2396 }
2397 }
2398
2399 // 2. installed path.
2400 if (found.isEmpty()) {
2401 const char *testObjectName = QTestResult::currentTestObjectName();
2402 if (testObjectName) {
2404 const QString candidate = "%1/%2/%3"_L1
2405 .arg(testsPath, QFile::decodeName(testObjectName).toLower(), base);
2406 if (QFileInfo::exists(candidate)) {
2407 found = candidate;
2408 } else if (QTestLog::verboseLevel() >= 2) {
2409 QTestLog::info(qPrintable("testdata %1 not found in tests install path [%2]; "
2410 "checking next location"_L1
2411 .arg(base, QDir::toNativeSeparators(candidate))),
2412 file, line);
2413 }
2414 }
2415 }
2416
2417 // 3. relative to test source.
2418 if (found.isEmpty() && qstrncmp(file, ":/", 2) != 0) {
2419 // srcdir is the directory containing the calling source file.
2421
2422 // If the srcdir is relative, that means it is relative to the current working
2423 // directory of the compiler at compile time, which should be passed in as `builddir'.
2424 if (!srcdir.isAbsolute() && builddir)
2425 srcdir.setFile(QFile::decodeName(builddir) + u'/' + srcdir.filePath());
2426
2427 const QString canonicalPath = srcdir.canonicalFilePath();
2428 const QString candidate = "%1/%2"_L1.arg(canonicalPath, base);
2429 if (!canonicalPath.isEmpty() && QFileInfo::exists(candidate)) {
2430 found = candidate;
2431 } else if (QTestLog::verboseLevel() >= 2) {
2433 "testdata %1 not found relative to source path [%2]"_L1
2434 .arg(base, QDir::toNativeSeparators(candidate))),
2435 file, line);
2436 }
2437 }
2438
2439 // 4. Try resources
2440 if (found.isEmpty()) {
2441 const QString candidate = ":/%1"_L1.arg(base);
2442 if (QFileInfo::exists(candidate)) {
2443 found = candidate;
2444 } else if (QTestLog::verboseLevel() >= 2) {
2446 "testdata %1 not found in resources [%2]"_L1
2447 .arg(base, QDir::toNativeSeparators(candidate))),
2448 file, line);
2449 }
2450 }
2451
2452 // 5. Try current directory
2453 if (found.isEmpty()) {
2454 const QString candidate = QDir::currentPath() + u'/' + base;
2455 if (QFileInfo::exists(candidate)) {
2456 found = candidate;
2457 } else if (QTestLog::verboseLevel() >= 2) {
2459 "testdata %1 not found in current directory [%2]"_L1
2460 .arg(base, QDir::toNativeSeparators(candidate))),
2461 file, line);
2462 }
2463 }
2464
2465 // 6. Try main source directory
2466 if (found.isEmpty()) {
2467 const QString candidate = QTest::mainSourcePath % u'/' % base;
2468 if (QFileInfo::exists(candidate)) {
2469 found = candidate;
2470 } else if (QTestLog::verboseLevel() >= 2) {
2472 "testdata %1 not found in main source directory [%2]"_L1
2473 .arg(base, QDir::toNativeSeparators(candidate))),
2474 file, line);
2475 }
2476 }
2477
2478 // 7. Try the supplied source directory
2479 if (found.isEmpty() && sourcedir) {
2480 const QString candidate = QFile::decodeName(sourcedir) % u'/' % base;
2481 if (QFileInfo::exists(candidate)) {
2482 found = candidate;
2483 } else if (QTestLog::verboseLevel() >= 2) {
2485 "testdata %1 not found in supplied source directory [%2]"_L1
2486 .arg(base, QDir::toNativeSeparators(candidate))),
2487 file, line);
2488 }
2489 }
2490
2491
2492 if (found.isEmpty()) {
2494 "testdata %1 could not be located!"_L1.arg(base)),
2495 file, line);
2496 } else if (QTestLog::verboseLevel() >= 1) {
2498 "testdata %1 was located at %2"_L1.arg(base, QDir::toNativeSeparators(found))),
2499 file, line);
2500 }
2501
2502 return found;
2503}
2504
2507QString QTest::qFindTestData(const char *base, const char *file, int line, const char *builddir,
2508 const char *sourcedir)
2509{
2510 return qFindTestData(QFile::decodeName(base), file, line, builddir, sourcedir);
2511}
2512
2515void *QTest::qData(const char *tagName, int typeId)
2516{
2517 return fetchData(QTestResult::currentTestData(), tagName, typeId);
2518}
2519
2522void *QTest::qGlobalData(const char *tagName, int typeId)
2523{
2524 return fetchData(QTestResult::currentGlobalTestData(), tagName, typeId);
2525}
2526
2529void *QTest::qElementData(const char *tagName, int metaTypeId)
2530{
2531 QTEST_ASSERT(tagName);
2534 QTEST_ASSERT(data->parent());
2535
2536 int idx = data->parent()->indexOf(tagName);
2537 QTEST_ASSERT(idx != -1);
2538 QTEST_ASSERT(data->parent()->elementTypeId(idx) == metaTypeId);
2539
2540 return data->data(data->parent()->indexOf(tagName));
2541}
2542
2545void QTest::addColumnInternal(int id, const char *name)
2546{
2548 QTEST_ASSERT_X(tbl, "QTest::addColumn()", "Cannot add testdata outside of a _data slot.");
2549
2550 tbl->addColumn(id, name);
2551}
2552
2573QTestData &QTest::newRow(const char *dataTag)
2574{
2575 QTEST_ASSERT_X(dataTag, "QTest::newRow()", "Data tag cannot be null");
2577 QTEST_ASSERT_X(tbl, "QTest::newRow()", "Cannot add testdata outside of a _data slot.");
2578 QTEST_ASSERT_X(tbl->elementCount(), "QTest::newRow()",
2579 "Must add columns before attempting to add rows.");
2580
2581 return *tbl->newData(dataTag);
2582}
2583
2611{
2612 QTEST_ASSERT_X(format, "QTest::addRow()", "Format string cannot be null");
2614 QTEST_ASSERT_X(tbl, "QTest::addRow()", "Cannot add testdata outside of a _data slot.");
2615 QTEST_ASSERT_X(tbl->elementCount(), "QTest::addRow()",
2616 "Must add columns before attempting to add rows.");
2617
2618 char buf[1024];
2619
2620 va_list va;
2621 va_start(va, format);
2622 // we don't care about failures, we accept truncation, as well as trailing garbage.
2623 // Names with more than 1K characters are nonsense, anyway.
2624 (void)qvsnprintf(buf, sizeof buf, format, va);
2625 buf[sizeof buf - 1] = '\0';
2626 va_end(va);
2627
2628 return *tbl->newData(buf);
2629}
2630
2659{
2661}
2662
2671{
2673}
2674
2680{
2682}
2683
2693
2711
2721{
2722 return QTest::inTestFunction;
2723}
2724
2728{
2729 return currentTestObject;
2730}
2731
2734void QTest::setMainSourcePath(const char *file, const char *builddir)
2735{
2736 QString mainSourceFile = QFile::decodeName(file);
2737 QFileInfo fi;
2738 if (builddir)
2739 fi.setFile(QDir(QFile::decodeName(builddir)), mainSourceFile);
2740 else
2741 fi.setFile(mainSourceFile);
2742 QTest::mainSourcePath = fi.absolutePath();
2743}
2744
2745#if QT_DEPRECATED_SINCE(6, 4)
2764bool QTest::compare_helper(bool success, const char *failureMsg,
2765 char *actualVal, char *expectedVal,
2766 const char *actual, const char *expected,
2767 const char *file, int line)
2768{
2769 return QTestResult::compare(success, failureMsg, actualVal, expectedVal,
2770 actual, expected, file, line);
2771}
2772#endif // QT_DEPRECATED_SINCE(6, 4)
2773
2774#if QT_DEPRECATED_SINCE(6, 8)
2788bool QTest::compare_helper(bool success, const char *failureMsg,
2789 qxp::function_ref<const char *()> actualVal,
2790 qxp::function_ref<const char *()> expectedVal,
2791 const char *actual, const char *expected,
2792 const char *file, int line)
2793{
2794 return QTestResult::reportResult(success, &actualVal, &expectedVal,
2795 QTest::functionRefFormatter,
2796 QTest::functionRefFormatter, actual, expected,
2798 file, line, failureMsg);
2799}
2800#endif // QT_DEPRECATED_SINCE(6, 8)
2801
2812bool QTest::compare_helper(bool success, const char *failureMsg,
2813 const void *actualPtr, const void *expectedPtr,
2814 const char *(*actualFormatter)(const void *),
2815 const char *(*expectedFormatter)(const void *),
2816 const char *actual, const char *expected,
2817 const char *file, int line)
2818{
2819 return QTestResult::reportResult(success, actualPtr, expectedPtr,
2820 actualFormatter, expectedFormatter,
2821 actual, expected,
2823 file, line, failureMsg);
2824}
2825
2836bool QTest::compare_helper(bool success, const char *failureMsg, const char *actual,
2837 const char *expected, const char *file, int line)
2838{
2839 return QTestResult::compare(success, failureMsg, actual, expected, file, line);
2840}
2841
2842template <typename T>
2843static bool floatingCompare(const T &actual, const T &expected)
2844{
2845 switch (qFpClassify(expected))
2846 {
2847 case FP_INFINITE:
2848 return (expected < 0) == (actual < 0) && qFpClassify(actual) == FP_INFINITE;
2849 case FP_NAN:
2850 return qFpClassify(actual) == FP_NAN;
2851 default:
2852 if (!qFuzzyIsNull(expected))
2853 return qFuzzyCompare(actual, expected);
2854 Q_FALLTHROUGH();
2855 case FP_SUBNORMAL: // subnormal is always fuzzily null
2856 case FP_ZERO:
2857 return qFuzzyIsNull(actual);
2858 }
2859}
2860
2864bool QTest::qCompare(qfloat16 const &t1, qfloat16 const &t2, const char *actual, const char *expected,
2865 const char *file, int line)
2866{
2867 auto formatter = Internal::genericToString<qfloat16>;
2869 "Compared qfloat16s are not the same (fuzzy compare)",
2870 &t1, &t2, formatter, formatter,
2871 actual, expected, file, line);
2872}
2873
2877bool QTest::qCompare(float const &t1, float const &t2, const char *actual, const char *expected,
2878 const char *file, int line)
2879{
2881 "Compared floats are not the same (fuzzy compare)",
2882 t1, t2, actual, expected, file, line);
2883}
2884
2888bool QTest::qCompare(double const &t1, double const &t2, const char *actual, const char *expected,
2889 const char *file, int line)
2890{
2892 "Compared doubles are not the same (fuzzy compare)",
2893 t1, t2, actual, expected, file, line);
2894}
2895
2900bool QTest::qCompare(int t1, int t2, const char *actual, const char *expected,
2901 const char *file, int line)
2902{
2903 return QTestResult::compare(t1 == t2,
2904 "Compared values are not the same",
2905 t1, t2, actual, expected, file, line);
2906}
2907
2908#if QT_POINTER_SIZE == 8
2914bool QTest::qCompare(qsizetype t1, qsizetype t2, const char *actual, const char *expected,
2915 const char *file, int line)
2916{
2917 return QTestResult::compare(t1 == t2,
2918 "Compared values are not the same",
2919 t1, t2, actual, expected, file, line);
2920}
2921#endif // QT_POINTER_SIZE == 8
2922
2927bool QTest::qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected,
2928 const char *file, int line)
2929{
2930 return QTestResult::compare(t1 == t2,
2931 "Compared values are not the same",
2932 t1, t2, actual, expected, file, line);
2933}
2934
2939bool QTest::qCompare(QStringView t1, QStringView t2, const char *actual, const char *expected,
2940 const char *file, int line)
2941{
2942 return QTestResult::compare(t1 == t2,
2943 "Compared values are not the same",
2944 t1, t2, actual, expected, file, line);
2945}
2946
2951bool QTest::qCompare(QStringView t1, const QLatin1StringView &t2, const char *actual, const char *expected,
2952 const char *file, int line)
2953{
2954 return QTestResult::compare(t1 == t2,
2955 "Compared values are not the same",
2956 t1, t2, actual, expected, file, line);
2957}
2958
2963bool QTest::qCompare(const QLatin1StringView &t1, QStringView t2, const char *actual, const char *expected,
2964 const char *file, int line)
2965{
2966 return QTestResult::compare(t1 == t2,
2967 "Compared values are not the same",
2968 t1, t2, actual, expected, file, line);
2969}
2970
2994#define TO_STRING_IMPL(TYPE, FORMAT) \
2995template <> Q_TESTLIB_EXPORT char *QTest::toString<TYPE>(const TYPE &t) \
2996{ \
2997 char *msg = new char[128]; \
2998 qsnprintf(msg, 128, #FORMAT, t); \
2999 return msg; \
3000}
3001
3002TO_STRING_IMPL(short, %hd)
3004TO_STRING_IMPL(int, %d)
3006TO_STRING_IMPL(long, %ld)
3008#if defined(Q_OS_WIN)
3009TO_STRING_IMPL(qint64, %I64d)
3010TO_STRING_IMPL(quint64, %I64u)
3011#else
3014#endif
3015TO_STRING_IMPL(bool, %d)
3016TO_STRING_IMPL(signed char, %hhd)
3017TO_STRING_IMPL(unsigned char, %hhu)
3018
3019
3029static void massageExponent(char *text)
3030{
3031 char *p = strchr(text, 'e');
3032 if (!p)
3033 return;
3034 const char *const end = p + strlen(p); // *end is '\0'
3035 p += (p[1] == '-' || p[1] == '+') ? 2 : 1;
3036 if (p[0] != '0' || end - 2 <= p)
3037 return;
3038 // We have a leading 0 on an exponent of at least two more digits
3039 const char *n = p + 1;
3040 while (end - 2 > n && n[0] == '0')
3041 ++n;
3042 memmove(p, n, end + 1 - n);
3043}
3044
3045// Be consistent about display of infinities and NaNs (snprintf()'s varies,
3046// notably on MinGW, despite POSIX documenting "[-]inf" or "[-]infinity" for %f,
3047// %e and %g, uppercasing for their capital versions; similar for "nan"):
3048#define TO_STRING_FLOAT(TYPE, FORMAT) \
3049template <> Q_TESTLIB_EXPORT char *QTest::toString<TYPE>(const TYPE &t) \
3050{ \
3051 char *msg = new char[128]; \
3052 switch (qFpClassify(t)) { \
3053 case FP_INFINITE: \
3054 qstrncpy(msg, (t < 0 ? "-inf" : "inf"), 128); \
3055 break; \
3056 case FP_NAN: \
3057 qstrncpy(msg, "nan", 128); \
3058 break; \
3059 default: \
3060 qsnprintf(msg, 128, #FORMAT, double(t)); \
3061 massageExponent(msg); \
3062 break; \
3063 } \
3064 return msg; \
3065}
3066
3068TO_STRING_FLOAT(float, %g)
3069TO_STRING_FLOAT(double, %.12g)
3070
3071template <> Q_TESTLIB_EXPORT char *QTest::toString<char>(const char &t)
3072{
3073 unsigned char c = static_cast<unsigned char>(t);
3074 char *msg = new char[16];
3075 switch (c) {
3076 case 0x00:
3077 qstrcpy(msg, "'\\0'");
3078 break;
3079 case 0x07:
3080 qstrcpy(msg, "'\\a'");
3081 break;
3082 case 0x08:
3083 qstrcpy(msg, "'\\b'");
3084 break;
3085 case 0x09:
3086 qstrcpy(msg, "'\\t'");
3087 break;
3088 case 0x0a:
3089 qstrcpy(msg, "'\\n'");
3090 break;
3091 case 0x0b:
3092 qstrcpy(msg, "'\\v'");
3093 break;
3094 case 0x0c:
3095 qstrcpy(msg, "'\\f'");
3096 break;
3097 case 0x0d:
3098 qstrcpy(msg, "'\\r'");
3099 break;
3100 case 0x22:
3101 qstrcpy(msg, "'\\\"'");
3102 break;
3103 case 0x27:
3104 qstrcpy(msg, "'\\\''");
3105 break;
3106 case 0x5c:
3107 qstrcpy(msg, "'\\\\'");
3108 break;
3109 default:
3110 if (c < 0x20 || c >= 0x7F)
3111 qsnprintf(msg, 16, "'\\x%02x'", c);
3112 else
3113 qsnprintf(msg, 16, "'%c'" , c);
3114 }
3115 return msg;
3116}
3117
3120char *QTest::toString(const char *str)
3121{
3122 if (!str) {
3123 char *msg = new char[1];
3124 *msg = '\0';
3125 return msg;
3126 }
3127 char *msg = new char[strlen(str) + 1];
3128 return qstrcpy(msg, str);
3129}
3130
3133char *QTest::toString(const volatile void *p) // Use volatile to match compare_ptr_helper()
3134{
3135 char *msg = new char[128];
3136 qsnprintf(msg, 128, "%p", p);
3137 return msg;
3138}
3139
3142char *QTest::toString(const volatile QObject *vo)
3143{
3144 if (vo == nullptr)
3145 return qstrdup("<null>");
3146
3147 auto *o = const_cast<const QObject*>(vo);
3148 const QString &name = o->objectName();
3149 const char *className = o->metaObject()->className();
3150 char *msg = new char[256];
3151 if (name.isEmpty())
3152 qsnprintf(msg, 256, "%s/%p", className, o);
3153 else
3154 qsnprintf(msg, 256, "%s/\"%s\"", className, qPrintable(name));
3155 return msg;
3156}
3157
3184bool QTest::compare_string_helper(const char *t1, const char *t2, const char *actual,
3185 const char *expected, const char *file, int line)
3186{
3187 auto formatter = Internal::genericToString<const char *>;
3188 return compare_helper(qstrcmp(t1, t2) == 0, "Compared strings are not the same",
3189 &t1, &t2, formatter, formatter,
3190 actual, expected, file, line);
3191}
3192
std::unique_ptr< QTimer > watchDog
static bool preventsStderrLogging()
static QBenchmarkGlobalData * current
static void setCounter(const char *name)
static QBenchmarkTestMethodData * current
static QString outFileBase(qint64 pid=-1)
static bool rerunThroughCallgrind(const QStringList &origAppArgs, int &exitCode)
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:107
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
static QString applicationDirPath()
Returns the directory that contains the application executable.
static QStringList arguments()
static void sendPostedEvents(QObject *receiver=nullptr, int event_type=0)
Immediately dispatches all events which have been previously queued with QCoreApplication::postEvent(...
The QDirListing class provides an STL-style iterator for directory entries.
Definition qdirlisting.h:18
\inmodule QtCore
Definition qdir.h:20
bool mkpath(const QString &dirPath) const
Creates the directory path dirPath.
Definition qdir.cpp:1578
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
static QString currentPath()
Returns the absolute path of the application's current directory.
Definition qdir.cpp:2054
@ DeferredDelete
Definition qcoreevent.h:100
void setFile(const QString &file)
bool exists() const
Returns true if the file system entry this QFileInfo refers to exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
bool setPermissions(Permissions permissionSpec) override
Sets the permissions for the file to the permissions specified.
Definition qfile.cpp:1159
bool copy(const QString &newName)
Copies the file named fileName() to newName.
Definition qfile.cpp:765
void setFileName(const QString &name)
Sets the name of the file.
Definition qfile.cpp:302
static QString decodeName(const QByteArray &localFileName)
This does the reverse of QFile::encodeName() using localFileName.
Definition qfile.h:162
QString errorString() const
Returns a human-readable description of the last device error that occurred.
bool contains(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
static QString path(LibraryPath p)
Definition qlist.h:75
qsizetype size() const noexcept
Definition qlist.h:397
const_pointer constData() const noexcept
Definition qlist.h:433
bool isEmpty() const noexcept
Definition qlist.h:401
T & last()
Definition qlist.h:648
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void reserve(qsizetype size)
Definition qlist.h:753
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qmetaobject.h:19
QByteArray methodSignature() const
\inmodule QtCore
Definition qmetatype.h:341
constexpr const char * name() const
Definition qmetatype.h:2680
\inmodule QtCore
Definition qobject.h:103
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:127
\inmodule QtCore \reentrant
static QSharedPointer create(Args &&...arguments)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static void endDump()
static void startDump()
static void setEnabled(bool)
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString sliced(qsizetype pos) const &
Definition qstring.h:394
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8870
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6664
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7263
const char * dataTag() const
Definition qtestdata.cpp:87
static int verboseLevel()
Definition qtestlog.cpp:609
static int failCount()
Definition qtestlog.cpp:668
static void startLogging()
Definition qtestlog.cpp:481
static void setInstalledTestCoverage(bool installed)
Definition qtestlog.cpp:695
static void setVerboseLevel(int level)
Definition qtestlog.cpp:604
static bool hasLoggers()
Definition qtestlog.cpp:558
static bool loggerUsingStdout()
Definition qtestlog.cpp:578
static void setMaxWarnings(int max)
Definition qtestlog.cpp:651
static void info(const char *msg, const char *file, int line)
Definition qtestlog.cpp:596
static void setPrintAvailableTagsMode()
Definition qtestlog.cpp:658
static void addBenchmarkResults(const QList< QBenchmarkResult > &result)
Definition qtestlog.cpp:475
static bool isRepeatSupported()
Definition qtestlog.cpp:568
static void stopLogging()
Definition qtestlog.cpp:490
static void failOnWarning()
Definition qtestlog.cpp:632
static void warn(const char *msg, const char *file, int line)
Definition qtestlog.cpp:588
static void addLogger(LogMode mode, const char *filename)
Definition qtestlog.cpp:500
static void ignoreMessage(QtMsgType type, const char *msg)
Definition qtestlog.cpp:614
Disables App Nap by registering a background activity.
static const char * currentTestObjectName()
static void fail(const char *message, const char *file, int line)
static const char * currentAppName()
static void finishedCurrentTestDataCleanup()
This function is called after completing each test function, including test functions that are not da...
static void finishedCurrentTestData()
This function is called after completing each test function, including test functions that are not da...
static bool expectFail(const char *dataIndex, const char *comment, QTest::TestFailMode mode, const char *file, int line)
static bool verify(bool statement, const char *statementStr, const char *extraInfo, const char *file, int line)
static bool currentTestFailed()
static void setSkipCurrentTest(bool value)
static void setCurrentAppName(const char *appName)
static void reset()
static void setCurrentTestFunction(const char *func)
static void setBlacklistCurrentTest(bool b)
static void setCurrentTestObject(const char *name)
static const char * currentDataTag()
static bool compare(bool success, const char *failureMsg, char *val1, char *val2, const char *actual, const char *expected, const char *file, int line)
static void addFailure(const char *message, const char *file=nullptr, int line=0)
static bool skipCurrentTest()
static void setCurrentGlobalTestData(QTestData *data)
static void finishedCurrentTestFunction()
This function is called after completing each test function, including test functions that are data-d...
static void setCurrentTestData(QTestData *data)
static bool reportResult(bool success, const void *lhs, const void *rhs, const char *(*lhsFormatter)(const void *), const char *(*rhsFormatter)(const void *), const char *lhsExpr, const char *rhsExpr, QTest::ComparisonOperation op, const char *file, int line, const char *failureMessage=nullptr)
static void addSkip(const char *message, const char *file, int line)
static QTestData * currentGlobalTestData()
static QTestData * currentTestData()
static const char * currentTestFunction()
int dataCount() const
bool isEmpty() const
static QTestTable * currentTestTable()
QTestData * testData(int index) const
static void clearGlobalTestTable()
static QTestTable * globalTestTable()
static QMetaMethod findMethod(const QObject *obj, const char *signature)
TestMethods(const QObject *o, MetaMethods m={})
void invokeTests(QObject *testObject) const
std::vector< QMetaMethod > MetaMethods
static TestRegistry * instance()
const void * constData() const
Definition qvariant.h:451
static int parseCommandLineArgument(const char *argument)
static bool canLogTestProgress()
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:47
QJSValue expected
Definition qjsengine.cpp:12
QString str
[2]
QString text
QList< QVariant > arguments
else opt state
[0]
Combined button and popup list for selecting options.
Lock qt_scoped_lock(Mutex &mutex)
Definition qlocking_p.h:58
Lock qt_unique_lock(Mutex &mutex)
Definition qlocking_p.h:64
Q_TESTLIB_EXPORT Qt::MouseButtons qtestMouseButtons
bool checkBlackLists(const char *slot, const char *data, const char *global)
void disableWindowRestore()
Q_TESTLIB_EXPORT void maybeThrowOnFail()
Q_TESTLIB_EXPORT QString formatTryTimeoutDebugMessage(q_no_char8_t::QUtf8StringView expr, int timeout, int actual)
Q_TESTLIB_EXPORT void throwOnFail()
Q_TESTLIB_EXPORT void maybeThrowOnSkip()
Q_TESTLIB_EXPORT void throwOnSkip()
Q_TESTLIB_EXPORT int lastMouseTimestamp
constexpr qsizetype PrettyUnicodeMaxIncrement
Q_TESTLIB_EXPORT int qRun()
Q_TESTLIB_EXPORT bool currentTestResolved()
static bool skipBlacklisted
Q_TESTLIB_EXPORT bool reportResult(bool success, const void *lhs, const void *rhs, const char *(*lhsFormatter)(const void *), const char *(*rhsFormatter)(const void *), const char *lhsExpr, const char *rhsExpr, ComparisonOperation op, const char *file, int line)
constexpr qsizetype PrettyUnicodeMaxOutputSize
Q_TESTLIB_EXPORT QTestData & newRow(const char *dataTag)
Appends a new row to the current test data.
static void invokeTestMethodIfExists(const char *methodName, QObject *obj=QTest::currentTestObject)
Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool qml)
Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description, const char *file, int line)
void * fetchData(QTestData *data, const char *tagName, int typeId)
static QList< QBenchmarkResult > qMedian(const QList< QList< QBenchmarkResult > > &container)
Q_TESTLIB_EXPORT const char * currentTestFunction()
Returns the name of the test function that is currently executed.
Q_TESTLIB_EXPORT QObject * testObject()
int Q_TESTLIB_EXPORT defaultMouseDelay()
Q_TESTLIB_EXPORT bool runningTest()
static Q_CONSTINIT QBasicMutex mutex
Definition qtestlog.cpp:142
Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir=nullptr)
static void qPrintDataTags(FILE *stream)
Q_TESTLIB_EXPORT void * qElementData(const char *elementName, int metaTypeId)
int Q_TESTLIB_EXPORT defaultKeyDelay()
void setThrowOnFail(bool enable) noexcept
Q_TESTLIB_EXPORT bool qExpectFail(const char *dataIndex, const char *comment, TestFailMode mode, const char *file, int line)
char * toString(const MyPoint &point)
static int keyDelay
Q_TESTLIB_EXPORT QStringList testFunctions
static bool invokeTestMethodIfValid(QMetaMethod m, QObject *obj=QTest::currentTestObject)
static bool qPrintTestSlots(FILE *stream, const char *filter=nullptr, const char *preamble="")
Q_TESTLIB_EXPORT void * qData(const char *tagName, int typeId)
int defaultEventDelay()
Q_TESTLIB_EXPORT bool currentTestFailed()
Returns true if the current test function has failed, otherwise false.
static bool installedTestCoverage
Definition qtestlog.cpp:150
static Q_CONSTINIT QBasicAtomicInt g_throwOnFail
Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc=0, char **argv=nullptr)
void setThrowOnSkip(bool enable) noexcept
Q_TESTLIB_EXPORT QStringList testTags
static int mouseDelay
static Q_CONSTINIT QBasicAtomicInt g_throwOnSkip
char * formatString(const char *prefix, const char *suffix, size_t numArguments,...)
char * toPrettyCString(const char *p, qsizetype length)
char * toHexRepresentation(const char *ba, qsizetype length)
Returns a pointer to a string that is the string ba represented as a space-separated sequence of hex ...
Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual, const char *expected, const char *file, int line)
static void printUnknownDataTagError(QLatin1StringView name, QLatin1StringView tag, const QTestTable &lTable, const QTestTable &gTable)
Q_TESTLIB_EXPORT char * toPrettyUnicode(QStringView string)
Q_TESTLIB_EXPORT void failOnWarning()
Q_DECL_COLD_FUNCTION Q_TESTLIB_EXPORT void qCaught(const char *expected, const char *what, const char *file, int line)
static int eventDelay
Q_TESTLIB_EXPORT bool printAvailableFunctions
Q_TESTLIB_EXPORT QString qFindTestData(const char *basepath, const char *file=nullptr, int line=0, const char *builddir=nullptr, const char *sourcedir=nullptr)
static int repetitions
ComparisonOperation
Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message)
Ignores messages created by qDebug(), qInfo() or qWarning().
Q_TESTLIB_EXPORT void qSkip(const char *message, const char *file, int line)
bool qCompare(QString const &t1, QLatin1StringView const &t2, const char *actual, const char *expected, const char *file, int line)
Definition qtest.h:31
static int qToInt(const char *str)
Q_TESTLIB_EXPORT const char * currentDataTag()
Returns the name of the current test data.
Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc=0, char **argv=nullptr)
Executes tests declared in testObject.
Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg, const void *actualPtr, const void *expectedPtr, const char *(*actualFormatter)(const void *), const char *(*expectedFormatter)(const void *), const char *actual, const char *expected, const char *file, int line)
Q_TESTLIB_EXPORT QTestData & addRow(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
static bool repeatForever
Q_TESTLIB_EXPORT void qCleanup()
Q_TESTLIB_EXPORT void addColumnInternal(int id, const char *name)
Q_DECL_COLD_FUNCTION Q_TESTLIB_EXPORT void qFail(const char *message, const char *file, int line)
Q_TESTLIB_EXPORT void * qGlobalData(const char *tagName, int typeId)
static QObject * currentTestObject
Q_TESTLIB_EXPORT const char * currentAppName()
Returns the name of the binary that is currently executed.
static bool inTestFunction
static QString mainSourcePath
QTCONCURRENT_RUN_NODISCARD auto run(QThreadPool *pool, Function &&f, Args &&...args)
constexpr char toHexUpper(char32_t value) noexcept
Definition qtools_p.h:27
constexpr int fromHex(char32_t c) noexcept
Definition qtools_p.h:44
@ NoButton
Definition qnamespace.h:57
@ CaseInsensitive
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
size_t qstrlen(const char *str)
int qstrncmp(const char *str1, const char *str2, size_t len)
Q_CORE_EXPORT int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap)
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt,...)
Q_CORE_EXPORT char * qstrdup(const char *)
Q_CORE_EXPORT char * qstrcpy(char *dst, const char *src)
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
#define qApp
AudioChannelLayoutTag tag
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char * destination
static QString methodName(const QDBusIntrospection::Method &method)
EGLStreamKHR stream
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
int qFpClassify(qfloat16 f) noexcept
Definition qfloat16.h:286
static void installCoverageTool(QLibraryPrivate *libPrivate)
Definition qlibrary.cpp:280
QtMsgType
Definition qlogging.h:29
#define qWarning
Definition qlogging.h:166
#define qFatal
Definition qlogging.h:168
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
static bool matches(const QJsonObject &object, const QString &osName, const QVersionNumber &kernelVersion, const QString &osRelease, const QOpenGLConfig::Gpu &gpu)
Definition qopengl.cpp:270
GLboolean GLboolean GLboolean b
GLenum mode
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLbitfield GLuint64 timeout
[4]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
[4]
GLenum GLuint buffer
GLenum type
GLenum GLenum dst
GLenum GLuint GLenum GLsizei const GLchar * buf
GLboolean enable
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint GLsizei const GLchar * message
GLuint start
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLuint name
GLint first
GLfloat n
GLint GLsizei GLsizei GLenum format
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLsizei len
GLubyte * pattern
GLenum GLenum GLsizei void * table
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static void qInit(QSqlQuery *q, const QString &query, const QSqlDatabase &db)
SSL_CTX int void * arg
static QString canonicalPath(const QString &rootPath)
#define qPrintable(string)
Definition qstring.h:1531
#define qUtf16Printable(string)
Definition qstring.h:1543
#define t2
#define QT_CONFIG(feature)
bool qputenv(const char *varName, QByteArrayView raw)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define QTEST_ASSERT(cond)
Definition qtestassert.h:11
#define QTEST_ASSERT_X(cond, where, what)
Definition qtestassert.h:13
static bool floatingCompare(const T &actual, const T &expected)
#define TO_STRING_FLOAT(TYPE, FORMAT)
#define TO_STRING_IMPL(TYPE, FORMAT)
static bool installCoverageTool(const char *appname, const char *testname)
static bool isValidSlot(const QMetaMethod &sl)
static void initEnvironment()
static void massageExponent(char *text)
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
unsigned long ulong
Definition qtypes.h:35
unsigned long long quint64
Definition qtypes.h:61
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
unsigned short ushort
Definition qtypes.h:33
double qreal
Definition qtypes.h:187
static const uint base
Definition qurlidna.cpp:20
class Preamble preamble
const char className[16]
[1]
Definition qwizard.cpp:100
#define explicit
QList< int > vector
[14]
QByteArray ba
[0]
QFile file
[0]
obj metaObject() -> className()
QAction * at
void testObject()
[11]
QJSValueList args
QJSValue global
\inmodule QtCore
QTestDataSetter(QTestData *data)