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->testSpec().hasFilters()) 59 m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) ); 60 if( m_config->rngSeed() != 0 ) 61 m_xml.scopedElement( "Randomness" ) 62 .writeAttribute( "seed", m_config->rngSeed() ); 63 } 64 testGroupStarting(GroupInfo const & groupInfo)65 void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { 66 StreamingReporterBase::testGroupStarting( groupInfo ); 67 m_xml.startElement( "Group" ) 68 .writeAttribute( "name", groupInfo.name ); 69 } 70 testCaseStarting(TestCaseInfo const & testInfo)71 void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { 72 StreamingReporterBase::testCaseStarting(testInfo); 73 m_xml.startElement( "TestCase" ) 74 .writeAttribute( "name", trim( testInfo.name ) ) 75 .writeAttribute( "description", testInfo.description ) 76 .writeAttribute( "tags", testInfo.tagsAsString() ); 77 78 writeSourceInfo( testInfo.lineInfo ); 79 80 if ( m_config->showDurations() == ShowDurations::Always ) 81 m_testCaseTimer.start(); 82 m_xml.ensureTagClosed(); 83 } 84 sectionStarting(SectionInfo const & sectionInfo)85 void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { 86 StreamingReporterBase::sectionStarting( sectionInfo ); 87 if( m_sectionDepth++ > 0 ) { 88 m_xml.startElement( "Section" ) 89 .writeAttribute( "name", trim( sectionInfo.name ) ); 90 writeSourceInfo( sectionInfo.lineInfo ); 91 m_xml.ensureTagClosed(); 92 } 93 } 94 assertionStarting(AssertionInfo const &)95 void XmlReporter::assertionStarting( AssertionInfo const& ) { } 96 assertionEnded(AssertionStats const & assertionStats)97 bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { 98 99 AssertionResult const& result = assertionStats.assertionResult; 100 101 bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); 102 103 if( includeResults || result.getResultType() == ResultWas::Warning ) { 104 // Print any info messages in <Info> tags. 105 for( auto const& msg : assertionStats.infoMessages ) { 106 if( msg.type == ResultWas::Info && includeResults ) { 107 m_xml.scopedElement( "Info" ) 108 .writeText( msg.message ); 109 } else if ( msg.type == ResultWas::Warning ) { 110 m_xml.scopedElement( "Warning" ) 111 .writeText( msg.message ); 112 } 113 } 114 } 115 116 // Drop out if result was successful but we're not printing them. 117 if( !includeResults && result.getResultType() != ResultWas::Warning ) 118 return true; 119 120 121 // Print the expression if there is one. 122 if( result.hasExpression() ) { 123 m_xml.startElement( "Expression" ) 124 .writeAttribute( "success", result.succeeded() ) 125 .writeAttribute( "type", result.getTestMacroName() ); 126 127 writeSourceInfo( result.getSourceInfo() ); 128 129 m_xml.scopedElement( "Original" ) 130 .writeText( result.getExpression() ); 131 m_xml.scopedElement( "Expanded" ) 132 .writeText( result.getExpandedExpression() ); 133 } 134 135 // And... Print a result applicable to each result type. 136 switch( result.getResultType() ) { 137 case ResultWas::ThrewException: 138 m_xml.startElement( "Exception" ); 139 writeSourceInfo( result.getSourceInfo() ); 140 m_xml.writeText( result.getMessage() ); 141 m_xml.endElement(); 142 break; 143 case ResultWas::FatalErrorCondition: 144 m_xml.startElement( "FatalErrorCondition" ); 145 writeSourceInfo( result.getSourceInfo() ); 146 m_xml.writeText( result.getMessage() ); 147 m_xml.endElement(); 148 break; 149 case ResultWas::Info: 150 m_xml.scopedElement( "Info" ) 151 .writeText( result.getMessage() ); 152 break; 153 case ResultWas::Warning: 154 // Warning will already have been written 155 break; 156 case ResultWas::ExplicitFailure: 157 m_xml.startElement( "Failure" ); 158 writeSourceInfo( result.getSourceInfo() ); 159 m_xml.writeText( result.getMessage() ); 160 m_xml.endElement(); 161 break; 162 default: 163 break; 164 } 165 166 if( result.hasExpression() ) 167 m_xml.endElement(); 168 169 return true; 170 } 171 sectionEnded(SectionStats const & sectionStats)172 void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { 173 StreamingReporterBase::sectionEnded( sectionStats ); 174 if( --m_sectionDepth > 0 ) { 175 XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); 176 e.writeAttribute( "successes", sectionStats.assertions.passed ); 177 e.writeAttribute( "failures", sectionStats.assertions.failed ); 178 e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); 179 180 if ( m_config->showDurations() == ShowDurations::Always ) 181 e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); 182 183 m_xml.endElement(); 184 } 185 } 186 testCaseEnded(TestCaseStats const & testCaseStats)187 void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { 188 StreamingReporterBase::testCaseEnded( testCaseStats ); 189 XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); 190 e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); 191 192 if ( m_config->showDurations() == ShowDurations::Always ) 193 e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); 194 195 if( !testCaseStats.stdOut.empty() ) 196 m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline ); 197 if( !testCaseStats.stdErr.empty() ) 198 m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline ); 199 200 m_xml.endElement(); 201 } 202 testGroupEnded(TestGroupStats const & testGroupStats)203 void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { 204 StreamingReporterBase::testGroupEnded( testGroupStats ); 205 // TODO: Check testGroupStats.aborting and act accordingly. 206 m_xml.scopedElement( "OverallResults" ) 207 .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) 208 .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) 209 .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); 210 m_xml.endElement(); 211 } 212 testRunEnded(TestRunStats const & testRunStats)213 void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { 214 StreamingReporterBase::testRunEnded( testRunStats ); 215 m_xml.scopedElement( "OverallResults" ) 216 .writeAttribute( "successes", testRunStats.totals.assertions.passed ) 217 .writeAttribute( "failures", testRunStats.totals.assertions.failed ) 218 .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); 219 m_xml.endElement(); 220 } 221 222 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) benchmarkPreparing(std::string const & name)223 void XmlReporter::benchmarkPreparing(std::string const& name) { 224 m_xml.startElement("BenchmarkResults") 225 .writeAttribute("name", name); 226 } 227 benchmarkStarting(BenchmarkInfo const & info)228 void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) { 229 m_xml.writeAttribute("samples", info.samples) 230 .writeAttribute("resamples", info.resamples) 231 .writeAttribute("iterations", info.iterations) 232 .writeAttribute("clockResolution", info.clockResolution) 233 .writeAttribute("estimatedDuration", info.estimatedDuration) 234 .writeComment("All values in nano seconds"); 235 } 236 benchmarkEnded(BenchmarkStats<> const & benchmarkStats)237 void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { 238 m_xml.startElement("mean") 239 .writeAttribute("value", benchmarkStats.mean.point.count()) 240 .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count()) 241 .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count()) 242 .writeAttribute("ci", benchmarkStats.mean.confidence_interval); 243 m_xml.endElement(); 244 m_xml.startElement("standardDeviation") 245 .writeAttribute("value", benchmarkStats.standardDeviation.point.count()) 246 .writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count()) 247 .writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count()) 248 .writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval); 249 m_xml.endElement(); 250 m_xml.startElement("outliers") 251 .writeAttribute("variance", benchmarkStats.outlierVariance) 252 .writeAttribute("lowMild", benchmarkStats.outliers.low_mild) 253 .writeAttribute("lowSevere", benchmarkStats.outliers.low_severe) 254 .writeAttribute("highMild", benchmarkStats.outliers.high_mild) 255 .writeAttribute("highSevere", benchmarkStats.outliers.high_severe); 256 m_xml.endElement(); 257 m_xml.endElement(); 258 } 259 benchmarkFailed(std::string const & error)260 void XmlReporter::benchmarkFailed(std::string const &error) { 261 m_xml.scopedElement("failed"). 262 writeAttribute("message", error); 263 m_xml.endElement(); 264 } 265 #endif // CATCH_CONFIG_ENABLE_BENCHMARKING 266 267 CATCH_REGISTER_REPORTER( "xml", XmlReporter ) 268 269 } // end namespace Catch 270 271 #if defined(_MSC_VER) 272 #pragma warning(pop) 273 #endif 274