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> // Fallback
250 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(const T &)
251 {
252 return nullptr;
253 }
254
255 template<typename F> // Output QFlags of registered enumerations
256 inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
257 {
258 const QMetaEnum me = QMetaEnum::fromType<F>();
259 return qstrdup(me.valueToKeys(int(f)).constData());
260 }
261
262 template <typename F> // Fallback: Output hex value
263 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
264 {
265 const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0'
266 char *msg = new char[space];
267 qsnprintf(msg, space, "0x%x", unsigned(f));
268 return msg;
269 }
270
271 } // namespace Internal
272
273 template<typename T>
274 inline char *toString(const T &t)
275 {
276 return Internal::toString(t);
277 }
278
279 template <typename T1, typename T2>
280 inline char *toString(const QPair<T1, T2> &pair);
281
282 template <typename T1, typename T2>
283 inline char *toString(const std::pair<T1, T2> &pair);
284
285 template <class... Types>
286 inline char *toString(const std::tuple<Types...> &tuple);
287
288 Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, int length);
289 Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, int length);
290 Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
291 Q_TESTLIB_EXPORT char *toString(const char *);
292 Q_TESTLIB_EXPORT char *toString(const void *);
293
294 Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc = 0, char **argv = nullptr);
295 Q_TESTLIB_EXPORT int qRun();
296 Q_TESTLIB_EXPORT void qCleanup();
297
298 Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = nullptr);
299 Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments);
300
301 Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir = nullptr);
302
303 Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description,
304 const char *file, int line);
305 Q_TESTLIB_EXPORT void qFail(const char *statementStr, const char *file, int line);
306 Q_TESTLIB_EXPORT void qSkip(const char *message, const char *file, int line);
307 Q_TESTLIB_EXPORT bool qExpectFail(const char *dataIndex, const char *comment, TestFailMode mode,
308 const char *file, int line);
309 Q_TESTLIB_EXPORT void qWarn(const char *message, const char *file = nullptr, int line = 0);
310 Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message);
311#if QT_CONFIG(regularexpression)
312 Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern);
313#endif
314
315#if QT_CONFIG(temporaryfile)
316 Q_TESTLIB_EXPORT QSharedPointer<QTemporaryDir> qExtractTestData(const QString &dirName);
317#endif
318 Q_TESTLIB_EXPORT QString qFindTestData(const char* basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr, const char* sourcedir = nullptr);
319 Q_TESTLIB_EXPORT QString qFindTestData(const QString& basepath, const char* file = nullptr, int line = 0, const char* builddir = nullptr, const char *sourcedir = nullptr);
320
321 Q_TESTLIB_EXPORT void *qData(const char *tagName, int typeId);
322 Q_TESTLIB_EXPORT void *qGlobalData(const char *tagName, int typeId);
323 Q_TESTLIB_EXPORT void *qElementData(const char *elementName, int metaTypeId);
324 Q_TESTLIB_EXPORT QObject *testObject();
325
326 Q_TESTLIB_EXPORT const char *currentAppName();
327
328 Q_TESTLIB_EXPORT const char *currentTestFunction();
329 Q_TESTLIB_EXPORT const char *currentDataTag();
330 Q_TESTLIB_EXPORT bool currentTestFailed();
331
332 Q_TESTLIB_EXPORT Qt::Key asciiToKey(char ascii);
333 Q_TESTLIB_EXPORT char keyToAscii(Qt::Key key);
334
335 Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
336 char *val1, char *val2,
337 const char *actual, const char *expected,
338 const char *file, int line);
339 Q_TESTLIB_EXPORT void addColumnInternal(int id, const char *name);
340
341 template <typename T>
342 inline void addColumn(const char *name, T * = nullptr)
343 {
344 using QIsSameTConstChar = std::is_same<T, const char*>;
345 static_assert(!QIsSameTConstChar::value, "const char* is not allowed as a test data format.");
346 addColumnInternal(qMetaTypeId<T>(), name);
347 }
348 Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag);
349 Q_TESTLIB_EXPORT QTestData &addRow(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2);
350
351#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
352 // kept after adding implementation of <T1, T2> out of paranoia:
353 template <typename T>
354 inline bool qCompare(T const &t1, T const &t2, const char *actual, const char *expected,
355 const char *file, int line)
356 {
357 return compare_helper(t1 == t2, "Compared values are not the same",
358 toString(t1), toString(t2), actual, expected, file, line);
359 }
360#endif
361
362 Q_TESTLIB_EXPORT bool qCompare(qfloat16 const &t1, qfloat16 const &t2,
363 const char *actual, const char *expected, const char *file, int line);
364
365 Q_TESTLIB_EXPORT bool qCompare(float const &t1, float const &t2,
366 const char *actual, const char *expected, const char *file, int line);
367
368 Q_TESTLIB_EXPORT bool qCompare(double const &t1, double const &t2,
369 const char *actual, const char *expected, const char *file, int line);
370
371 Q_TESTLIB_EXPORT bool qCompare(int t1, int t2, const char *actual, const char *expected,
372 const char *file, int line);
373
374 Q_TESTLIB_EXPORT bool qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected,
375 const char *file, int line);
376
377 Q_TESTLIB_EXPORT bool qCompare(QStringView t1, QStringView t2,
378 const char *actual, const char *expected,
379 const char *file, int line);
380 Q_TESTLIB_EXPORT bool qCompare(QStringView t1, const QLatin1String &t2,
381 const char *actual, const char *expected,
382 const char *file, int line);
383 Q_TESTLIB_EXPORT bool qCompare(const QLatin1String &t1, QStringView t2,
384 const char *actual, const char *expected,
385 const char *file, int line);
386 inline bool qCompare(const QString &t1, const QString &t2,
387 const char *actual, const char *expected,
388 const char *file, int line)
389 {
390 return qCompare(QStringView(t1), QStringView(t2), actual, expected, file, line);
391 }
392 inline bool qCompare(const QString &t1, const QLatin1String &t2,
393 const char *actual, const char *expected,
394 const char *file, int line)
395 {
396 return qCompare(QStringView(t1), t2, actual, expected, file, line);
397 }
398 inline bool qCompare(const QLatin1String &t1, const QString &t2,
399 const char *actual, const char *expected,
400 const char *file, int line)
401 {
402 return qCompare(t1, QStringView(t2), actual, expected, file, line);
403 }
404
405 inline bool compare_ptr_helper(const volatile void *t1, const volatile void *t2, const char *actual,
406 const char *expected, const char *file, int line)
407 {
408 return compare_helper(t1 == t2, "Compared pointers are not the same",
409 toString(t1), toString(t2), actual, expected, file, line);
410 }
411
412 inline bool compare_ptr_helper(const volatile void *t1, std::nullptr_t, const char *actual,
413 const char *expected, const char *file, int line)
414 {
415 return compare_helper(t1 == nullptr, "Compared pointers are not the same",
416 toString(t1), toString(nullptr), actual, expected, file, line);
417 }
418
419 inline bool compare_ptr_helper(std::nullptr_t, const volatile void *t2, const char *actual,
420 const char *expected, const char *file, int line)
421 {
422 return compare_helper(nullptr == t2, "Compared pointers are not the same",
423 toString(nullptr), toString(t2), actual, expected, file, line);
424 }
425
426 Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
427 const char *expected, const char *file, int line);
428
429 Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...);
430
431#ifndef Q_QDOC
432 QTEST_COMPARE_DECL(short)
433 QTEST_COMPARE_DECL(ushort)
434 QTEST_COMPARE_DECL(int)
435 QTEST_COMPARE_DECL(uint)
436 QTEST_COMPARE_DECL(long)
437 QTEST_COMPARE_DECL(ulong)
438 QTEST_COMPARE_DECL(qint64)
439 QTEST_COMPARE_DECL(quint64)
440
441 QTEST_COMPARE_DECL(float)
442 QTEST_COMPARE_DECL(double)
443 QTEST_COMPARE_DECL(qfloat16)
444 QTEST_COMPARE_DECL(char)
445 QTEST_COMPARE_DECL(signed char)
446 QTEST_COMPARE_DECL(unsigned char)
447 QTEST_COMPARE_DECL(bool)
448#endif
449
450 template <typename T1, typename T2>
451 inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected,
452 const char *file, int line)
453 {
454 return compare_helper(t1 == t2, "Compared values are not the same",
455 toString(t1), toString(t2), actual, expected, file, line);
456 }
457
458 inline bool qCompare(double const &t1, float const &t2, const char *actual,
459 const char *expected, const char *file, int line)
460 {
461 return qCompare(qreal(t1), qreal(t2), actual, expected, file, line);
462 }
463
464 inline bool qCompare(float const &t1, double const &t2, const char *actual,
465 const char *expected, const char *file, int line)
466 {
467 return qCompare(qreal(t1), qreal(t2), actual, expected, file, line);
468 }
469
470 template <typename T>
471 inline bool qCompare(const T *t1, const T *t2, const char *actual, const char *expected,
472 const char *file, int line)
473 {
474 return compare_ptr_helper(t1, t2, actual, expected, file, line);
475 }
476 template <typename T>
477 inline bool qCompare(T *t1, T *t2, const char *actual, const char *expected,
478 const char *file, int line)
479 {
480 return compare_ptr_helper(t1, t2, actual, expected, file, line);
481 }
482
483 template <typename T>
484 inline bool qCompare(T *t1, std::nullptr_t, const char *actual, const char *expected,
485 const char *file, int line)
486 {
487 return compare_ptr_helper(t1, nullptr, actual, expected, file, line);
488 }
489 template <typename T>
490 inline bool qCompare(std::nullptr_t, T *t2, const char *actual, const char *expected,
491 const char *file, int line)
492 {
493 return compare_ptr_helper(nullptr, t2, actual, expected, file, line);
494 }
495
496 template <typename T1, typename T2>
497 inline bool qCompare(const T1 *t1, const T2 *t2, const char *actual, const char *expected,
498 const char *file, int line)
499 {
500 return compare_ptr_helper(t1, static_cast<const T1 *>(t2), actual, expected, file, line);
501 }
502 template <typename T1, typename T2>
503 inline bool qCompare(T1 *t1, T2 *t2, const char *actual, const char *expected,
504 const char *file, int line)
505 {
506 return compare_ptr_helper(const_cast<const T1 *>(t1),
507 static_cast<const T1 *>(const_cast<const T2 *>(t2)), actual, expected, file, line);
508 }
509 inline bool qCompare(const char *t1, const char *t2, const char *actual,
510 const char *expected, const char *file, int line)
511 {
512 return compare_string_helper(t1, t2, actual, expected, file, line);
513 }
514 inline bool qCompare(char *t1, char *t2, const char *actual, const char *expected,
515 const char *file, int line)
516 {
517 return compare_string_helper(t1, t2, actual, expected, file, line);
518 }
519
520 /* The next two overloads are for MSVC that shows problems with implicit
521 conversions
522 */
523 inline bool qCompare(char *t1, const char *t2, const char *actual,
524 const char *expected, const char *file, int line)
525 {
526 return compare_string_helper(t1, t2, actual, expected, file, line);
527 }
528 inline bool qCompare(const char *t1, char *t2, const char *actual,
529 const char *expected, const char *file, int line)
530 {
531 return compare_string_helper(t1, t2, actual, expected, file, line);
532 }
533
534 template <class T>
535 inline bool qTest(const T& actual, const char *elementName, const char *actualStr,
536 const char *expected, const char *file, int line)
537 {
538 return qCompare(actual, *static_cast<const T *>(QTest::qElementData(elementName,
539 qMetaTypeId<T>())), actualStr, expected, file, line);
540 }
541}
542
543#undef QTEST_COMPARE_DECL
544
545QT_END_NAMESPACE
546
547#endif
548