1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // Copyright (C) 2020 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 | #ifndef QTEST_H |
6 | #define QTEST_H |
7 | |
8 | #if 0 |
9 | #pragma qt_class(QTest) |
10 | #endif |
11 | |
12 | #include <QtTest/qttestglobal.h> |
13 | #include <QtTest/qtestcase.h> |
14 | #include <QtTest/qtestdata.h> |
15 | #include <QtTest/qtesttostring.h> |
16 | #include <QtTest/qbenchmark.h> |
17 | |
18 | #if defined(TESTCASE_LOWDPI) |
19 | #include <QtCore/qcoreapplication.h> |
20 | #endif |
21 | |
22 | #include <cstdio> |
23 | #include <initializer_list> |
24 | #include <memory> |
25 | |
26 | QT_BEGIN_NAMESPACE |
27 | |
28 | namespace QTest |
29 | { |
30 | |
31 | template<> |
32 | inline bool qCompare(QString const &t1, QLatin1StringView const &t2, const char *actual, |
33 | const char *expected, const char *file, int line) |
34 | { |
35 | return qCompare(t1, t2: QString(t2), actual, expected, file, line); |
36 | } |
37 | template<> |
38 | inline bool qCompare(QLatin1StringView const &t1, QString const &t2, const char *actual, |
39 | const char *expected, const char *file, int line) |
40 | { |
41 | return qCompare(t1: QString(t1), t2, actual, expected, file, line); |
42 | } |
43 | |
44 | // Compare sequences of equal size |
45 | template <typename ActualIterator, typename ExpectedIterator> |
46 | bool _q_compareSequence(ActualIterator actualIt, ActualIterator actualEnd, |
47 | ExpectedIterator expectedBegin, ExpectedIterator expectedEnd, |
48 | const char *actual, const char *expected, |
49 | const char *file, int line) |
50 | { |
51 | char msg[1024]; |
52 | msg[0] = '\0'; |
53 | |
54 | const qsizetype actualSize = actualEnd - actualIt; |
55 | const qsizetype expectedSize = expectedEnd - expectedBegin; |
56 | bool isOk = actualSize == expectedSize; |
57 | |
58 | if (!isOk) { |
59 | std::snprintf(s: msg, maxlen: sizeof(msg), format: "Compared lists have different sizes.\n" |
60 | " Actual (%s) size: %lld\n" |
61 | " Expected (%s) size: %lld" , |
62 | actual, qlonglong(actualSize), |
63 | expected, qlonglong(expectedSize)); |
64 | } |
65 | |
66 | for (auto expectedIt = expectedBegin; isOk && expectedIt < expectedEnd; ++actualIt, ++expectedIt) { |
67 | if (!(*actualIt == *expectedIt)) { |
68 | const qsizetype i = qsizetype(expectedIt - expectedBegin); |
69 | char *val1 = toString(*actualIt); |
70 | char *val2 = toString(*expectedIt); |
71 | |
72 | std::snprintf(s: msg, maxlen: sizeof(msg), format: "Compared lists differ at index %lld.\n" |
73 | " Actual (%s): %s\n" |
74 | " Expected (%s): %s" , |
75 | qlonglong(i), actual, val1 ? val1 : "<null>" , |
76 | expected, val2 ? val2 : "<null>" ); |
77 | isOk = false; |
78 | |
79 | delete [] val1; |
80 | delete [] val2; |
81 | } |
82 | } |
83 | return compare_helper(success: isOk, failureMsg: msg, actual, expected, file, line); |
84 | } |
85 | |
86 | namespace Internal { |
87 | |
88 | #if defined(TESTCASE_LOWDPI) |
89 | void disableHighDpi() |
90 | { |
91 | qputenv("QT_ENABLE_HIGHDPI_SCALING" , "0" ); |
92 | } |
93 | Q_CONSTRUCTOR_FUNCTION(disableHighDpi); |
94 | #endif |
95 | |
96 | } // namespace Internal |
97 | |
98 | template <typename T> |
99 | inline bool qCompare(QList<T> const &t1, QList<T> const &t2, const char *actual, const char *expected, |
100 | const char *file, int line) |
101 | { |
102 | return _q_compareSequence(t1.cbegin(), t1.cend(), t2.cbegin(), t2.cend(), |
103 | actual, expected, file, line); |
104 | } |
105 | |
106 | template <typename T, int N> |
107 | bool qCompare(QList<T> const &t1, std::initializer_list<T> t2, |
108 | const char *actual, const char *expected, |
109 | const char *file, int line) |
110 | { |
111 | return _q_compareSequence(t1.cbegin(), t1.cend(), t2.cbegin(), t2.cend(), |
112 | actual, expected, file, line); |
113 | } |
114 | |
115 | // Compare QList against array |
116 | template <typename T, int N> |
117 | bool qCompare(QList<T> const &t1, const T (& t2)[N], |
118 | const char *actual, const char *expected, |
119 | const char *file, int line) |
120 | { |
121 | return _q_compareSequence(t1.cbegin(), t1.cend(), t2, t2 + N, |
122 | actual, expected, file, line); |
123 | } |
124 | |
125 | template <typename T> |
126 | inline bool qCompare(QFlags<T> const &t1, T const &t2, const char *actual, const char *expected, |
127 | const char *file, int line) |
128 | { |
129 | using Int = typename QFlags<T>::Int; |
130 | return qCompare(Int(t1), Int(t2), actual, expected, file, line); |
131 | } |
132 | |
133 | template <typename T> |
134 | inline bool qCompare(QFlags<T> const &t1, int const &t2, const char *actual, const char *expected, |
135 | const char *file, int line) |
136 | { |
137 | using Int = typename QFlags<T>::Int; |
138 | return qCompare(Int(t1), Int(t2), actual, expected, file, line); |
139 | } |
140 | |
141 | template<> |
142 | inline bool qCompare(qint64 const &t1, qint32 const &t2, const char *actual, |
143 | const char *expected, const char *file, int line) |
144 | { |
145 | return qCompare(t1, t2: static_cast<qint64>(t2), actual, expected, file, line); |
146 | } |
147 | |
148 | template<> |
149 | inline bool qCompare(qint64 const &t1, quint32 const &t2, const char *actual, |
150 | const char *expected, const char *file, int line) |
151 | { |
152 | return qCompare(t1, t2: static_cast<qint64>(t2), actual, expected, file, line); |
153 | } |
154 | |
155 | template<> |
156 | inline bool qCompare(quint64 const &t1, quint32 const &t2, const char *actual, |
157 | const char *expected, const char *file, int line) |
158 | { |
159 | return qCompare(t1, t2: static_cast<quint64>(t2), actual, expected, file, line); |
160 | } |
161 | |
162 | template<> |
163 | inline bool qCompare(qint32 const &t1, qint64 const &t2, const char *actual, |
164 | const char *expected, const char *file, int line) |
165 | { |
166 | return qCompare(t1: static_cast<qint64>(t1), t2, actual, expected, file, line); |
167 | } |
168 | |
169 | template<> |
170 | inline bool qCompare(quint32 const &t1, qint64 const &t2, const char *actual, |
171 | const char *expected, const char *file, int line) |
172 | { |
173 | return qCompare(t1: static_cast<qint64>(t1), t2, actual, expected, file, line); |
174 | } |
175 | |
176 | template<> |
177 | inline bool qCompare(quint32 const &t1, quint64 const &t2, const char *actual, |
178 | const char *expected, const char *file, int line) |
179 | { |
180 | return qCompare(t1: static_cast<quint64>(t1), t2, actual, expected, file, line); |
181 | } |
182 | namespace Internal { |
183 | |
184 | template <typename T> |
185 | class HasInitMain // SFINAE test for the presence of initMain() |
186 | { |
187 | private: |
188 | using YesType = char[1]; |
189 | using NoType = char[2]; |
190 | |
191 | template <typename C> static YesType& test( decltype(&C::initMain) ) ; |
192 | template <typename C> static NoType& test(...); |
193 | |
194 | public: |
195 | enum { value = sizeof(test<T>(nullptr)) == sizeof(YesType) }; |
196 | }; |
197 | |
198 | template<typename T> |
199 | typename std::enable_if<HasInitMain<T>::value, void>::type callInitMain() |
200 | { |
201 | T::initMain(); |
202 | } |
203 | |
204 | template<typename T> |
205 | typename std::enable_if<!HasInitMain<T>::value, void>::type callInitMain() |
206 | { |
207 | } |
208 | |
209 | } // namespace Internal |
210 | |
211 | } // namespace QTest |
212 | QT_END_NAMESPACE |
213 | |
214 | #ifdef QT_TESTCASE_BUILDDIR |
215 | # define QTEST_SET_MAIN_SOURCE_PATH QTest::setMainSourcePath(__FILE__, QT_TESTCASE_BUILDDIR); |
216 | #else |
217 | # define QTEST_SET_MAIN_SOURCE_PATH QTest::setMainSourcePath(__FILE__); |
218 | #endif |
219 | |
220 | // Hooks for coverage-testing of QTestLib itself: |
221 | #if QT_CONFIG(testlib_selfcover) && defined(__COVERAGESCANNER__) |
222 | struct QtCoverageScanner |
223 | { |
224 | QtCoverageScanner(const char *name) |
225 | { |
226 | __coveragescanner_clear(); |
227 | __coveragescanner_testname(name); |
228 | } |
229 | ~QtCoverageScanner() |
230 | { |
231 | __coveragescanner_save(); |
232 | __coveragescanner_testname("" ); |
233 | } |
234 | }; |
235 | #define TESTLIB_SELFCOVERAGE_START(name) QtCoverageScanner _qtCoverageScanner(name); |
236 | #else |
237 | #define TESTLIB_SELFCOVERAGE_START(name) |
238 | #endif |
239 | |
240 | #if !defined(QTEST_BATCH_TESTS) |
241 | // Internal (but used by some testlib selftests to hack argc and argv). |
242 | // Tests should normally implement initMain() if they have set-up to do before |
243 | // instantiating the test class. |
244 | #define QTEST_MAIN_WRAPPER(TestObject, ...) \ |
245 | int main(int argc, char *argv[]) \ |
246 | { \ |
247 | TESTLIB_SELFCOVERAGE_START(#TestObject) \ |
248 | QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<TestObject>(); \ |
249 | __VA_ARGS__ \ |
250 | TestObject tc; \ |
251 | QTEST_SET_MAIN_SOURCE_PATH \ |
252 | return QTest::qExec(&tc, argc, argv); \ |
253 | } |
254 | #else |
255 | // BATCHED_TEST_NAME is defined for each test in a batch in cmake. Some odd |
256 | // targets, like snippets, don't define it though. Play safe by providing a |
257 | // default value. |
258 | #if !defined(BATCHED_TEST_NAME) |
259 | #define BATCHED_TEST_NAME "other" |
260 | #endif |
261 | #define QTEST_MAIN_WRAPPER(TestObject, ...) \ |
262 | \ |
263 | void qRegister##TestObject() \ |
264 | { \ |
265 | auto runTest = [](int argc, char** argv) -> int { \ |
266 | TESTLIB_SELFCOVERAGE_START(TestObject) \ |
267 | QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<TestObject>(); \ |
268 | __VA_ARGS__ \ |
269 | TestObject tc; \ |
270 | QTEST_SET_MAIN_SOURCE_PATH \ |
271 | return QTest::qExec(&tc, argc, argv); \ |
272 | }; \ |
273 | QTest::qRegisterTestCase(QStringLiteral(BATCHED_TEST_NAME), runTest); \ |
274 | } \ |
275 | \ |
276 | Q_CONSTRUCTOR_FUNCTION(qRegister##TestObject) |
277 | #endif |
278 | |
279 | // For when you don't even want a QApplication: |
280 | #define QTEST_APPLESS_MAIN(TestObject) QTEST_MAIN_WRAPPER(TestObject) |
281 | |
282 | #include <QtTest/qtestsystem.h> |
283 | |
284 | #if defined(QT_NETWORK_LIB) |
285 | # include <QtTest/qtest_network.h> |
286 | #endif |
287 | |
288 | // Internal |
289 | #define QTEST_QAPP_SETUP(klaz) \ |
290 | klaz app(argc, argv); \ |
291 | app.setAttribute(Qt::AA_Use96Dpi, true); |
292 | |
293 | #if defined(QT_WIDGETS_LIB) |
294 | # include <QtTest/qtest_widgets.h> |
295 | # ifdef QT_KEYPAD_NAVIGATION |
296 | # define QTEST_DISABLE_KEYPAD_NAVIGATION QApplication::setNavigationMode(Qt::NavigationModeNone); |
297 | # else |
298 | # define QTEST_DISABLE_KEYPAD_NAVIGATION |
299 | # endif |
300 | // Internal |
301 | # define QTEST_MAIN_SETUP() QTEST_QAPP_SETUP(QApplication) QTEST_DISABLE_KEYPAD_NAVIGATION |
302 | #elif defined(QT_GUI_LIB) |
303 | # include <QtTest/qtest_gui.h> |
304 | // Internal |
305 | # define QTEST_MAIN_SETUP() QTEST_QAPP_SETUP(QGuiApplication) |
306 | #else |
307 | // Internal |
308 | # define QTEST_MAIN_SETUP() QTEST_QAPP_SETUP(QCoreApplication) |
309 | #endif // QT_GUI_LIB |
310 | |
311 | // For most tests: |
312 | #define QTEST_MAIN(TestObject) QTEST_MAIN_WRAPPER(TestObject, QTEST_MAIN_SETUP()) |
313 | |
314 | // For command-line tests |
315 | #define QTEST_GUILESS_MAIN(TestObject) \ |
316 | QTEST_MAIN_WRAPPER(TestObject, QTEST_QAPP_SETUP(QCoreApplication)) |
317 | |
318 | #endif |
319 | |