bump catch2 headers to v2.13.9 (#25678)
	
		
	
				
					
				
			
							parent
							
								
									69e9b285b3
								
							
						
					
					
						commit
						9fb2c40cfd
					
				
				 5 changed files with 1153 additions and 982 deletions
			
			
		
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						| @ -1,62 +1,62 @@ | ||||
| /*
 | ||||
|  *  Created by Justin R. Wilson on 2/19/2017. | ||||
|  *  Copyright 2017 Justin R. Wilson. 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_AUTOMAKE_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED | ||||
| 
 | ||||
| // Don't #include any Catch headers here - we can assume they are already
 | ||||
| // included before this header.
 | ||||
| // This is not good practice in general but is necessary in this case so this
 | ||||
| // file can be distributed as a single header that works with the main
 | ||||
| // Catch single header.
 | ||||
| 
 | ||||
| namespace Catch { | ||||
| 
 | ||||
|     struct AutomakeReporter : StreamingReporterBase<AutomakeReporter> { | ||||
|         AutomakeReporter( ReporterConfig const& _config ) | ||||
|           :   StreamingReporterBase( _config ) | ||||
|         {} | ||||
| 
 | ||||
|         ~AutomakeReporter() override; | ||||
| 
 | ||||
|         static std::string getDescription() { | ||||
|             return "Reports test results in the format of Automake .trs files"; | ||||
|         } | ||||
| 
 | ||||
|         void assertionStarting( AssertionInfo const& ) override {} | ||||
| 
 | ||||
|         bool assertionEnded( AssertionStats const& /*_assertionStats*/ ) override { return true; } | ||||
| 
 | ||||
|         void testCaseEnded( TestCaseStats const& _testCaseStats ) override { | ||||
|             // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
 | ||||
|             stream << ":test-result: "; | ||||
|             if (_testCaseStats.totals.assertions.allPassed()) { | ||||
|                 stream << "PASS"; | ||||
|             } else if (_testCaseStats.totals.assertions.allOk()) { | ||||
|                 stream << "XFAIL"; | ||||
|             } else { | ||||
|                 stream << "FAIL"; | ||||
|             } | ||||
|             stream << ' ' << _testCaseStats.testInfo.name << '\n'; | ||||
|             StreamingReporterBase::testCaseEnded( _testCaseStats ); | ||||
|         } | ||||
| 
 | ||||
|         void skipTest( TestCaseInfo const& testInfo ) override { | ||||
|             stream << ":test-result: SKIP " << testInfo.name << '\n'; | ||||
|         } | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
| #ifdef CATCH_IMPL | ||||
|     AutomakeReporter::~AutomakeReporter() {} | ||||
| #endif | ||||
| 
 | ||||
|     CATCH_REGISTER_REPORTER( "automake", AutomakeReporter) | ||||
| 
 | ||||
| } // end namespace Catch
 | ||||
| 
 | ||||
| #endif // TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
 | ||||
| /*
 | ||||
|  *  Created by Justin R. Wilson on 2/19/2017. | ||||
|  *  Copyright 2017 Justin R. Wilson. 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_AUTOMAKE_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED | ||||
| 
 | ||||
| // Don't #include any Catch headers here - we can assume they are already
 | ||||
| // included before this header.
 | ||||
| // This is not good practice in general but is necessary in this case so this
 | ||||
| // file can be distributed as a single header that works with the main
 | ||||
| // Catch single header.
 | ||||
| 
 | ||||
| namespace Catch { | ||||
| 
 | ||||
|     struct AutomakeReporter : StreamingReporterBase<AutomakeReporter> { | ||||
|         AutomakeReporter( ReporterConfig const& _config ) | ||||
|           :   StreamingReporterBase( _config ) | ||||
|         {} | ||||
| 
 | ||||
|         ~AutomakeReporter() override; | ||||
| 
 | ||||
|         static std::string getDescription() { | ||||
|             return "Reports test results in the format of Automake .trs files"; | ||||
|         } | ||||
| 
 | ||||
|         void assertionStarting( AssertionInfo const& ) override {} | ||||
| 
 | ||||
|         bool assertionEnded( AssertionStats const& /*_assertionStats*/ ) override { return true; } | ||||
| 
 | ||||
|         void testCaseEnded( TestCaseStats const& _testCaseStats ) override { | ||||
|             // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
 | ||||
|             stream << ":test-result: "; | ||||
|             if (_testCaseStats.totals.assertions.allPassed()) { | ||||
|                 stream << "PASS"; | ||||
|             } else if (_testCaseStats.totals.assertions.allOk()) { | ||||
|                 stream << "XFAIL"; | ||||
|             } else { | ||||
|                 stream << "FAIL"; | ||||
|             } | ||||
|             stream << ' ' << _testCaseStats.testInfo.name << '\n'; | ||||
|             StreamingReporterBase::testCaseEnded( _testCaseStats ); | ||||
|         } | ||||
| 
 | ||||
|         void skipTest( TestCaseInfo const& testInfo ) override { | ||||
|             stream << ":test-result: SKIP " << testInfo.name << '\n'; | ||||
|         } | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
| #ifdef CATCH_IMPL | ||||
|     AutomakeReporter::~AutomakeReporter() {} | ||||
| #endif | ||||
| 
 | ||||
|     CATCH_REGISTER_REPORTER( "automake", AutomakeReporter) | ||||
| 
 | ||||
| } // end namespace Catch
 | ||||
| 
 | ||||
| #endif // TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
 | ||||
|  | ||||
| @ -1,181 +1,181 @@ | ||||
| /*
 | ||||
|  *  Created by Daniel Garcia on 2018-12-04. | ||||
|  *  Copyright Social Point SL. 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 CATCH_REPORTER_SONARQUBE_HPP_INCLUDED | ||||
| #define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED | ||||
| 
 | ||||
| 
 | ||||
| // Don't #include any Catch headers here - we can assume they are already
 | ||||
| // included before this header.
 | ||||
| // This is not good practice in general but is necessary in this case so this
 | ||||
| // file can be distributed as a single header that works with the main
 | ||||
| // Catch single header.
 | ||||
| 
 | ||||
| #include <map> | ||||
| 
 | ||||
| namespace Catch { | ||||
| 
 | ||||
|     struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> { | ||||
| 
 | ||||
|         SonarQubeReporter(ReporterConfig const& config) | ||||
|         : CumulativeReporterBase(config) | ||||
|         , xml(config.stream()) { | ||||
|             m_reporterPrefs.shouldRedirectStdOut = true; | ||||
|             m_reporterPrefs.shouldReportAllAssertions = true; | ||||
|         } | ||||
| 
 | ||||
|         ~SonarQubeReporter() override; | ||||
| 
 | ||||
|         static std::string getDescription() { | ||||
|             return "Reports test results in the Generic Test Data SonarQube XML format"; | ||||
|         } | ||||
| 
 | ||||
|         static std::set<Verbosity> getSupportedVerbosities() { | ||||
|             return { Verbosity::Normal }; | ||||
|         } | ||||
| 
 | ||||
|         void noMatchingTestCases(std::string const& /*spec*/) override {} | ||||
| 
 | ||||
