1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QTESTCASE_H |
5 | #define QTESTCASE_H |
6 | |
7 | #include <QtTest/qttestglobal.h> |
8 | |
9 | #include <QtCore/qstring.h> |
10 | #include <QtCore/qnamespace.h> |
11 | #include <QtCore/qmetatype.h> |
12 | #include <QtCore/qmetaobject.h> |
13 | #include <QtCore/qsharedpointer.h> |
14 | #include <QtCore/qtemporarydir.h> |
15 | #include <QtCore/qthread.h> |
16 | #include <QtCore/qxpfunctional.h> |
17 | |
18 | #include <string.h> |
19 | |
20 | #ifndef QT_NO_EXCEPTIONS |
21 | # include <exception> |
22 | #endif // QT_NO_EXCEPTIONS |
23 | |
24 | QT_BEGIN_NAMESPACE |
25 | |
26 | class qfloat16; |
27 | class QRegularExpression; |
28 | |
29 | #define QVERIFY(statement) \ |
30 | do {\ |
31 | if (!QTest::qVerify(static_cast<bool>(statement), #statement, "", __FILE__, __LINE__))\ |
32 | return;\ |
33 | } while (false) |
34 | |
35 | #define QFAIL(message) \ |
36 | do {\ |
37 | QTest::qFail(static_cast<const char *>(message), __FILE__, __LINE__);\ |
38 | return;\ |
39 | } while (false) |
40 | |
41 | #define QVERIFY2(statement, description) \ |
42 | do {\ |
43 | if (statement) {\ |
44 | if (!QTest::qVerify(true, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\ |
45 | return;\ |
46 | } else {\ |
47 | if (!QTest::qVerify(false, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\ |
48 | return;\ |
49 | }\ |
50 | } while (false) |
51 | |
52 | #define QCOMPARE(actual, expected) \ |
53 | do {\ |
54 | if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\ |
55 | return;\ |
56 | } while (false) |
57 | |
58 | // A wrapper lambda is introduced to extend the lifetime of lhs and rhs in |
59 | // case they are temporary objects. |
60 | // We also use IILE to prevent potential name clashes and shadowing of variables |
61 | // from user code. A drawback of the approach is that it looks ugly :( |
62 | #define QCOMPARE_OP_IMPL(lhs, rhs, op, opId) \ |
63 | do { \ |
64 | if (![](auto &&qt_lhs_arg, auto &&qt_rhs_arg) { \ |
65 | /* assumes that op does not actually move from qt_{lhs, rhs}_arg */ \ |
66 | return QTest::reportResult(std::forward<decltype(qt_lhs_arg)>(qt_lhs_arg) \ |
67 | op \ |
68 | std::forward<decltype(qt_rhs_arg)>(qt_rhs_arg), \ |
69 | [&qt_lhs_arg] { return QTest::toString(qt_lhs_arg); }, \ |
70 | [&qt_rhs_arg] { return QTest::toString(qt_rhs_arg); }, \ |
71 | #lhs, #rhs, QTest::ComparisonOperation::opId, \ |
72 | __FILE__, __LINE__); \ |
73 | }(lhs, rhs)) { \ |
74 | return; \ |
75 | } \ |
76 | } while (false) |
77 | |
78 | #define QCOMPARE_EQ(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, ==, Equal) |
79 | #define QCOMPARE_NE(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, !=, NotEqual) |
80 | #define QCOMPARE_LT(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, <, LessThan) |
81 | #define QCOMPARE_LE(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, <=, LessThanOrEqual) |
82 | #define QCOMPARE_GT(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, >, GreaterThan) |
83 | #define QCOMPARE_GE(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, >=, GreaterThanOrEqual) |
84 | |
85 | #ifndef QT_NO_EXCEPTIONS |
86 | |
87 | # define QVERIFY_THROWS_NO_EXCEPTION(...) \ |
88 | do { \ |
89 | QT_TRY { \ |
90 | __VA_ARGS__; \ |
91 | /* success */ \ |
92 | } QT_CATCH (const std::exception &e) { \ |
93 | QTest::qCaught(nullptr, e.what(), __FILE__, __LINE__); \ |
94 | return; \ |
95 | } QT_CATCH (...) { \ |
96 | QTest::qCaught(nullptr, nullptr, __FILE__, __LINE__); \ |
97 | QT_RETHROW; \ |
98 | } \ |
99 | } while (false) \ |
100 | /* end */ |
101 | |
102 | #if QT_DEPRECATED_SINCE(6, 3) |
103 | namespace QTest { |
104 | QT_DEPRECATED_VERSION_X_6_3("Don't use QVERIFY_EXCEPTION_THROWN(expr, type) anymore, " |
105 | "use QVERIFY_THROWS_EXCEPTION(type, expr...) instead" ) |
106 | inline void useVerifyThrowsException() {} |
107 | } // namespace QTest |
108 | # define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \ |
109 | QVERIFY_THROWS_EXCEPTION(exceptiontype, QTest::useVerifyThrowsException(); expression) |
110 | #endif |
111 | |
112 | # define QVERIFY_THROWS_EXCEPTION(exceptiontype, ...) \ |
113 | do {\ |
114 | QT_TRY {\ |
115 | QT_TRY {\ |
116 | __VA_ARGS__;\ |
117 | QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \ |
118 | " but no exception caught", __FILE__, __LINE__);\ |
119 | return;\ |
120 | } QT_CATCH (const exceptiontype &) {\ |
121 | /* success */\ |
122 | }\ |
123 | } QT_CATCH (const std::exception &e) {\ |
124 | QTest::qCaught(#exceptiontype, e.what(), __FILE__, __LINE__);\ |
125 | return;\ |
126 | } QT_CATCH (...) {\ |
127 | QTest::qCaught(#exceptiontype, nullptr, __FILE__, __LINE__);\ |
128 | QT_RETHROW;\ |
129 | }\ |
130 | } while (false) |
131 | |
132 | #else // QT_NO_EXCEPTIONS |
133 | |
134 | /* |
135 | * These macros check whether the expression passed throws exceptions, but we can't |
136 | * catch them to check because Qt has been compiled without exception support. We can't |
137 | * skip the expression because it may have side effects and must be executed. |
138 | * So, users must use Qt with exception support enabled if they use exceptions |
139 | * in their code. |
140 | */ |
141 | # define QVERIFY_THROWS_EXCEPTION(...) \ |
142 | static_assert(false, "Support for exceptions is disabled") |
143 | # define QVERIFY_THROWS_NO_EXCEPTION(...) \ |
144 | static_assert(false, "Support for exceptions is disabled") |
145 | |
146 | #endif // !QT_NO_EXCEPTIONS |
147 | |
148 | /* Ideally we would adapt qWaitFor(), or a variant on it, to implement roughly |
149 | * what the following provides as QTRY_LOOP_IMPL(); however, for now, the |
150 | * reporting of how much to increase the timeout to (if within a factor of two) |
151 | * on failure and the check for (QTest::runningTest() && |
152 | * QTest::currentTestResolved()) go beyond qWaitFor(). (We no longer care about |
153 | * the bug in MSVC < 2017 that precluded using qWaitFor() in the implementation |
154 | * here, see QTBUG-59096.) |
155 | */ |
156 | |
157 | // NB: not do {...} while (0) wrapped, as qt_test_i is accessed after it |
158 | #define QTRY_LOOP_IMPL(expr, timeoutValue, step) \ |
159 | if (!(expr)) { \ |
160 | QTest::qWait(0); \ |
161 | } \ |
162 | int qt_test_i = 0; \ |
163 | for (; qt_test_i < timeoutValue && !(QTest::runningTest() && QTest::currentTestResolved()) \ |
164 | && !(expr); qt_test_i += step) { \ |
165 | QTest::qWait(step); \ |
166 | } |
167 | // Ends in a for-block, so doesn't want a following semicolon. |
168 | |
169 | #define QTRY_TIMEOUT_DEBUG_IMPL(expr, timeoutValue, step) \ |
170 | if (!(QTest::runningTest() && QTest::currentTestResolved()) && !(expr)) { \ |
171 | QTRY_LOOP_IMPL(expr, 2 * (timeoutValue), step) \ |
172 | if ((expr)) { \ |
173 | QFAIL(qPrintable(QTest::Internal::formatTryTimeoutDebugMessage(\ |
174 | u8"" #expr, timeoutValue, timeoutValue + qt_test_i))); \ |
175 | } \ |
176 | } |
177 | |
178 | #define QTRY_IMPL(expr, timeout)\ |
179 | const int qt_test_step = timeout < 350 ? timeout / 7 + 1 : 50; \ |
180 | const int qt_test_timeoutValue = timeout; \ |
181 | { QTRY_LOOP_IMPL(expr, qt_test_timeoutValue, qt_test_step) } \ |
182 | QTRY_TIMEOUT_DEBUG_IMPL(expr, qt_test_timeoutValue, qt_test_step) |
183 | // Ends with an if-block, so doesn't want a following semicolon. |
184 | |
185 | // Will try to wait for the expression to become true while allowing event processing |
186 | #define QTRY_VERIFY_WITH_TIMEOUT(expr, timeout) \ |
187 | do { \ |
188 | QTRY_IMPL(expr, timeout) \ |
189 | QVERIFY(expr); \ |
190 | } while (false) |
191 | |
192 | #define QTRY_VERIFY(expr) QTRY_VERIFY_WITH_TIMEOUT(expr, 5000) |
193 | |
194 | // Will try to wait for the expression to become true while allowing event processing |
195 | #define QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, timeout) \ |
196 | do { \ |
197 | QTRY_IMPL(expr, timeout) \ |
198 | QVERIFY2(expr, messageExpression); \ |
199 | } while (false) |
200 | |
201 | #define QTRY_VERIFY2(expr, messageExpression) QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, 5000) |
202 | |
203 | // Will try to wait for the comparison to become successful while allowing event processing |
204 | #define QTRY_COMPARE_WITH_TIMEOUT(expr, expected, timeout) \ |
205 | do { \ |
206 | QTRY_IMPL((expr) == (expected), timeout) \ |
207 | QCOMPARE(expr, expected); \ |
208 | } while (false) |
209 | |
210 | #define QTRY_COMPARE(expr, expected) QTRY_COMPARE_WITH_TIMEOUT(expr, expected, 5000) |
211 | |
212 | #define QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, op, opId, timeout) \ |
213 | do { \ |
214 | QTRY_IMPL(((computed) op (baseline)), timeout) \ |
215 | QCOMPARE_OP_IMPL(computed, baseline, op, opId); \ |
216 | } while (false) |
217 | |
218 | #define QTRY_COMPARE_EQ_WITH_TIMEOUT(computed, baseline, timeout) \ |
219 | QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, ==, Equal, timeout) |
220 | |
221 | #define QTRY_COMPARE_EQ(computed, baseline) QTRY_COMPARE_EQ_WITH_TIMEOUT(computed, baseline, 5000) |
222 | |
223 | #define QTRY_COMPARE_NE_WITH_TIMEOUT(computed, baseline, timeout) \ |
224 | QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, !=, NotEqual, timeout) |
225 | |
226 | #define QTRY_COMPARE_NE(computed, baseline) QTRY_COMPARE_NE_WITH_TIMEOUT(computed, baseline, 5000) |
227 | |
228 | #define QTRY_COMPARE_LT_WITH_TIMEOUT(computed, baseline, timeout) \ |
229 | QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, <, LessThan, timeout) |
230 | |
231 | #define QTRY_COMPARE_LT(computed, baseline) QTRY_COMPARE_LT_WITH_TIMEOUT(computed, baseline, 5000) |
232 | |
233 | #define QTRY_COMPARE_LE_WITH_TIMEOUT(computed, baseline, timeout) \ |
234 | QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, <=, LessThanOrEqual, timeout) |
235 | |
236 | #define QTRY_COMPARE_LE(computed, baseline) QTRY_COMPARE_LE_WITH_TIMEOUT(computed, baseline, 5000) |
237 | |
238 | #define QTRY_COMPARE_GT_WITH_TIMEOUT(computed, baseline, timeout) \ |
239 | QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, >, GreaterThan, timeout) |
240 | |
241 | #define QTRY_COMPARE_GT(computed, baseline) QTRY_COMPARE_GT_WITH_TIMEOUT(computed, baseline, 5000) |
242 | |
243 | #define QTRY_COMPARE_GE_WITH_TIMEOUT(computed, baseline, timeout) \ |
244 | QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, >=, GreaterThanOrEqual, timeout) |
245 | |
246 | #define QTRY_COMPARE_GE(computed, baseline) QTRY_COMPARE_GE_WITH_TIMEOUT(computed, baseline, 5000) |
247 | |
248 | #define QSKIP_INTERNAL(statement) \ |
249 | do {\ |
250 | QTest::qSkip(static_cast<const char *>(statement), __FILE__, __LINE__);\ |
251 | return;\ |
252 | } while (false) |
253 | |
254 | #define QSKIP(statement, ...) QSKIP_INTERNAL(statement) |
255 | |
256 | #define QEXPECT_FAIL(dataIndex, comment, mode)\ |
257 | do {\ |
258 | if (!QTest::qExpectFail(dataIndex, static_cast<const char *>(comment), QTest::mode, __FILE__, __LINE__))\ |
259 | return;\ |
260 | } while (false) |
261 | |
262 | #define QFETCH(Type, name)\ |
263 | Type name = *static_cast<Type *>(QTest::qData(#name, ::qMetaTypeId<typename std::remove_cv<Type >::type>())) |
264 | |
265 | #define QFETCH_GLOBAL(Type, name)\ |
266 | Type name = *static_cast<Type *>(QTest::qGlobalData(#name, ::qMetaTypeId<typename std::remove_cv<Type >::type>())) |
267 | |
268 | #define QTEST(actual, testElement)\ |
269 | do {\ |
270 | if (!QTest::qTest(actual, testElement, #actual, #testElement, __FILE__, __LINE__))\ |
271 | return;\ |
272 | } while (false) |
273 | |
274 | #ifdef QT_TESTCASE_BUILDDIR |
275 | |
276 | #ifndef QT_TESTCASE_SOURCEDIR |
277 | #define QT_TESTCASE_SOURCEDIR nullptr |
278 | #endif |
279 | |
280 | # define QFINDTESTDATA(basepath)\ |
281 | QTest::qFindTestData(basepath, __FILE__, __LINE__, QT_TESTCASE_BUILDDIR, QT_TESTCASE_SOURCEDIR) |
282 | #else |
283 | # define QFINDTESTDATA(basepath)\ |
284 | QTest::qFindTestData(basepath, __FILE__, __LINE__) |
285 | #endif |
286 | |
287 | # define (resourcePath) \ |
288 | QTest::qExtractTestData(resourcePath) |
289 | |
290 | class QObject; |
291 | class QTestData; |
292 | |
293 | #define QTEST_COMPARE_DECL(KLASS)\ |
294 | template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &); |
295 | |
296 | namespace QTest |
297 | { |
298 | namespace Internal { |
299 | |
300 | Q_TESTLIB_EXPORT QString formatTryTimeoutDebugMessage(q_no_char8_t::QUtf8StringView expr, int timeout, int actual); |
301 | |
302 | template<typename T> // Output registered enums |
303 | inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e) |
304 | { |
305 | QMetaEnum me = QMetaEnum::fromType<T>(); |
306 | return qstrdup(me.valueToKey(value: int(e))); // int cast is necessary to support enum classes |
307 | } |
308 | |
309 | template <typename T> |
310 | inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e) |
311 | { |
312 | return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData()); |
313 | } |
314 | |
315 | template <typename T> // Fallback; for built-in types debug streaming must be possible |
316 | inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char *>::type toString(const T &t) |
317 | { |
318 | char *result = nullptr; |
319 | #ifndef QT_NO_DEBUG_STREAM |
320 | if constexpr (QTypeTraits::has_ostream_operator_v<QDebug, T>) { |
321 | result = qstrdup(QDebug::toString(t).toUtf8().constData()); |
322 | } else { |
323 | static_assert(!QMetaTypeId2<T>::IsBuiltIn, |
324 | "Built-in type must implement debug streaming operator " |
325 | "or provide QTest::toString specialization" ); |
326 | } |
327 | #endif |
328 | return result; |
329 | } |
330 | |
331 | template<typename F> // Output QFlags of registered enumerations |
332 | inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f) |
333 | { |
334 | const QMetaEnum me = QMetaEnum::fromType<F>(); |
335 | return qstrdup(me.valueToKeys(value: int(f.toInt())).constData()); |
336 | } |
337 | |
338 | template <typename F> // Fallback: Output hex value |
339 | inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f) |
340 | { |
341 | const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0' |
342 | char *msg = new char[space]; |
343 | qsnprintf(str: msg, n: space, fmt: "0x%x" , unsigned(f.toInt())); |
344 | return msg; |
345 | } |
346 | |
347 | } // namespace Internal |
348 | |
349 | template<typename T> |
350 | inline char *toString(const T &t) |
351 | { |
352 | return Internal::toString(t); |
353 | } |
354 | |
355 | template <typename T1, typename T2> |
356 | inline char *toString(const QPair<T1, T2> &pair); |
357 | |
358 | template <typename T1, typename T2> |
359 | inline char *toString(const std::pair<T1, T2> &pair); |
360 | |
361 | template <class... Types> |
362 | inline char *toString(const std::tuple<Types...> &tuple); |
363 | |
364 | template <typename Rep, typename Period> |
365 | inline char *toString(std::chrono::duration<Rep, Period> duration); |
366 | |
367 | Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length); |
368 | Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length); |
369 | Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string); |
370 | Q_TESTLIB_EXPORT char *toString(const char *); |
371 | Q_TESTLIB_EXPORT char *toString(const volatile void *); |
372 | Q_TESTLIB_EXPORT char *toString(const void *); // ### FIXME: Qt 7: Remove |
373 | Q_TESTLIB_EXPORT char *toString(const volatile QObject *); |
374 | |
375 | Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc = 0, char **argv = nullptr); |
376 | Q_TESTLIB_EXPORT int qRun(); |
377 | Q_TESTLIB_EXPORT void qCleanup(); |
378 | |
379 | Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = nullptr); |
380 | Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments); |
381 | |
382 | #if QT_CONFIG(batch_test_support) || defined(Q_QDOC) |
383 | using TestEntryFunction = int (*)(int, char **); |
384 | Q_TESTLIB_EXPORT void qRegisterTestCase(const QString &name, TestEntryFunction entryFunction); |
385 | #endif // QT_CONFIG(batch_test_support) |
386 | |
387 | Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir = nullptr); |
388 | |
389 | Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description, |
390 | const char *file, int line); |
391 | Q_DECL_COLD_FUNCTION |
392 | Q_TESTLIB_EXPORT void qFail(const char *message, const char *file, int line); |
393 | Q_TESTLIB_EXPORT void qSkip(const char *message, const char *file, int line); |
394 | Q_TESTLIB_EXPORT bool qExpectFail(const char *dataIndex, const char *, TestFailMode mode, |
395 | const char *file, int line); |
396 | Q_DECL_COLD_FUNCTION |
397 | Q_TESTLIB_EXPORT void qCaught(const char *expected, const char *what, const char *file, int line); |
398 | #if QT_DEPRECATED_SINCE(6, 3) |
399 | QT_DEPRECATED_VERSION_X_6_3("Use qWarning() instead" ) |
400 | Q_TESTLIB_EXPORT void qWarn(const char *message, const char *file = nullptr, int line = 0); |
401 | #endif |
402 | Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message); |
403 | #if QT_CONFIG(regularexpression) |
404 | Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern); |
405 | #endif |
406 | Q_TESTLIB_EXPORT void failOnWarning(const char *message); |
407 | #if QT_CONFIG(regularexpression) |
408 | Q_TESTLIB_EXPORT void failOnWarning(const QRegularExpression &messagePattern); |
409 | #endif |
410 | |
411 | #if QT_CONFIG(temporaryfile) |
412 | Q_TESTLIB_EXPORT QSharedPointer<QTemporaryDir> (const QString &dirName); |
413 | #endif |
414 | Q_TESTLIB_EXPORT QString qFindTestData(const char* basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr, const char* sourcedir = nullptr); |
415 | Q_TESTLIB_EXPORT QString qFindTestData(const QString& basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr, const char *sourcedir = nullptr); |
416 | |
417 | Q_TESTLIB_EXPORT void *qData(const char *tagName, int typeId); |
418 | Q_TESTLIB_EXPORT void *qGlobalData(const char *tagName, int typeId); |
419 | Q_TESTLIB_EXPORT void *qElementData(const char *elementName, int metaTypeId); |
420 | Q_TESTLIB_EXPORT QObject *testObject(); |
421 | |
422 | Q_TESTLIB_EXPORT const char *currentAppName(); |
423 | |
424 | Q_TESTLIB_EXPORT const char *currentTestFunction(); |
425 | Q_TESTLIB_EXPORT const char *currentDataTag(); |
426 | Q_TESTLIB_EXPORT bool currentTestFailed(); |
427 | Q_TESTLIB_EXPORT bool currentTestResolved(); |
428 | Q_TESTLIB_EXPORT bool runningTest(); // Internal, for use by macros and QTestEventLoop. |
429 | |
430 | Q_TESTLIB_EXPORT Qt::Key asciiToKey(char ascii); |
431 | Q_TESTLIB_EXPORT char keyToAscii(Qt::Key key); |
432 | |
433 | // ### TODO: remove QTestResult::compare() overload that takes char * values |
434 | // when this overload is removed. |
435 | #if QT_DEPRECATED_SINCE(6, 4) |
436 | QT_DEPRECATED_VERSION_X_6_4("use an overload that takes function_ref as parameters, " |
437 | "or an overload that takes only failure message, if you " |
438 | "do not need to stringify the values" ) |
439 | Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg, |
440 | char *actualVal, char *expectedVal, |
441 | const char *actual, const char *expected, |
442 | const char *file, int line); |
443 | #endif // QT_DEPRECATED_SINCE(6, 4) |
444 | Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg, |
445 | qxp::function_ref<const char*()> actualVal, |
446 | qxp::function_ref<const char*()> expectedVal, |
447 | const char *actual, const char *expected, |
448 | const char *file, int line); |
449 | Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg, |
450 | const char *actual, const char *expected, |
451 | const char *file, int line); |
452 | |
453 | Q_TESTLIB_EXPORT void addColumnInternal(int id, const char *name); |
454 | |
455 | template <typename T> |
456 | inline void addColumn(const char *name, T * = nullptr) |
457 | { |
458 | using QIsSameTConstChar = std::is_same<T, const char*>; |
459 | static_assert(!QIsSameTConstChar::value, "const char* is not allowed as a test data format." ); |
460 | addColumnInternal(qMetaTypeId<T>(), name); |
461 | } |
462 | Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag); |
463 | Q_TESTLIB_EXPORT QTestData &addRow(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2); |
464 | |
465 | Q_TESTLIB_EXPORT bool qCompare(qfloat16 const &t1, qfloat16 const &t2, |
466 | const char *actual, const char *expected, const char *file, int line); |
467 | |
468 | Q_TESTLIB_EXPORT bool qCompare(float const &t1, float const &t2, |
469 | const char *actual, const char *expected, const char *file, int line); |
470 | |
471 | Q_TESTLIB_EXPORT bool qCompare(double const &t1, double const &t2, |
472 | const char *actual, const char *expected, const char *file, int line); |
473 | |
474 | Q_TESTLIB_EXPORT bool qCompare(int t1, int t2, const char *actual, const char *expected, |
475 | const char *file, int line); |
476 | |
477 | #if QT_POINTER_SIZE == 8 |
478 | Q_TESTLIB_EXPORT bool qCompare(qsizetype t1, qsizetype t2, const char *actual, const char *expected, |
479 | const char *file, int line); |
480 | #endif |
481 | |
482 | Q_TESTLIB_EXPORT bool qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected, |
483 | const char *file, int line); |
484 | |
485 | Q_TESTLIB_EXPORT bool qCompare(QStringView t1, QStringView t2, |
486 | const char *actual, const char *expected, |
487 | const char *file, int line); |
488 | Q_TESTLIB_EXPORT bool qCompare(QStringView t1, const QLatin1StringView &t2, |
489 | const char *actual, const char *expected, |
490 | const char *file, int line); |
491 | Q_TESTLIB_EXPORT bool qCompare(const QLatin1StringView &t1, QStringView t2, |
492 | const char *actual, const char *expected, |
493 | const char *file, int line); |
494 | inline bool qCompare(const QString &t1, const QString &t2, |
495 | const char *actual, const char *expected, |
496 | const char *file, int line) |
497 | { |
498 | return qCompare(t1: QStringView(t1), t2: QStringView(t2), actual, expected, file, line); |
499 | } |
500 | inline bool qCompare(const QString &t1, const QLatin1StringView &t2, |
501 | const char *actual, const char *expected, |
502 | const char *file, int line) |
503 | { |
504 | return qCompare(t1: QStringView(t1), t2, actual, expected, file, line); |
505 | } |
506 | inline bool qCompare(const QLatin1StringView &t1, const QString &t2, |
507 | const char *actual, const char *expected, |
508 | const char *file, int line) |
509 | { |
510 | return qCompare(t1, t2: QStringView(t2), actual, expected, file, line); |
511 | } |
512 | |
513 | inline bool compare_ptr_helper(const volatile void *t1, const volatile void *t2, const char *actual, |
514 | const char *expected, const char *file, int line) |
515 | { |
516 | return compare_helper(success: t1 == t2, failureMsg: "Compared pointers are not the same" , |
517 | actualVal: [t1] { return toString(t1); }, expectedVal: [t2] { return toString(t2); }, |
518 | actual, expected, file, line); |
519 | } |
520 | |
521 | inline bool compare_ptr_helper(const volatile QObject *t1, const volatile QObject *t2, const char *actual, |
522 | const char *expected, const char *file, int line) |
523 | { |
524 | return compare_helper(success: t1 == t2, failureMsg: "Compared QObject pointers are not the same" , |
525 | actualVal: [t1] { return toString(t1); }, expectedVal: [t2] { return toString(t2); }, |
526 | actual, expected, file, line); |
527 | } |
528 | |
529 | inline bool compare_ptr_helper(const volatile QObject *t1, std::nullptr_t, const char *actual, |
530 | const char *expected, const char *file, int line) |
531 | { |
532 | return compare_helper(success: t1 == nullptr, failureMsg: "Compared QObject pointers are not the same" , |
533 | actualVal: [t1] { return toString(t1); }, expectedVal: [] { return toString(t: nullptr); }, |
534 | actual, expected, file, line); |
535 | } |
536 | |
537 | inline bool compare_ptr_helper(std::nullptr_t, const volatile QObject *t2, const char *actual, |
538 | const char *expected, const char *file, int line) |
539 | { |
540 | return compare_helper(success: nullptr == t2, failureMsg: "Compared QObject pointers are not the same" , |
541 | actualVal: [] { return toString(t: nullptr); }, expectedVal: [t2] { return toString(t2); }, |
542 | actual, expected, file, line); |
543 | } |
544 | |
545 | inline bool compare_ptr_helper(const volatile void *t1, std::nullptr_t, const char *actual, |
546 | const char *expected, const char *file, int line) |
547 | { |
548 | return compare_helper(success: t1 == nullptr, failureMsg: "Compared pointers are not the same" , |
549 | actualVal: [t1] { return toString(t1); }, expectedVal: [] { return toString(t: nullptr); }, |
550 | actual, expected, file, line); |
551 | } |
552 | |
553 | inline bool compare_ptr_helper(std::nullptr_t, const volatile void *t2, const char *actual, |
554 | const char *expected, const char *file, int line) |
555 | { |
556 | return compare_helper(success: nullptr == t2, failureMsg: "Compared pointers are not the same" , |
557 | actualVal: [] { return toString(t: nullptr); }, expectedVal: [t2] { return toString(t2); }, |
558 | actual, expected, file, line); |
559 | } |
560 | |
561 | Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual, |
562 | const char *expected, const char *file, int line); |
563 | |
564 | Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...); |
565 | |
566 | #ifndef Q_QDOC |
567 | QTEST_COMPARE_DECL(short) |
568 | QTEST_COMPARE_DECL(ushort) |
569 | QTEST_COMPARE_DECL(int) |
570 | QTEST_COMPARE_DECL(uint) |
571 | QTEST_COMPARE_DECL(long) |
572 | QTEST_COMPARE_DECL(ulong) |
573 | QTEST_COMPARE_DECL(qint64) |
574 | QTEST_COMPARE_DECL(quint64) |
575 | |
576 | QTEST_COMPARE_DECL(float) |
577 | QTEST_COMPARE_DECL(double) |
578 | QTEST_COMPARE_DECL(qfloat16) |
579 | QTEST_COMPARE_DECL(char) |
580 | QTEST_COMPARE_DECL(signed char) |
581 | QTEST_COMPARE_DECL(unsigned char) |
582 | QTEST_COMPARE_DECL(bool) |
583 | #endif |
584 | |
585 | template <typename T1, typename T2 = T1> |
586 | inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected, |
587 | const char *file, int line) |
588 | { |
589 | return compare_helper(t1 == t2, "Compared values are not the same" , |
590 | [&t1] { return toString(t1); }, [&t2] { return toString(t2); }, |
591 | actual, expected, file, line); |
592 | } |
593 | |
594 | inline bool qCompare(double const &t1, float const &t2, const char *actual, |
595 | const char *expected, const char *file, int line) |
596 | { |
597 | return qCompare(t1: qreal(t1), t2: qreal(t2), actual, expected, file, line); |
598 | } |
599 | |
600 | inline bool qCompare(float const &t1, double const &t2, const char *actual, |
601 | const char *expected, const char *file, int line) |
602 | { |
603 | return qCompare(t1: qreal(t1), t2: qreal(t2), actual, expected, file, line); |
604 | } |
605 | |
606 | template <typename T> |
607 | inline bool qCompare(const T *t1, const T *t2, const char *actual, const char *expected, |
608 | const char *file, int line) |
609 | { |
610 | return compare_ptr_helper(t1, t2, actual, expected, file, line); |
611 | } |
612 | template <typename T> |
613 | inline bool qCompare(T *t1, T *t2, const char *actual, const char *expected, |
614 | const char *file, int line) |
615 | { |
616 | return compare_ptr_helper(t1, t2, actual, expected, file, line); |
617 | } |
618 | |
619 | template <typename T> |
620 | inline bool qCompare(T *t1, std::nullptr_t, const char *actual, const char *expected, |
621 | const char *file, int line) |
622 | { |
623 | return compare_ptr_helper(t1, nullptr, actual, expected, file, line); |
624 | } |
625 | template <typename T> |
626 | inline bool qCompare(std::nullptr_t, T *t2, const char *actual, const char *expected, |
627 | const char *file, int line) |
628 | { |
629 | return compare_ptr_helper(nullptr, t2, actual, expected, file, line); |
630 | } |
631 | |
632 | template <typename T1, typename T2> |
633 | inline bool qCompare(const T1 *t1, const T2 *t2, const char *actual, const char *expected, |
634 | const char *file, int line) |
635 | { |
636 | return compare_ptr_helper(t1, static_cast<const T1 *>(t2), actual, expected, file, line); |
637 | } |
638 | template <typename T1, typename T2> |
639 | inline bool qCompare(T1 *t1, T2 *t2, const char *actual, const char *expected, |
640 | const char *file, int line) |
641 | { |
642 | return compare_ptr_helper(const_cast<const T1 *>(t1), |
643 | static_cast<const T1 *>(const_cast<const T2 *>(t2)), actual, expected, file, line); |
644 | } |
645 | inline bool qCompare(const char *t1, const char *t2, const char *actual, |
646 | const char *expected, const char *file, int line) |
647 | { |
648 | return compare_string_helper(t1, t2, actual, expected, file, line); |
649 | } |
650 | inline bool qCompare(char *t1, char *t2, const char *actual, const char *expected, |
651 | const char *file, int line) |
652 | { |
653 | return compare_string_helper(t1, t2, actual, expected, file, line); |
654 | } |
655 | |
656 | /* The next two overloads are for MSVC that shows problems with implicit |
657 | conversions |
658 | */ |
659 | inline bool qCompare(char *t1, const char *t2, const char *actual, |
660 | const char *expected, const char *file, int line) |
661 | { |
662 | return compare_string_helper(t1, t2, actual, expected, file, line); |
663 | } |
664 | inline bool qCompare(const char *t1, char *t2, const char *actual, |
665 | const char *expected, const char *file, int line) |
666 | { |
667 | return compare_string_helper(t1, t2, actual, expected, file, line); |
668 | } |
669 | |
670 | template <class T> |
671 | inline bool qTest(const T& actual, const char *elementName, const char *actualStr, |
672 | const char *expected, const char *file, int line) |
673 | { |
674 | return qCompare(actual, *static_cast<const T *>(QTest::qElementData(elementName, |
675 | metaTypeId: qMetaTypeId<T>())), actualStr, expected, file, line); |
676 | } |
677 | |
678 | Q_TESTLIB_EXPORT bool reportResult(bool success, qxp::function_ref<const char*()> lhs, |
679 | qxp::function_ref<const char*()> rhs, |
680 | const char *lhsExpr, const char *rhsExpr, |
681 | ComparisonOperation op, const char *file, int line); |
682 | } |
683 | |
684 | #undef QTEST_COMPARE_DECL |
685 | |
686 | #define QWARN(msg) QTest::qWarn(static_cast<const char *>(msg), __FILE__, __LINE__) |
687 | |
688 | QT_END_NAMESPACE |
689 | |
690 | #endif |
691 | |