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#include <QtCore/qthread.h>
52
53#include <string.h>
54
55#ifndef QT_NO_EXCEPTIONS
56# include <exception>
57#endif // QT_NO_EXCEPTIONS
58
59QT_BEGIN_NAMESPACE
60
61class qfloat16;
62class QRegularExpression;
63
64#define QVERIFY(statement) \
65do {\
66 if (!QTest::qVerify(static_cast<bool>(statement), #statement, "", __FILE__, __LINE__))\
67 return;\
68} while (false)
69
70#define QFAIL(message) \
71do {\
72 QTest::qFail(static_cast<const char *>(message), __FILE__, __LINE__);\
73 return;\
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 return;\
81 } else {\
82 if (!QTest::qVerify(false, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\
83 return;\
84 }\
85} while (false)
86
87#define QCOMPARE(actual, expected) \
88do {\
89 if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\
90 return;\
91} while (false)
92
93
94#ifndef QT_NO_EXCEPTIONS
95
96# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \
97 do {\
98 QT_TRY {\
99 QT_TRY {\
100 expression;\
101 QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \
102 " but no exception caught", __FILE__, __LINE__);\
103 return;\
104 } QT_CATCH (const exceptiontype &) {\
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 return;\
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 static_assert(false, "Support of exceptions is disabled")
129
130#endif // !QT_NO_EXCEPTIONS
131
132// NB: not do {...} while (0) wrapped, as qt_test_i is accessed after it
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(QTest::currentTestFailed() || (expr), qt_test_timeoutValue, qt_test_step); } \
158 QTRY_TIMEOUT_DEBUG_IMPL(QTest::currentTestFailed() || (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
218#ifndef QT_TESTCASE_SOURCEDIR
219#define QT_TESTCASE_SOURCEDIR nullptr
220#endif
221
222# define QFINDTESTDATA(basepath)\
223 QTest::qFindTestData(basepath, __FILE__, __LINE__, QT_TESTCASE_BUILDDIR, QT_TESTCASE_SOURCEDIR)
224#else
225# define QFINDTESTDATA(basepath)\
226 QTest::qFindTestData(basepath, __FILE__, __LINE__)
227#endif
228
229# define QEXTRACTTESTDATA(resourcePath) \
230 QTest::qExtractTestData(resourcePath)
231
232class QObject;
233class QTestData;
234
235#define QTEST_COMPARE_DECL(KLASS)\
236 template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &);
237
238namespace QTest
239{
240 namespace Internal {
241
242 template<typename T> // Output registered enums
243 inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e)
244 {
245 QMetaEnum me = QMetaEnum::fromType<T>();
246 return qstrdup(me.valueToKey(int(e))); // int cast is necessary to support enum classes
247 }
248
249 template <typename T>
250 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e)
251 {
252 return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData());
253 }
254
255 template <typename T> // Fallback
256 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char*>::type toString(const T &)
257 {
258 return nullptr;
259 }
260
261 template<typename F> // Output QFlags of registered enumerations
262 inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
263 {
264 const QMetaEnum me = QMetaEnum::fromType<F>();
265 return qstrdup(me.valueToKeys(int(f)).constData());
266 }
267
268 template <typename F> // Fallback: Output hex value
269 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
270 {
271 const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0'
272 char *msg = new char[space];
273 qsnprintf(msg, space, "0x%x", unsigned(f));
274 return msg;
275 }
276
277 } // namespace Internal
278
279 template<typename T>
280 inline char *toString(const T &t)
281 {
282 return Internal::toString(t);
283 }
284
285 template <typename T1, typename T2>
286 inline char *toString(const QPair<T1, T2> &pair);
287
288 template <typename T1, typename T2>
289 inline char *toString(const std::pair<T1, T2> &pair);
290
291 template <class... Types>
292 inline char *toString(const std::tuple<Types...> &tuple);
293
294 Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, int length);
295 Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, int length);
296 Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
297 Q_TESTLIB_EXPORT char *toString(const char *);
298 Q_TESTLIB_EXPORT char *toString(const void *);
299
300 Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc = 0, char **argv = nullptr);
301 Q_TESTLIB_EXPORT int qRun();
302 Q_TESTLIB_EXPORT void qCleanup();
303
304 Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = nullptr);
305 Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments);
306
307 Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir = nullptr);
308
309 Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description,
310 const char *file, int line);
311 Q_TESTLIB_EXPORT void qFail(const char *statementStr, const char *file, int line);
312 Q_TESTLIB_EXPORT void qSkip(const char *message, const char *file, int line);
313 Q_TESTLIB_EXPORT bool qExpectFail(const char *dataIndex, const char *comment, TestFailMode mode,
314 const char *file, int line);
315 Q_TESTLIB_EXPORT void qWarn(const char *message, const char *file = nullptr, int line = 0);
316 Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message);
317#if QT_CONFIG(regularexpression)
318 Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern);
319#endif
320
321#if QT_CONFIG(temporaryfile)
322 Q_TESTLIB_EXPORT QSharedPointer<QTemporaryDir> qExtractTestData(const QString &dirName);
323#endif
324 Q_TESTLIB_EXPORT QString qFindTestData(const char* basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr, const char* sourcedir = nullptr);
325 Q_TESTLIB_EXPORT QString qFindTestData(const QString& basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr, const char *sourcedir = nullptr);
326
327 Q_TESTLIB_EXPORT void *qData(const char *tagName, int typeId);
328 Q_TESTLIB_EXPORT void *qGlobalData(const char *tagName, int typeId);
329 Q_TESTLIB_EXPORT void *qElementData(const char *elementName, int metaTypeId);
330 Q_TESTLIB_EXPORT QObject *testObject();
331
332 Q_TESTLIB_EXPORT const char *currentAppName();
333
334 Q_TESTLIB_EXPORT const char *currentTestFunction();
335 Q_TESTLIB_EXPORT const char *currentDataTag();
336 Q_TESTLIB_EXPORT bool currentTestFailed();
337
338 Q_TESTLIB_EXPORT Qt::Key asciiToKey(char ascii);
339 Q_TESTLIB_EXPORT char keyToAscii(Qt::Key key);
340
341 Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
342 char *val1, char *val2,
343 const char *actual, const char *expected,
344 const char *file, int line);
345 Q_TESTLIB_EXPORT void addColumnInternal(int id, const char *name);
346
347 template <typename T>
348 inline void addColumn(const char *name, T * = nullptr)
349 {
350 using QIsSameTConstChar = std::is_same<T, const char*>;
351 static_assert(!QIsSameTConstChar::value, "const char* is not allowed as a test data format.");
352 addColumnInternal(qMetaTypeId<T>(), name);
353 }
354 Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag);
355 Q_TESTLIB_EXPORT QTestData &addRow(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2);
356
357#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
358 // kept after adding implementation of <T1, T2> out of paranoia:
359 template <typename T>
360 inline bool qCompare(T const &t1, T const &t2, const char *actual, const char *expected,
361 const char *file, int line)
362 {
363 return compare_helper(t1 == t2, "Compared values are not the same",
364 toString(t1), toString(t2), actual, expected, file, line);
365 }
366#endif
367
368 Q_TESTLIB_EXPORT bool qCompare(qfloat16 const &t1, qfloat16 const &t2,
369 const char *actual, const char *expected, const char *file, int line);
370
371 Q_TESTLIB_EXPORT bool qCompare(float const &t1, float const &t2,
372 const char *actual, const char *expected, const char *file, int line);
373
374 Q_TESTLIB_EXPORT bool qCompare(double const &t1, double const &t2,
375 const char *actual, const char *expected, const char *file, int line);
376
377 Q_TESTLIB_EXPORT bool qCompare(int t1, int t2, const char *actual, const char *expected,
378 const char *file, int line);
379
380#if QT_POINTER_SIZE == 8
381 Q_TESTLIB_EXPORT bool qCompare(qsizetype t1, qsizetype t2, const char *actual, const char *expected,
382 const char *file, int line);
383#endif
384
385 Q_TESTLIB_EXPORT bool qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected,
386 const char *file, int line);
387
388 Q_TESTLIB_EXPORT bool qCompare(QStringView t1, QStringView t2,
389 const char *actual, const char *expected,
390 const char *file, int line);
391 Q_TESTLIB_EXPORT bool qCompare(QStringView t1, const QLatin1String &t2,
392 const char *actual, const char *expected,
393 const char *file, int line);
394 Q_TESTLIB_EXPORT bool qCompare(const QLatin1String &t1, QStringView t2,
395 const char *actual, const char *expected,
396 const char *file, int line);
397 inline bool qCompare(const QString &t1, const QString &t2,
398 const char *actual, const char *expected,
399 const char *file, int line)
400 {
401 return qCompare(QStringView(t1), QStringView(t2), actual, expected, file, line);
402 }
403 inline bool qCompare(const QString &t1, const QLatin1String &t2,
404 const char *actual, const char *expected,
405 const char *file, int line)
406 {
407 return qCompare(QStringView(t1), t2, actual, expected, file, line);
408 }
409 inline bool qCompare(const QLatin1String &t1, const QString &t2,
410 const char *actual, const char *expected,
411 const char *file, int line)
412 {
413 return qCompare(t1, QStringView(t2), actual, expected, file, line);
414 }
415
416 inline bool compare_ptr_helper(const volatile void *t1, const volatile void *t2, const char *actual,
417 const char *expected, const char *file, int line)
418 {
419 return compare_helper(t1 == t2, "Compared pointers are not the same",
420 toString(t1), toString(t2), actual, expected, file, line);
421 }
422
423 inline bool compare_ptr_helper(const volatile void *t1, std::nullptr_t, const char *actual,
424 const char *expected, const char *file, int line)
425 {
426 return compare_helper(t1 == nullptr, "Compared pointers are not the same",
427 toString(t1), toString(nullptr), actual, expected, file, line);
428 }
429
430 inline bool compare_ptr_helper(std::nullptr_t, const volatile void *t2, const char *actual,
431 const char *expected, const char *file, int line)
432 {
433 return compare_helper(nullptr == t2, "Compared pointers are not the same",
434 toString(nullptr), toString(t2), actual, expected, file, line);
435 }
436
437 Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
438 const char *expected, const char *file, int line);
439
440 Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...);
441
442#ifndef Q_QDOC
443 QTEST_COMPARE_DECL(short)
444 QTEST_COMPARE_DECL(ushort)
445 QTEST_COMPARE_DECL(int)
446 QTEST_COMPARE_DECL(uint)
447 QTEST_COMPARE_DECL(long)
448 QTEST_COMPARE_DECL(ulong)
449 QTEST_COMPARE_DECL(qint64)
450 QTEST_COMPARE_DECL(quint64)
451
452 QTEST_COMPARE_DECL(float)
453 QTEST_COMPARE_DECL(double)
454 QTEST_COMPARE_DECL(qfloat16)
455 QTEST_COMPARE_DECL(char)
456 QTEST_COMPARE_DECL(signed char)
457 QTEST_COMPARE_DECL(unsigned char)
458 QTEST_COMPARE_DECL(bool)
459#endif
460
461 template <typename T1, typename T2>
462 inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected,
463 const char *file, int line)
464 {
465 return compare_helper(t1 == t2, "Compared values are not the same",
466 toString(t1), toString(t2), actual, expected, file, line);
467 }
468
469 inline bool qCompare(double const &t1, float const &t2, const char *actual,
470 const char *expected, const char *file, int line)
471 {
472 return qCompare(qreal(t1), qreal(t2), actual, expected, file, line);
473 }
474
475 inline bool qCompare(float const &t1, double const &t2, const char *actual,
476 const char *expected, const char *file, int line)
477 {
478 return qCompare(qreal(t1), qreal(t2), actual, expected, file, line);
479 }
480
481 template <typename T>
482 inline bool qCompare(const T *t1, const T *t2, const char *actual, const char *expected,
483 const char *file, int line)
484 {
485 return compare_ptr_helper(t1, t2, actual, expected, file, line);
486 }
487 template <typename T>
488 inline bool qCompare(T *t1, T *t2, const char *actual, const char *expected,
489 const char *file, int line)
490 {
491 return compare_ptr_helper(t1, t2, actual, expected, file, line);
492 }
493
494 template <typename T>
495 inline bool qCompare(T *t1, std::nullptr_t, const char *actual, const char *expected,
496 const char *file, int line)
497 {
498 return compare_ptr_helper(t1, nullptr, actual, expected, file, line);
499 }
500 template <typename T>
501 inline bool qCompare(std::nullptr_t, T *t2, const char *actual, const char *expected,
502 const char *file, int line)
503 {
504 return compare_ptr_helper(nullptr, t2, actual, expected, file, line);
505 }
506
507 template <typename T1, typename T2>
508 inline bool qCompare(const T1 *t1, const T2 *t2, const char *actual, const char *expected,
509 const char *file, int line)
510 {
511 return compare_ptr_helper(t1, static_cast<const T1 *>(t2), actual, expected, file, line);
512 }
513 template <typename T1, typename T2>
514 inline bool qCompare(T1 *t1, T2 *t2, const char *actual, const char *expected,
515 const char *file, int line)
516 {
517 return compare_ptr_helper(const_cast<const T1 *>(t1),
518 static_cast<const T1 *>(const_cast<const T2 *>(t2)), actual, expected, file, line);
519 }
520 inline bool qCompare(const 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(char *t1, char *t2, const char *actual, const char *expected,
526 const char *file, int line)
527 {
528 return compare_string_helper(t1, t2, actual, expected, file, line);
529 }
530
531 /* The next two overloads are for MSVC that shows problems with implicit
532 conversions
533 */
534 inline bool qCompare(char *t1, const char *t2, const char *actual,
535 const char *expected, const char *file, int line)
536 {
537 return compare_string_helper(t1, t2, actual, expected, file, line);
538 }
539 inline bool qCompare(const char *t1, char *t2, const char *actual,
540 const char *expected, const char *file, int line)
541 {
542 return compare_string_helper(t1, t2, actual, expected, file, line);
543 }
544
545 template <class T>
546 inline bool qTest(const T& actual, const char *elementName, const char *actualStr,
547 const char *expected, const char *file, int line)
548 {
549 return qCompare(actual, *static_cast<const T *>(QTest::qElementData(elementName,
550 qMetaTypeId<T>())), actualStr, expected, file, line);
551 }
552}
553
554#undef QTEST_COMPARE_DECL
555
556QT_END_NAMESPACE
557
558#endif
559