|         void testRunStarting(TestRunInfo const& testRunInfo) override { | ||||
|             CumulativeReporterBase::testRunStarting(testRunInfo); | ||||
|             xml.startElement("testExecutions"); | ||||
|             xml.writeAttribute("version", "1"); | ||||
|         } | ||||
| 
 | ||||
|         void testGroupEnded(TestGroupStats const& testGroupStats) override { | ||||
|             CumulativeReporterBase::testGroupEnded(testGroupStats); | ||||
|             writeGroup(*m_testGroups.back()); | ||||
|         } | ||||
| 
 | ||||
|         void testRunEndedCumulative() override { | ||||
|             xml.endElement(); | ||||
|         } | ||||
| 
 | ||||
|         void writeGroup(TestGroupNode const& groupNode) { | ||||
|             std::map<std::string, TestGroupNode::ChildNodes> testsPerFile; | ||||
|             for(auto const& child : groupNode.children) | ||||
|                 testsPerFile[child->value.testInfo.lineInfo.file].push_back(child); | ||||
| 
 | ||||
|             for(auto const& kv : testsPerFile) | ||||
|                 writeTestFile(kv.first.c_str(), kv.second); | ||||
|         } | ||||
| 
 | ||||
|         void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) { | ||||
|             XmlWriter::ScopedElement e = xml.scopedElement("file"); | ||||
|             xml.writeAttribute("path", filename); | ||||
| 
 | ||||
|             for(auto const& child : testCaseNodes) | ||||
|                 writeTestCase(*child); | ||||
|         } | ||||
| 
 | ||||
|         void writeTestCase(TestCaseNode const& testCaseNode) { | ||||
|             // All test cases have exactly one section - which represents the
 | ||||
|             // test case itself. That section may have 0-n nested sections
 | ||||
|             assert(testCaseNode.children.size() == 1); | ||||
|             SectionNode const& rootSection = *testCaseNode.children.front(); | ||||
|             writeSection("", rootSection, testCaseNode.value.testInfo.okToFail()); | ||||
|         } | ||||
| 
 | ||||
|         void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) { | ||||
|             std::string name = trim(sectionNode.stats.sectionInfo.name); | ||||
|             if(!rootName.empty()) | ||||
|                 name = rootName + '/' + name; | ||||
| 
 | ||||
|             if(!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) { | ||||
|                 XmlWriter::ScopedElement e = xml.scopedElement("testCase"); | ||||
|                 xml.writeAttribute("name", name); | ||||
|                 xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000)); | ||||
| 
 | ||||
|                 writeAssertions(sectionNode, okToFail); | ||||
|             } | ||||
| 
 | ||||
|             for(auto const& childNode : sectionNode.childSections) | ||||
|                 writeSection(name, *childNode, okToFail); | ||||
|         } | ||||
| 
 | ||||
|         void writeAssertions(SectionNode const& sectionNode, bool okToFail) { | ||||
|             for(auto const& assertion : sectionNode.assertions) | ||||
|                 writeAssertion( assertion, okToFail); | ||||
|         } | ||||
| 
 | ||||
|         void writeAssertion(AssertionStats const& stats, bool okToFail) { | ||||
|             AssertionResult const& result = stats.assertionResult; | ||||
|             if(!result.isOk()) { | ||||
|                 std::string elementName; | ||||
|                 if(okToFail) { | ||||
|                     elementName = "skipped"; | ||||
|                 } | ||||
|                 else { | ||||
|                     switch(result.getResultType()) { | ||||
|                         case ResultWas::ThrewException: | ||||
|                         case ResultWas::FatalErrorCondition: | ||||
|                             elementName = "error"; | ||||
|                             break; | ||||
|                         case ResultWas::ExplicitFailure: | ||||
|                             elementName = "failure"; | ||||
|                             break; | ||||
|                         case ResultWas::ExpressionFailed: | ||||
|                             elementName = "failure"; | ||||
|                             break; | ||||
|                         case ResultWas::DidntThrowException: | ||||
|                             elementName = "failure"; | ||||
|                             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); | ||||
| 
 | ||||
|                 ReusableStringStream messageRss; | ||||
|                 messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")"; | ||||
|                 xml.writeAttribute("message", messageRss.str()); | ||||
| 
 | ||||
|                 ReusableStringStream textRss; | ||||
|                 if (stats.totals.assertions.total() > 0) { | ||||
|                     textRss << "FAILED:\n"; | ||||
|                     if (result.hasExpression()) { | ||||
|                         textRss << "\t" << result.getExpressionInMacro() << "\n"; | ||||
|                     } | ||||
|                     if (result.hasExpandedExpression()) { | ||||
|                         textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n"; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if(!result.getMessage().empty()) | ||||
|                     textRss << result.getMessage() << "\n"; | ||||
| 
 | ||||
|                 for(auto const& msg : stats.infoMessages) | ||||
|                     if(msg.type == ResultWas::Info) | ||||
|                         textRss << msg.message << "\n"; | ||||
| 
 | ||||
|                 textRss << "at " << result.getSourceInfo(); | ||||
|                 xml.writeText(textRss.str(), XmlFormatting::Newline); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         XmlWriter xml; | ||||
|     }; | ||||
| 
 | ||||
| #ifdef CATCH_IMPL | ||||
|     SonarQubeReporter::~SonarQubeReporter() {} | ||||
| #endif | ||||
| 
 | ||||
|     CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter ) | ||||
| 
 | ||||
| } // end namespace Catch
 | ||||
| 
 | ||||
| /*
 | ||||
|  *  Created by Daniel Garcia on 2018-12-04. | ||||
|  *  Copyright Social Point SL. 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 CATCH_REPORTER_SONARQUBE_HPP_INCLUDED | ||||
| #define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED | ||||
| 
 | ||||
| 
 | ||||
| // Don't #include any Catch headers here - we can assume they are already
 | ||||
| // included before this header.
 | ||||
| // This is not good practice in general but is necessary in this case so this
 | ||||
| // file can be distributed as a single header that works with the main
 | ||||
| // Catch single header.
 | ||||
| 
 | ||||
| #include <map> | ||||
| 
 | ||||
| namespace Catch { | ||||
| 
 | ||||
|     struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> { | ||||
| 
 | ||||
|         SonarQubeReporter(ReporterConfig const& config) | ||||
|         : CumulativeReporterBase(config) | ||||
|         , xml(config.stream()) { | ||||
|             m_reporterPrefs.shouldRedirectStdOut = true; | ||||
|             m_reporterPrefs.shouldReportAllAssertions = true; | ||||
|         } | ||||
| 
 | ||||
|         ~SonarQubeReporter() override; | ||||
| 
 | ||||
|         static std::string getDescription() { | ||||
|             return "Reports test results in the Generic Test Data SonarQube XML format"; | ||||
|         } | ||||
| 
 | ||||
|         static std::set<Verbosity> getSupportedVerbosities() { | ||||
|             return { Verbosity::Normal }; | ||||
|         } | ||||
| 
 | ||||
|         void noMatchingTestCases(std::string const& /*spec*/) override {} | ||||
| 
 | ||||
|         void testRunStarting(TestRunInfo const& testRunInfo) override { | ||||
|             CumulativeReporterBase::testRunStarting(testRunInfo); | ||||
|             xml.startElement("testExecutions"); | ||||
|             xml.writeAttribute("version", "1"); | ||||
|         } | ||||
| 
 | ||||
|         void testGroupEnded(TestGroupStats const& testGroupStats) override { | ||||
|             CumulativeReporterBase::testGroupEnded(testGroupStats); | ||||
|             writeGroup(*m_testGroups.back()); | ||||
|         } | ||||
| 
 | ||||
|         void testRunEndedCumulative() override { | ||||
|             xml.endElement(); | ||||
|         } | ||||
| 
 | ||||
|         void writeGroup(TestGroupNode const& groupNode) { | ||||
|             std::map<std::string, TestGroupNode::ChildNodes> testsPerFile; | ||||
|             for(auto const& child : groupNode.children) | ||||
|                 testsPerFile[child->value.testInfo.lineInfo.file].push_back(child); | ||||
| 
 | ||||
|             for(auto const& kv : testsPerFile) | ||||
|                 writeTestFile(kv.first.c_str(), kv.second); | ||||
|         } | ||||
| 
 | ||||
|         void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) { | ||||
|             XmlWriter::ScopedElement e = xml.scopedElement("file"); | ||||
|             xml.writeAttribute("path", filename); | ||||
| 
 | ||||
|             for(auto const& child : testCaseNodes) | ||||
|                 writeTestCase(*child); | ||||
|         } | ||||
| 
 | ||||
