From 9327d1aaf79d4214db78ec86b8b6df7738bd1875 Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Mon, 30 May 2022 12:07:17 +0200 Subject: [PATCH] Testlib: teach TAP test logger to support new QCOMPARE_* operators The TAP test logger will now correctly print comparison types such as QCOMPARE_NE or QCOMPARE_LT, and also provide a proper expected/wanted value (by adding proper arithmetical operators in front of the value). Sample output: type: QCOMPARE_GE message: Left value is expected to be greater than or equal to right value, but is not wanted: >= 1 (rhs) found: 0 (lhs) expected: >= 1 (rhs) actual: 0 (lhs) at: tst_ExtendedCompare::compareUnregistereEnum() (tst_extendedcompare.cpp:232) file: tst_extendedcompare.cpp line: 232 As a drive-by: make some variables const. Task-number: QTBUG-98873 Change-Id: Idb54eaabcb937b42d3fc844f30041aab82d73f69 Reviewed-by: Edward Welbourne --- src/testlib/qtaptestlogger.cpp | 81 +++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/src/testlib/qtaptestlogger.cpp b/src/testlib/qtaptestlogger.cpp index b6f8c871443..b6fa4295bc3 100644 --- a/src/testlib/qtaptestlogger.cpp +++ b/src/testlib/qtaptestlogger.cpp @@ -281,25 +281,53 @@ void QTapTestLogger::addIncident(IncidentTypes type, const char *description, const char *indent = isExpectedFail ? YAML_INDENT YAML_INDENT YAML_INDENT : YAML_INDENT; if (!ok) { #if QT_CONFIG(regularexpression) + enum class OperationType { + Unknown, + Compare, /* Plain old QCOMPARE */ + Verify, /* QVERIFY */ + CompareOp, /* QCOMPARE_OP */ + }; + // This is fragile, but unfortunately testlib doesn't plumb // the expected and actual values to the loggers (yet). - static QRegularExpression verifyRegex(u"^'(?.*)' returned " - "(?\\w+).+\\((?.*)\\)$"_s); + static const QRegularExpression verifyRegex( + u"^'(?.*)' returned " + "(?\\w+).+\\((?.*)\\)$"_s); - static QRegularExpression compareRegex( + static const QRegularExpression compareRegex( u"^(?.*)\n" "\\s*Actual\\s+\\((?.*)\\)\\s*: (?.*)\n" "\\s*Expected\\s+\\((?.*)\\)\\s*: " "(?.*)$"_s); - QString descriptionString = QString::fromUtf8(description); - QRegularExpressionMatch match = verifyRegex.match(descriptionString); - const bool isVerify = match.hasMatch(); - if (!isVerify) - match = compareRegex.match(descriptionString); + static const QRegularExpression compareOpRegex( + u"^(?.*)\n" + "\\s*Left\\s+\\((?.*)\\)\\s*: (?.*)\n" + "\\s*Right\\s+\\((?.*)\\)\\s*: " + "(?.*)$"_s); - if (match.hasMatch()) { + const QString descriptionString = QString::fromUtf8(description); + QRegularExpressionMatch match = verifyRegex.match(descriptionString); + + OperationType opType = OperationType::Unknown; + if (match.hasMatch()) + opType = OperationType::Verify; + + if (opType == OperationType::Unknown) { + match = compareRegex.match(descriptionString); + if (match.hasMatch()) + opType = OperationType::Compare; + } + + if (opType == OperationType::Unknown) { + match = compareOpRegex.match(descriptionString); + if (match.hasMatch()) + opType = OperationType::CompareOp; + } + + if (opType != OperationType::Unknown) { QString message = match.captured(u"message"); + QLatin1StringView comparisonType; QString expected; QString actual; const auto parenthesize = [&match](QLatin1StringView key) -> QString { @@ -307,16 +335,45 @@ void QTapTestLogger::addIncident(IncidentTypes type, const char *description, }; const QString actualExpression = parenthesize("actualexpression"_L1); - if (isVerify) { + if (opType == OperationType::Verify) { + comparisonType = "QVERIFY"_L1; actual = match.captured(u"actual").toLower() % actualExpression; expected = (actual.startsWith("true "_L1) ? "false"_L1 : "true"_L1) % actualExpression; if (message.isEmpty()) message = u"Verification failed"_s; - } else { + } else if (opType == OperationType::Compare) { + comparisonType = "QCOMPARE"_L1; expected = match.captured(u"expected") % parenthesize("expectedexpresssion"_L1); actual = match.captured(u"actual") % actualExpression; + } else { + struct ComparisonInfo { + const char *comparisonType; + const char *comparisonStringOp; + }; + // get a proper comparison type based on the error message + const auto info = [](const QString &err) -> ComparisonInfo { + if (err.contains("different"_L1)) + return { "QCOMPARE_NE", "!= " }; + else if (err.contains("less than or equal to"_L1)) + return { "QCOMPARE_LE", "<= " }; + else if (err.contains("greater than or equal to"_L1)) + return { "QCOMPARE_GE", ">= " }; + else if (err.contains("less than"_L1)) + return { "QCOMPARE_LT", "< " }; + else if (err.contains("greater than"_L1)) + return { "QCOMPARE_GT", "> " }; + else if (err.contains("to be equal to"_L1)) + return { "QCOMPARE_EQ", "== " }; + else + return { "Unknown", "" }; + }(message); + comparisonType = QLatin1StringView(info.comparisonType); + expected = QLatin1StringView(info.comparisonStringOp) + % match.captured(u"expected") + % parenthesize("expectedexpresssion"_L1); + actual = match.captured(u"actual") % actualExpression; } QTestCharBuffer diagnosticsYamlish; @@ -329,7 +386,7 @@ void QTapTestLogger::addIncident(IncidentTypes type, const char *description, "%sfound: %s\n" "%sexpected: %s\n" "%sactual: %s\n", - indent, isVerify ? "QVERIFY" : "QCOMPARE", + indent, comparisonType.latin1(), indent, qPrintable(message), indent, qPrintable(expected), indent, qPrintable(actual), indent, qPrintable(expected), indent, qPrintable(actual)