Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtestresult.cpp
Go to the documentation of this file.
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#include <QtTest/private/qtestresult_p.h>
5#include <QtCore/qglobal.h>
6#include <QtCore/qmutex.h>
7#include <QtCore/qstringview.h>
8
9#include <QtTest/private/qtestlog_p.h>
10#include <QtTest/qtest.h> // toString() specializations for QStringView
11#include <QtTest/qtestdata.h>
12#include <QtTest/qtestcase.h>
13#include <QtTest/qtestassert.h>
14#include <QtTest/qtesteventloop.h>
15
16#include <climits>
17#include <cwchar>
18#include <QtCore/q26numeric.h>
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23
24static const char *currentAppName = nullptr;
25
26QT_BEGIN_NAMESPACE
27
28namespace QTest
29{
30 namespace Internal {
31 static bool failed = false;
32 }
33
34 static void setFailed(bool failed)
35 {
36 static const bool fatalFailure = []() {
37 static const char * const environmentVar = "QTEST_FATAL_FAIL";
38 if (!qEnvironmentVariableIsSet(environmentVar))
39 return false;
40
41 bool ok;
42 const int fatal = qEnvironmentVariableIntValue(environmentVar, &ok);
43 return ok && fatal;
44 }();
45
46 if (failed && fatalFailure)
47 std::terminate();
48 Internal::failed = failed;
49 }
50
51 static void resetFailed()
52 {
53 setFailed(false);
54 }
55
56 static bool hasFailed()
57 {
58 return Internal::failed;
59 }
60
61 static QTestData *currentTestData = nullptr;
63 static const char *currentTestFunc = nullptr;
64 static const char *currentTestObjectName = nullptr;
65 static bool skipCurrentTest = false;
66 static bool blacklistCurrentTest = false;
67
68 static const char *expectFailComment = nullptr;
69 static int expectFailMode = 0;
70
71 // The pointers above belong to the main thread, and the strings they point at don't
72 // outlive the test function: currentTestFunc points into a QByteArray local to
73 // invokeTest(), and the QTestData rows are owned by a QTestTable local to it. Loggers,
74 // however, run on whatever thread called qDebug(), so they must not read them. They get
75 // these copies instead, which testlib owns and only hands out under identifierMutex.
76 // See QTestResult::IdentifierLocker.
77 Q_CONSTINIT static QBasicMutex identifierMutex;
78 static char *identifierObjectName = nullptr;
79 static char *identifierTestFunc = nullptr;
80 static char *identifierDataTag = nullptr;
81 static char *identifierGlobalDataTag = nullptr;
82
83 static void storeIdentifierString(char *&dest, const char *src)
84 {
85 delete[] std::exchange(dest, src ? qstrdup(src) : nullptr);
86 }
87
88 // Call from the main thread after changing any of the above. Must not be called with
89 // identifierMutex held.
90 static void updateIdentifier()
91 {
92 // Read before locking, through the accessors: the data belongs to this thread, and
93 // they are where absent names are turned into whatever the loggers expect.
94 const char *objectName = QTestResult::currentTestObjectName();
95 const char *testFunc = QTestResult::currentTestFunction();
96 const char *dataTag = QTestResult::currentDataTag();
97 const char *globalDataTag = QTestResult::currentGlobalDataTag();
98
99 const QMutexLocker locker(&identifierMutex);
104 }
105}
106
107/*!
108 \class QTestResult
109 \inmodule QtTest
110 \internal
111*/
112
113QTestResult::IdentifierLocker::IdentifierLocker()
114{
115 QTest::identifierMutex.lock();
116}
117
118QTestResult::IdentifierLocker::~IdentifierLocker()
119{
120 QTest::identifierMutex.unlock();
121}
122
123const char *QTestResult::IdentifierLocker::objectName() const
124{
125 return QTest::identifierObjectName;
126}
127
128const char *QTestResult::IdentifierLocker::testFunction() const
129{
130 return QTest::identifierTestFunc;
131}
132
133const char *QTestResult::IdentifierLocker::dataTag() const
134{
135 return QTest::identifierDataTag;
136}
137
138const char *QTestResult::IdentifierLocker::globalDataTag() const
139{
140 return QTest::identifierGlobalDataTag;
141}
142
143void QTestResult::reset()
144{
145 QTest::currentTestData = nullptr;
146 QTest::currentGlobalTestData = nullptr;
147 QTest::currentTestFunc = nullptr;
148 QTest::currentTestObjectName = nullptr;
149 QTest::updateIdentifier();
150 QTest::resetFailed();
151
152 QTest::expectFailComment = nullptr;
153 QTest::expectFailMode = 0;
154 QTest::blacklistCurrentTest = false;
155
156 QTestLog::resetCounters();
157}
158
159void QTestResult::setBlacklistCurrentTest(bool b)
160{
161 QTest::blacklistCurrentTest = b;
162}
163
164bool QTestResult::currentTestFailed()
165{
166 return QTest::hasFailed();
167}
168
169QTestData *QTestResult::currentGlobalTestData()
170{
171 return QTest::currentGlobalTestData;
172}
173
174QTestData *QTestResult::currentTestData()
175{
176 return QTest::currentTestData;
177}
178
179void QTestResult::setCurrentGlobalTestData(QTestData *data)
180{
181 QTest::currentGlobalTestData = data;
182 QTest::updateIdentifier();
183}
184
185void QTestResult::setCurrentTestData(QTestData *data)
186{
187 QTest::currentTestData = data;
188 QTest::updateIdentifier();
189 QTest::resetFailed();
190 if (data)
191 QTestLog::enterTestData(data);
192}
193
194void QTestResult::setCurrentTestFunction(const char *func)
195{
196 QTest::currentTestFunc = func;
197 QTest::updateIdentifier();
198 QTest::resetFailed();
199 if (func)
200 QTestLog::enterTestFunction(func);
201}
202
203static void clearExpectFail()
204{
206 delete [] const_cast<char *>(QTest::expectFailComment);
207 QTest::expectFailComment = nullptr;
208}
209
210/*!
211 This function is called after completing each test function,
212 including test functions that are not data-driven.
213
214 For data-driven functions, this is called after each call to the test
215 function, with distinct data. Otherwise, this function is called once,
216 with currentTestData() and currentGlobalTestData() set to \nullptr.
217
218 The function is called before the test's cleanup(), if it has one.
219
220 For benchmarks, this will be called after each repeat of a function
221 (with the same data row), when the benchmarking code decides to
222 re-run one to get sufficient data.
223
224 \sa finishedCurrentTestDataCleanup()
225*/
226void QTestResult::finishedCurrentTestData()
227{
228 if (QTest::expectFailMode)
229 addFailure("QEXPECT_FAIL was called without any subsequent verification statements");
230
231 clearExpectFail();
232}
233
234/*!
235 This function is called after completing each test function,
236 including test functions that are not data-driven.
237
238 For data-driven functions, this is called after each call to the test
239 function, with distinct data. Otherwise, this function is called once,
240 with currentTestData() and currentGlobalTestData() set to \nullptr.
241
242 The function is called after the test's cleanup(), if it has one.
243
244 For benchmarks, this is called after all repeat calls to the function
245 (with a given data row).
246
247 \sa finishedCurrentTestData()
248*/
249void QTestResult::finishedCurrentTestDataCleanup()
250{
251 if (!QTest::hasFailed() && QTestLog::unhandledIgnoreMessages()) {
252 QTestLog::printUnhandledIgnoreMessages();
253 addFailure("Not all expected messages were received");
254 }
255
256 // If the current test hasn't failed or been skipped, then it passes.
257 if (!QTest::hasFailed() && !QTest::skipCurrentTest) {
258 if (QTest::blacklistCurrentTest)
259 QTestLog::addBPass("");
260 else
261 QTestLog::addPass("");
262 }
263
264 QTestLog::clearCurrentTestState();
265 QTest::resetFailed();
266}
267
268/*!
269 This function is called after completing each test function,
270 including test functions that are data-driven.
271
272 For data-driven functions, this is called after all data rows
273 have been tested, and the data table has been cleared, so both
274 currentTestData() and currentGlobalTestData() will be \nullptr.
275*/
276void QTestResult::finishedCurrentTestFunction()
277{
278 QTestLog::clearCurrentTestState(); // Needed if _data() skipped.
279 QTestLog::leaveTestFunction();
280
281 QTest::currentTestFunc = nullptr;
282 QTest::resetFailed();
283}
284
285const char *QTestResult::currentTestFunction()
286{
287 return QTest::currentTestFunc;
288}
289
290const char *QTestResult::currentDataTag()
291{
292 return QTest::currentTestData ? QTest::currentTestData->dataTag() : nullptr;
293}
294
295const char *QTestResult::currentGlobalDataTag()
296{
297 return QTest::currentGlobalTestData ? QTest::currentGlobalTestData->dataTag() : nullptr;
298}
299
300static bool isExpectFailData(const char *dataIndex)
301{
302 if (!dataIndex || dataIndex[0] == '\0')
303 return true;
304 if (!QTest::currentTestData)
305 return false;
306 if (strcmp(dataIndex, QTest::currentTestData->dataTag()) == 0)
307 return true;
308 return false;
309}
310
311bool QTestResult::expectFail(const char *dataIndex, const char *comment,
312 QTest::TestFailMode mode, const char *file, int line)
313{
314 QTEST_ASSERT(comment);
315 QTEST_ASSERT(mode > 0);
316
317 if (!isExpectFailData(dataIndex)) {
318 delete[] comment;
319 return true; // we don't care
320 }
321
322 if (QTest::expectFailMode) {
323 delete[] comment;
324 addFailure("Already expecting a fail", file, line);
325 return false;
326 }
327
328 QTest::expectFailMode = mode;
329 QTest::expectFailComment = comment;
330 return true;
331}
332
333static bool checkStatement(bool statement, const char *msg, const char *file, int line)
334{
335 if (statement) {
337 if (QTest::blacklistCurrentTest)
338 QTestLog::addBXPass(msg, file, line);
339 else
340 QTestLog::addXPass(msg, file, line);
341
343 // Should B?XPass always (a) continue or (b) abort, regardless of mode ?
344 bool doContinue = (QTest::expectFailMode == QTest::Continue);
346 return doContinue;
347 }
348 return true;
349 }
350
352 if (QTest::blacklistCurrentTest)
353 QTestLog::addBXFail(QTest::expectFailComment, file, line);
354 else
355 QTestLog::addXFail(QTest::expectFailComment, file, line);
356 bool doContinue = (QTest::expectFailMode == QTest::Continue);
358 return doContinue;
359 }
360
361 QTestResult::addFailure(msg, file, line);
362 return false;
363}
364
365void QTestResult::fail(const char *msg, const char *file, int line)
366{
367 checkStatement(false, msg, file, line);
368}
369
370// QPalette's << operator produces 1363 characters. A comparison failure
371// involving two palettes can therefore require 2726 characters, not including
372// the other output produced by QTest. Users might also have their own types
373// with large amounts of output, so use a sufficiently high value here.
374static constexpr size_t maxMsgLen = 4096;
375
376bool QTestResult::verify(bool statement, const char *statementStr,
377 const char *description, const char *file, int line)
378{
379 QTEST_ASSERT(statementStr);
380
381 Q_DECL_UNINITIALIZED char msg[maxMsgLen];
382 msg[0] = '\0';
383
384 if (QTestLog::verboseLevel() >= 2) {
385 std::snprintf(msg, maxMsgLen, "QVERIFY(%s)", statementStr);
386 QTestLog::info(msg, file, line);
387 }
388
389 if (statement == !!QTest::expectFailMode) {
390 std::snprintf(msg, maxMsgLen,
391 statement ? "'%s' returned TRUE unexpectedly. (%s)" : "'%s' returned FALSE. (%s)",
392 statementStr, description ? description : "");
393 }
394
395 return checkStatement(statement, msg, file, line);
396}
397
398static const char *leftArgNameForOp(QTest::ComparisonOperation op)
399{
400 switch (op) {
401 case QTest::ComparisonOperation::CustomCompare:
402 return "Actual ";
403 case QTest::ComparisonOperation::ThreeWayCompare:
404 return "Left ";
405 case QTest::ComparisonOperation::Equal:
406 case QTest::ComparisonOperation::NotEqual:
407 case QTest::ComparisonOperation::LessThan:
408 case QTest::ComparisonOperation::LessThanOrEqual:
409 case QTest::ComparisonOperation::GreaterThan:
410 case QTest::ComparisonOperation::GreaterThanOrEqual:
411 return "Computed ";
412 }
413 Q_UNREACHABLE_RETURN("");
414}
415
416static const char *rightArgNameForOp(QTest::ComparisonOperation op)
417{
418 switch (op) {
419 case QTest::ComparisonOperation::CustomCompare:
420 return "Expected ";
421 case QTest::ComparisonOperation::ThreeWayCompare:
422 return "Right ";
423 case QTest::ComparisonOperation::Equal:
424 case QTest::ComparisonOperation::NotEqual:
425 case QTest::ComparisonOperation::LessThan:
426 case QTest::ComparisonOperation::LessThanOrEqual:
427 case QTest::ComparisonOperation::GreaterThan:
428 case QTest::ComparisonOperation::GreaterThanOrEqual:
429 return "Baseline ";
430 }
431 Q_UNREACHABLE_RETURN("");
432}
433
434static int approx_wide_len(const char *s)
435{
436 std::mbstate_t state = {};
437 // QNX might stop at max when dst == nullptr, so pass INT_MAX,
438 // being the largest value this function will return:
439 auto r = std::mbsrtowcs(nullptr, &s, INT_MAX, &state);
440 if (r == size_t(-1)) // encoding error, fall back to strlen()
441 r = strlen(s); // `s` was not advanced since `dst == nullptr`
442 return q26::saturating_cast<int>(r);
443}
444
445// Overload to format failures for "const char *" - no need to strdup().
447void formatFailMessage(char *msg, size_t maxMsgLen,
448 const char *failureMsg,
449 const char *val1, const char *val2,
450 const char *actual, const char *expected,
451 QTest::ComparisonOperation op)
452{
453 const auto len1 = approx_wide_len(actual);
454 const auto len2 = approx_wide_len(expected);
455 const int written = std::snprintf(msg, maxMsgLen, "%s\n", failureMsg);
456 msg += written;
457 maxMsgLen -= written;
458
459 const auto protect = [](const char *s) { return s ? s : "<null>"; };
460
461 if (val1 || val2) {
462 std::snprintf(msg, maxMsgLen, " %s(%s)%*s %s\n %s(%s)%*s %s",
463 leftArgNameForOp(op), actual, qMax(len1, len2) - len1 + 1, ":",
464 protect(val1),
465 rightArgNameForOp(op), expected, qMax(len1, len2) - len2 + 1, ":",
466 protect(val2));
467 } else {
468 // only print variable names if neither value can be represented as a string
469 std::snprintf(msg, maxMsgLen, " %s: %s\n %s: %s",
470 leftArgNameForOp(op), actual, rightArgNameForOp(op), expected);
471 }
472}
473
474const char *
475QTest::Internal::formatPropertyTestHelperFailure(char *msg, size_t maxMsgLen,
476 const char *actual, const char *expected,
477 const char *actualExpr, const char *expectedExpr)
478{
479 formatFailMessage(msg, maxMsgLen, "Comparison failed!",
480 actual, expected, actualExpr, expectedExpr,
481 QTest::ComparisonOperation::CustomCompare);
482 return msg;
483}
484
485// Format failures using the toString() template
486template <class Actual, class Expected>
488void formatFailMessage(char *msg, size_t maxMsgLen,
489 const char *failureMsg,
490 const Actual &val1, const Expected &val2,
491 const char *actual, const char *expected,
492 QTest::ComparisonOperation op)
493{
494 const char *val1S = QTest::toString(val1);
495 const char *val2S = QTest::toString(val2);
496
497 formatFailMessage(msg, maxMsgLen, failureMsg, val1S, val2S, actual, expected, op);
498
499 delete [] val1S;
500 delete [] val2S;
501}
502
503template <class Actual, class Expected>
504static bool compareHelper(bool success, const char *failureMsg,
505 const Actual &val1, const Expected &val2,
506 const char *actual, const char *expected,
507 const char *file, int line,
508 bool hasValues = true)
509{
510 Q_DECL_UNINITIALIZED char msg[maxMsgLen];
511 msg[0] = '\0';
512
513 QTEST_ASSERT(expected);
514 QTEST_ASSERT(actual);
515
516 if (QTestLog::verboseLevel() >= 2) {
517 std::snprintf(msg, maxMsgLen, "QCOMPARE(%s, %s)", actual, expected);
518 QTestLog::info(msg, file, line);
519 }
520
521 if (!failureMsg)
522 failureMsg = "Compared values are not the same";
523
524 if (success) {
526 std::snprintf(msg, maxMsgLen,
527 "QCOMPARE(%s, %s) returned TRUE unexpectedly.", actual, expected);
528 }
529 return checkStatement(success, msg, file, line);
530 }
531
532
533 if (!hasValues) {
534 std::snprintf(msg, maxMsgLen, "%s", failureMsg);
535 return checkStatement(success, msg, file, line);
536 }
537
538 formatFailMessage(msg, maxMsgLen, failureMsg, val1, val2, actual, expected,
539 QTest::ComparisonOperation::CustomCompare);
540
541 return checkStatement(success, msg, file, line);
542}
543
544// A simplified version of compareHelper that does not use string
545// representations of the values, and prints only failureMsg when the
546// comparison fails.
547static bool compareHelper(bool success, const char *failureMsg,
548 const char *actual, const char *expected,
549 const char *file, int line)
550{
551 const size_t maxMsgLen = 1024;
552 Q_DECL_UNINITIALIZED char msg[maxMsgLen];
553 msg[0] = '\0';
554
555 QTEST_ASSERT(expected);
556 QTEST_ASSERT(actual);
557 // failureMsg can be null, if we do not use it
558 QTEST_ASSERT(success || failureMsg);
559
560 if (QTestLog::verboseLevel() >= 2) {
561 std::snprintf(msg, maxMsgLen, "QCOMPARE(%s, %s)", actual, expected);
562 QTestLog::info(msg, file, line);
563 }
564
565 if (success) {
567 std::snprintf(msg, maxMsgLen, "QCOMPARE(%s, %s) returned TRUE unexpectedly.",
568 actual, expected);
569 }
570 return checkStatement(success, msg, file, line);
571 }
572
573 return checkStatement(success, failureMsg, file, line);
574}
575
576bool QTestResult::compare(bool success, const char *failureMsg,
577 char *val1, char *val2,
578 const char *actual, const char *expected,
579 const char *file, int line)
580{
581 const bool result = compareHelper(success, failureMsg,
582 val1 != nullptr ? val1 : "<null>",
583 val2 != nullptr ? val2 : "<null>",
584 actual, expected, file, line,
585 val1 != nullptr && val2 != nullptr);
586
587 // Our caller got these from QTest::toString()
588 delete [] val1;
589 delete [] val2;
590
591 return result;
592}
593
594bool QTestResult::compare(bool success, const char *failureMsg,
595 double val1, double val2,
596 const char *actual, const char *expected,
597 const char *file, int line)
598{
599 return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
600}
601
602bool QTestResult::compare(bool success, const char *failureMsg,
603 float val1, float val2,
604 const char *actual, const char *expected,
605 const char *file, int line)
606{
607 return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
608}
609
610bool QTestResult::compare(bool success, const char *failureMsg,
611 int val1, int val2,
612 const char *actual, const char *expected,
613 const char *file, int line)
614{
615 return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
616}
617
618#if QT_POINTER_SIZE == 8
619bool QTestResult::compare(bool success, const char *failureMsg,
620 qsizetype val1, qsizetype val2,
621 const char *actual, const char *expected,
622 const char *file, int line)
623{
624 return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
625}
626#endif // QT_POINTER_SIZE == 8
627
628bool QTestResult::compare(bool success, const char *failureMsg,
629 unsigned val1, unsigned val2,
630 const char *actual, const char *expected,
631 const char *file, int line)
632{
633 return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
634}
635
636bool QTestResult::compare(bool success, const char *failureMsg,
637 QStringView val1, QStringView val2,
638 const char *actual, const char *expected,
639 const char *file, int line)
640{
641 return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
642}
643
644bool QTestResult::compare(bool success, const char *failureMsg,
645 QStringView val1, const QLatin1StringView &val2,
646 const char *actual, const char *expected,
647 const char *file, int line)
648{
649 return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
650}
651
652bool QTestResult::compare(bool success, const char *failureMsg,
653 const QLatin1StringView & val1, QStringView val2,
654 const char *actual, const char *expected,
655 const char *file, int line)
656{
657 return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
658}
659
660// Simplified version of compare() that does not take the values, because they
661// can't be converted to strings (or the user didn't want to do that).
662bool QTestResult::compare(bool success, const char *failureMsg,
663 const char *actual, const char *expeceted,
664 const char *file, int line)
665{
666 return compareHelper(success, failureMsg, actual, expeceted, file, line);
667}
668
669void QTestResult::addFailure(const char *message, const char *file, int line)
670{
671 clearExpectFail();
672 if (qApp && QThread::currentThread() == qApp->thread())
673 QTestEventLoop::instance().exitLoop();
674
675 if (QTest::blacklistCurrentTest)
676 QTestLog::addBFail(message, file, line);
677 else
678 QTestLog::addFail(message, file, line);
679 QTest::setFailed(true);
680}
681
682void QTestResult::addSkip(const char *message, const char *file, int line)
683{
684 clearExpectFail();
685
686 QTestLog::addSkip(message, file, line);
687}
688
689void QTestResult::setCurrentTestObject(const char *name)
690{
691 QTest::currentTestObjectName = name;
692 QTest::updateIdentifier();
693}
694
695const char *QTestResult::currentTestObjectName()
696{
697 return QTest::currentTestObjectName ? QTest::currentTestObjectName : "";
698}
699
700void QTestResult::setSkipCurrentTest(bool value)
701{
702 QTest::skipCurrentTest = value;
703}
704
705bool QTestResult::skipCurrentTest()
706{
707 return QTest::skipCurrentTest;
708}
709
710void QTestResult::setCurrentAppName(const char *appName)
711{
712 ::currentAppName = appName;
713}
714
715const char *QTestResult::currentAppName()
716{
717 return ::currentAppName;
718}
719
720static const char *macroNameForOp(QTest::ComparisonOperation op)
721{
722 using namespace QTest;
723 switch (op) {
724 case ComparisonOperation::CustomCompare:
725 return "QCOMPARE"; /* not used */
726 case ComparisonOperation::Equal:
727 return "QCOMPARE_EQ";
728 case ComparisonOperation::NotEqual:
729 return "QCOMPARE_NE";
730 case ComparisonOperation::LessThan:
731 return "QCOMPARE_LT";
732 case ComparisonOperation::LessThanOrEqual:
733 return "QCOMPARE_LE";
734 case ComparisonOperation::GreaterThan:
735 return "QCOMPARE_GT";
736 case ComparisonOperation::GreaterThanOrEqual:
737 return "QCOMPARE_GE";
738 case ComparisonOperation::ThreeWayCompare:
739 return "QCOMPARE_3WAY";
740 }
741 Q_UNREACHABLE_RETURN("");
742}
743
744static const char *failureMessageForOp(QTest::ComparisonOperation op)
745{
746 using namespace QTest;
747 switch (op) {
748 case ComparisonOperation::CustomCompare:
749 return "Compared values are not the same"; /* not used */
750 case ComparisonOperation::ThreeWayCompare:
751 return "The result of operator<=>() is not what was expected";
752 case ComparisonOperation::Equal:
753 return "The computed value is expected to be equal to the baseline, but is not";
754 case ComparisonOperation::NotEqual:
755 return "The computed value is expected to be different from the baseline, but is not";
756 case ComparisonOperation::LessThan:
757 return "The computed value is expected to be less than the baseline, but is not";
758 case ComparisonOperation::LessThanOrEqual:
759 return "The computed value is expected to be less than or equal to the baseline, but is not";
760 case ComparisonOperation::GreaterThan:
761 return "The computed value is expected to be greater than the baseline, but is not";
762 case ComparisonOperation::GreaterThanOrEqual:
763 return "The computed value is expected to be greater than or equal to the baseline, but is not";
764 }
765 Q_UNREACHABLE_RETURN("");
766}
767
768bool QTestResult::reportResult(bool success, const void *lhs, const void *rhs,
769 const char *(*lhsFormatter)(const void*),
770 const char *(*rhsFormatter)(const void*),
771 const char *lhsExpr, const char *rhsExpr,
772 QTest::ComparisonOperation op, const char *file, int line,
773 const char *failureMessage)
774{
775 Q_DECL_UNINITIALIZED char msg[maxMsgLen];
776 msg[0] = '\0';
777
778 QTEST_ASSERT(lhsExpr);
779 QTEST_ASSERT(rhsExpr);
780
781 if (QTestLog::verboseLevel() >= 2) {
782 std::snprintf(msg, maxMsgLen, "%s(%s, %s)", macroNameForOp(op), lhsExpr, rhsExpr);
783 QTestLog::info(msg, file, line);
784 }
785
786 if (success) {
787 if (QTest::expectFailMode) {
788 std::snprintf(msg, maxMsgLen, "%s(%s, %s) returned TRUE unexpectedly.",
789 macroNameForOp(op), lhsExpr, rhsExpr);
790 }
791 return checkStatement(success, msg, file, line);
792 }
793
794 const std::unique_ptr<const char[]> lhsPtr{ lhsFormatter(lhs) };
795 const std::unique_ptr<const char[]> rhsPtr{ rhsFormatter(rhs) };
796
797 if (!failureMessage)
798 failureMessage = failureMessageForOp(op);
799
800 formatFailMessage(msg, maxMsgLen, failureMessage, lhsPtr.get(), rhsPtr.get(),
801 lhsExpr, rhsExpr, op);
802
803 return checkStatement(success, msg, file, line);
804}
805
806bool QTestResult::report3WayResult(bool success,
807 const char *failureMessage,
808 const void *lhs, const void *rhs,
809 const char *(*lhsFormatter)(const void*),
810 const char *(*rhsFormatter)(const void*),
811 const char *lhsExpression, const char *rhsExpression,
812 const char *(*actualOrderFormatter)(const void *),
813 const char *(*expectedOrderFormatter)(const void *),
814 const void *actualOrder, const void *expectedOrder,
815 const char *expectedExpression,
816 const char *file, int line)
817{
818 char msg[maxMsgLen];
819 msg[0] = '\0';
820
821 QTEST_ASSERT(lhsExpression);
822 QTEST_ASSERT(rhsExpression);
823 QTEST_ASSERT(expectedExpression);
824 const char *macroName = macroNameForOp(QTest::ComparisonOperation::ThreeWayCompare);
825 const std::string actualExpression = std::string(lhsExpression) + " <=> " + rhsExpression;
826
827 if (QTestLog::verboseLevel() >= 2) {
828 std::snprintf(msg, maxMsgLen, "%s(%s, %s, %s)",
829 macroName, lhsExpression, rhsExpression, expectedExpression);
830 QTestLog::info(msg, file, line);
831 }
832
833 if (success) {
834 if (QTest::expectFailMode) {
835 std::snprintf(msg, maxMsgLen, "%s(%s, %s, %s) returned TRUE unexpectedly.",
836 macroName, lhsExpression, rhsExpression, expectedExpression);
837 }
838 return checkStatement(success, msg, file, line);
839 }
840 const std::unique_ptr<const char[]> lhsStr{lhsFormatter(lhs)};
841 const std::unique_ptr<const char[]> rhsStr{rhsFormatter(rhs)};
842
843 const std::unique_ptr<const char[]> actual{actualOrderFormatter(actualOrder)};
844 const std::unique_ptr<const char[]> expected{expectedOrderFormatter(expectedOrder)};
845
846 if (!failureMessage)
847 failureMessage = failureMessageForOp(QTest::ComparisonOperation::ThreeWayCompare);
848
849 // Left and Right compared parameters of QCOMPARE_3WAY
850 formatFailMessage(msg, maxMsgLen, failureMessage,
851 lhsStr.get(), rhsStr.get(),
852 lhsExpression, rhsExpression,
853 QTest::ComparisonOperation::ThreeWayCompare);
854
855 // Actual and Expected results of comparison
856 formatFailMessage(msg + strlen(msg), maxMsgLen - strlen(msg), "",
857 actual.get(), expected.get(),
858 actualExpression.c_str(), expectedExpression,
859 QTest::ComparisonOperation::CustomCompare);
860
861 return checkStatement(success, msg, file, line);
862}
863
864QT_END_NAMESPACE
Q_TESTLIB_EXPORT Q_DECL_COLD_FUNCTION const char * formatPropertyTestHelperFailure(char *msg, size_t maxMsgLen, const char *actual, const char *expected, const char *actualExpr, const char *expectedExpr)
static bool failed
static char * identifierTestFunc
static char * identifierDataTag
static char * identifierGlobalDataTag
static void resetFailed()
static const char * expectFailComment
static void storeIdentifierString(char *&dest, const char *src)
static bool skipCurrentTest
static bool blacklistCurrentTest
static const char * currentTestFunc
static void setFailed(bool failed)
static bool hasFailed()
static const char * currentTestObjectName
static QTestData * currentTestData
static char * identifierObjectName
static QTestData * currentGlobalTestData
static void updateIdentifier()
static int expectFailMode
static Q_DECL_COLD_FUNCTION void formatFailMessage(char *msg, size_t maxMsgLen, const char *failureMsg, const Actual &val1, const Expected &val2, const char *actual, const char *expected, QTest::ComparisonOperation op)
static Q_DECL_COLD_FUNCTION void formatFailMessage(char *msg, size_t maxMsgLen, const char *failureMsg, const char *val1, const char *val2, const char *actual, const char *expected, QTest::ComparisonOperation op)
static bool checkStatement(bool statement, const char *msg, const char *file, int line)
static bool isExpectFailData(const char *dataIndex)
static const char * rightArgNameForOp(QTest::ComparisonOperation op)
static constexpr size_t maxMsgLen
static const char * failureMessageForOp(QTest::ComparisonOperation op)
static int approx_wide_len(const char *s)
static bool compareHelper(bool success, const char *failureMsg, const char *actual, const char *expected, const char *file, int line)
static const char * currentAppName
static bool compareHelper(bool success, const char *failureMsg, const Actual &val1, const Expected &val2, const char *actual, const char *expected, const char *file, int line, bool hasValues=true)
static const char * macroNameForOp(QTest::ComparisonOperation op)
static const char * leftArgNameForOp(QTest::ComparisonOperation op)
static void clearExpectFail()