|         void writeTestCase(TestCaseNode const& testCaseNode) { | ||||
|             // All test cases have exactly one section - which represents the
 | ||||
|             // test case itself. That section may have 0-n nested sections
 | ||||
|             assert(testCaseNode.children.size() == 1); | ||||
|             SectionNode const& rootSection = *testCaseNode.children.front(); | ||||
|             writeSection("", rootSection, testCaseNode.value.testInfo.okToFail()); | ||||
|         } | ||||
| 
 | ||||
|         void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) { | ||||
|             std::string name = trim(sectionNode.stats.sectionInfo.name); | ||||
|             if(!rootName.empty()) | ||||
|                 name = rootName + '/' + name; | ||||
| 
 | ||||
|             if(!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) { | ||||
|                 XmlWriter::ScopedElement e = xml.scopedElement("testCase"); | ||||
|                 xml.writeAttribute("name", name); | ||||
|                 xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000)); | ||||
| 
 | ||||
|                 writeAssertions(sectionNode, okToFail); | ||||
|             } | ||||
| 
 | ||||
|             for(auto const& childNode : sectionNode.childSections) | ||||
|                 writeSection(name, *childNode, okToFail); | ||||
|         } | ||||
| 
 | ||||
|         void writeAssertions(SectionNode const& sectionNode, bool okToFail) { | ||||
|             for(auto const& assertion : sectionNode.assertions) | ||||
|                 writeAssertion( assertion, okToFail); | ||||
|         } | ||||
| 
 | ||||
