mirror of
https://github.com/catchorg/Catch2.git
synced 2024-12-28 05:33:30 +01:00
02c7e41c7c
SCENARIO does not add leading spaces to the test name (only BDD-style section names are modified), so the trimming is not necessary. But if the name is trimmed, it makes it harder to correlate the output of XML reporter with tests that have leading spaces in their name: e.g. these tests will have the same name attribute: TEST_CASE("Test") {} TEST_CASE(" Test") {}
200 lines
8.6 KiB
C++
200 lines
8.6 KiB
C++
/*
|
|
* Created by Phil on 28/10/2010.
|
|
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
|
|
*
|
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
*/
|
|
#ifndef TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
|
|
#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
|
|
|
|
#include "catch_reporter_bases.hpp"
|
|
|
|
#include "../internal/catch_capture.hpp"
|
|
#include "../internal/catch_reporter_registrars.hpp"
|
|
#include "../internal/catch_xmlwriter.hpp"
|
|
#include "../internal/catch_timer.h"
|
|
|
|
namespace Catch {
|
|
class XmlReporter : public StreamingReporterBase {
|
|
public:
|
|
XmlReporter( ReporterConfig const& _config )
|
|
: StreamingReporterBase( _config ),
|
|
m_sectionDepth( 0 )
|
|
{
|
|
m_reporterPrefs.shouldRedirectStdOut = true;
|
|
}
|
|
|
|
virtual ~XmlReporter() CATCH_OVERRIDE;
|
|
|
|
static std::string getDescription() {
|
|
return "Reports test results as an XML document";
|
|
}
|
|
|
|
public: // StreamingReporterBase
|
|
|
|
virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE {
|
|
StreamingReporterBase::noMatchingTestCases( s );
|
|
}
|
|
|
|
virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
|
|
StreamingReporterBase::testRunStarting( testInfo );
|
|
m_xml.setStream( stream );
|
|
m_xml.startElement( "Catch" );
|
|
if( !m_config->name().empty() )
|
|
m_xml.writeAttribute( "name", m_config->name() );
|
|
}
|
|
|
|
virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
|
|
StreamingReporterBase::testGroupStarting( groupInfo );
|
|
m_xml.startElement( "Group" )
|
|
.writeAttribute( "name", groupInfo.name );
|
|
}
|
|
|
|
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
|
|
StreamingReporterBase::testCaseStarting(testInfo);
|
|
m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.name );
|
|
|
|
if ( m_config->showDurations() == ShowDurations::Always )
|
|
m_testCaseTimer.start();
|
|
}
|
|
|
|
virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
|
|
StreamingReporterBase::sectionStarting( sectionInfo );
|
|
if( m_sectionDepth++ > 0 ) {
|
|
m_xml.startElement( "Section" )
|
|
.writeAttribute( "name", trim( sectionInfo.name ) )
|
|
.writeAttribute( "description", sectionInfo.description );
|
|
}
|
|
}
|
|
|
|
virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { }
|
|
|
|
virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
|
|
const AssertionResult& assertionResult = assertionStats.assertionResult;
|
|
|
|
// Print any info messages in <Info> tags.
|
|
if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
|
|
for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
|
|
it != itEnd;
|
|
++it ) {
|
|
if( it->type == ResultWas::Info ) {
|
|
m_xml.scopedElement( "Info" )
|
|
.writeText( it->message );
|
|
} else if ( it->type == ResultWas::Warning ) {
|
|
m_xml.scopedElement( "Warning" )
|
|
.writeText( it->message );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Drop out if result was successful but we're not printing them.
|
|
if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) )
|
|
return true;
|
|
|
|
// Print the expression if there is one.
|
|
if( assertionResult.hasExpression() ) {
|
|
m_xml.startElement( "Expression" )
|
|
.writeAttribute( "success", assertionResult.succeeded() )
|
|
.writeAttribute( "type", assertionResult.getTestMacroName() )
|
|
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
|
.writeAttribute( "line", assertionResult.getSourceInfo().line );
|
|
|
|
m_xml.scopedElement( "Original" )
|
|
.writeText( assertionResult.getExpression() );
|
|
m_xml.scopedElement( "Expanded" )
|
|
.writeText( assertionResult.getExpandedExpression() );
|
|
}
|
|
|
|
// And... Print a result applicable to each result type.
|
|
switch( assertionResult.getResultType() ) {
|
|
case ResultWas::ThrewException:
|
|
m_xml.scopedElement( "Exception" )
|
|
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
|
.writeAttribute( "line", assertionResult.getSourceInfo().line )
|
|
.writeText( assertionResult.getMessage() );
|
|
break;
|
|
case ResultWas::FatalErrorCondition:
|
|
m_xml.scopedElement( "Fatal Error Condition" )
|
|
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
|
.writeAttribute( "line", assertionResult.getSourceInfo().line )
|
|
.writeText( assertionResult.getMessage() );
|
|
break;
|
|
case ResultWas::Info:
|
|
m_xml.scopedElement( "Info" )
|
|
.writeText( assertionResult.getMessage() );
|
|
break;
|
|
case ResultWas::Warning:
|
|
// Warning will already have been written
|
|
break;
|
|
case ResultWas::ExplicitFailure:
|
|
m_xml.scopedElement( "Failure" )
|
|
.writeText( assertionResult.getMessage() );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if( assertionResult.hasExpression() )
|
|
m_xml.endElement();
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
|
|
StreamingReporterBase::sectionEnded( sectionStats );
|
|
if( --m_sectionDepth > 0 ) {
|
|
XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
|
|
e.writeAttribute( "successes", sectionStats.assertions.passed );
|
|
e.writeAttribute( "failures", sectionStats.assertions.failed );
|
|
e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
|
|
|
|
if ( m_config->showDurations() == ShowDurations::Always )
|
|
e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
|
|
|
|
m_xml.endElement();
|
|
}
|
|
}
|
|
|
|
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
|
|
StreamingReporterBase::testCaseEnded( testCaseStats );
|
|
XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
|
|
e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
|
|
|
|
if ( m_config->showDurations() == ShowDurations::Always )
|
|
e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
|
|
|
|
m_xml.endElement();
|
|
}
|
|
|
|
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
|
|
StreamingReporterBase::testGroupEnded( testGroupStats );
|
|
// TODO: Check testGroupStats.aborting and act accordingly.
|
|
m_xml.scopedElement( "OverallResults" )
|
|
.writeAttribute( "successes", testGroupStats.totals.assertions.passed )
|
|
.writeAttribute( "failures", testGroupStats.totals.assertions.failed )
|
|
.writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
|
|
m_xml.endElement();
|
|
}
|
|
|
|
virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
|
|
StreamingReporterBase::testRunEnded( testRunStats );
|
|
m_xml.scopedElement( "OverallResults" )
|
|
.writeAttribute( "successes", testRunStats.totals.assertions.passed )
|
|
.writeAttribute( "failures", testRunStats.totals.assertions.failed )
|
|
.writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
|
|
m_xml.endElement();
|
|
}
|
|
|
|
private:
|
|
Timer m_testCaseTimer;
|
|
XmlWriter m_xml;
|
|
int m_sectionDepth;
|
|
};
|
|
|
|
INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
|
|
|
|
} // end namespace Catch
|
|
|
|
#endif // TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
|