216void QTapTestLogger::addIncident(IncidentTypes type,
const char *description,
217 const char *file,
int line)
219 const bool isExpectedFail = type == XFail || type == BlacklistedXFail;
220 const bool ok = (m_firstExpectedFail.isEmpty()
221 && (type == Pass || type == BlacklistedPass || type == Skip
222 || type == XPass || type == BlacklistedXPass));
224 const char *
const incident = [type](
const char *priorXFail) {
228 case BlacklistedPass:
229 if (priorXFail[0] !=
'\0')
232 case XFail:
case BlacklistedXFail:
233 case XPass:
case BlacklistedXPass:
234 case BlacklistedFail:
239 if (priorXFail[0] !=
'\0')
245 return static_cast<
const char *>(
nullptr);
246 }(m_firstExpectedFail.constData());
248 QTestCharBuffer directive;
250 QTest::qt_asprintf(&directive,
"%s%s%s%s",
251 isExpectedFail ?
"" :
" # ", incident,
252 description && description[0] ?
" " :
"", description);
255 if (!isExpectedFail) {
256 m_gatherMessages =
false;
257 outputTestLine(ok, QTestLog::totalCount(), directive);
258 }
else if (m_gatherMessages && m_firstExpectedFail.isEmpty()) {
259 QTestPrivate::appendCharBuffer(&m_firstExpectedFail, directive);
263 if (!ok || !m_messages.isEmpty()) {
266 if (isExpectedFail) {
267 QTestCharBuffer message;
268 if (m_gatherMessages) {
271 directive.constData() + 4);
273 QTest::qt_asprintf(&message,
YAML_INDENT "# xfail:%s\n", directive.constData() + 4);
275 outputBuffer(message);
280 if (!isExpectedFail || m_gatherMessages) {
283#if QT_CONFIG(regularexpression)
284 enum class OperationType {
293 static const QRegularExpression verifyRegex(
294 u"^'(?<actualexpression>.*)' returned "
295 "(?<actual>\\w+)\\. \\((?<message>.*)\\)$"_s);
297 static const QRegularExpression compareRegex(
299 "\\s*Actual\\s+\\((?<actualexpression>.*)\\)\\s*: (?<actual>.*)\n"
300 "\\s*Expected\\s+\\((?<expectedexpresssion>.*)\\)\\s*: "
301 "(?<expected>.*)$"_s);
303 static const QRegularExpression compareOpRegex(
305 "\\s*Computed\\s+\\((?<actualexpression>.*)\\)\\s*: (?<actual>.*)\n"
306 "\\s*Baseline\\s+\\((?<expectedexpresssion>.*)\\)\\s*: "
307 "(?<expected>.*)$"_s);
309 const QString descriptionString = QString::fromUtf8(description);
310 QRegularExpressionMatch match = verifyRegex.match(descriptionString);
312 OperationType opType = OperationType::Unknown;
313 if (match.hasMatch())
314 opType = OperationType::Verify;
316 if (opType == OperationType::Unknown) {
317 match = compareRegex.match(descriptionString);
318 if (match.hasMatch())
319 opType = OperationType::Compare;
322 if (opType == OperationType::Unknown) {
323 match = compareOpRegex.match(descriptionString);
324 if (match.hasMatch())
325 opType = OperationType::CompareOp;
328 if (opType != OperationType::Unknown) {
329 QString message = match.captured(u"message");
330 QLatin1StringView comparisonType;
333 const auto parenthesize = [&match](QLatin1StringView key) -> QString {
334 return " ("_L1 % match.captured(key) % u')';
336 const QString actualExpression = parenthesize(
"actualexpression"_L1);
338 if (opType == OperationType::Verify) {
339 comparisonType =
"QVERIFY"_L1;
340 actual = match.captured(u"actual").toLower() % actualExpression;
341 expected = (actual.startsWith(
"true "_L1) ?
"false"_L1 :
"true"_L1)
343 if (message.isEmpty())
344 message = u"Verification failed"_s;
345 }
else if (opType == OperationType::Compare) {
346 comparisonType =
"QCOMPARE"_L1;
347 expected = match.captured(u"expected")
348 % parenthesize(
"expectedexpresssion"_L1);
349 actual = match.captured(u"actual") % actualExpression;
351 struct ComparisonInfo {
352 const char *comparisonType;
353 const char *comparisonStringOp;
356 const auto info = [](
const QString &err) -> ComparisonInfo {
357 if (err.contains(
"different"_L1))
358 return {
"QCOMPARE_NE",
"!= " };
359 else if (err.contains(
"less than or equal to"_L1))
360 return {
"QCOMPARE_LE",
"<= " };
361 else if (err.contains(
"greater than or equal to"_L1))
362 return {
"QCOMPARE_GE",
">= " };
363 else if (err.contains(
"less than"_L1))
364 return {
"QCOMPARE_LT",
"< " };
365 else if (err.contains(
"greater than"_L1))
366 return {
"QCOMPARE_GT",
"> " };
367 else if (err.contains(
"to be equal to"_L1))
368 return {
"QCOMPARE_EQ",
"== " };
370 return {
"Unknown",
"" };
372 comparisonType = QLatin1StringView(info.comparisonType);
373 expected = QLatin1StringView(info.comparisonStringOp)
374 % match.captured(u"expected")
375 % parenthesize(
"expectedexpresssion"_L1);
376 actual = match.captured(u"actual") % actualExpression;
379 QTestCharBuffer diagnosticsYamlish;
380 QTest::qt_asprintf(&diagnosticsYamlish,
389 indent, comparisonType.latin1(),
390 indent, qPrintable(message),
391 indent, qPrintable(expected), indent, qPrintable(actual),
392 indent, qPrintable(expected), indent, qPrintable(actual)
395 outputBuffer(diagnosticsYamlish);
398 if (description && !incident) {
399 QTestCharBuffer unparsableDescription;
400 QTest::qt_asprintf(&unparsableDescription,
YAML_INDENT "# %s\n", description);
401 outputBuffer(unparsableDescription);
406 QTestCharBuffer location;
407 QTest::qt_asprintf(&location,
409 "%sat: %s::%s() (%s:%d)\n"
416 indent, QTestResult::currentTestObjectName(),
417 QTestResult::currentTestFunction(),
418 file, line, indent, file, indent, line
420 outputBuffer(location);
429void QTapTestLogger::addMessage(MessageTypes type,
const QString &message,
430 const char *file,
int line)
434 const char *
const flavor = [type]() {
436 case QDebug:
return "debug";
437 case QInfo:
return "info";
438 case QWarning:
return "warning";
439 case QCritical:
return "critical";
440 case QFatal:
return "fatal";
442 case Info:
return "# inform";
443 case Warn:
return "# warn";
445 return "unrecognised message";
448 QTestCharBuffer diagnostic;
449 if (!m_gatherMessages) {
450 QTest::qt_asprintf(&diagnostic,
"%s%s: %s\n",
451 flavor[0] ==
'#' ?
"" :
"# ",
452 flavor, qPrintable(message));
453 outputString(diagnostic.constData());
454 }
else if (flavor[0] ==
'#') {
455 QTest::qt_asprintf(&diagnostic,
YAML_INDENT "%s: %s\n",
456 flavor, qPrintable(message));
457 QTestPrivate::appendCharBuffer(&m_comments, diagnostic);
463 flavor, qPrintable(message));
464 QTestPrivate::appendCharBuffer(&m_messages, diagnostic);