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