|         void writeAssertion(AssertionStats const& stats, bool okToFail) { | ||||
|             AssertionResult const& result = stats.assertionResult; | ||||
|             if(!result.isOk()) { | ||||
|                 std::string elementName; | ||||
|                 if(okToFail) { | ||||
|                     elementName = "skipped"; | ||||
|                 } | ||||
|                 else { | ||||
|                     switch(result.getResultType()) { | ||||
|                         case ResultWas::ThrewException: | ||||
|                         case ResultWas::FatalErrorCondition: | ||||
|                             elementName = "error"; | ||||
|                             break; | ||||
|                         case ResultWas::ExplicitFailure: | ||||
|                             elementName = "failure"; | ||||
|                             break; | ||||
|                         case ResultWas::ExpressionFailed: | ||||
|                             elementName = "failure"; | ||||
|                             break; | ||||
|                         case ResultWas::DidntThrowException: | ||||
|                             elementName = "failure"; | ||||
|                             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); | ||||
| 
 | ||||
|                 ReusableStringStream messageRss; | ||||
|                 messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")"; | ||||
|                 xml.writeAttribute("message", messageRss.str()); | ||||
| 
 | ||||
|                 ReusableStringStream textRss; | ||||
|                 if (stats.totals.assertions.total() > 0) { | ||||
|                     textRss << "FAILED:\n"; | ||||
|                     if (result.hasExpression()) { | ||||
|                         textRss << "\t" << result.getExpressionInMacro() << "\n"; | ||||
|                     } | ||||
|                     if (result.hasExpandedExpression()) { | ||||
|                         textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n"; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if(!result.getMessage().empty()) | ||||
|                     textRss << result.getMessage() << "\n"; | ||||
| 
 | ||||
|                 for(auto const& msg : stats.infoMessages) | ||||
|                     if(msg.type == ResultWas::Info) | ||||
|                         textRss << msg.message << "\n"; | ||||
| 
 | ||||
|                 textRss << "at " << result.getSourceInfo(); | ||||
|                 xml.writeText(textRss.str(), XmlFormatting::Newline); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         XmlWriter xml; | ||||
|     }; | ||||
| 
 | ||||
| #ifdef CATCH_IMPL | ||||
|     SonarQubeReporter::~SonarQubeReporter() {} | ||||
| #endif | ||||
| 
 | ||||
|     CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter ) | ||||
| 
 | ||||
| } // end namespace Catch
 | ||||
| 
 | ||||
| #endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
 | ||||
| @ -1,254 +1,254 @@ | ||||
| /*
 | ||||
|  *  Created by Colton Wolkins on 2015-08-15. | ||||
|  *  Copyright 2015 Martin Moene. 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_TAP_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED | ||||
| 
 | ||||
| 
 | ||||
| // Don't #include any Catch headers here - we can assume they are already
 | ||||
| // included before this header.
 | ||||
| // This is not good practice in general but is necessary in this case so this
 | ||||
| // file can be distributed as a single header that works with the main
 | ||||
| // Catch single header.
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
| namespace Catch { | ||||
| 
 | ||||
|     struct TAPReporter : StreamingReporterBase<TAPReporter> { | ||||
| 
 | ||||
|         using StreamingReporterBase::StreamingReporterBase; | ||||
| 
 | ||||
|         TAPReporter( ReporterConfig const& config ): | ||||
|             StreamingReporterBase( config ) { | ||||
|             m_reporterPrefs.shouldReportAllAssertions = true; | ||||
|         } | ||||
| 
 | ||||
|         ~TAPReporter() override; | ||||
| 
 | ||||
|         static std::string getDescription() { | ||||
|             return "Reports test results in TAP format, suitable for test harnesses"; | ||||
|         } | ||||
| 
 | ||||
|         void noMatchingTestCases( std::string const& spec ) override { | ||||
|             stream << "# No test cases matched '" << spec << "'" << std::endl; | ||||
|         } | ||||
| 
 | ||||
|         void assertionStarting( AssertionInfo const& ) override {} | ||||
| 
 | ||||
|         bool assertionEnded( AssertionStats const& _assertionStats ) override { | ||||
|             ++counter; | ||||
| 
 | ||||
|             stream << "# " << currentTestCaseInfo->name << std::endl; | ||||
|             AssertionPrinter printer( stream, _assertionStats, counter ); | ||||
|             printer.print(); | ||||
| 
 | ||||
|             stream << std::endl; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         void testRunEnded( TestRunStats const& _testRunStats ) override { | ||||
|             printTotals( _testRunStats.totals ); | ||||
|             stream << "\n" << std::endl; | ||||
|             StreamingReporterBase::testRunEnded( _testRunStats ); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         std::size_t counter = 0; | ||||
|         class AssertionPrinter { | ||||
|         public: | ||||
|             AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; | ||||
|             AssertionPrinter( AssertionPrinter const& ) = delete; | ||||
|             AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter ) | ||||
|             : stream( _stream ) | ||||
|             , result( _stats.assertionResult ) | ||||
|             , messages( _stats.infoMessages ) | ||||
|             , itMessage( _stats.infoMessages.begin() ) | ||||
|             , printInfoMessages( true ) | ||||
|             , counter(_counter) | ||||
|             {} | ||||
| 
 | ||||
|             void print() { | ||||
|                 itMessage = messages.begin(); | ||||
| 
 | ||||
|                 switch( result.getResultType() ) { | ||||
|                     case ResultWas::Ok: | ||||
|                         printResultType( passedString() ); | ||||
|                         printOriginalExpression(); | ||||
|                         printReconstructedExpression(); | ||||
|                         if ( ! result.hasExpression() ) | ||||
|                             printRemainingMessages( Colour::None ); | ||||
|                         else | ||||
|                             printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::ExpressionFailed: | ||||
|                         if (result.isOk()) { | ||||
|                             printResultType(passedString()); | ||||
|                         } else { | ||||
|                             printResultType(failedString()); | ||||
|                         } | ||||
|                         printOriginalExpression(); | ||||
|                         printReconstructedExpression(); | ||||
|                         if (result.isOk()) { | ||||
|                             printIssue(" # TODO"); | ||||
|                         } | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::ThrewException: | ||||
|                         printResultType( failedString() ); | ||||
|                         printIssue( "unexpected exception with message:" ); | ||||
|                         printMessage(); | ||||
|                         printExpressionWas(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::FatalErrorCondition: | ||||
|                         printResultType( failedString() ); | ||||
|                         printIssue( "fatal error condition with message:" ); | ||||
|                         printMessage(); | ||||
|                         printExpressionWas(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::DidntThrowException: | ||||
|                         printResultType( failedString() ); | ||||
|                         printIssue( "expected exception, got none" ); | ||||
|                         printExpressionWas(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::Info: | ||||
|                         printResultType( "info" ); | ||||
|                         printMessage(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::Warning: | ||||
|                         printResultType( "warning" ); | ||||
|                         printMessage(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::ExplicitFailure: | ||||
|                         printResultType( failedString() ); | ||||
|                         printIssue( "explicitly" ); | ||||
|                         printRemainingMessages( Colour::None ); | ||||
|                         break; | ||||
|                     // These cases are here to prevent compiler warnings
 | ||||
|                     case ResultWas::Unknown: | ||||
|                     case ResultWas::FailureBit: | ||||
|                     case ResultWas::Exception: | ||||
|                         printResultType( "** internal error **" ); | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         private: | ||||
|             static Colour::Code dimColour() { return Colour::FileName; } | ||||
| 
 | ||||
|             static const char* failedString() { return "not ok"; } | ||||
|             static const char* passedString() { return "ok"; } | ||||
| 
 | ||||
|             void printSourceInfo() const { | ||||
|                 Colour colourGuard( dimColour() ); | ||||
|                 stream << result.getSourceInfo() << ":"; | ||||
|             } | ||||
| 
 | ||||
|             void printResultType( std::string const& passOrFail ) const { | ||||
|                 if( !passOrFail.empty() ) { | ||||
|                     stream << passOrFail << ' ' << counter << " -"; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printIssue( std::string const& issue ) const { | ||||
|                 stream << " " << issue; | ||||
|             } | ||||
| 
 | ||||
|             void printExpressionWas() { | ||||
|                 if( result.hasExpression() ) { | ||||
|                     stream << ";"; | ||||
|                     { | ||||
|                         Colour colour( dimColour() ); | ||||
|                         stream << " expression was:"; | ||||
|                     } | ||||
|                     printOriginalExpression(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printOriginalExpression() const { | ||||
|                 if( result.hasExpression() ) { | ||||
|                     stream << " " << result.getExpression(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printReconstructedExpression() const { | ||||
|                 if( result.hasExpandedExpression() ) { | ||||
|                     { | ||||
|                         Colour colour( dimColour() ); | ||||
|                         stream << " for: "; | ||||
|                     } | ||||
|                     std::string expr = result.getExpandedExpression(); | ||||
|                     std::replace( expr.begin(), expr.end(), '\n', ' '); | ||||
|                     stream << expr; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printMessage() { | ||||
|                 if ( itMessage != messages.end() ) { | ||||
|                     stream << " '" << itMessage->message << "'"; | ||||
|                     ++itMessage; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printRemainingMessages( Colour::Code colour = dimColour() ) { | ||||
|                 if (itMessage == messages.end()) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 const auto itEnd = messages.cend(); | ||||
|                 const auto N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) ); | ||||
| 
 | ||||
|                 { | ||||
|                     Colour colourGuard( colour ); | ||||
|                     stream << " with " << pluralise( N, "message" ) << ":"; | ||||
|                 } | ||||
| 
 | ||||
|                 while( itMessage != itEnd ) { | ||||
|                     // If this assertion is a warning ignore any INFO messages
 | ||||
|                     if( printInfoMessages || itMessage->type != ResultWas::Info ) { | ||||
|                         stream << " '" << itMessage->message << "'"; | ||||
|                         if ( ++itMessage != itEnd ) { | ||||
|                             Colour colourGuard( dimColour() ); | ||||
|                             stream << " and"; | ||||
|                         } | ||||
|                         continue; | ||||
|                     } | ||||
|                     ++itMessage; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         private: | ||||
|             std::ostream& stream; | ||||
|             AssertionResult const& result; | ||||
|             std::vector<MessageInfo> messages; | ||||
|             std::vector<MessageInfo>::const_iterator itMessage; | ||||
|             bool printInfoMessages; | ||||
|             std::size_t counter; | ||||
|         }; | ||||
| 
 | ||||
|         void printTotals( const Totals& totals ) const { | ||||
|             stream << "1.." << totals.assertions.total(); | ||||
|             if( totals.testCases.total() == 0 ) { | ||||
|                 stream << " # Skipped: No tests ran."; | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| #ifdef CATCH_IMPL | ||||
|     TAPReporter::~TAPReporter() {} | ||||
| #endif | ||||
| 
 | ||||
|     CATCH_REGISTER_REPORTER( "tap", TAPReporter ) | ||||
| 
 | ||||
| } // end namespace Catch
 | ||||
| 
 | ||||
| #endif // TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
 | ||||
| /*
 | ||||
|  *  Created by Colton Wolkins on 2015-08-15. | ||||
|  *  Copyright 2015 Martin Moene. 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_TAP_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED | ||||
| 
 | ||||
| 
 | ||||
| // Don't #include any Catch headers here - we can assume they are already
 | ||||
| // included before this header.
 | ||||
| // This is not good practice in general but is necessary in this case so this
 | ||||
| // file can be distributed as a single header that works with the main
 | ||||
| // Catch single header.
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
| namespace Catch { | ||||
| 
 | ||||
|     struct TAPReporter : StreamingReporterBase<TAPReporter> { | ||||
| 
 | ||||
|         using StreamingReporterBase::StreamingReporterBase; | ||||
| 
 | ||||
|         TAPReporter( ReporterConfig const& config ): | ||||
|             StreamingReporterBase( config ) { | ||||
|             m_reporterPrefs.shouldReportAllAssertions = true; | ||||
|         } | ||||
| 
 | ||||
|         ~TAPReporter() override; | ||||
| 
 | ||||
|         static std::string getDescription() { | ||||
|             return "Reports test results in TAP format, suitable for test harnesses"; | ||||
|         } | ||||
| 
 | ||||
|         void noMatchingTestCases( std::string const& spec ) override { | ||||
|             stream << "# No test cases matched '" << spec << "'" << std::endl; | ||||
|         } | ||||
| 
 | ||||
|         void assertionStarting( AssertionInfo const& ) override {} | ||||
| 
 | ||||
|         bool assertionEnded( AssertionStats const& _assertionStats ) override { | ||||
|             ++counter; | ||||
| 
 | ||||
|             stream << "# " << currentTestCaseInfo->name << std::endl; | ||||
|             AssertionPrinter printer( stream, _assertionStats, counter ); | ||||
|             printer.print(); | ||||
| 
 | ||||
|             stream << std::endl; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         void testRunEnded( TestRunStats const& _testRunStats ) override { | ||||
|             printTotals( _testRunStats.totals ); | ||||
|             stream << "\n" << std::endl; | ||||
|             StreamingReporterBase::testRunEnded( _testRunStats ); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         std::size_t counter = 0; | ||||
|         class AssertionPrinter { | ||||
|         public: | ||||
|             AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; | ||||
|             AssertionPrinter( AssertionPrinter const& ) = delete; | ||||
|             AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter ) | ||||
|             : stream( _stream ) | ||||
|             , result( _stats.assertionResult ) | ||||
|             , messages( _stats.infoMessages ) | ||||
|             , itMessage( _stats.infoMessages.begin() ) | ||||
|             , printInfoMessages( true ) | ||||
|             , counter(_counter) | ||||
|             {} | ||||
| 
 | ||||
|             void print() { | ||||
|                 itMessage = messages.begin(); | ||||
| 
 | ||||
|                 switch( result.getResultType() ) { | ||||
|                     case ResultWas::Ok: | ||||
|                         printResultType( passedString() ); | ||||
|                         printOriginalExpression(); | ||||
|                         printReconstructedExpression(); | ||||
|                         if ( ! result.hasExpression() ) | ||||
|                             printRemainingMessages( Colour::None ); | ||||
|                         else | ||||
|                             printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::ExpressionFailed: | ||||
|                         if (result.isOk()) { | ||||
|                             printResultType(passedString()); | ||||
|                         } else { | ||||
|                             printResultType(failedString()); | ||||
|                         } | ||||
|                         printOriginalExpression(); | ||||
|                         printReconstructedExpression(); | ||||
|                         if (result.isOk()) { | ||||
|                             printIssue(" # TODO"); | ||||
|                         } | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::ThrewException: | ||||
|                         printResultType( failedString() ); | ||||
|                         printIssue( "unexpected exception with message:" ); | ||||
|                         printMessage(); | ||||
|                         printExpressionWas(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::FatalErrorCondition: | ||||
|                         printResultType( failedString() ); | ||||
|                         printIssue( "fatal error condition with message:" ); | ||||
|                         printMessage(); | ||||
|                         printExpressionWas(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::DidntThrowException: | ||||
|                         printResultType( failedString() ); | ||||
|                         printIssue( "expected exception, got none" ); | ||||
|                         printExpressionWas(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::Info: | ||||
|                         printResultType( "info" ); | ||||
|                         printMessage(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::Warning: | ||||
|                         printResultType( "warning" ); | ||||
|                         printMessage(); | ||||
|                         printRemainingMessages(); | ||||
|                         break; | ||||
|                     case ResultWas::ExplicitFailure: | ||||
|                         printResultType( failedString() ); | ||||
|                         printIssue( "explicitly" ); | ||||
|                         printRemainingMessages( Colour::None ); | ||||
|                         break; | ||||
|                     // These cases are here to prevent compiler warnings
 | ||||
|                     case ResultWas::Unknown: | ||||
|                     case ResultWas::FailureBit: | ||||
|                     case ResultWas::Exception: | ||||
|                         printResultType( "** internal error **" ); | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         private: | ||||
|             static Colour::Code dimColour() { return Colour::FileName; } | ||||
| 
 | ||||
|             static const char* failedString() { return "not ok"; } | ||||
|             static const char* passedString() { return "ok"; } | ||||
| 
 | ||||
|             void printSourceInfo() const { | ||||
|                 Colour colourGuard( dimColour() ); | ||||
|                 stream << result.getSourceInfo() << ":"; | ||||
|             } | ||||
| 
 | ||||
|             void printResultType( std::string const& passOrFail ) const { | ||||
|                 if( !passOrFail.empty() ) { | ||||
|                     stream << passOrFail << ' ' << counter << " -"; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printIssue( std::string const& issue ) const { | ||||
|                 stream << " " << issue; | ||||
|             } | ||||
| 
 | ||||
|             void printExpressionWas() { | ||||
|                 if( result.hasExpression() ) { | ||||
|                     stream << ";"; | ||||
|                     { | ||||
|                         Colour colour( dimColour() ); | ||||
|                         stream << " expression was:"; | ||||
|                     } | ||||
|                     printOriginalExpression(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printOriginalExpression() const { | ||||
|                 if( result.hasExpression() ) { | ||||
|                     stream << " " << result.getExpression(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printReconstructedExpression() const { | ||||
|                 if( result.hasExpandedExpression() ) { | ||||
|                     { | ||||
|                         Colour colour( dimColour() ); | ||||
|                         stream << " for: "; | ||||
|                     } | ||||
|                     std::string expr = result.getExpandedExpression(); | ||||
|                     std::replace( expr.begin(), expr.end(), '\n', ' '); | ||||
|                     stream << expr; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printMessage() { | ||||
|                 if ( itMessage != messages.end() ) { | ||||
|                     stream << " '" << itMessage->message << "'"; | ||||
|                     ++itMessage; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             void printRemainingMessages( Colour::Code colour = dimColour() ) { | ||||
|                 if (itMessage == messages.end()) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 const auto itEnd = messages.cend(); | ||||
|                 const auto N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) ); | ||||
| 
 | ||||
|                 { | ||||
|                     Colour colourGuard( colour ); | ||||
|                     stream << " with " << pluralise( N, "message" ) << ":"; | ||||
|                 } | ||||
| 
 | ||||
|                 while( itMessage != itEnd ) { | ||||
|                     // If this assertion is a warning ignore any INFO messages
 | ||||
|                     if( printInfoMessages || itMessage->type != ResultWas::Info ) { | ||||
|                         stream << " '" << itMessage->message << "'"; | ||||
|                         if ( ++itMessage != itEnd ) { | ||||
|                             Colour colourGuard( dimColour() ); | ||||
|                             stream << " and"; | ||||
|                         } | ||||
|                         continue; | ||||
|                     } | ||||
|                     ++itMessage; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         private: | ||||
|             std::ostream& stream; | ||||
|             AssertionResult const& result; | ||||
|             std::vector<MessageInfo> messages; | ||||
|             std::vector<MessageInfo>::const_iterator itMessage; | ||||
|             bool printInfoMessages; | ||||
|             std::size_t counter; | ||||
|         }; | ||||
| 
 | ||||
|         void printTotals( const Totals& totals ) const { | ||||
|             stream << "1.." << totals.assertions.total(); | ||||
|             if( totals.testCases.total() == 0 ) { | ||||
|                 stream << " # Skipped: No tests ran."; | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| #ifdef CATCH_IMPL | ||||
|     TAPReporter::~TAPReporter() {} | ||||
| #endif | ||||
| 
 | ||||
|     CATCH_REGISTER_REPORTER( "tap", TAPReporter ) | ||||
| 
 | ||||
| } // end namespace Catch
 | ||||
| 
 | ||||
| #endif // TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
 | ||||
|  | ||||
| @ -1,219 +1,219 @@ | ||||
| /*
 | ||||
|  *  Created by Phil Nash on 19th December 2014 | ||||
|  *  Copyright 2014 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_TEAMCITY_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED | ||||
| 
 | ||||
| // Don't #include any Catch headers here - we can assume they are already
 | ||||
| // included before this header.
 | ||||
| // This is not good practice in general but is necessary in this case so this
 | ||||
| // file can be distributed as a single header that works with the main
 | ||||
| // Catch single header.
 | ||||
| 
 | ||||
| #include <cstring> | ||||
| 
 | ||||
| #ifdef __clang__ | ||||
| #   pragma clang diagnostic push | ||||
| #   pragma clang diagnostic ignored "-Wpadded" | ||||
| #endif | ||||
| 
 | ||||
| namespace Catch { | ||||
| 
 | ||||
|     struct TeamCityReporter : StreamingReporterBase<TeamCityReporter> { | ||||
|         TeamCityReporter( ReporterConfig const& _config ) | ||||
|         :   StreamingReporterBase( _config ) | ||||
|         { | ||||
|             m_reporterPrefs.shouldRedirectStdOut = true; | ||||
|         } | ||||
| 
 | ||||
|         static std::string escape( std::string const& str ) { | ||||
|             std::string escaped = str; | ||||
|             replaceInPlace( escaped, "|", "||" ); | ||||
|             replaceInPlace( escaped, "'", "|'" ); | ||||
|             replaceInPlace( escaped, "\n", "|n" ); | ||||
|             replaceInPlace( escaped, "\r", "|r" ); | ||||
|             replaceInPlace( escaped, "[", "|[" ); | ||||
|             replaceInPlace( escaped, "]", "|]" ); | ||||
|             return escaped; | ||||
|         } | ||||
|         ~TeamCityReporter() override; | ||||
| 
 | ||||
|         static std::string getDescription() { | ||||
|             return "Reports test results as TeamCity service messages"; | ||||
|         } | ||||
| 
 | ||||
|         void skipTest( TestCaseInfo const& /* testInfo */ ) override { | ||||
|         } | ||||
| 
 | ||||
|         void noMatchingTestCases( std::string const& /* spec */ ) override {} | ||||
| 
 | ||||
|         void testGroupStarting( GroupInfo const& groupInfo ) override { | ||||
|             StreamingReporterBase::testGroupStarting( groupInfo ); | ||||
|             stream << "##teamcity[testSuiteStarted name='" | ||||
|                 << escape( groupInfo.name ) << "']\n"; | ||||
|         } | ||||
|         void testGroupEnded( TestGroupStats const& testGroupStats ) override { | ||||
|             StreamingReporterBase::testGroupEnded( testGroupStats ); | ||||
|             stream << "##teamcity[testSuiteFinished name='" | ||||
|                 << escape( testGroupStats.groupInfo.name ) << "']\n"; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         void assertionStarting( AssertionInfo const& ) override {} | ||||
| 
 | ||||
|         bool assertionEnded( AssertionStats const& assertionStats ) override { | ||||
|             AssertionResult const& result = assertionStats.assertionResult; | ||||
|             if( !result.isOk() ) { | ||||
| 
 | ||||
|                 ReusableStringStream msg; | ||||
|                 if( !m_headerPrintedForThisSection ) | ||||
|                     printSectionHeader( msg.get() ); | ||||
|                 m_headerPrintedForThisSection = true; | ||||
| 
 | ||||
|                 msg << result.getSourceInfo() << "\n"; | ||||
| 
 | ||||
|                 switch( result.getResultType() ) { | ||||
|                     case ResultWas::ExpressionFailed: | ||||
|                         msg << "expression failed"; | ||||
|                         break; | ||||
|                     case ResultWas::ThrewException: | ||||
|                         msg << "unexpected exception"; | ||||
|                         break; | ||||
|                     case ResultWas::FatalErrorCondition: | ||||
|                         msg << "fatal error condition"; | ||||
|                         break; | ||||
|                     case ResultWas::DidntThrowException: | ||||
|                         msg << "no exception was thrown where one was expected"; | ||||
|                         break; | ||||
|                     case ResultWas::ExplicitFailure: | ||||
|                         msg << "explicit failure"; | ||||
|                         break; | ||||
| 
 | ||||
|                     // We shouldn't get here because of the isOk() test
 | ||||
|                     case ResultWas::Ok: | ||||
|                     case ResultWas::Info: | ||||
|                     case ResultWas::Warning: | ||||
|                         CATCH_ERROR( "Internal error in TeamCity reporter" ); | ||||
|                     // These cases are here to prevent compiler warnings
 | ||||
|                     case ResultWas::Unknown: | ||||
|                     case ResultWas::FailureBit: | ||||
|                     case ResultWas::Exception: | ||||
|                         CATCH_ERROR( "Not implemented" ); | ||||
|                 } | ||||
|                 if( assertionStats.infoMessages.size() == 1 ) | ||||
|                     msg << " with message:"; | ||||
|                 if( assertionStats.infoMessages.size() > 1 ) | ||||
|                     msg << " with messages:"; | ||||
|                 for( auto const& messageInfo : assertionStats.infoMessages ) | ||||
|                     msg << "\n  \"" << messageInfo.message << "\""; | ||||
| 
 | ||||
| 
 | ||||
|                 if( result.hasExpression() ) { | ||||
|                     msg << | ||||
|                         "\n  " << result.getExpressionInMacro() << "\n" | ||||
|                         "with expansion:\n" << | ||||
|                         "  " << result.getExpandedExpression() << "\n"; | ||||
|                 } | ||||
| 
 | ||||
|                 if( currentTestCaseInfo->okToFail() ) { | ||||
|                     msg << "- failure ignore as test marked as 'ok to fail'\n"; | ||||
|                     stream << "##teamcity[testIgnored" | ||||
|                            << " name='" << escape( currentTestCaseInfo->name )<< "'" | ||||
|                            << " message='" << escape( msg.str() ) << "'" | ||||
|                            << "]\n"; | ||||
|                 } | ||||
|                 else { | ||||
|                     stream << "##teamcity[testFailed" | ||||
|                            << " name='" << escape( currentTestCaseInfo->name )<< "'" | ||||
|                            << " message='" << escape( msg.str() ) << "'" | ||||
|                            << "]\n"; | ||||
|                 } | ||||
|             } | ||||
|             stream.flush(); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         void sectionStarting( SectionInfo const& sectionInfo ) override { | ||||
|             m_headerPrintedForThisSection = false; | ||||
|             StreamingReporterBase::sectionStarting( sectionInfo ); | ||||
|         } | ||||
| 
 | ||||
|         void testCaseStarting( TestCaseInfo const& testInfo ) override { | ||||
|             m_testTimer.start(); | ||||
|             StreamingReporterBase::testCaseStarting( testInfo ); | ||||
|             stream << "##teamcity[testStarted name='" | ||||
|                 << escape( testInfo.name ) << "']\n"; | ||||
|             stream.flush(); | ||||
|         } | ||||
| 
 | ||||
|         void testCaseEnded( TestCaseStats const& testCaseStats ) override { | ||||
|             StreamingReporterBase::testCaseEnded( testCaseStats ); | ||||
|             if( !testCaseStats.stdOut.empty() ) | ||||
|                 stream << "##teamcity[testStdOut name='" | ||||
|                     << escape( testCaseStats.testInfo.name ) | ||||
|                     << "' out='" << escape( testCaseStats.stdOut ) << "']\n"; | ||||
|             if( !testCaseStats.stdErr.empty() ) | ||||
|                 stream << "##teamcity[testStdErr name='" | ||||
|                     << escape( testCaseStats.testInfo.name ) | ||||
|                     << "' out='" << escape( testCaseStats.stdErr ) << "']\n"; | ||||
|             stream << "##teamcity[testFinished name='" | ||||
|                     << escape( testCaseStats.testInfo.name ) << "' duration='" | ||||
|                     << m_testTimer.getElapsedMilliseconds() << "']\n"; | ||||
|             stream.flush(); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         void printSectionHeader( std::ostream& os ) { | ||||
|             assert( !m_sectionStack.empty() ); | ||||
| 
 | ||||
|             if( m_sectionStack.size() > 1 ) { | ||||
|                 os << getLineOfChars<'-'>() << "\n"; | ||||
| 
 | ||||
|                 std::vector<SectionInfo>::const_iterator | ||||
|                 it = m_sectionStack.begin()+1, // Skip first section (test case)
 | ||||
|                 itEnd = m_sectionStack.end(); | ||||
|                 for( ; it != itEnd; ++it ) | ||||
|                     printHeaderString( os, it->name ); | ||||
|                 os << getLineOfChars<'-'>() << "\n"; | ||||
|             } | ||||
| 
 | ||||
|             SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; | ||||
| 
 | ||||
|             os << lineInfo << "\n"; | ||||
|             os << getLineOfChars<'.'>() << "\n\n"; | ||||
|         } | ||||
| 
 | ||||
|         // if string has a : in first line will set indent to follow it on
 | ||||
|         // subsequent lines
 | ||||
|         static void printHeaderString( std::ostream& os, std::string const& _string, std::size_t indent = 0 ) { | ||||
|             std::size_t i = _string.find( ": " ); | ||||
|             if( i != std::string::npos ) | ||||
|                 i+=2; | ||||
|             else | ||||
|                 i = 0; | ||||
|             os << Column( _string ) | ||||
|                            .indent( indent+i) | ||||
|                            .initialIndent( indent ) << "\n"; | ||||
|         } | ||||
|     private: | ||||
|         bool m_headerPrintedForThisSection = false; | ||||
|         Timer m_testTimer; | ||||
|     }; | ||||
| 
 | ||||
| #ifdef CATCH_IMPL | ||||
|     TeamCityReporter::~TeamCityReporter() {} | ||||
| #endif | ||||
| 
 | ||||
|     CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter ) | ||||
| 
 | ||||
| } // end namespace Catch
 | ||||
| 
 | ||||
| #ifdef __clang__ | ||||
| #   pragma clang diagnostic pop | ||||
| #endif | ||||
| 
 | ||||
| #endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
 | ||||
| /*
 | ||||
|  *  Created by Phil Nash on 19th December 2014 | ||||
|  *  Copyright 2014 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_TEAMCITY_HPP_INCLUDED | ||||
| #define TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED | ||||
| 
 | ||||
| // Don't #include any Catch headers here - we can assume they are already
 | ||||
| // included before this header.
 | ||||
| // This is not good practice in general but is necessary in this case so this
 | ||||
| // file can be distributed as a single header that works with the main
 | ||||
| // Catch single header.
 | ||||
| 
 | ||||
| #include <cstring> | ||||
| 
 | ||||
| #ifdef __clang__ | ||||
| #   pragma clang diagnostic push | ||||
| #   pragma clang diagnostic ignored "-Wpadded" | ||||
| #endif | ||||
| 
 | ||||
| namespace Catch { | ||||
| 
 | ||||
|     struct TeamCityReporter : StreamingReporterBase<TeamCityReporter> { | ||||
|         TeamCityReporter( ReporterConfig const& _config ) | ||||
|         :   StreamingReporterBase( _config ) | ||||
|         { | ||||
|             m_reporterPrefs.shouldRedirectStdOut = true; | ||||
|         } | ||||
| 
 | ||||
|         static std::string escape( std::string const& str ) { | ||||
|             std::string escaped = str; | ||||
|             replaceInPlace( escaped, "|", "||" ); | ||||
|             replaceInPlace( escaped, "'", "|'" ); | ||||
|             replaceInPlace( escaped, "\n", "|n" ); | ||||
|             replaceInPlace( escaped, "\r", "|r" ); | ||||
|             replaceInPlace( escaped, "[", "|[" ); | ||||
|             replaceInPlace( escaped, "]", "|]" ); | ||||
|             return escaped; | ||||
|         } | ||||
|         ~TeamCityReporter() override; | ||||
| 
 | ||||
|         static std::string getDescription() { | ||||
|             return "Reports test results as TeamCity service messages"; | ||||
|         } | ||||
| 
 | ||||
|         void skipTest( TestCaseInfo const& /* testInfo */ ) override { | ||||
|         } | ||||
| 
 | ||||
