1 /* 2 * Created by Phil on 28/10/2010. 3 * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 9 #include "catch_reporter_xml.h" 10 11 #include "../internal/catch_capture.hpp" 12 #include "../internal/catch_reporter_registrars.hpp" 13 14 #if defined(_MSC_VER) 15 #pragma warning(push) 16 #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch 17 // Note that 4062 (not all labels are handled 18 // and default is missing) is enabled 19 #endif 20 21 namespace Catch { XmlReporter(ReporterConfig const & _config)22 XmlReporter::XmlReporter( ReporterConfig const& _config ) 23 : StreamingReporterBase( _config ), 24 m_xml(_config.stream()) 25 { 26 m_reporterPrefs.shouldRedirectStdOut = true; 27 m_reporterPrefs.shouldReportAllAssertions = true; 28 } 29 30 XmlReporter::~XmlReporter() = default; 31 getDescription()32 std::string XmlReporter::getDescription() { 33 return "Reports test results as an XML document"; 34 } 35 getStylesheetRef() const36 std::string XmlReporter::getStylesheetRef() const { 37 return std::string(); 38 } 39 writeSourceInfo(SourceLineInfo const & sourceInfo)40 void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { 41 m_xml 42 .writeAttribute( "filename", sourceInfo.file ) 43 .writeAttribute( "line", sourceInfo.line ); 44 } 45 noMatchingTestCases(std::string const & s)46 void XmlReporter::noMatchingTestCases( std::string const& s ) { 47 StreamingReporterBase::noMatchingTestCases( s ); 48 } 49 testRunStarting(TestRunInfo const & testInfo)50 void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { 51 StreamingReporterBase::testRunStarting( testInfo ); 52 std::string stylesheetRef = getStylesheetRef(); 53 if( !stylesheetRef.empty() ) 54 m_xml.writeStylesheetRef( stylesheetRef ); 55 m_xml.startElement( "Catch" ); 56 if( !m_config->name().empty() ) 57 m_xml.writeAttribute( "name", m_config->name() ); 58 if( m_config->rngSeed() != 0 ) 59 m_xml.scopedElement( "Randomness" ) 60 .writeAttribute( "seed", m_config->rngSeed() ); 61 } 62 testGroupStarting(GroupInfo const & groupInfo)63 void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { 64 StreamingReporterBase::testGroupStarting( groupInfo ); 65 m_xml.startElement( "Group" ) 66 .writeAttribute( "name", groupInfo.name ); 67 } 68 testCaseStarting(TestCaseInfo const & testInfo)69 void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { 70 StreamingReporterBase::testCaseStarting(testInfo); 71 m_xml.startElement( "TestCase" ) 72 .writeAttribute( "name", trim( testInfo.name ) ) 73 .writeAttribute( "description", testInfo.description ) 74 .writeAttribute( "tags", testInfo.tagsAsString() ); 75 76 writeSourceInfo( testInfo.lineInfo ); 77 78 if ( m_config->showDurations() == ShowDurations::Always ) 79 m_testCaseTimer.start(); 80 m_xml.ensureTagClosed(); 81 } 82 sectionStarting(SectionInfo const & sectionInfo)83 void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { 84 StreamingReporterBase::sectionStarting( sectionInfo ); 85 if( m_sectionDepth++ > 0 ) { 86 m_xml.startElement( "Section" ) 87 .writeAttribute( "name", trim( sectionInfo.name ) ); 88 writeSourceInfo( sectionInfo.lineInfo ); 89 m_xml.ensureTagClosed(); 90 } 91 } 92 assertionStarting(AssertionInfo const &)93 void XmlReporter::assertionStarting( AssertionInfo const& ) { } 94 assertionEnded(AssertionStats const & assertionStats)95 bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { 96 97 AssertionResult const& result = assertionStats.assertionResult; 98 99 bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); 100 101 if( includeResults || result.getResultType() == ResultWas::Warning ) { 102 // Print any info messages in <Info> tags. 103 for( auto const& msg : assertionStats.infoMessages ) { 104 if( msg.type == ResultWas::Info && includeResults ) { 105 m_xml.scopedElement( "Info" ) 106 .writeText( msg.message ); 107 } else if ( msg.type == ResultWas::Warning ) { 108 m_xml.scopedElement( "Warning" ) 109 .writeText( msg.message ); 110 } 111 } 112 } 113 114 // Drop out if result was successful but we're not printing them. 115 if( !includeResults && result.getResultType() != ResultWas::Warning ) 116 return true; 117 118 119 // Print the expression if there is one. 120 if( result.hasExpression() ) { 121 m_xml.startElement( "Expression" ) 122 .writeAttribute( "success", result.succeeded() ) 123 .writeAttribute( "type", result.getTestMacroName() ); 124 125 writeSourceInfo( result.getSourceInfo() ); 126 127 m_xml.scopedElement( "Original" ) 128 .writeText( result.getExpression() ); 129 m_xml.scopedElement( "Expanded" ) 130 .writeText( result.getExpandedExpression() ); 131 } 132 133 // And... Print a result applicable to each result type. 134 switch( result.getResultType() ) { 135 case ResultWas::ThrewException: 136 m_xml.startElement( "Exception" ); 137 writeSourceInfo( result.getSourceInfo() ); 138 m_xml.writeText( result.getMessage() ); 139 m_xml.endElement(); 140 break; 141 case ResultWas::FatalErrorCondition: 142 m_xml.startElement( "FatalErrorCondition" ); 143 writeSourceInfo( result.getSourceInfo() ); 144 m_xml.writeText( result.getMessage() ); 145 m_xml.endElement(); 146 break; 147 case ResultWas::Info: 148 m_xml.scopedElement( "Info" ) 149 .writeText( result.getMessage() ); 150 break; 151 case ResultWas::Warning: 152 // Warning will already have been written 153 break; 154 case ResultWas::ExplicitFailure: 155 m_xml.startElement( "Failure" ); 156 writeSourceInfo( result.getSourceInfo() ); 157 m_xml.writeText( result.getMessage() ); 158 m_xml.endElement(); 159 break; 160 default: 161 break; 162 } 163 164 if( result.hasExpression() ) 165 m_xml.endElement(); 166 167 return true; 168 } 169 sectionEnded(SectionStats const & sectionStats)170 void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { 171 StreamingReporterBase::sectionEnded( sectionStats ); 172 if( --m_sectionDepth > 0 ) { 173 XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); 174 e.writeAttribute( "successes", sectionStats.assertions.passed ); 175 e.writeAttribute( "failures", sectionStats.assertions.failed ); 176 e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); 177 178 if ( m_config->showDurations() == ShowDurations::Always ) 179 e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); 180 181 m_xml.endElement(); 182 } 183 } 184 testCaseEnded(TestCaseStats const & testCaseStats)185 void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { 186 StreamingReporterBase::testCaseEnded( testCaseStats ); 187 XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); 188 e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); 189 190 if ( m_config->showDurations() == ShowDurations::Always ) 191 e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); 192 193 if( !testCaseStats.stdOut.empty() ) 194 m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); 195 if( !testCaseStats.stdErr.empty() ) 196 m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); 197 198 m_xml.endElement(); 199 } 200 testGroupEnded(TestGroupStats const & testGroupStats)201 void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { 202 StreamingReporterBase::testGroupEnded( testGroupStats ); 203 // TODO: Check testGroupStats.aborting and act accordingly. 204 m_xml.scopedElement( "OverallResults" ) 205 .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) 206 .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) 207 .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); 208 m_xml.endElement(); 209 } 210 testRunEnded(TestRunStats const & testRunStats)211 void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { 212 StreamingReporterBase::testRunEnded( testRunStats ); 213 m_xml.scopedElement( "OverallResults" ) 214 .writeAttribute( "successes", testRunStats.totals.assertions.passed ) 215 .writeAttribute( "failures", testRunStats.totals.assertions.failed ) 216 .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); 217 m_xml.endElement(); 218 } 219 220 CATCH_REGISTER_REPORTER( "xml", XmlReporter ) 221 222 } // end namespace Catch 223 224 #if defined(_MSC_VER) 225 #pragma warning(pop) 226 #endif 227