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
qtestblacklist.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qtestblacklist_p.h"
4#include "qtestresult_p.h"
5
6#include <QtTest/qtestcase.h>
7#include <QtCore/qbytearray.h>
8#include <QtCore/qfile.h>
9#include <QtCore/qset.h>
10#include <QtCore/qcoreapplication.h>
11#include <QtCore/qvariant.h>
12#include <QtCore/QSysInfo>
13#include <QtCore/QOperatingSystemVersion>
14
15#include <set>
16
18
19using namespace Qt::StringLiterals;
20
21/*
22 The BLACKLIST file format is a grouped listing of keywords.
23
24 Blank lines and everything after # is simply ignored. An initial #-line
25 referring to this documentation is kind to readers. Comments can also be used
26 to indicate the reasons for ignoring particular cases.
27
28 Each blacklist line is interpreted as a list of keywords in an AND-relationship.
29 To blacklist a test for multiple platforms (OR-relationship), use separate lines.
30
31 The key "ci" applies only when run by COIN. Other keys name platforms, operating systems,
32 distributions, tool-chains or architectures; a ! prefix reverses what it
33 checks. A version, joined to a key (at present, only for distributions and
34 for msvc) with a hyphen, limits the key to the specific version. A keyword
35 line matches if every key on it applies to the present run. Successive lines
36 are alternate conditions for ignoring a test.
37
38 Ungrouped lines at the beginning of a file apply to the whole testcase. A
39 group starts with a [square-bracketed] identification of a test function to
40 ignore. For data-driven tests, this identification can be narrowed by the
41 inclusion of global and local data row tags, separated from the function name
42 and each other by colons. If both global and function-specific data rows tags
43 are supplied, the global one comes first (as in the tag reported in test
44 output, albeit in parentheses after the function name). Even when a test does
45 have global and local data tags, you can omit either or both. (If a global
46 data row's name coincides with that of a local data row, some unintended
47 matches may result; try to keep your data-row tags distinct.)
48
49 Subsequent lines give conditions for ignoring this test. You need at least
50 one or the group has no effect.
51
52 # See qtbase/src/testlib/qtestblacklist.cpp for format
53 # Test doesn't work on QNX at all
54 qnx
55
56 # QTBUG-12345
57 [testFunction]
58 linux
59 windows 64bit
60
61 # Flaky in COIN on macOS, not reproducible by developers
62 [testSlowly]
63 macos ci
64
65 # Needs basic C++11 support
66 [testfunction2:testData]
67 msvc-2010
68
69 [getFile:withProxy SSL:localhost]
70 android
71
72 QML test functions are identified using the following format:
73
74 <TestCase name>::<function name>:<data tag>
75
76 For example, to blacklist a QML test on RHEL 7.6:
77
78 # QTBUG-12345
79 [Button::test_display:TextOnly]
80 ci rhel-7.6
81
82 Keys are lower-case. Distribution name and version are supported if
83 QSysInfo's productType() and productVersion() return them.
84
85 Keys can be added via the space-separated QTEST_ENVIRONMENT
86 environment variable:
87
88 QTEST_ENVIRONMENT=ci ./tst_stuff
89
90 This can be used to "mock" a test environment. In the example above,
91 we add "ci" to the list of keys for the test environment, making it
92 possible to test BLACKLIST files that blacklist tests in a CI environment.
93
94 The other known keys are listed below:
95*/
96
97static QSet<QByteArray> keywords()
98{
99 // this list can be extended with new keywords as required
100 QSet<QByteArray> set = QSet<QByteArray>()
101 << "*"
102#ifdef Q_OS_LINUX
103 << "linux"
104#endif
105#ifdef Q_OS_MACOS
106 << "osx"
107 << "macos"
108#endif
109#if defined(Q_OS_WIN)
110 << "windows"
111#endif
112#ifdef Q_OS_IOS
113 << "ios"
114#endif
115#ifdef Q_OS_TVOS
116 << "tvos"
117#endif
118#ifdef Q_OS_WATCHOS
119 << "watchos"
120#endif
121#ifdef Q_OS_VISIONOS
122 << "visionos"
123#endif
124#ifdef Q_OS_ANDROID
125 << "android"
126#endif
127#ifdef Q_OS_QNX
128 << "qnx"
129#endif
130#ifdef Q_OS_WEBOS
131 << "webos"
132#endif
133
134#if QT_POINTER_SIZE == 8
135 << "64bit"
136#else
137 << "32bit"
138#endif
139
140#ifdef Q_CC_GNU
141 << "gcc"
142#endif
143#ifdef Q_CC_CLANG
144 << "clang"
145#endif
146#ifdef Q_CC_MSVC
147 << "msvc"
148# if _MSC_VER <= 1600
149 << "msvc-2010"
150# elif _MSC_VER <= 1700
151 << "msvc-2012"
152# elif _MSC_VER <= 1800
153 << "msvc-2013"
154# elif _MSC_VER <= 1900
155 << "msvc-2015"
156# elif _MSC_VER <= 1916
157 << "msvc-2017"
158# elif _MSC_VER <= 1929
159 << "msvc-2019"
160# else
161 << "msvc-2022"
162# endif
163#endif
164
165#ifdef Q_PROCESSOR_X86
166 << "x86"
167#endif
168#ifdef Q_PROCESSOR_ARM
169 << "arm"
170#endif
171
172#ifdef QT_BUILD_INTERNAL
173 << "developer-build"
174#endif
175 ;
176
178 if (app) {
179 const QVariant platformName = app->property("platformName");
180 if (platformName.isValid())
181 set << platformName.toByteArray();
182 }
183
184 return set;
185}
186
187static QSet<QByteArray> activeConditions()
188{
189 QSet<QByteArray> result = keywords();
190
191 QByteArray distributionName = QSysInfo::productType().toLower().toUtf8();
192 QByteArray distributionRelease = QSysInfo::productVersion().toLower().toUtf8();
193 if (!distributionName.isEmpty()) {
194 if (result.find(distributionName) == result.end())
195 result.insert(distributionName);
196 // backwards compatibility with Qt 5
197 if (distributionName == "macos") {
198 if (result.find(distributionName) == result.end())
199 result.insert("osx");
200 const auto version = QOperatingSystemVersion::current();
201 if (version.majorVersion() >= 11)
202 distributionRelease = QByteArray::number(version.majorVersion());
203 }
204 if (!distributionRelease.isEmpty()) {
205 QByteArray versioned = distributionName + "-" + distributionRelease;
206 if (result.find(versioned) == result.end())
207 result.insert(versioned);
208 if (distributionName == "macos") {
209 QByteArray versioned = "osx-" + distributionRelease;
210 if (result.find(versioned) == result.end())
211 result.insert(versioned);
212 }
213 }
214 }
215
216 if (qEnvironmentVariableIsSet("QTEST_ENVIRONMENT")) {
217 for (const QByteArray &k : qgetenv("QTEST_ENVIRONMENT").split(' '))
218 result.insert(k);
219 }
220
221 return result;
222}
223
225{
226 static const QSet<QByteArray> matchedConditions = activeConditions();
227 QList<QByteArray> conds = condition.split(' ');
228
229 for (QByteArray c : conds) {
230 bool result = c.startsWith('!');
231 if (result)
232 c.remove(0, 1);
233
234 result ^= matchedConditions.contains(c);
235 if (!result)
236 return false;
237 }
238 return true;
239}
240
241static bool ignoreAll = false;
242static std::set<QByteArray> *ignoredTests = nullptr;
243
244namespace QTestPrivate {
245
247{
248 QString filename = QTest::qFindTestData(QStringLiteral("BLACKLIST"));
249 if (filename.isEmpty())
250 return;
251 QFile ignored(filename);
252 if (!ignored.open(QIODevice::ReadOnly))
253 return;
254
256
257 while (!ignored.atEnd()) {
258 QByteArray line = ignored.readLine();
259 const int commentPosition = line.indexOf('#');
260 if (commentPosition >= 0)
261 line.truncate(commentPosition);
262 line = line.simplified();
263 if (line.isEmpty())
264 continue;
265 if (line.startsWith('[')) {
266 function = line.mid(1, line.size() - 2);
267 continue;
268 }
270 if (condition) {
271 if (!function.size()) {
272 ignoreAll = true;
273 } else {
274 if (!ignoredTests)
275 ignoredTests = new std::set<QByteArray>;
276 ignoredTests->insert(function);
277 }
278 }
279 }
280}
281
282// Returns \c true if this test-case is blacklisted.
283bool checkBlackLists(const char *slot, const char *data, const char *global)
284{
285 bool ignore = ignoreAll;
286
287 if (!ignore && ignoredTests) {
288 QByteArray s = slot;
289 ignore = ignoredTests->find(s) != ignoredTests->end();
290 if (!ignore && data) {
291 s = (s + ':') + data;
292 ignore = ignoredTests->find(s) != ignoredTests->end();
293 }
294
295 if (!ignore && global) {
296 s = slot + ":"_ba + global;
297 ignore = ignoredTests->find(s) != ignoredTests->end();
298 if (!ignore && data) {
299 s = (s + ':') + data;
300 ignore = ignoredTests->find(s) != ignoredTests->end();
301 }
302 }
303 }
304
305 return ignore;
306}
307
308} // QTestPrivate
309
\inmodule QtCore
Definition qbytearray.h:57
QByteArray & insert(qsizetype i, QByteArrayView data)
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
\inmodule QtCore
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
\inmodule QtCore
Definition qfile.h:93
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
static Q_CORE_EXPORT QOperatingSystemVersionBase current()
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4517
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
void truncate(qsizetype pos)
Truncates the string at the given position index.
Definition qstring.cpp:6319
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QString simplified() const &
Definition qstring.h:451
static QString productType()
Definition qsysinfo.cpp:769
static QString productVersion()
Definition qsysinfo.cpp:839
\inmodule QtCore
Definition qvariant.h:65
bool isValid() const
Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns fal...
Definition qvariant.h:714
QByteArray toByteArray() const
Returns the variant as a QByteArray if the variant has userType() \l QMetaType::QByteArray or \l QMet...
Combined button and popup list for selecting options.
bool checkBlackLists(const char *slot, const char *data, const char *global)
Q_TESTLIB_EXPORT QString qFindTestData(const char *basepath, const char *file=nullptr, int line=0, const char *builddir=nullptr, const char *sourcedir=nullptr)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
GLenum condition
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLuint64EXT * result
[6]
#define QStringLiteral(str)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
static std::set< QByteArray > * ignoredTests
static bool ignoreAll
static QSet< QByteArray > keywords()
static bool checkCondition(const QByteArray &condition)
static QSet< QByteArray > activeConditions()
QFuture< QSet< QChar > > set
[10]
QApplication app(argc, argv)
[0]
QJSValue global