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#include <QtTest/qtesttostring.h>
9
10#include <QtCore/qstring.h>
11#include <QtCore/qnamespace.h>
12#include <QtCore/qmetatype.h>
13#include <QtCore/qmetaobject.h>
14#include <QtCore/qsharedpointer.h>
15#include <QtCore/qtemporarydir.h>
16#include <QtCore/qthread.h>
17
18#ifdef __cpp_concepts
19#include <concepts>
20#endif
21#include <QtCore/qxpfunctional.h>
22#include <QtCore/qxptype_traits.h>
23#include <QtCore/q20utility.h>
24
25#include <string.h>
26
27#ifndef QT_NO_EXCEPTIONS
28# include <exception>
29#endif // QT_NO_EXCEPTIONS
30
31QT_BEGIN_NAMESPACE
32
33#ifndef QT_NO_EXCEPTIONS
34
35#ifdef QTEST_THROW_ON_FAIL
36# define QTEST_FAIL_ACTION QTest::Internal::throwOnFail()
37#else
38# define QTEST_FAIL_ACTION do { QTest::Internal::maybeThrowOnFail(); return; } while (false)
39#endif
40
41#ifdef QTEST_THROW_ON_SKIP
42# define QTEST_SKIP_ACTION QTest::Internal::throwOnSkip()
43#else
44# define QTEST_SKIP_ACTION do { QTest::Internal::maybeThrowOnSkip(); return; } while (false)
45#endif
46
47#else
48# if defined(QTEST_THROW_ON_FAIL) || defined(QTEST_THROW_ON_SKIP)
49# error QTEST_THROW_ON_FAIL/SKIP require exception support enabled.
50# endif
51#endif // QT_NO_EXCEPTIONS
52
53#ifndef QTEST_FAIL_ACTION
54# define QTEST_FAIL_ACTION return
55#endif
56
57#ifndef QTEST_SKIP_ACTION
58# define QTEST_SKIP_ACTION return
59#endif
60
61class qfloat16;
62class QRegularExpression;
63
64#define QVERIFY(statement) \
65do {\
66 if (!QTest::qVerify(static_cast<bool>(statement), #statement, "", __FILE__, __LINE__))\
67 QTEST_FAIL_ACTION; \
68} while (false)
69
70#define QFAIL(message) \
71do {\
72 QTest::qFail(static_cast<const char *>(message), __FILE__, __LINE__);\
73 QTEST_FAIL_ACTION; \
74} while (false)
75
76#define QVERIFY2(statement, description) \
77do {\
78 if (statement) {\
79 if (!QTest::qVerify(true, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\
80 QTEST_FAIL_ACTION; \
81 } else {\
82 if (!QTest::qVerify(false, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\
83 QTEST_FAIL_ACTION; \
84 }\
85} while (false)
86
87#define QCOMPARE(actual, expected) \
88do {\
89 if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\
90 QTEST_FAIL_ACTION; \
91} while (false)
92
93#define QCOMPARE_OP_IMPL(lhs, rhs, op, opId) \
94do { \
95 if (!QTest::qCompareOp<QTest::ComparisonOperation::opId>(lhs, rhs, #lhs, #rhs, __FILE__, __LINE__)) \
96 QTEST_FAIL_ACTION; \
97} while (false)
98
99#define QCOMPARE_EQ(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, ==, Equal)
100#define QCOMPARE_NE(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, !=, NotEqual)
101#define QCOMPARE_LT(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, <, LessThan)
102#define QCOMPARE_LE(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, <=, LessThanOrEqual)
103#define QCOMPARE_GT(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, >, GreaterThan)
104#define QCOMPARE_GE(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, >=, GreaterThanOrEqual)
105
106#ifndef QT_NO_EXCEPTIONS
107
108# define QVERIFY_THROWS_NO_EXCEPTION(...) \
109 do { \
110 QT_TRY { \
111 __VA_ARGS__; \
112 /* success */ \
113 } QT_CATCH (...) { \
114 QTest::qCaught(nullptr, __FILE__, __LINE__); \
115 QTEST_FAIL_ACTION; \
116 } \
117 } while (false) \
118 /* end */
119
120#if QT_DEPRECATED_SINCE(6, 3)
121namespace QTest {
122QT_DEPRECATED_VERSION_X_6_3("Don't use QVERIFY_EXCEPTION_THROWN(expr, type) anymore, "
123 "use QVERIFY_THROWS_EXCEPTION(type, expr...) instead")
124inline void useVerifyThrowsException() {}
125} // namespace QTest
126# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \
127 QVERIFY_THROWS_EXCEPTION(exceptiontype, QTest::useVerifyThrowsException(); expression)
128#endif
129
130# define QVERIFY_THROWS_EXCEPTION(exceptiontype, ...) \
131 do {\
132 bool qverify_throws_exception_did_not_throw = false; \
133 QT_TRY {\
134 __VA_ARGS__; \
135 QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \
136 " but no exception caught", __FILE__, __LINE__); \
137 qverify_throws_exception_did_not_throw = true; \
138 } QT_CATCH (const exceptiontype &) { \
139 /* success */ \
140 } QT_CATCH (...) {\
141 QTest::qCaught(#exceptiontype, __FILE__, __LINE__); \
142 QTEST_FAIL_ACTION; \
143 }\
144 if (qverify_throws_exception_did_not_throw) \
145 QTEST_FAIL_ACTION; \
146 } while (false)
147
148#else // QT_NO_EXCEPTIONS
149
150/*
151 * These macros check whether the expression passed throws exceptions, but we can't
152 * catch them to check because Qt has been compiled without exception support. We can't
153 * skip the expression because it may have side effects and must be executed.
154 * So, users must use Qt with exception support enabled if they use exceptions
155 * in their code.
156 */
157# define QVERIFY_THROWS_EXCEPTION(...) \
158 static_assert(false, "Support for exceptions is disabled")
159# define QVERIFY_THROWS_NO_EXCEPTION(...) \
160 static_assert(false, "Support for exceptions is disabled")
161
162#endif // !QT_NO_EXCEPTIONS
163
164/* Ideally we would adapt qWaitFor(), or a variant on it, to implement roughly
165 * what the following provides as QTRY_LOOP_IMPL(); however, for now, the
166 * reporting of how much to increase the timeout to (if within a factor of two)
167 * on failure and the check for (QTest::runningTest() &&
168 * QTest::currentTestResolved()) go beyond qWaitFor(). (We no longer care about
169 * the bug in MSVC < 2017 that precluded using qWaitFor() in the implementation
170 * here, see QTBUG-59096.)
171 */
172
173// NB: not do {...} while (0) wrapped, as qt_test_i is accessed after it
174#define QTRY_LOOP_IMPL(expr, timeoutValue, step) \
175 if (!(expr)) { \
176 QTest::qWait(0); \
177 } \
178 int qt_test_i = 0; \
179 for (; qt_test_i < timeoutValue && !(QTest::runningTest() && QTest::currentTestResolved()) \
180 && !(expr); qt_test_i += step) { \
181 QTest::qWait(step); \
182 }
183// Ends in a for-block, so doesn't want a following semicolon.
184
185#define QTRY_TIMEOUT_DEBUG_IMPL(expr, timeoutValue, step) \
186 if (!(QTest::runningTest() && QTest::currentTestResolved()) && !(expr)) { \
187 QTRY_LOOP_IMPL(expr, 2 * (timeoutValue), step) \
188 if ((expr)) { \
189 QFAIL(qPrintable(QTest::Internal::formatTryTimeoutDebugMessage(\
190 u8"" #expr, timeoutValue, timeoutValue + qt_test_i))); \
191 } \
192 }
193
194#define QTRY_IMPL(expr, timeoutAsGiven)\
195 const auto qt_test_timeoutAsMs = [&] { \
196 /* make 5s work w/o user action: */ \
197 using namespace std::chrono_literals; \
198 return std::chrono::milliseconds{timeoutAsGiven}; \
199 }(); \
200 const int qt_test_step = qt_test_timeoutAsMs.count() < 350 ? qt_test_timeoutAsMs.count() / 7 + 1 : 50; \
201 const int qt_test_timeoutValue = qt_test_timeoutAsMs.count(); \
202 { QTRY_LOOP_IMPL(expr, qt_test_timeoutValue, qt_test_step) } \
203 QTRY_TIMEOUT_DEBUG_IMPL(expr, qt_test_timeoutValue, qt_test_step)
204// Ends with an if-block, so doesn't want a following semicolon.
205
206// Will try to wait for the expression to become true while allowing event processing
207#define QTRY_VERIFY_WITH_TIMEOUT(expr, timeout) \
208do { \
209 QTRY_IMPL(expr, timeout) \
210 QVERIFY(expr); \
211} while (false)
212
213#define QTRY_VERIFY(expr) QTRY_VERIFY_WITH_TIMEOUT(expr, QTest::Internal::defaultTryTimeout)
214
215// Will try to wait for the expression to become true while allowing event processing
216#define QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, timeout) \
217do { \
218 QTRY_IMPL(expr, timeout) \
219 QVERIFY2(expr, messageExpression); \
220} while (false)
221
222#define QTRY_VERIFY2(expr, messageExpression) \
223 QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, QTest::Internal::defaultTryTimeout)
224
225// Will try to wait for the comparison to become successful while allowing event processing
226#define QTRY_COMPARE_WITH_TIMEOUT(expr, expected, timeout) \
227do { \
228 QTRY_IMPL((expr) == (expected), timeout) \
229 QCOMPARE(expr, expected); \
230} while (false)
231
232#define QTRY_COMPARE(expr, expected) \
233 QTRY_COMPARE_WITH_TIMEOUT(expr, expected, QTest::Internal::defaultTryTimeout)
234
235#define QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, op, opId, timeout) \
236do { \
237 using Q_Cmp = QTest::Internal::Compare<QTest::ComparisonOperation::opId>; \
238 QTRY_IMPL(Q_Cmp::compare((computed), (baseline)), timeout) \
239 QCOMPARE_OP_IMPL(computed, baseline, op, opId); \
240} while (false)
241
242#define QTRY_COMPARE_EQ_WITH_TIMEOUT(computed, baseline, timeout) \
243 QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, ==, Equal, timeout)
244
245#define QTRY_COMPARE_EQ(computed, baseline) \
246 QTRY_COMPARE_EQ_WITH_TIMEOUT(computed, baseline, QTest::Internal::defaultTryTimeout)
247
248#define QTRY_COMPARE_NE_WITH_TIMEOUT(computed, baseline, timeout) \
249 QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, !=, NotEqual, timeout)
250
251#define QTRY_COMPARE_NE(computed, baseline) \
252 QTRY_COMPARE_NE_WITH_TIMEOUT(computed, baseline, QTest::Internal::defaultTryTimeout)
253
254#define QTRY_COMPARE_LT_WITH_TIMEOUT(computed, baseline, timeout) \
255 QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, <, LessThan, timeout)
256
257#define QTRY_COMPARE_LT(computed, baseline) \
258 QTRY_COMPARE_LT_WITH_TIMEOUT(computed, baseline, QTest::Internal::defaultTryTimeout)
259
260#define QTRY_COMPARE_LE_WITH_TIMEOUT(computed, baseline, timeout) \
261 QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, <=, LessThanOrEqual, timeout)
262
263#define QTRY_COMPARE_LE(computed, baseline) \
264 QTRY_COMPARE_LE_WITH_TIMEOUT(computed, baseline, QTest::Internal::defaultTryTimeout)
265
266#define QTRY_COMPARE_GT_WITH_TIMEOUT(computed, baseline, timeout) \
267 QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, >, GreaterThan, timeout)
268
269#define QTRY_COMPARE_GT(computed, baseline) \
270 QTRY_COMPARE_GT_WITH_TIMEOUT(computed, baseline, QTest::Internal::defaultTryTimeout)
271
272#define QTRY_COMPARE_GE_WITH_TIMEOUT(computed, baseline, timeout) \
273 QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, >=, GreaterThanOrEqual, timeout)
274
275#define QTRY_COMPARE_GE(computed, baseline) \
276 QTRY_COMPARE_GE_WITH_TIMEOUT(computed, baseline, QTest::Internal::defaultTryTimeout)
277
278#define QSKIP_INTERNAL(statement) \
279do {\
280 QTest::qSkip(static_cast<const char *>(statement), __FILE__, __LINE__);\
281 QTEST_SKIP_ACTION; \
282} while (false)
283
284#define QSKIP(statement, ...) QSKIP_INTERNAL(statement)
285
286#define QEXPECT_FAIL(dataIndex, comment, mode)\
287do {\
288 if (!QTest::qExpectFail(dataIndex, static_cast<const char *>(comment), QTest::mode, __FILE__, __LINE__))\
289 QTEST_FAIL_ACTION; \
290} while (false)
291
292#define QFETCH(Type, name)\
293 Type name = *static_cast<Type *>(QTest::qData(#name, ::qMetaTypeId<typename std::remove_cv<Type >::type>()))
294
295#define QFETCH_GLOBAL(Type, name)\
296 Type name = *static_cast<Type *>(QTest::qGlobalData(#name, ::qMetaTypeId<typename std::remove_cv<Type >::type>()))
297
298#define QTEST(actual, testElement)\
299do {\
300 if (!QTest::qTest(actual, testElement, #actual, #testElement, __FILE__, __LINE__))\
301 QTEST_FAIL_ACTION; \
302} while (false)
303
304#ifdef __cpp_lib_three_way_comparison
305#define QCOMPARE_3WAY(lhs, rhs, order) \
306do { \
307 if (!QTest::qCompare3Way(lhs, rhs, order, #lhs, #rhs, #order, __FILE__, __LINE__)) \
308 QTEST_FAIL_ACTION; \
309} while (false)
310#else
311#define QCOMPARE_3WAY(...) \
312 static_assert(false, "QCOMPARE_3WAY test requires C++20 operator<=>()")
313#endif // __cpp_lib_three_way_comparison
314
315#ifdef QT_TESTCASE_BUILDDIR
316
317#ifndef QT_TESTCASE_SOURCEDIR
318#define QT_TESTCASE_SOURCEDIR nullptr
319#endif
320
321# define QFINDTESTDATA(basepath)\
322 QTest::qFindTestData(basepath, __FILE__, __LINE__, QT_TESTCASE_BUILDDIR, QT_TESTCASE_SOURCEDIR)
323#else
324# define QFINDTESTDATA(basepath)\
325 QTest::qFindTestData(basepath, __FILE__, __LINE__)
326#endif
327
328# define QEXTRACTTESTDATA(resourcePath) \
329 QTest::qExtractTestData(resourcePath)
330
331class QObject;
332class QTestData;
333
334namespace QTest
335{
336 namespace Internal {
337
338 [[noreturn]] Q_TESTLIB_EXPORT void throwOnFail();
339 [[noreturn]] Q_TESTLIB_EXPORT void throwOnSkip();
340 Q_TESTLIB_EXPORT void maybeThrowOnFail();
341 Q_TESTLIB_EXPORT void maybeThrowOnSkip();
342
343 Q_DECL_COLD_FUNCTION
344 Q_TESTLIB_EXPORT QString formatTryTimeoutDebugMessage(q_no_char8_t::QUtf8StringView expr, int timeout, int actual);
345 Q_TESTLIB_EXPORT Q_DECL_COLD_FUNCTION
346 const char *formatPropertyTestHelperFailure(char *msg, size_t maxMsgLen,
347 const char *actual, const char *expected,
348 const char *actualExpr,
349 const char *expectedExpr);
350
351 template <ComparisonOperation> struct Compare;
352 template <> struct Compare<ComparisonOperation::Equal>
353 {
354 template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
355 { return std::forward<T1>(lhs) == std::forward<T2>(rhs); }
356 };
357 template <> struct Compare<ComparisonOperation::NotEqual>
358 {
359 template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
360 { return std::forward<T1>(lhs) != std::forward<T2>(rhs); }
361 };
362 template <> struct Compare<ComparisonOperation::LessThan>
363 {
364 template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
365 { return std::forward<T1>(lhs) < std::forward<T2>(rhs); }
366 };
367 template <> struct Compare<ComparisonOperation::LessThanOrEqual>
368 {
369 template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
370 { return std::forward<T1>(lhs) <= std::forward<T2>(rhs); }
371 };
372 template <> struct Compare<ComparisonOperation::GreaterThan>
373 {
374 template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
375 { return std::forward<T1>(lhs) > std::forward<T2>(rhs); }
376 };
377 template <> struct Compare<ComparisonOperation::GreaterThanOrEqual>
378 {
379 template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
380 { return std::forward<T1>(lhs) >= std::forward<T2>(rhs); }
381 };
382
383 template <typename T1> const char *genericToString(const void *arg)
384 {
385 using QTest::toString;
386 return toString(*static_cast<const T1 *>(arg));
387 }
388
389 template <> inline const char *genericToString<char *>(const void *arg)
390 {
391 using QTest::toString;
392 return toString(static_cast<const char *>(arg));
393 }
394
395 template <> inline const char *genericToString<std::nullptr_t>(const void *)
396 {
397 return QTest::toString(nullptr);
398 }
399
400 template <typename T> const char *pointerToString(const void *arg)
401 {
402 using QTest::toString;
403 return toString(static_cast<const T *>(arg));
404 }
405
406 // Exported so Qt Quick Test can also use it for generating backtraces upon crashes.
407 Q_TESTLIB_EXPORT extern bool noCrashHandler;
408
409 } // namespace Internal
410
411 Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc = 0, char **argv = nullptr);
412 Q_TESTLIB_EXPORT int qRun();
413 Q_TESTLIB_EXPORT void qCleanup();
414
415 Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = nullptr);
416 Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments);
417
418#if QT_CONFIG(batch_test_support) || defined(Q_QDOC)
419 using TestEntryFunction = int (*)(int, char **);
420 Q_TESTLIB_EXPORT void qRegisterTestCase(const QString &name, TestEntryFunction entryFunction);
421#endif // QT_CONFIG(batch_test_support)
422
423 Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir = nullptr);
424 Q_TESTLIB_EXPORT void setThrowOnFail(bool enable) noexcept;
425 Q_TESTLIB_EXPORT void setThrowOnSkip(bool enable) noexcept;
426
427 class ThrowOnFailEnabler {
428 Q_DISABLE_COPY_MOVE(ThrowOnFailEnabler)
429 public:
430 ThrowOnFailEnabler() { setThrowOnFail(true); }
431 ~ThrowOnFailEnabler() { setThrowOnFail(false); }
432 };
433
434 class ThrowOnSkipEnabler {
435 Q_DISABLE_COPY_MOVE(ThrowOnSkipEnabler)
436 public:
437 ThrowOnSkipEnabler() { setThrowOnSkip(true); }
438 ~ThrowOnSkipEnabler() { setThrowOnSkip(false); }
439 };
440
441 class ThrowOnFailDisabler {
442 Q_DISABLE_COPY_MOVE(ThrowOnFailDisabler)
443 public:
444 ThrowOnFailDisabler() { setThrowOnFail(false); }
445 ~ThrowOnFailDisabler() { setThrowOnFail(true); }
446 };
447
448 class ThrowOnSkipDisabler {
449 Q_DISABLE_COPY_MOVE(ThrowOnSkipDisabler)
450 public:
451 ThrowOnSkipDisabler() { setThrowOnSkip(false); }
452 ~ThrowOnSkipDisabler() { setThrowOnSkip(true); }
453 };
454
455 Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description,
456 const char *file, int line);
457 Q_DECL_COLD_FUNCTION
458 Q_TESTLIB_EXPORT void qFail(const char *message, const char *file, int line);
459 Q_TESTLIB_EXPORT void qSkip(const char *message, const char *file, int line);
460 Q_TESTLIB_EXPORT bool qExpectFail(const char *dataIndex, const char *comment, TestFailMode mode,
461 const char *file, int line);
462 Q_DECL_COLD_FUNCTION
463 Q_TESTLIB_EXPORT void qCaught(const char *expected, const char *what, const char *file, int line);
464 Q_DECL_COLD_FUNCTION
465 Q_TESTLIB_EXPORT void qCaught(const char *expected, const char *file, int line);
466#if QT_DEPRECATED_SINCE(6, 3)
467 QT_DEPRECATED_VERSION_X_6_3("Use qWarning() instead")
468 Q_TESTLIB_EXPORT void qWarn(const char *message, const char *file = nullptr, int line = 0);
469#endif
470 Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message);
471#if QT_CONFIG(regularexpression)
472 Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern);
473#endif
474 Q_TESTLIB_EXPORT void failOnWarning();
475 Q_TESTLIB_EXPORT void failOnWarning(const char *message);
476#if QT_CONFIG(regularexpression)
477 Q_TESTLIB_EXPORT void failOnWarning(const QRegularExpression &messagePattern);
478#endif
479
480#if QT_CONFIG(temporaryfile)
481 Q_TESTLIB_EXPORT QSharedPointer<QTemporaryDir> qExtractTestData(const QString &dirName);
482#endif
483 Q_TESTLIB_EXPORT QString qFindTestData(const char* basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr, const char* sourcedir = nullptr);
484 Q_TESTLIB_EXPORT QString qFindTestData(const QString& basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr, const char *sourcedir = nullptr);
485
486 Q_TESTLIB_EXPORT void *qData(const char *tagName, int typeId);
487 Q_TESTLIB_EXPORT void *qGlobalData(const char *tagName, int typeId);
488 Q_TESTLIB_EXPORT void *qElementData(const char *elementName, int metaTypeId);
489 Q_TESTLIB_EXPORT QObject *testObject();
490
491 Q_TESTLIB_EXPORT const char *currentAppName();
492
493 Q_TESTLIB_EXPORT const char *currentTestFunction();
494 Q_TESTLIB_EXPORT const char *currentDataTag();
495 Q_TESTLIB_EXPORT bool currentTestFailed();
496 Q_TESTLIB_EXPORT bool currentTestResolved();
497 Q_TESTLIB_EXPORT bool runningTest(); // Internal, for use by macros and QTestEventLoop.
498
499 Q_TESTLIB_EXPORT Qt::Key asciiToKey(char ascii);
500 Q_TESTLIB_EXPORT char keyToAscii(Qt::Key key);
501
502#if QT_DEPRECATED_SINCE(6, 4)
503 QT_DEPRECATED_VERSION_X_6_4("use an overload that takes a formatter callback, "
504 "or an overload that takes only failure message, if you "
505 "do not need to stringify the values")
506 Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
507 char *actualVal, char *expectedVal,
508 const char *actual, const char *expected,
509 const char *file, int line);
510#endif // QT_DEPRECATED_SINCE(6, 4)
511#if QT_DEPRECATED_SINCE(6, 8)
512 QT_DEPRECATED_VERSION_X_6_8("use an overload that takes a formatter callback, "
513 "or an overload that takes only failure message, if you "
514 "do not need to stringify the values")
515 Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
516 qxp::function_ref<const char*()> actualVal,
517 qxp::function_ref<const char*()> expectedVal,
518 const char *actual, const char *expected,
519 const char *file, int line);
520#endif // QT_DEPRECATED_SINCE(6, 8)
521 Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
522 const void *actualPtr, const void *expectedPtr,
523 const char *(*actualFormatter)(const void *),
524 const char *(*expectedFormatter)(const void *),
525 const char *actual, const char *expected,
526 const char *file, int line);
527 Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
528 const char *actual, const char *expected,
529 const char *file, int line);
530
531 Q_TESTLIB_EXPORT bool compare_3way_helper(bool success, const char *failureMsg,
532 const void *lhsPtr, const void *rhsPtr,
533 const char *(*lhsFormatter)(const void*),
534 const char *(*rhsFormatter)(const void*),
535 const char *lhsStr, const char *rhsStr,
536 const char *(*actualOrderFormatter)(const void *),
537 const char *(*expectedOrderFormatter)(const void *),
538 const void *actualOrderPtr,
539 const void *expectedOrderPtr,
540 const char *expectedExpression,
541 const char *file, int line);
542
543 Q_TESTLIB_EXPORT void addColumnInternal(int id, const char *name);
544
545 template <typename T>
546 inline void addColumn(const char *name, T * = nullptr)
547 {
548 using QIsSameTConstChar = std::is_same<T, const char*>;
549 static_assert(!QIsSameTConstChar::value, "const char* is not allowed as a test data format.");
550 addColumnInternal(qMetaTypeId<T>(), name);
551 }
552 Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag);
553 Q_TESTLIB_EXPORT QTestData &addRow(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2);
554
555 Q_TESTLIB_EXPORT bool qCompare(qfloat16 const &t1, qfloat16 const &t2,
556 const char *actual, const char *expected, const char *file, int line);
557
558 Q_TESTLIB_EXPORT bool qCompare(float const &t1, float const &t2,
559 const char *actual, const char *expected, const char *file, int line);
560
561 Q_TESTLIB_EXPORT bool qCompare(double const &t1, double const &t2,
562 const char *actual, const char *expected, const char *file, int line);
563
564 Q_TESTLIB_EXPORT bool qCompare(int t1, int t2, const char *actual, const char *expected,
565 const char *file, int line);
566
567#if QT_POINTER_SIZE == 8
568 Q_TESTLIB_EXPORT bool qCompare(qsizetype t1, qsizetype t2, const char *actual, const char *expected,
569 const char *file, int line);
570#endif
571
572 Q_TESTLIB_EXPORT bool qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected,
573 const char *file, int line);
574
575 Q_TESTLIB_EXPORT bool qCompare(QStringView t1, QStringView t2,
576 const char *actual, const char *expected,
577 const char *file, int line);
578 Q_TESTLIB_EXPORT bool qCompare(QStringView t1, const QLatin1StringView &t2,
579 const char *actual, const char *expected,
580 const char *file, int line);
581 Q_TESTLIB_EXPORT bool qCompare(const QLatin1StringView &t1, QStringView t2,
582 const char *actual, const char *expected,
583 const char *file, int line);
584 inline bool qCompare(const QString &t1, const QString &t2,
585 const char *actual, const char *expected,
586 const char *file, int line)
587 {
588 return qCompare(t1: QStringView(t1), t2: QStringView(t2), actual, expected, file, line);
589 }
590 inline bool qCompare(const QString &t1, const QLatin1StringView &t2,
591 const char *actual, const char *expected,
592 const char *file, int line)
593 {
594 return qCompare(t1: QStringView(t1), t2, actual, expected, file, line);
595 }
596 inline bool qCompare(const QLatin1StringView &t1, const QString &t2,
597 const char *actual, const char *expected,
598 const char *file, int line)
599 {
600 return qCompare(t1, t2: QStringView(t2), actual, expected, file, line);
601 }
602
603 inline bool compare_ptr_helper(const volatile void *t1, const volatile void *t2, const char *actual,
604 const char *expected, const char *file, int line)
605 {
606 auto formatter = Internal::pointerToString<void>;
607 return compare_helper(success: t1 == t2, failureMsg: "Compared pointers are not the same",
608 actualPtr: const_cast<const void *>(t1), expectedPtr: const_cast<const void *>(t2),
609 actualFormatter: formatter, expectedFormatter: formatter, actual, expected, file, line);
610 }
611
612 inline bool compare_ptr_helper(const volatile QObject *t1, const volatile QObject *t2, const char *actual,
613 const char *expected, const char *file, int line)
614 {
615 auto formatter = Internal::pointerToString<QObject>;
616 return compare_helper(success: t1 == t2, failureMsg: "Compared QObject pointers are not the same",
617 actualPtr: const_cast<const QObject *>(t1), expectedPtr: const_cast<const QObject *>(t2),
618 actualFormatter: formatter, expectedFormatter: formatter, actual, expected, file, line);
619 }
620
621 inline bool compare_ptr_helper(const volatile QObject *t1, std::nullptr_t, const char *actual,
622 const char *expected, const char *file, int line)
623 {
624 auto lhsFormatter = Internal::pointerToString<QObject>;
625 auto rhsFormatter = Internal::genericToString<std::nullptr_t>;
626 return compare_helper(success: t1 == nullptr, failureMsg: "Compared QObject pointers are not the same",
627 actualPtr: const_cast<const QObject *>(t1), expectedPtr: nullptr,
628 actualFormatter: lhsFormatter, expectedFormatter: rhsFormatter, actual, expected, file, line);
629 }
630
631 inline bool compare_ptr_helper(std::nullptr_t, const volatile QObject *t2, const char *actual,
632 const char *expected, const char *file, int line)
633 {
634 auto lhsFormatter = Internal::genericToString<std::nullptr_t>;
635 auto rhsFormatter = Internal::pointerToString<QObject>;
636 return compare_helper(success: nullptr == t2, failureMsg: "Compared QObject pointers are not the same",
637 actualPtr: nullptr, expectedPtr: const_cast<const QObject *>(t2),
638 actualFormatter: lhsFormatter, expectedFormatter: rhsFormatter, actual, expected, file, line);
639 }
640
641 inline bool compare_ptr_helper(const volatile void *t1, std::nullptr_t, const char *actual,
642 const char *expected, const char *file, int line)
643 {
644 auto lhsFormatter = Internal::pointerToString<void>;
645 auto rhsFormatter = Internal::genericToString<std::nullptr_t>;
646 return compare_helper(success: t1 == nullptr, failureMsg: "Compared pointers are not the same",
647 actualPtr: const_cast<const void *>(t1), expectedPtr: nullptr,
648 actualFormatter: lhsFormatter, expectedFormatter: rhsFormatter, actual, expected, file, line);
649 }
650
651 inline bool compare_ptr_helper(std::nullptr_t, const volatile void *t2, const char *actual,
652 const char *expected, const char *file, int line)
653 {
654 auto lhsFormatter = Internal::genericToString<std::nullptr_t>;
655 auto rhsFormatter = Internal::pointerToString<void>;
656 return compare_helper(success: nullptr == t2, failureMsg: "Compared pointers are not the same",
657 actualPtr: nullptr, expectedPtr: const_cast<const void *>(t2),
658 actualFormatter: lhsFormatter, expectedFormatter: rhsFormatter, actual, expected, file, line);
659 }
660
661 template <typename T1, typename T2 = T1>
662 inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected,
663 const char *file, int line)
664 {
665 using Internal::genericToString;
666 if constexpr (QtPrivate::is_standard_or_extended_integer_type_v<T1>
667 && QtPrivate::is_standard_or_extended_integer_type_v<T2>) {
668 return compare_helper(q20::cmp_equal(t1, t2), "Compared values are not the same",
669 std::addressof(t1), std::addressof(t2),
670 genericToString<T1>, genericToString<T2>,
671 actual, expected, file, line);
672 } else {
673 return compare_helper(t1 == t2, "Compared values are not the same",
674 std::addressof(t1), std::addressof(t2),
675 genericToString<T1>, genericToString<T2>,
676 actual, expected, file, line);
677 }
678 }
679
680 inline bool qCompare(double const &t1, float const &t2, const char *actual,
681 const char *expected, const char *file, int line)
682 {
683 return qCompare(t1: qreal(t1), t2: qreal(t2), actual, expected, file, line);
684 }
685
686 inline bool qCompare(float const &t1, double const &t2, const char *actual,
687 const char *expected, const char *file, int line)
688 {
689 return qCompare(t1: qreal(t1), t2: qreal(t2), actual, expected, file, line);
690 }
691
692 template <typename T>
693 inline bool qCompare(const T *t1, const T *t2, const char *actual, const char *expected,
694 const char *file, int line)
695 {
696 return compare_ptr_helper(t1, t2, actual, expected, file, line);
697 }
698 template <typename T>
699 inline bool qCompare(T *t1, T *t2, const char *actual, const char *expected,
700 const char *file, int line)
701 {
702 return compare_ptr_helper(t1, t2, actual, expected, file, line);
703 }
704
705 template <typename T>
706 inline bool qCompare(T *t1, std::nullptr_t, const char *actual, const char *expected,
707 const char *file, int line)
708 {
709 return compare_ptr_helper(t1, nullptr, actual, expected, file, line);
710 }
711 template <typename T>
712 inline bool qCompare(std::nullptr_t, T *t2, const char *actual, const char *expected,
713 const char *file, int line)
714 {
715 return compare_ptr_helper(nullptr, t2, actual, expected, file, line);
716 }
717
718 template <typename T1, typename T2>
719 inline bool qCompare(const T1 *t1, const T2 *t2, const char *actual, const char *expected,
720 const char *file, int line)
721 {
722 return compare_ptr_helper(t1, static_cast<const T1 *>(t2), actual, expected, file, line);
723 }
724 template <typename T1, typename T2>
725 inline bool qCompare(T1 *t1, T2 *t2, const char *actual, const char *expected,
726 const char *file, int line)
727 {
728 return compare_ptr_helper(const_cast<const T1 *>(t1),
729 static_cast<const T1 *>(const_cast<const T2 *>(t2)), actual, expected, file, line);
730 }
731 inline bool qCompare(const char *t1, const char *t2, const char *actual,
732 const char *expected, const char *file, int line)
733 {
734 return compare_string_helper(t1, t2, actual, expected, file, line);
735 }
736 inline bool qCompare(char *t1, char *t2, const char *actual, const char *expected,
737 const char *file, int line)
738 {
739 return compare_string_helper(t1, t2, actual, expected, file, line);
740 }
741
742 /* The next two overloads are for MSVC that shows problems with implicit
743 conversions
744 */
745 inline bool qCompare(char *t1, const char *t2, const char *actual,
746 const char *expected, const char *file, int line)
747 {
748 return compare_string_helper(t1, t2, actual, expected, file, line);
749 }
750 inline bool qCompare(const char *t1, char *t2, const char *actual,
751 const char *expected, const char *file, int line)
752 {
753 return compare_string_helper(t1, t2, actual, expected, file, line);
754 }
755
756 template <class T>
757 inline bool qTest(const T& actual, const char *elementName, const char *actualStr,
758 const char *expected, const char *file, int line)
759 {
760 return qCompare(actual, *static_cast<const T *>(QTest::qElementData(elementName,
761 metaTypeId: qMetaTypeId<T>())), actualStr, expected, file, line);
762 }
763
764#if QT_DEPRECATED_SINCE(6, 8)
765 QT_DEPRECATED_VERSION_X_6_8("use the overload without qxp::function_ref")
766 Q_TESTLIB_EXPORT bool reportResult(bool success, qxp::function_ref<const char*()> lhs,
767 qxp::function_ref<const char*()> rhs,
768 const char *lhsExpr, const char *rhsExpr,
769 ComparisonOperation op, const char *file, int line);
770#endif // QT_DEPRECATED_SINCE(6, 8)
771
772 Q_TESTLIB_EXPORT bool reportResult(bool success, const void *lhs, const void *rhs,
773 const char *(*lhsFormatter)(const void*),
774 const char *(*rhsFormatter)(const void*),
775 const char *lhsExpr, const char *rhsExpr,
776 ComparisonOperation op, const char *file, int line);
777
778 template <ComparisonOperation op, typename T1, typename T2 = T1>
779 inline bool qCompareOp(T1 &&lhs, T2 &&rhs, const char *lhsExpr, const char *rhsExpr,
780 const char *file, int line)
781 {
782 using D1 = std::decay_t<T1>;
783 using D2 = std::decay_t<T2>;
784 using Internal::genericToString;
785 using Comparator = Internal::Compare<op>;
786
787 // force decaying of T1 and T2
788 auto doReport = [&](bool result, const D1 &lhs_, const D2 &rhs_) {
789 return reportResult(result, std::addressof(lhs_), std::addressof(rhs_),
790 genericToString<D1>, genericToString<D2>,
791 lhsExpr, rhsExpr, op, file, line);
792 };
793
794 /* assumes that op does not actually move from lhs and rhs */
795 bool result = Comparator::compare(std::forward<T1>(lhs), std::forward<T2>(rhs));
796 return doReport(result, std::forward<T1>(lhs), std::forward<T2>(rhs));
797 }
798
799#if defined(__cpp_lib_three_way_comparison)
800 template <typename OrderingType, typename LHS, typename RHS = LHS>
801 inline bool qCompare3Way(LHS &&lhs, RHS &&rhs, OrderingType order,
802 const char *lhsExpression,
803 const char *rhsExpression,
804 const char *resultExpression,
805 const char *file, int line)
806 {
807#if defined(__cpp_concepts)
808 static_assert(requires { lhs <=> rhs; },
809 "The three-way comparison operator (<=>) is not implemented");
810#endif // __cpp_concepts
811 static_assert(QtOrderingPrivate::is_ordering_type_v<OrderingType>,
812 "Please provide, as the order parameter, a value "
813 "of one of the Qt::{partial,weak,strong}_ordering or "
814 "std::{partial,weak,strong}_ordering types.");
815
816 const auto comparisonResult = std::forward<LHS>(lhs) <=> std::forward<RHS>(rhs);
817 static_assert(std::is_same_v<decltype(QtOrderingPrivate::to_Qt(comparisonResult)),
818 decltype(QtOrderingPrivate::to_Qt(order))>,
819 "The expected and actual ordering types should be the same "
820 "strength for proper comparison.");
821
822 const OrderingType actualOrder = comparisonResult;
823 using DLHS = q20::remove_cvref_t<LHS>;
824 using DRHS = q20::remove_cvref_t<RHS>;
825 using Internal::genericToString;
826
827 return compare_3way_helper(actualOrder == order,
828 "The result of operator<=>() is not what was expected",
829 std::addressof(lhs), std::addressof(rhs),
830 genericToString<DLHS>, genericToString<DRHS>,
831 lhsExpression, rhsExpression,
832 genericToString<decltype(comparisonResult)>,
833 genericToString<OrderingType>,
834 std::addressof(comparisonResult),
835 std::addressof(order),
836 resultExpression, file, line);
837 }
838#else
839 template <typename OrderingType, typename LHS, typename RHS = LHS>
840 void qCompare3Way(LHS &&lhs, RHS &&rhs, OrderingType order,
841 const char *lhsExpression,
842 const char *rhsExpression,
843 const char *resultExpression,
844 const char *file, int line) = delete;
845#endif // __cpp_lib_three_way_comparison
846
847}
848
849#define QWARN(msg) QTest::qWarn(static_cast<const char *>(msg), __FILE__, __LINE__)
850
851QT_END_NAMESPACE
852
853#endif
854

source code of qtbase/src/testlib/qtestcase.h