1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtTest module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QTESTCASE_H
41#define QTESTCASE_H
42
43#include <QtTest/qttestglobal.h>
44
45#include <QtCore/qstring.h>
46#include <QtCore/qnamespace.h>
47#include <QtCore/qmetatype.h>
48#include <QtCore/qmetaobject.h>
49#include <QtCore/qsharedpointer.h>
50#include <QtCore/qtemporarydir.h>
51
52#include <string.h>
53
54#ifndef QT_NO_EXCEPTIONS
55# include <exception>
56#endif // QT_NO_EXCEPTIONS
57
58QT_BEGIN_NAMESPACE
59
60class qfloat16;
61class QRegularExpression;
62
63#define QVERIFY(statement) \
64do {\
65 if (!QTest::qVerify(static_cast<bool>(statement), #statement, "", __FILE__, __LINE__))\
66 return;\
67} while (false)
68
69#define QFAIL(message) \
70do {\
71 QTest::qFail(static_cast<const char *>(message), __FILE__, __LINE__);\
72 return;\
73} while (false)
74
75#define QVERIFY2(statement, description) \
76do {\
77 if (statement) {\
78 if (!QTest::qVerify(true, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\
79 return;\
80 } else {\
81 if (!QTest::qVerify(false, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\
82 return;\
83 }\
84} while (false)
85
86#define QCOMPARE(actual, expected) \
87do {\
88 if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\
89 return;\
90} while (false)
91
92
93#ifndef QT_NO_EXCEPTIONS
94
95# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \
96 do {\
97 QT_TRY {\
98 QT_TRY {\
99 expression;\
100 QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \
101 " but no exception caught", __FILE__, __LINE__);\
102 return;\
103 } QT_CATCH (const exceptiontype &) {\
104 /* success */\
105 }\
106 } QT_CATCH (const std::exception &e) {\
107 QByteArray msg = QByteArray() + "Expected exception of type " #exceptiontype \
108 " to be thrown but std::exception caught with message: " + e.what(); \
109 QTest::qFail(msg.constData(), __FILE__, __LINE__);\
110 return;\
111 } QT_CATCH (...) {\
112 QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \
113 " but unknown exception caught", __FILE__, __LINE__);\
114 QT_RETHROW;\
115 }\
116 } while (false)
117
118#else // QT_NO_EXCEPTIONS
119
120/*
121 * The expression passed to the macro should throw an exception and we can't
122 * catch it because Qt has been compiled without exception support. We can't
123 * skip the expression because it may have side effects and must be executed.
124 * So, users must use Qt with exception support enabled if they use exceptions
125 * in their code.
126 */
127# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \
128 Q_STATIC_ASSERT_X(false, "Support of exceptions is disabled")
129
130#endif // !QT_NO_EXCEPTIONS
131
132
133#define QTRY_LOOP_IMPL(expr, timeoutValue, step) \
134 if (!(expr)) { \
135 QTest::qWait(0); \
136 } \
137 int qt_test_i = 0; \
138 for (; qt_test_i < timeoutValue && !(expr); qt_test_i += step) { \
139 QTest::qWait(step); \
140 }
141
142#define QTRY_TIMEOUT_DEBUG_IMPL(expr, timeoutValue, step)\
143 if (!(expr)) { \
144 QTRY_LOOP_IMPL((expr), (2 * timeoutValue), step);\
145 if (expr) { \
146 QString msg = QString::fromUtf8("QTestLib: This test case check (\"%1\") failed because the requested timeout (%2 ms) was too short, %3 ms would have been sufficient this time."); \
147 msg = msg.arg(QString::fromUtf8(#expr)).arg(timeoutValue).arg(timeoutValue + qt_test_i); \
148 QFAIL(qPrintable(msg)); \
149 } \
150 }
151
152// Ideally we'd use qWaitFor instead of QTRY_LOOP_IMPL, but due
153// to a compiler bug on MSVC < 2017 we can't (see QTBUG-59096)
154#define QTRY_IMPL(expr, timeout)\
155 const int qt_test_step = timeout < 350 ? timeout / 7 + 1 : 50; \
156 const int qt_test_timeoutValue = timeout; \
157 { QTRY_LOOP_IMPL((expr), qt_test_timeoutValue, qt_test_step); } \
158 QTRY_TIMEOUT_DEBUG_IMPL((expr), qt_test_timeoutValue, qt_test_step)\
159
160// Will try to wait for the expression to become true while allowing event processing
161#define QTRY_VERIFY_WITH_TIMEOUT(expr, timeout) \
162do { \
163 QTRY_IMPL((expr), timeout);\
164 QVERIFY(expr); \
165} while (false)
166
167#define QTRY_VERIFY(expr) QTRY_VERIFY_WITH_TIMEOUT((expr), 5000)
168
169// Will try to wait for the expression to become true while allowing event processing
170#define QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, timeout) \
171do { \
172 QTRY_IMPL((expr), timeout);\
173 QVERIFY2(expr, messageExpression); \
174} while (false)
175
176#define QTRY_VERIFY2(expr, messageExpression) QTRY_VERIFY2_WITH_TIMEOUT((expr), (messageExpression), 5000)
177
178// Will try to wait for the comparison to become successful while allowing event processing
179#define QTRY_COMPARE_WITH_TIMEOUT(expr, expected, timeout) \
180do { \
181 QTRY_IMPL(((expr) == (expected)), timeout);\
182 QCOMPARE((expr), expected); \
183} while (false)
184
185#define QTRY_COMPARE(expr, expected) QTRY_COMPARE_WITH_TIMEOUT((expr), expected, 5000)
186
187#define QSKIP_INTERNAL(statement) \
188do {\
189 QTest::qSkip(static_cast<const char *>(statement), __FILE__, __LINE__);\
190 return;\
191} while (false)
192
193#define QSKIP(statement, ...) QSKIP_INTERNAL(statement)
194
195#define QEXPECT_FAIL(dataIndex, comment, mode)\
196do {\
197 if (!QTest::qExpectFail(dataIndex, static_cast<const char *>(comment), QTest::mode, __FILE__, __LINE__))\
198 return;\
199} while (false)
200
201#define QFETCH(Type, name)\
202 Type name = *static_cast<Type *>(QTest::qData(#name, ::qMetaTypeId<typename std::remove_cv<Type >::type>()))
203
204#define QFETCH_GLOBAL(Type, name)\
205 Type name = *static_cast<Type *>(QTest::qGlobalData(#name, ::qMetaTypeId<typename std::remove_cv<Type >::type>()))
206
207#define QTEST(actual, testElement)\
208do {\
209 if (!QTest::qTest(actual, testElement, #actual, #testElement, __FILE__, __LINE__))\
210 return;\
211} while (false)
212
213#define QWARN(msg)\
214 QTest::qWarn(static_cast<const char *>(msg), __FILE__, __LINE__)
215
216#ifdef QT_TESTCASE_BUILDDIR
217# define QFINDTESTDATA(basepath)\
218 QTest::qFindTestData(basepath, __FILE__, __LINE__, QT_TESTCASE_BUILDDIR)
219#else
220# define QFINDTESTDATA(basepath)\
221 QTest::qFindTestData(basepath, __FILE__, __LINE__)
222#endif
223
224# define QEXTRACTTESTDATA(resourcePath) \
225 QTest::qExtractTestData(resourcePath)
226
227class QObject;
228class QTestData;
229
230#define QTEST_COMPARE_DECL(KLASS)\
231 template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &);
232
233namespace QTest
234{
235 namespace Internal {
236
237 template<typename T> // Output registered enums
238 inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e)
239 {
240 QMetaEnum me = QMetaEnum::fromType<T>();
241 return qstrdup(me.valueToKey(value: int(e))); // int cast is necessary to support enum classes
242 }
243
244 template <typename T> // Fallback
245 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(const T &)
246 {
247 return nullptr;
248 }
249
250 template<typename F> // Output QFlags of registered enumerations
251 inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
252 {
253 const QMetaEnum me = QMetaEnum::fromType<F>();
254 return qstrdup(me.valueToKeys(value: int(f)).constData());
255 }
256
257 template <typename F> // Fallback: Output hex value
258 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
259 {
260 const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0'
261 char *msg = new char[space];
262 qsnprintf(str: msg, n: space, fmt: "0x%x", unsigned(f));
263 return msg;
264 }
265
266 } // namespace Internal
267
268 template<typename T>
269 inline char *toString(const T &t)
270 {
271 return Internal::toString(t);
272 }
273
274 template <typename T1, typename T2>
275 inline char *toString(const QPair<T1, T2> &pair);
276
277 template <typename T1, typename T2>
278 inline char *toString(const std::pair<T1, T2> &pair);
279
280 template <class... Types>
281 inline char *toString(const std::tuple<Types...> &tuple);
282
283 Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, int length);
284 Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, int length);
285 Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
286 Q_TESTLIB_EXPORT char *toString(const char *);
287 Q_TESTLIB_EXPORT char *toString(const volatile void *);
288 Q_TESTLIB_EXPORT char *toString(const void *); // ### FIXME: Qt 7: Remove
289
290 Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc = 0, char **argv = nullptr);
291 Q_TESTLIB_EXPORT int qRun();
292 Q_TESTLIB_EXPORT void qCleanup();
293
294 Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = nullptr);
295 Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments);
296
297 Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir = nullptr);
298
299 Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description,
300 const char *file, int line);
301 Q_TESTLIB_EXPORT void qFail(const char *statementStr, const char *file, int line);
302 Q_TESTLIB_EXPORT void qSkip(const char *message, const char *file, int line);
303 Q_TESTLIB_EXPORT bool qExpectFail(const char *dataIndex, const char *comment, TestFailMode mode,
304 const char *file, int line);
305 Q_TESTLIB_EXPORT void qWarn(const char *message, const char *file = nullptr, int line = 0);
306 Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message);
307#if QT_CONFIG(regularexpression)
308 Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern);
309#endif
310
311#if QT_CONFIG(temporaryfile)
312 Q_TESTLIB_EXPORT QSharedPointer<QTemporaryDir> qExtractTestData(const QString &dirName);
313#endif
314 Q_TESTLIB_EXPORT QString qFindTestData(const char* basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr);
315 Q_TESTLIB_EXPORT QString qFindTestData(const QString& basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr);
316
317 Q_TESTLIB_EXPORT void *qData(const char *tagName, int typeId);
318 Q_TESTLIB_EXPORT void *qGlobalData(const char *tagName, int typeId);
319 Q_TESTLIB_EXPORT void *qElementData(const char *elementName, int metaTypeId);
320 Q_TESTLIB_EXPORT QObject *testObject();
321
322 Q_TESTLIB_EXPORT const char *currentAppName();
323
324 Q_TESTLIB_EXPORT const char *currentTestFunction();
325 Q_TESTLIB_EXPORT const char *currentDataTag();
326 Q_TESTLIB_EXPORT bool currentTestFailed();
327
328 Q_TESTLIB_EXPORT Qt::Key asciiToKey(char ascii);
329 Q_TESTLIB_EXPORT char keyToAscii(Qt::Key key);
330
331 Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
332 char *val1, char *val2,
333 const char *actual, const char *expected,
334 const char *file, int line);
335 Q_TESTLIB_EXPORT void qSleep(int ms);
336 Q_TESTLIB_EXPORT void addColumnInternal(int id, const char *name);
337
338 template <typename T>
339 inline void addColumn(const char *name, T * = nullptr)
340 {
341 using QIsSameTConstChar = std::is_same<T, const char*>;
342 Q_STATIC_ASSERT_X(!QIsSameTConstChar::value, "const char* is not allowed as a test data format.");
343 addColumnInternal(qMetaTypeId<T>(), name);
344 }
345 Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag);
346 Q_TESTLIB_EXPORT QTestData &addRow(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2);
347
348#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
349 // kept after adding implementation of <T1, T2> out of paranoia:
350 template <typename T>
351 inline bool qCompare(T const &t1, T const &t2, const char *actual, const char *expected,
352 const char *file, int line)
353 {
354 return compare_helper(t1 == t2, "Compared values are not the same",
355 toString(t1), toString(t2), actual, expected, file, line);
356 }
357#endif
358
359 Q_TESTLIB_EXPORT bool qCompare(qfloat16 const &t1, qfloat16 const &t2,
360 const char *actual, const char *expected, const char *file, int line);
361
362 Q_TESTLIB_EXPORT bool qCompare(float const &t1, float const &t2,
363 const char *actual, const char *expected, const char *file, int line);
364
365 Q_TESTLIB_EXPORT bool qCompare(double const &t1, double const &t2,
366 const char *actual, const char *expected, const char *file, int line);
367
368 Q_TESTLIB_EXPORT bool qCompare(int t1, int t2, const char *actual, const char *expected,
369 const char *file, int line);
370
371 Q_TESTLIB_EXPORT bool qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected,
372 const char *file, int line);
373
374 Q_TESTLIB_EXPORT bool qCompare(QStringView t1, QStringView t2,
375 const char *actual, const char *expected,
376 const char *file, int line);
377 Q_TESTLIB_EXPORT bool qCompare(QStringView t1, const QLatin1String &t2,
378 const char *actual, const char *expected,
379 const char *file, int line);
380 Q_TESTLIB_EXPORT bool qCompare(const QLatin1String &t1, QStringView t2,
381 const char *actual, const char *expected,
382 const char *file, int line);
383 inline bool qCompare(const QString &t1, const QString &t2,
384 const char *actual, const char *expected,
385 const char *file, int line)
386 {
387 return qCompare(t1: QStringView(t1), t2: QStringView(t2), actual, expected, file, line);
388 }
389 inline bool qCompare(const QString &t1, const QLatin1String &t2,
390 const char *actual, const char *expected,
391 const char *file, int line)
392 {
393 return qCompare(t1: QStringView(t1), t2, actual, expected, file, line);
394 }
395 inline bool qCompare(const QLatin1String &t1, const QString &t2,
396 const char *actual, const char *expected,
397 const char *file, int line)
398 {
399 return qCompare(t1, t2: QStringView(t2), actual, expected, file, line);
400 }
401
402 inline bool compare_ptr_helper(const volatile void *t1, const volatile void *t2, const char *actual,
403 const char *expected, const char *file, int line)
404 {
405 return compare_helper(success: t1 == t2, failureMsg: "Compared pointers are not the same",
406 val1: toString(t1), val2: toString(t2), actual, expected, file, line);
407 }
408
409 inline bool compare_ptr_helper(const volatile void *t1, std::nullptr_t, const char *actual,
410 const char *expected, const char *file, int line)
411 {
412 return compare_helper(success: t1 == nullptr, failureMsg: "Compared pointers are not the same",
413 val1: toString(t1), val2: toString(t: nullptr), actual, expected, file, line);
414 }
415
416 inline bool compare_ptr_helper(std::nullptr_t, const volatile void *t2, const char *actual,
417 const char *expected, const char *file, int line)
418 {
419 return compare_helper(success: nullptr == t2, failureMsg: "Compared pointers are not the same",
420 val1: toString(t: nullptr), val2: toString(t2), actual, expected, file, line);
421 }
422
423 Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
424 const char *expected, const char *file, int line);
425
426 Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...);
427
428#ifndef Q_QDOC
429 QTEST_COMPARE_DECL(short)
430 QTEST_COMPARE_DECL(ushort)
431 QTEST_COMPARE_DECL(int)
432 QTEST_COMPARE_DECL(uint)
433 QTEST_COMPARE_DECL(long)
434 QTEST_COMPARE_DECL(ulong)
435 QTEST_COMPARE_DECL(qint64)
436 QTEST_COMPARE_DECL(quint64)
437
438 QTEST_COMPARE_DECL(float)
439 QTEST_COMPARE_DECL(double)
440 QTEST_COMPARE_DECL(qfloat16)
441 QTEST_COMPARE_DECL(char)
442 QTEST_COMPARE_DECL(signed char)
443 QTEST_COMPARE_DECL(unsigned char)
444 QTEST_COMPARE_DECL(bool)
445#endif
446
447 template <typename T1, typename T2>
448 inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected,
449 const char *file, int line)
450 {
451 return compare_helper(t1 == t2, "Compared values are not the same",
452 toString(t1), toString(t2), actual, expected, file, line);
453 }
454
455 inline bool qCompare(double const &t1, float const &t2, const char *actual,
456 const char *expected, const char *file, int line)
457 {
458 return qCompare(t1: qreal(t1), t2: qreal(t2), actual, expected, file, line);
459 }
460
461 inline bool qCompare(float const &t1, double const &t2, const char *actual,
462 const char *expected, const char *file, int line)
463 {
464 return qCompare(t1: qreal(t1), t2: qreal(t2), actual, expected, file, line);
465 }
466
467 template <typename T>
468 inline bool qCompare(const T *t1, const T *t2, const char *actual, const char *expected,
469 const char *file, int line)
470 {
471 return compare_ptr_helper(t1, t2, actual, expected, file, line);
472 }
473 template <typename T>
474 inline bool qCompare(T *t1, T *t2, const char *actual, const char *expected,
475 const char *file, int line)
476 {
477 return compare_ptr_helper(t1, t2, actual, expected, file, line);
478 }
479
480 template <typename T>
481 inline bool qCompare(T *t1, std::nullptr_t, const char *actual, const char *expected,
482 const char *file, int line)
483 {
484 return compare_ptr_helper(t1, nullptr, actual, expected, file, line);
485 }
486 template <typename T>
487 inline bool qCompare(std::nullptr_t, T *t2, const char *actual, const char *expected,
488 const char *file, int line)
489 {
490 return compare_ptr_helper(nullptr, t2, actual, expected, file, line);
491 }
492
493 template <typename T1, typename T2>
494 inline bool qCompare(const T1 *t1, const T2 *t2, const char *actual, const char *expected,
495 const char *file, int line)
496 {
497 return compare_ptr_helper(t1, static_cast<const T1 *>(t2), actual, expected, file, line);
498 }
499 template <typename T1, typename T2>
500 inline bool qCompare(T1 *t1, T2 *t2, const char *actual, const char *expected,
501 const char *file, int line)
502 {
503 return compare_ptr_helper(const_cast<const T1 *>(t1),
504 static_cast<const T1 *>(const_cast<const T2 *>(t2)), actual, expected, file, line);
505 }
506 inline bool qCompare(const char *t1, const char *t2, const char *actual,
507 const char *expected, const char *file, int line)
508 {
509 return compare_string_helper(t1, t2, actual, expected, file, line);
510 }
511 inline bool qCompare(char *t1, char *t2, const char *actual, const char *expected,
512 const char *file, int line)
513 {
514 return compare_string_helper(t1, t2, actual, expected, file, line);
515 }
516
517 /* The next two overloads are for MSVC that shows problems with implicit
518 conversions
519 */
520 inline bool qCompare(char *t1, const char *t2, const char *actual,
521 const char *expected, const char *file, int line)
522 {
523 return compare_string_helper(t1, t2, actual, expected, file, line);
524 }
525 inline bool qCompare(const char *t1, char *t2, const char *actual,
526 const char *expected, const char *file, int line)
527 {
528 return compare_string_helper(t1, t2, actual, expected, file, line);
529 }
530
531 template <class T>
532 inline bool qTest(const T& actual, const char *elementName, const char *actualStr,
533 const char *expected, const char *file, int line)
534 {
535 return qCompare(actual, *static_cast<const T *>(QTest::qElementData(elementName,
536 metaTypeId: qMetaTypeId<T>())), actualStr, expected, file, line);
537 }
538}
539
540#undef QTEST_COMPARE_DECL
541
542QT_END_NAMESPACE
543
544#endif
545

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