From b0e53a8ee006cee203a40bf3c1454e8806135d9c Mon Sep 17 00:00:00 2001 From: "Sean D. Cline" Date: Sat, 11 Oct 2014 17:20:55 -0400 Subject: [PATCH 1/3] Move the xml reporter away from the deprecated IReporter interface. --- include/internal/catch_impl.hpp | 2 - include/reporters/catch_reporter_xml.hpp | 160 +++++++++++++---------- 2 files changed, 94 insertions(+), 68 deletions(-) diff --git a/include/internal/catch_impl.hpp b/include/internal/catch_impl.hpp index cc03ae08..820b4975 100644 --- a/include/internal/catch_impl.hpp +++ b/include/internal/catch_impl.hpp @@ -88,8 +88,6 @@ namespace Catch { Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} - - INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter ) } #ifdef __clang__ diff --git a/include/reporters/catch_reporter_xml.hpp b/include/reporters/catch_reporter_xml.hpp index 4687471a..6b31107a 100644 --- a/include/reporters/catch_reporter_xml.hpp +++ b/include/reporters/catch_reporter_xml.hpp @@ -15,78 +15,83 @@ #include "../internal/catch_xmlwriter.hpp" namespace Catch { - class XmlReporter : public SharedImpl { + class XmlReporter : public StreamingReporterBase { public: - XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {} + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + {} + virtual ~XmlReporter(); + static std::string getDescription() { return "Reports test results as an XML document"; } - virtual ~XmlReporter(); - private: // IReporter - - virtual bool shouldRedirectStdout() const { - return true; + public: // StreamingReporterBase + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; } - virtual void StartTesting() { - m_xml.setStream( m_config.stream() ); + virtual void noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); m_xml.startElement( "Catch" ); - if( !m_config.fullConfig()->name().empty() ) - m_xml.writeAttribute( "name", m_config.fullConfig()->name() ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); } - virtual void EndTesting( const Totals& totals ) { - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", totals.assertions.passed ) - .writeAttribute( "failures", totals.assertions.failed ) - .writeAttribute( "expectedFailures", totals.assertions.failedButOk ); - m_xml.endElement(); - } - - virtual void StartGroup( const std::string& groupName ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) - .writeAttribute( "name", groupName ); + .writeAttribute( "name", groupInfo.name ); } - virtual void EndGroup( const std::string&, const Totals& totals ) { - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", totals.assertions.passed ) - .writeAttribute( "failures", totals.assertions.failed ) - .writeAttribute( "expectedFailures", totals.assertions.failedButOk ); - m_xml.endElement(); + virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); } - virtual void StartSection( const std::string& sectionName, const std::string& description ) { + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionName ) ) - .writeAttribute( "description", description ); - } - } - virtual void NoAssertionsInSection( const std::string& ) {} - virtual void NoAssertionsInTestCase( const std::string& ) {} - - virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) { - if( --m_sectionDepth > 0 ) { - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", assertions.passed ) - .writeAttribute( "failures", assertions.failed ) - .writeAttribute( "expectedFailures", assertions.failedButOk ); - m_xml.endElement(); + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); } } - virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) { - m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); - m_currentTestSuccess = true; - } + virtual void assertionStarting( AssertionInfo const& ) { } - virtual void Result( const Catch::AssertionResult& assertionResult ) { - if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok ) - return; + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::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() ) @@ -97,23 +102,23 @@ namespace Catch { .writeText( assertionResult.getExpression() ); m_xml.scopedElement( "Expanded" ) .writeText( assertionResult.getExpandedExpression() ); - m_currentTestSuccess &= assertionResult.succeeded(); } + // And... Print a result applicable to each result type. switch( assertionResult.getResultType() ) { + default: + break; case ResultWas::ThrewException: m_xml.scopedElement( "Exception" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() ); - m_currentTestSuccess = false; break; case ResultWas::FatalErrorCondition: m_xml.scopedElement( "Fatal Error Condition" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() ); - m_currentTestSuccess = false; break; case ResultWas::Info: m_xml.scopedElement( "Info" ) @@ -126,36 +131,59 @@ namespace Catch { case ResultWas::ExplicitFailure: m_xml.scopedElement( "Failure" ) .writeText( assertionResult.getMessage() ); - m_currentTestSuccess = false; - break; - case ResultWas::Unknown: - case ResultWas::Ok: - case ResultWas::FailureBit: - case ResultWas::ExpressionFailed: - case ResultWas::Exception: - case ResultWas::DidntThrowException: break; } + if( assertionResult.hasExpression() ) m_xml.endElement(); + + return true; } - virtual void Aborted() { - // !TBD + virtual void sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", sectionStats.assertions.passed ) + .writeAttribute( "failures", sectionStats.assertions.failed ) + .writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + m_xml.endElement(); + } } - virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) { - m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + m_xml.scopedElement( "OverallResult" ) + .writeAttribute( "success", testCaseStats.totals.assertions.allPassed() ); + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + 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 ) { + 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: - ReporterConfig m_config; - bool m_currentTestSuccess; XmlWriter m_xml; int m_sectionDepth; }; + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + } // end namespace Catch #endif // TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED From ea81e98d6a01fc7858ac2339ddde90b7cb8162bd Mon Sep 17 00:00:00 2001 From: "Sean D. Cline" Date: Sat, 11 Oct 2014 19:57:45 -0400 Subject: [PATCH 2/3] XmlReporter enhancement: Add attributes for duration when requested by the command line. --- include/reporters/catch_reporter_xml.hpp | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/include/reporters/catch_reporter_xml.hpp b/include/reporters/catch_reporter_xml.hpp index 6b31107a..530bb3c5 100644 --- a/include/reporters/catch_reporter_xml.hpp +++ b/include/reporters/catch_reporter_xml.hpp @@ -13,6 +13,7 @@ #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 { @@ -56,6 +57,9 @@ namespace Catch { virtual void testCaseStarting( TestCaseInfo const& testInfo ) { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); } virtual void sectionStarting( SectionInfo const& sectionInfo ) { @@ -143,18 +147,26 @@ namespace Catch { virtual void sectionEnded( SectionStats const& sectionStats ) { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", sectionStats.assertions.passed ) - .writeAttribute( "failures", sectionStats.assertions.failed ) - .writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + 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 ) { StreamingReporterBase::testCaseEnded( testCaseStats ); - m_xml.scopedElement( "OverallResult" ) - .writeAttribute( "success", testCaseStats.totals.assertions.allPassed() ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allPassed() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + m_xml.endElement(); } @@ -178,6 +190,7 @@ namespace Catch { } private: + Timer m_testCaseTimer; XmlWriter m_xml; int m_sectionDepth; }; From 6e996956103a390046525a88487cbfe739625c45 Mon Sep 17 00:00:00 2001 From: "Sean D. Cline" Date: Sat, 11 Oct 2014 20:01:14 -0400 Subject: [PATCH 3/3] XmlReporter enhancement: Add an attribute for the macro name of an expression. --- include/reporters/catch_reporter_xml.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/reporters/catch_reporter_xml.hpp b/include/reporters/catch_reporter_xml.hpp index 530bb3c5..1b7c0199 100644 --- a/include/reporters/catch_reporter_xml.hpp +++ b/include/reporters/catch_reporter_xml.hpp @@ -99,6 +99,7 @@ namespace Catch { 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 );