Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorMartin Hořeňovský2026-04-04 15:12:49 +0200
committerMartin Hořeňovský2026-04-04 15:12:56 +0200
commit57f738b380d97c60b0ee920fa06b888d4f8c37c3 (patch)
treef08df9dfa512e6dc59c0b75f32d84650f36129af /src
parent1df10d28aec9967120c1faf10dae87adbd875b8b (diff)
downloadcatch3-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.cpp113
-rw-r--r--src/catch2/reporters/catch_reporter_junit.hpp2
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;