|         void noMatchingTestCases( std::string const& /* spec */ ) override {} | ||||
| 
 | ||||
|         void testGroupStarting( GroupInfo const& groupInfo ) override { | ||||
|             StreamingReporterBase::testGroupStarting( groupInfo ); | ||||
|             stream << "##teamcity[testSuiteStarted name='" | ||||
|                 << escape( groupInfo.name ) << "']\n"; | ||||
|         } | ||||
|         void testGroupEnded( TestGroupStats const& testGroupStats ) override { | ||||
|             StreamingReporterBase::testGroupEnded( testGroupStats ); | ||||
|             stream << "##teamcity[testSuiteFinished name='" | ||||
|                 << escape( testGroupStats.groupInfo.name ) << "']\n"; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         void assertionStarting( AssertionInfo const& ) override {} | ||||
| 
 | ||||
|         bool assertionEnded( AssertionStats const& assertionStats ) override { | ||||
|             AssertionResult const& result = assertionStats.assertionResult; | ||||
|             if( !result.isOk() ) { | ||||
| 
 | ||||
|                 ReusableStringStream msg; | ||||
|                 if( !m_headerPrintedForThisSection ) | ||||
|                     printSectionHeader( msg.get() ); | ||||
|                 m_headerPrintedForThisSection = true; | ||||
| 
 | ||||
|                 msg << result.getSourceInfo() << "\n"; | ||||
| 
 | ||||
|                 switch( result.getResultType() ) { | ||||
|                     case ResultWas::ExpressionFailed: | ||||
|                         msg << "expression failed"; | ||||
|                         break; | ||||
|                     case ResultWas::ThrewException: | ||||
|                         msg << "unexpected exception"; | ||||
|                         break; | ||||
|                     case ResultWas::FatalErrorCondition: | ||||
|                         msg << "fatal error condition"; | ||||
|                         break; | ||||
|                     case ResultWas::DidntThrowException: | ||||
|                         msg << "no exception was thrown where one was expected"; | ||||
|                         break; | ||||
|                     case ResultWas::ExplicitFailure: | ||||
|                         msg << "explicit failure"; | ||||
|                         break; | ||||
| 
 | ||||
|                     // We shouldn't get here because of the isOk() test
 | ||||
|                     case ResultWas::Ok: | ||||
|                     case ResultWas::Info: | ||||
|                     case ResultWas::Warning: | ||||
|                         CATCH_ERROR( "Internal error in TeamCity reporter" ); | ||||
|                     // These cases are here to prevent compiler warnings
 | ||||
|                     case ResultWas::Unknown: | ||||
|                     case ResultWas::FailureBit: | ||||
|                     case ResultWas::Exception: | ||||
|                         CATCH_ERROR( "Not implemented" ); | ||||
|                 } | ||||
|                 if( assertionStats.infoMessages.size() == 1 ) | ||||
|                     msg << " with message:"; | ||||
|                 if( assertionStats.infoMessages.size() > 1 ) | ||||
|                     msg << " with messages:"; | ||||
|                 for( auto const& messageInfo : assertionStats.infoMessages ) | ||||
|                     msg << "\n  \"" << messageInfo.message << "\""; | ||||
| 
 | ||||
| 
 | ||||
|                 if( result.hasExpression() ) { | ||||
|                     msg << | ||||
|                         "\n  " << result.getExpressionInMacro() << "\n" | ||||
|                         "with expansion:\n" << | ||||
|                         "  " << result.getExpandedExpression() << "\n"; | ||||
|                 } | ||||
| 
 | ||||
|                 if( currentTestCaseInfo->okToFail() ) { | ||||
|                     msg << "- failure ignore as test marked as 'ok to fail'\n"; | ||||
|                     stream << "##teamcity[testIgnored" | ||||
|                            << " name='" << escape( currentTestCaseInfo->name )<< "'" | ||||
|                            << " message='" << escape( msg.str() ) << "'" | ||||
|                            << "]\n"; | ||||
|                 } | ||||
|                 else { | ||||
|                     stream << "##teamcity[testFailed" | ||||
|                            << " name='" << escape( currentTestCaseInfo->name )<< "'" | ||||
|                            << " message='" << escape( msg.str() ) << "'" | ||||
|                            << "]\n"; | ||||
|                 } | ||||
|             } | ||||
|             stream.flush(); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         void sectionStarting( SectionInfo const& sectionInfo ) override { | ||||
|             m_headerPrintedForThisSection = false; | ||||
|             StreamingReporterBase::sectionStarting( sectionInfo ); | ||||
|         } | ||||
| 
 | ||||
|         void testCaseStarting( TestCaseInfo const& testInfo ) override { | ||||
|             m_testTimer.start(); | ||||
|             StreamingReporterBase::testCaseStarting( testInfo ); | ||||
|             stream << "##teamcity[testStarted name='" | ||||
|                 << escape( testInfo.name ) << "']\n"; | ||||
|             stream.flush(); | ||||
|         } | ||||
| 
 | ||||
|         void testCaseEnded( TestCaseStats const& testCaseStats ) override { | ||||
|             StreamingReporterBase::testCaseEnded( testCaseStats ); | ||||
|             if( !testCaseStats.stdOut.empty() ) | ||||
|                 stream << "##teamcity[testStdOut name='" | ||||
|                     << escape( testCaseStats.testInfo.name ) | ||||
|                     << "' out='" << escape( testCaseStats.stdOut ) << "']\n"; | ||||
|             if( !testCaseStats.stdErr.empty() ) | ||||
|                 stream << "##teamcity[testStdErr name='" | ||||
|                     << escape( testCaseStats.testInfo.name ) | ||||
|                     << "' out='" << escape( testCaseStats.stdErr ) << "']\n"; | ||||
|             stream << "##teamcity[testFinished name='" | ||||
|                     << escape( testCaseStats.testInfo.name ) << "' duration='" | ||||
|                     << m_testTimer.getElapsedMilliseconds() << "']\n"; | ||||
|             stream.flush(); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         void printSectionHeader( std::ostream& os ) { | ||||
|             assert( !m_sectionStack.empty() ); | ||||
| 
 | ||||
|             if( m_sectionStack.size() > 1 ) { | ||||
|                 os << getLineOfChars<'-'>() << "\n"; | ||||
| 
 | ||||
|                 std::vector<SectionInfo>::const_iterator | ||||
|                 it = m_sectionStack.begin()+1, // Skip first section (test case)
 | ||||
|                 itEnd = m_sectionStack.end(); | ||||
|                 for( ; it != itEnd; ++it ) | ||||
|                     printHeaderString( os, it->name ); | ||||
|                 os << getLineOfChars<'-'>() << "\n"; | ||||
|             } | ||||
| 
 | ||||
|             SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; | ||||
| 
 | ||||
|             os << lineInfo << "\n"; | ||||
|             os << getLineOfChars<'.'>() << "\n\n"; | ||||
|         } | ||||
| 
 | ||||
|         // if string has a : in first line will set indent to follow it on
 | ||||
|         // subsequent lines
 | ||||
|         static void printHeaderString( std::ostream& os, std::string const& _string, std::size_t indent = 0 ) { | ||||
|             std::size_t i = _string.find( ": " ); | ||||
|             if( i != std::string::npos ) | ||||
|                 i+=2; | ||||
|             else | ||||
|                 i = 0; | ||||
|             os << Column( _string ) | ||||
|                            .indent( indent+i) | ||||
|                            .initialIndent( indent ) << "\n"; | ||||
|         } | ||||
|     private: | ||||
|         bool m_headerPrintedForThisSection = false; | ||||
|         Timer m_testTimer; | ||||
|     }; | ||||
| 
 | ||||
| #ifdef CATCH_IMPL | ||||
|     TeamCityReporter::~TeamCityReporter() {} | ||||
| #endif | ||||
| 
 | ||||
|     CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter ) | ||||
| 
 | ||||
| } // end namespace Catch
 | ||||
| 
 | ||||
| #ifdef __clang__ | ||||
| #   pragma clang diagnostic pop | ||||
| #endif | ||||
| 
 | ||||
| #endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
 | ||||
|  | ||||
					Loading…
					
					
				
		Reference in new issue