diff options
| author | Martin Hořeňovský | 2026-04-04 15:12:49 +0200 |
|---|---|---|
| committer | Martin Hořeňovský | 2026-04-04 15:12:56 +0200 |
| commit | 57f738b380d97c60b0ee920fa06b888d4f8c37c3 (patch) | |
| tree | f08df9dfa512e6dc59c0b75f32d84650f36129af /src | |
| parent | 1df10d28aec9967120c1faf10dae87adbd875b8b (diff) | |
| download | catch3-57f738b380d97c60b0ee920fa06b888d4f8c37c3.tar.gz | |
JUnit reporter output single failed assertion node per test case
Ideally JUnit tools would handle multiple failures per test case,
but they don't, so here we are.
Closes #1919
Diffstat (limited to 'src')
| -rw-r--r-- | src/catch2/reporters/catch_reporter_junit.cpp | 113 | ||||
| -rw-r--r-- | src/catch2/reporters/catch_reporter_junit.hpp | 2 |
2 files changed, 61 insertions, 54 deletions
diff --git a/src/catch2/reporters/catch_reporter_junit.cpp b/src/catch2/reporters/catch_reporter_junit.cpp index 3be4e2f9..00b45876 100644 --- a/src/catch2/reporters/catch_reporter_junit.cpp +++ b/src/catch2/reporters/catch_reporter_junit.cpp @@ -241,70 +241,77 @@ namespace Catch { void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) { if (assertionOrBenchmark.isAssertion()) { - writeAssertion(assertionOrBenchmark.asAssertion()); + // JUnit XML format supports only 1 error/failure/skip + // assertion elements per test case + if (writeAssertion(assertionOrBenchmark.asAssertion())) { + break; + } } } } - void JunitReporter::writeAssertion( AssertionStats const& stats ) { + bool JunitReporter::writeAssertion( AssertionStats const& stats ) { AssertionResult const& result = stats.assertionResult; - if ( !result.isOk() || - result.getResultType() == ResultWas::ExplicitSkip ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - case ResultWas::ExpressionFailed: - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - case ResultWas::ExplicitSkip: - elementName = "skipped"; - break; - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } + if ( result.isOk() && + result.getResultType() != ResultWas::ExplicitSkip ) { + return false; + } + std::string elementName; + switch ( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + case ResultWas::ExpressionFailed: + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + case ResultWas::ExplicitSkip: + elementName = "skipped"; + break; + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - xml.writeAttribute( "message"_sr, result.getExpression() ); - xml.writeAttribute( "type"_sr, result.getTestMacroName() ); + xml.writeAttribute( "message"_sr, result.getExpression() ); + xml.writeAttribute( "type"_sr, result.getTestMacroName() ); - ReusableStringStream rss; - if ( result.getResultType() == ResultWas::ExplicitSkip ) { - rss << "SKIPPED\n"; - } else { - rss << "FAILED:\n"; - if (result.hasExpression()) { - rss << " "; - rss << result.getExpressionInMacro(); - rss << '\n'; - } - if (result.hasExpandedExpression()) { - rss << "with expansion:\n"; - rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n'; - } + ReusableStringStream rss; + if ( result.getResultType() == ResultWas::ExplicitSkip ) { + rss << "SKIPPED\n"; + } else { + rss << "FAILED:\n"; + if ( result.hasExpression() ) { + rss << " "; + rss << result.getExpressionInMacro(); + rss << '\n'; } + if ( result.hasExpandedExpression() ) { + rss << "with expansion:\n"; + rss << TextFlow::Column( result.getExpandedExpression() ) + .indent( 2 ) + << '\n'; + } + } - if( result.hasMessage() ) - rss << result.getMessage() << '\n'; - for( auto const& msg : stats.infoMessages ) - if( msg.type == ResultWas::Info ) - rss << msg.message << '\n'; - - rss << "at " << result.getSourceInfo(); - xml.writeText( rss.str(), XmlFormatting::Newline ); + if ( result.hasMessage() ) { rss << result.getMessage() << '\n'; } + for ( auto const& msg : stats.infoMessages ) { + if ( msg.type == ResultWas::Info ) { rss << msg.message << '\n'; } } + + rss << "at " << result.getSourceInfo(); + xml.writeText( rss.str(), XmlFormatting::Newline ); + return true; } } // end namespace Catch diff --git a/src/catch2/reporters/catch_reporter_junit.hpp b/src/catch2/reporters/catch_reporter_junit.hpp index 7cb53c25..a265f78a 100644 --- a/src/catch2/reporters/catch_reporter_junit.hpp +++ b/src/catch2/reporters/catch_reporter_junit.hpp @@ -41,7 +41,7 @@ namespace Catch { bool testOkToFail ); void writeAssertions(SectionNode const& sectionNode); - void writeAssertion(AssertionStats const& stats); + bool writeAssertion(AssertionStats const& stats); XmlWriter xml; Timer suiteTimer; |