QTestLib: Speed up QCOMPARE for float, double, int, unsigned

Factor out a helper template formatting the QCOMPARE failure message
delaying the formatting of the parameters with toString() and use that
for float, double, int and unsigned. This removes the need to always
format and allocate strings for the operands even in the success case,
speeding up the QColor test from 3.3s to 700ms (Windows/release).

Task-number: QTBUG-38890
Change-Id: I999484765bdaed921d3fc35f35a9fbbcd82a9704
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Friedemann Kleint 2019-05-21 12:47:44 +02:00
parent 9c8d1ca18b
commit 94aa350621
4 changed files with 154 additions and 23 deletions

View File

@ -2550,9 +2550,9 @@ bool QTest::qCompare(qfloat16 const &t1, qfloat16 const &t2, const char *actual,
bool QTest::qCompare(float const &t1, float const &t2, const char *actual, const char *expected,
const char *file, int line)
{
return compare_helper(floatingCompare(t1, t2),
"Compared floats are not the same (fuzzy compare)",
toString(t1), toString(t2), actual, expected, file, line);
return QTestResult::compare(floatingCompare(t1, t2),
"Compared floats are not the same (fuzzy compare)",
t1, t2, actual, expected, file, line);
}
/*! \fn bool QTest::qCompare(const double &t1, const double &t2, const char *actual, const char *expected, const char *file, int line)
@ -2561,9 +2561,33 @@ bool QTest::qCompare(float const &t1, float const &t2, const char *actual, const
bool QTest::qCompare(double const &t1, double const &t2, const char *actual, const char *expected,
const char *file, int line)
{
return compare_helper(floatingCompare(t1, t2),
"Compared doubles are not the same (fuzzy compare)",
toString(t1), toString(t2), actual, expected, file, line);
return QTestResult::compare(floatingCompare(t1, t2),
"Compared doubles are not the same (fuzzy compare)",
t1, t2, actual, expected, file, line);
}
/*! \fn bool QTest::qCompare(int t1, int t2, const char *actual, const char *expected, const char *file, int line)
\internal
\since 5.14
*/
bool QTest::qCompare(int t1, int t2, const char *actual, const char *expected,
const char *file, int line)
{
return QTestResult::compare(t1 == t2,
"Compared values are not the same",
t1, t2, actual, expected, file, line);
}
/*! \fn bool QTest::qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected, const char *file, int line)
\internal
\since 5.14
*/
bool QTest::qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected,
const char *file, int line)
{
return QTestResult::compare(t1 == t2,
"Compared values are not the same",
t1, t2, actual, expected, file, line);
}
/*! \fn bool QTest::qCompare(const double &t1, const float &t2, const char *actual, const char *expected, const char *file, int line)

View File

@ -363,6 +363,12 @@ namespace QTest
Q_TESTLIB_EXPORT bool qCompare(double const &t1, double const &t2,
const char *actual, const char *expected, const char *file, int line);
Q_TESTLIB_EXPORT bool qCompare(int t1, int t2, const char *actual, const char *expected,
const char *file, int line);
Q_TESTLIB_EXPORT bool qCompare(unsigned t1, unsigned t2, const char *actual, const char *expected,
const char *file, int line);
inline bool compare_ptr_helper(const volatile void *t1, const volatile void *t2, const char *actual,
const char *expected, const char *file, int line)
{

View File

@ -42,6 +42,7 @@
#include <QtTest/private/qtestlog_p.h>
#include <QtTest/qtestdata.h>
#include <QtTest/qtestcase.h>
#include <QtTest/qtestassert.h>
#include <stdlib.h>
@ -265,17 +266,54 @@ bool QTestResult::verify(bool statement, const char *statementStr,
return checkStatement(statement, msg, file, line);
}
bool QTestResult::compare(bool success, const char *failureMsg,
char *val1, char *val2,
const char *actual, const char *expected,
const char *file, int line)
// Format failures using the toString() template
template <class Actual, class Expected>
void formatFailMessage(char *msg, size_t maxMsgLen,
const char *failureMsg,
const Actual &val1, const Expected &val2,
const char *actual, const char *expected)
{
QTEST_ASSERT(expected);
QTEST_ASSERT(actual);
auto val1S = QTest::toString(val1);
auto val2S = QTest::toString(val2);
size_t len1 = mbstowcs(nullptr, actual, maxMsgLen); // Last parameter is not ignored on QNX
size_t len2 = mbstowcs(nullptr, expected, maxMsgLen); // (result is never larger than this).
qsnprintf(msg, maxMsgLen, "%s\n Actual (%s)%*s %s\n Expected (%s)%*s %s",
failureMsg,
actual, qMax(len1, len2) - len1 + 1, ":", val1S ? val1S : "<null>",
expected, qMax(len1, len2) - len2 + 1, ":", val2S ? val2S : "<null>");
delete [] val1S;
delete [] val2S;
}
// Overload to format failures for "const char *" - no need to strdup().
void formatFailMessage(char *msg, size_t maxMsgLen,
const char *failureMsg,
const char *val1, const char *val2,
const char *actual, const char *expected)
{
size_t len1 = mbstowcs(nullptr, actual, maxMsgLen); // Last parameter is not ignored on QNX
size_t len2 = mbstowcs(nullptr, expected, maxMsgLen); // (result is never larger than this).
qsnprintf(msg, maxMsgLen, "%s\n Actual (%s)%*s %s\n Expected (%s)%*s %s",
failureMsg,
actual, qMax(len1, len2) - len1 + 1, ":", val1 ? val1 : "<null>",
expected, qMax(len1, len2) - len2 + 1, ":", val2 ? val2 : "<null>");
}
template <class Actual, class Expected>
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)
{
const size_t maxMsgLen = 1024;
char msg[maxMsgLen] = {'\0'};
QTEST_ASSERT(expected);
QTEST_ASSERT(actual);
if (QTestLog::verboseLevel() >= 2) {
qsnprintf(msg, maxMsgLen, "QCOMPARE(%s, %s)", actual, expected);
QTestLog::info(msg, file, line);
@ -289,20 +327,68 @@ bool QTestResult::compare(bool success, const char *failureMsg,
qsnprintf(msg, maxMsgLen,
"QCOMPARE(%s, %s) returned TRUE unexpectedly.", actual, expected);
}
} else if (val1 || val2) {
size_t len1 = mbstowcs(NULL, actual, maxMsgLen); // Last parameter is not ignored on QNX
size_t len2 = mbstowcs(NULL, expected, maxMsgLen); // (result is never larger than this).
qsnprintf(msg, maxMsgLen, "%s\n Actual (%s)%*s %s\n Expected (%s)%*s %s",
failureMsg,
actual, qMax(len1, len2) - len1 + 1, ":", val1 ? val1 : "<null>",
expected, qMax(len1, len2) - len2 + 1, ":", val2 ? val2 : "<null>");
} else
qsnprintf(msg, maxMsgLen, "%s", failureMsg);
return checkStatement(success, msg, file, line);
}
if (!hasValues) {
qsnprintf(msg, maxMsgLen, "%s", failureMsg);
return checkStatement(success, msg, file, line);
}
formatFailMessage(msg, maxMsgLen, failureMsg, val1, val2, actual, expected);
return checkStatement(success, msg, file, line);
}
bool QTestResult::compare(bool success, const char *failureMsg,
char *val1, char *val2,
const char *actual, const char *expected,
const char *file, int line)
{
const bool result = compareHelper(success, failureMsg,
val1 != nullptr ? val1 : "<null>",
val2 != nullptr ? val2 : "<null>",
actual, expected, file, line,
val1 != nullptr && val2 != nullptr);
// Our caller got these from QTest::toString()
delete [] val1;
delete [] val2;
return checkStatement(success, msg, file, line);
return result;
}
bool QTestResult::compare(bool success, const char *failureMsg,
double val1, double val2,
const char *actual, const char *expected,
const char *file, int line)
{
return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
}
bool QTestResult::compare(bool success, const char *failureMsg,
float val1, float val2,
const char *actual, const char *expected,
const char *file, int line)
{
return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
}
bool QTestResult::compare(bool success, const char *failureMsg,
int val1, int val2,
const char *actual, const char *expected,
const char *file, int line)
{
return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
}
bool QTestResult::compare(bool success, const char *failureMsg,
unsigned val1, unsigned val2,
const char *actual, const char *expected,
const char *file, int line)
{
return compareHelper(success, failureMsg, val1, val2, actual, expected, file, line);
}
void QTestResult::addFailure(const char *message, const char *file, int line)

View File

@ -79,7 +79,22 @@ public:
char *val1, char *val2,
const char *actual, const char *expected,
const char *file, int line);
static bool compare(bool success, const char *failureMsg,
double val1, double val2,
const char *actual, const char *expected,
const char *file, int line);
static bool compare(bool success, const char *failureMsg,
float val1, float val2,
const char *actual, const char *expected,
const char *file, int line);
static bool compare(bool success, const char *failureMsg,
int val1, int val2,
const char *actual, const char *expected,
const char *file, int line);
static bool compare(bool success, const char *failureMsg,
unsigned val1, unsigned val2,
const char *actual, const char *expected,
const char *file, int line);
static void setCurrentGlobalTestData(QTestData *data);
static void setCurrentTestData(QTestData *data);
static void setCurrentTestFunction(const char *func);