Merge pull request #1104 from paulfd/submodule-updates-2207

Submodule updates - 2022-07
This commit is contained in:
Paul Ferrand 2022-07-29 02:50:02 +02:00 committed by GitHub
commit b6aea989d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 1078 additions and 978 deletions

2
external/abseil-cpp vendored

@ -1 +1 @@
Subproject commit 215105818dfde3174fe799600bb0f3cae233d0bf Subproject commit 273292d1cfc0a94a65082ee350509af1d113344d

2
external/filesystem vendored

@ -1 +1 @@
Subproject commit 614bbe87b80435d87ab8791564370e0c1d13627d Subproject commit cd6805e94dd5d6346be1b75a54cdc27787319dd2

View file

@ -1,7 +1,7 @@
/** /**
* pugixml parser - version 1.11 * pugixml parser - version 1.12
* -------------------------------------------------------- * --------------------------------------------------------
* Copyright (C) 2006-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at https://pugixml.org/ * Report bugs and download new versions at https://pugixml.org/
* *
* This library is distributed under the MIT License. See notice at the end * This library is distributed under the MIT License. See notice at the end
@ -52,7 +52,7 @@
#endif #endif
/** /**
* Copyright (c) 2006-2020 Arseny Kapoulkine * Copyright (c) 2006-2022 Arseny Kapoulkine
* *
* Permission is hereby granted, free of charge, to any person * Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation * obtaining a copy of this software and associated documentation

View file

@ -1,7 +1,7 @@
/** /**
* pugixml parser - version 1.11 * pugixml parser - version 1.12
* -------------------------------------------------------- * --------------------------------------------------------
* Copyright (C) 2006-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at https://pugixml.org/ * Report bugs and download new versions at https://pugixml.org/
* *
* This library is distributed under the MIT License. See notice at the end * This library is distributed under the MIT License. See notice at the end
@ -132,8 +132,10 @@ using std::memset;
#endif #endif
// In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features
#if defined(_MSC_VER) && !defined(__S3E__) #if defined(_MSC_VER) && !defined(__S3E__) && !defined(_WIN32_WCE)
# define PUGI__MSVC_CRT_VERSION _MSC_VER # define PUGI__MSVC_CRT_VERSION _MSC_VER
#elif defined(_WIN32_WCE)
# define PUGI__MSVC_CRT_VERSION 1310 // MSVC7.1
#endif #endif
// Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size. // Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size.
@ -526,7 +528,8 @@ PUGI__NS_BEGIN
xml_memory_page* page = xml_memory_page::construct(memory); xml_memory_page* page = xml_memory_page::construct(memory);
assert(page); assert(page);
page->allocator = _root->allocator; assert(this == _root->allocator);
page->allocator = this;
return page; return page;
} }
@ -4732,7 +4735,7 @@ PUGI__NS_BEGIN
// we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick
PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result) PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
{ {
#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
// there are 64-bit versions of fseek/ftell, let's use them // there are 64-bit versions of fseek/ftell, let's use them
typedef __int64 length_type; typedef __int64 length_type;
@ -6735,7 +6738,7 @@ namespace pugi
return const_cast<xml_node*>(&_wrap); // BCC5 workaround return const_cast<xml_node*>(&_wrap); // BCC5 workaround
} }
PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() PUGI__FN xml_node_iterator& xml_node_iterator::operator++()
{ {
assert(_wrap._root); assert(_wrap._root);
_wrap._root = _wrap._root->next_sibling; _wrap._root = _wrap._root->next_sibling;
@ -6749,7 +6752,7 @@ namespace pugi
return temp; return temp;
} }
PUGI__FN const xml_node_iterator& xml_node_iterator::operator--() PUGI__FN xml_node_iterator& xml_node_iterator::operator--()
{ {
_wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
return *this; return *this;
@ -6796,7 +6799,7 @@ namespace pugi
return const_cast<xml_attribute*>(&_wrap); // BCC5 workaround return const_cast<xml_attribute*>(&_wrap); // BCC5 workaround
} }
PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() PUGI__FN xml_attribute_iterator& xml_attribute_iterator::operator++()
{ {
assert(_wrap._attr); assert(_wrap._attr);
_wrap._attr = _wrap._attr->next_attribute; _wrap._attr = _wrap._attr->next_attribute;
@ -6810,7 +6813,7 @@ namespace pugi
return temp; return temp;
} }
PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--() PUGI__FN xml_attribute_iterator& xml_attribute_iterator::operator--()
{ {
_wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
return *this; return *this;
@ -6857,7 +6860,7 @@ namespace pugi
return const_cast<xml_node*>(&_wrap); // BCC5 workaround return const_cast<xml_node*>(&_wrap); // BCC5 workaround
} }
PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator++()
{ {
assert(_wrap._root); assert(_wrap._root);
_wrap = _wrap.next_sibling(_name); _wrap = _wrap.next_sibling(_name);
@ -6871,7 +6874,7 @@ namespace pugi
return temp; return temp;
} }
PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator--() PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator--()
{ {
if (_wrap._root) if (_wrap._root)
_wrap = _wrap.previous_sibling(_name); _wrap = _wrap.previous_sibling(_name);
@ -7091,8 +7094,12 @@ namespace pugi
#endif #endif
// move allocation state // move allocation state
doc->_root = other->_root; // note that other->_root may point to the embedded document page, in which case we should keep original (empty) state
doc->_busy_size = other->_busy_size; if (other->_root != PUGI__GETPAGE(other))
{
doc->_root = other->_root;
doc->_busy_size = other->_busy_size;
}
// move buffer state // move buffer state
doc->buffer = other->buffer; doc->buffer = other->buffer;
@ -8265,7 +8272,7 @@ PUGI__NS_BEGIN
} }
// gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)
{ {
// get base values // get base values
@ -11822,15 +11829,17 @@ PUGI__NS_BEGIN
lexeme_t l = _lexer.current(); lexeme_t l = _lexer.current();
_lexer.next(); _lexer.next();
if (++_depth > xpath_ast_depth_limit)
return error_rec();
if (l == lex_double_slash) if (l == lex_double_slash)
{ {
n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
if (!n) return 0; if (!n) return 0;
++_depth;
} }
if (++_depth > xpath_ast_depth_limit)
return error_rec();
n = parse_step(n); n = parse_step(n);
if (!n) return 0; if (!n) return 0;
} }
@ -12995,7 +13004,7 @@ namespace pugi
#endif #endif
/** /**
* Copyright (c) 2006-2020 Arseny Kapoulkine * Copyright (c) 2006-2022 Arseny Kapoulkine
* *
* Permission is hereby granted, free of charge, to any person * Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation * obtaining a copy of this software and associated documentation

View file

@ -1,7 +1,7 @@
/** /**
* pugixml parser - version 1.11 * pugixml parser - version 1.12
* -------------------------------------------------------- * --------------------------------------------------------
* Copyright (C) 2006-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at https://pugixml.org/ * Report bugs and download new versions at https://pugixml.org/
* *
* This library is distributed under the MIT License. See notice at the end * This library is distributed under the MIT License. See notice at the end
@ -11,10 +11,10 @@
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
*/ */
#ifndef PUGIXML_VERSION
// Define version macro; evaluates to major * 1000 + minor * 10 + patch so that it's safe to use in less-than comparisons // Define version macro; evaluates to major * 1000 + minor * 10 + patch so that it's safe to use in less-than comparisons
// Note: pugixml used major * 100 + minor * 10 + patch format up until 1.9 (which had version identifier 190); starting from pugixml 1.10, the minor version number is two digits // Note: pugixml used major * 100 + minor * 10 + patch format up until 1.9 (which had version identifier 190); starting from pugixml 1.10, the minor version number is two digits
# define PUGIXML_VERSION 1110 #ifndef PUGIXML_VERSION
# define PUGIXML_VERSION 1120 // 1.12
#endif #endif
// Include user configuration file (this can define various configuration macros) // Include user configuration file (this can define various configuration macros)
@ -312,6 +312,8 @@ namespace pugi
It begin() const { return _begin; } It begin() const { return _begin; }
It end() const { return _end; } It end() const { return _end; }
bool empty() const { return _begin == _end; }
private: private:
It _begin, _end; It _begin, _end;
}; };
@ -851,10 +853,10 @@ namespace pugi
xml_node& operator*() const; xml_node& operator*() const;
xml_node* operator->() const; xml_node* operator->() const;
const xml_node_iterator& operator++(); xml_node_iterator& operator++();
xml_node_iterator operator++(int); xml_node_iterator operator++(int);
const xml_node_iterator& operator--(); xml_node_iterator& operator--();
xml_node_iterator operator--(int); xml_node_iterator operator--(int);
}; };
@ -893,10 +895,10 @@ namespace pugi
xml_attribute& operator*() const; xml_attribute& operator*() const;
xml_attribute* operator->() const; xml_attribute* operator->() const;
const xml_attribute_iterator& operator++(); xml_attribute_iterator& operator++();
xml_attribute_iterator operator++(int); xml_attribute_iterator operator++(int);
const xml_attribute_iterator& operator--(); xml_attribute_iterator& operator--();
xml_attribute_iterator operator--(int); xml_attribute_iterator operator--(int);
}; };
@ -929,10 +931,10 @@ namespace pugi
xml_node& operator*() const; xml_node& operator*() const;
xml_node* operator->() const; xml_node* operator->() const;
const xml_named_node_iterator& operator++(); xml_named_node_iterator& operator++();
xml_named_node_iterator operator++(int); xml_named_node_iterator operator++(int);
const xml_named_node_iterator& operator--(); xml_named_node_iterator& operator--();
xml_named_node_iterator operator--(int); xml_named_node_iterator operator--(int);
private: private:
@ -1474,7 +1476,7 @@ namespace std
#endif #endif
/** /**
* Copyright (c) 2006-2020 Arseny Kapoulkine * Copyright (c) 2006-2022 Arseny Kapoulkine
* *
* Permission is hereby granted, free of charge, to any person * Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation * obtaining a copy of this software and associated documentation

File diff suppressed because it is too large Load diff

View file

@ -1,62 +1,62 @@
/* /*
* Created by Justin R. Wilson on 2/19/2017. * Created by Justin R. Wilson on 2/19/2017.
* Copyright 2017 Justin R. Wilson. All rights reserved. * Copyright 2017 Justin R. Wilson. All rights reserved.
* *
* Distributed under the Boost Software License, Version 1.0. (See accompanying * 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) * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/ */
#ifndef TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
#define 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 // Don't #include any Catch headers here - we can assume they are already
// included before this header. // included before this header.
// This is not good practice in general but is necessary in this case so this // 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 // file can be distributed as a single header that works with the main
// Catch single header. // Catch single header.
namespace Catch { namespace Catch {
struct AutomakeReporter : StreamingReporterBase<AutomakeReporter> { struct AutomakeReporter : StreamingReporterBase<AutomakeReporter> {
AutomakeReporter( ReporterConfig const& _config ) AutomakeReporter( ReporterConfig const& _config )
: StreamingReporterBase( _config ) : StreamingReporterBase( _config )
{} {}
~AutomakeReporter() override; ~AutomakeReporter() override;
static std::string getDescription() { static std::string getDescription() {
return "Reports test results in the format of Automake .trs files"; return "Reports test results in the format of Automake .trs files";
} }
void assertionStarting( AssertionInfo const& ) override {} void assertionStarting( AssertionInfo const& ) override {}
bool assertionEnded( AssertionStats const& /*_assertionStats*/ ) override { return true; } bool assertionEnded( AssertionStats const& /*_assertionStats*/ ) override { return true; }
void testCaseEnded( TestCaseStats const& _testCaseStats ) override { void testCaseEnded( TestCaseStats const& _testCaseStats ) override {
// Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR. // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
stream << ":test-result: "; stream << ":test-result: ";
if (_testCaseStats.totals.assertions.allPassed()) { if (_testCaseStats.totals.assertions.allPassed()) {
stream << "PASS"; stream << "PASS";
} else if (_testCaseStats.totals.assertions.allOk()) { } else if (_testCaseStats.totals.assertions.allOk()) {
stream << "XFAIL"; stream << "XFAIL";
} else { } else {
stream << "FAIL"; stream << "FAIL";
} }
stream << ' ' << _testCaseStats.testInfo.name << '\n'; stream << ' ' << _testCaseStats.testInfo.name << '\n';
StreamingReporterBase::testCaseEnded( _testCaseStats ); StreamingReporterBase::testCaseEnded( _testCaseStats );
} }
void skipTest( TestCaseInfo const& testInfo ) override { void skipTest( TestCaseInfo const& testInfo ) override {
stream << ":test-result: SKIP " << testInfo.name << '\n'; stream << ":test-result: SKIP " << testInfo.name << '\n';
} }
}; };
#ifdef CATCH_IMPL #ifdef CATCH_IMPL
AutomakeReporter::~AutomakeReporter() {} AutomakeReporter::~AutomakeReporter() {}
#endif #endif
CATCH_REGISTER_REPORTER( "automake", AutomakeReporter) CATCH_REGISTER_REPORTER( "automake", AutomakeReporter)
} // end namespace Catch } // end namespace Catch
#endif // TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED

View file

@ -1,181 +1,181 @@
/* /*
* Created by Daniel Garcia on 2018-12-04. * Created by Daniel Garcia on 2018-12-04.
* Copyright Social Point SL. All rights reserved. * Copyright Social Point SL. All rights reserved.
* *
* Distributed under the Boost Software License, Version 1.0. (See accompanying * 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) * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/ */
#ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED #ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
#define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED #define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
// Don't #include any Catch headers here - we can assume they are already // Don't #include any Catch headers here - we can assume they are already
// included before this header. // included before this header.
// This is not good practice in general but is necessary in this case so this // 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 // file can be distributed as a single header that works with the main
// Catch single header. // Catch single header.
#include <map> #include <map>
namespace Catch { namespace Catch {
struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> { struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> {
SonarQubeReporter(ReporterConfig const& config) SonarQubeReporter(ReporterConfig const& config)
: CumulativeReporterBase(config) : CumulativeReporterBase(config)
, xml(config.stream()) { , xml(config.stream()) {
m_reporterPrefs.shouldRedirectStdOut = true; m_reporterPrefs.shouldRedirectStdOut = true;
m_reporterPrefs.shouldReportAllAssertions = true; m_reporterPrefs.shouldReportAllAssertions = true;
} }
~SonarQubeReporter() override; ~SonarQubeReporter() override;
static std::string getDescription() { static std::string getDescription() {
return "Reports test results in the Generic Test Data SonarQube XML format"; return "Reports test results in the Generic Test Data SonarQube XML format";
} }
static std::set<Verbosity> getSupportedVerbosities() { static std::set<Verbosity> getSupportedVerbosities() {
return { Verbosity::Normal }; return { Verbosity::Normal };
} }
void noMatchingTestCases(std::string const& /*spec*/) override {} void noMatchingTestCases(std::string const& /*spec*/) override {}
void testRunStarting(TestRunInfo const& testRunInfo) override { void testRunStarting(TestRunInfo const& testRunInfo) override {
CumulativeReporterBase::testRunStarting(testRunInfo); CumulativeReporterBase::testRunStarting(testRunInfo);
xml.startElement("testExecutions"); xml.startElement("testExecutions");
xml.writeAttribute("version", "1"); xml.writeAttribute("version", "1");
} }
void testGroupEnded(TestGroupStats const& testGroupStats) override { void testGroupEnded(TestGroupStats const& testGroupStats) override {
CumulativeReporterBase::testGroupEnded(testGroupStats); CumulativeReporterBase::testGroupEnded(testGroupStats);
writeGroup(*m_testGroups.back()); writeGroup(*m_testGroups.back());
} }
void testRunEndedCumulative() override { void testRunEndedCumulative() override {
xml.endElement(); xml.endElement();
} }
void writeGroup(TestGroupNode const& groupNode) { void writeGroup(TestGroupNode const& groupNode) {
std::map<std::string, TestGroupNode::ChildNodes> testsPerFile; std::map<std::string, TestGroupNode::ChildNodes> testsPerFile;
for(auto const& child : groupNode.children) for(auto const& child : groupNode.children)
testsPerFile[child->value.testInfo.lineInfo.file].push_back(child); testsPerFile[child->value.testInfo.lineInfo.file].push_back(child);
for(auto const& kv : testsPerFile) for(auto const& kv : testsPerFile)
writeTestFile(kv.first.c_str(), kv.second); writeTestFile(kv.first.c_str(), kv.second);
} }
void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) { void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) {
XmlWriter::ScopedElement e = xml.scopedElement("file"); XmlWriter::ScopedElement e = xml.scopedElement("file");
xml.writeAttribute("path", filename); xml.writeAttribute("path", filename);
for(auto const& child : testCaseNodes) for(auto const& child : testCaseNodes)
writeTestCase(*child); writeTestCase(*child);
} }
void writeTestCase(TestCaseNode const& testCaseNode) { void writeTestCase(TestCaseNode const& testCaseNode) {
// All test cases have exactly one section - which represents the // All test cases have exactly one section - which represents the
// test case itself. That section may have 0-n nested sections // test case itself. That section may have 0-n nested sections
assert(testCaseNode.children.size() == 1); assert(testCaseNode.children.size() == 1);
SectionNode const& rootSection = *testCaseNode.children.front(); SectionNode const& rootSection = *testCaseNode.children.front();
writeSection("", rootSection, testCaseNode.value.testInfo.okToFail()); writeSection("", rootSection, testCaseNode.value.testInfo.okToFail());
} }
void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) { void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
std::string name = trim(sectionNode.stats.sectionInfo.name); std::string name = trim(sectionNode.stats.sectionInfo.name);
if(!rootName.empty()) if(!rootName.empty())
name = rootName + '/' + name; name = rootName + '/' + name;
if(!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) { if(!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) {
XmlWriter::ScopedElement e = xml.scopedElement("testCase"); XmlWriter::ScopedElement e = xml.scopedElement("testCase");
xml.writeAttribute("name", name); xml.writeAttribute("name", name);
xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000)); xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
writeAssertions(sectionNode, okToFail); writeAssertions(sectionNode, okToFail);
} }
for(auto const& childNode : sectionNode.childSections) for(auto const& childNode : sectionNode.childSections)
writeSection(name, *childNode, okToFail); writeSection(name, *childNode, okToFail);
} }
void writeAssertions(SectionNode const& sectionNode, bool okToFail) { void writeAssertions(SectionNode const& sectionNode, bool okToFail) {
for(auto const& assertion : sectionNode.assertions) for(auto const& assertion : sectionNode.assertions)
writeAssertion( assertion, okToFail); writeAssertion( assertion, okToFail);
} }
void writeAssertion(AssertionStats const& stats, bool okToFail) { void writeAssertion(AssertionStats const& stats, bool okToFail) {
AssertionResult const& result = stats.assertionResult; AssertionResult const& result = stats.assertionResult;
if(!result.isOk()) { if(!result.isOk()) {
std::string elementName; std::string elementName;
if(okToFail) { if(okToFail) {
elementName = "skipped"; elementName = "skipped";
} }
else { else {
switch(result.getResultType()) { switch(result.getResultType()) {
case ResultWas::ThrewException: case ResultWas::ThrewException:
case ResultWas::FatalErrorCondition: case ResultWas::FatalErrorCondition:
elementName = "error"; elementName = "error";
break; break;
case ResultWas::ExplicitFailure: case ResultWas::ExplicitFailure:
elementName = "failure"; elementName = "failure";
break; break;
case ResultWas::ExpressionFailed: case ResultWas::ExpressionFailed:
elementName = "failure"; elementName = "failure";
break; break;
case ResultWas::DidntThrowException: case ResultWas::DidntThrowException:
elementName = "failure"; elementName = "failure";
break; break;
// We should never see these here: // We should never see these here:
case ResultWas::Info: case ResultWas::Info:
case ResultWas::Warning: case ResultWas::Warning:
case ResultWas::Ok: case ResultWas::Ok:
case ResultWas::Unknown: case ResultWas::Unknown:
case ResultWas::FailureBit: case ResultWas::FailureBit:
case ResultWas::Exception: case ResultWas::Exception:
elementName = "internalError"; elementName = "internalError";
break; break;
} }
} }
XmlWriter::ScopedElement e = xml.scopedElement(elementName); XmlWriter::ScopedElement e = xml.scopedElement(elementName);
ReusableStringStream messageRss; ReusableStringStream messageRss;
messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")"; messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")";
xml.writeAttribute("message", messageRss.str()); xml.writeAttribute("message", messageRss.str());
ReusableStringStream textRss; ReusableStringStream textRss;
if (stats.totals.assertions.total() > 0) { if (stats.totals.assertions.total() > 0) {
textRss << "FAILED:\n"; textRss << "FAILED:\n";
if (result.hasExpression()) { if (result.hasExpression()) {
textRss << "\t" << result.getExpressionInMacro() << "\n"; textRss << "\t" << result.getExpressionInMacro() << "\n";
} }
if (result.hasExpandedExpression()) { if (result.hasExpandedExpression()) {
textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n"; textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n";
} }
} }
if(!result.getMessage().empty()) if(!result.getMessage().empty())
textRss << result.getMessage() << "\n"; textRss << result.getMessage() << "\n";
for(auto const& msg : stats.infoMessages) for(auto const& msg : stats.infoMessages)
if(msg.type == ResultWas::Info) if(msg.type == ResultWas::Info)
textRss << msg.message << "\n"; textRss << msg.message << "\n";
textRss << "at " << result.getSourceInfo(); textRss << "at " << result.getSourceInfo();
xml.writeText(textRss.str(), XmlFormatting::Newline); xml.writeText(textRss.str(), XmlFormatting::Newline);
} }
} }
private: private:
XmlWriter xml; XmlWriter xml;
}; };
#ifdef CATCH_IMPL #ifdef CATCH_IMPL
SonarQubeReporter::~SonarQubeReporter() {} SonarQubeReporter::~SonarQubeReporter() {}
#endif #endif
CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter ) CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter )
} // end namespace Catch } // end namespace Catch
#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED #endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED

View file

@ -1,254 +1,254 @@
/* /*
* Created by Colton Wolkins on 2015-08-15. * Created by Colton Wolkins on 2015-08-15.
* Copyright 2015 Martin Moene. All rights reserved. * Copyright 2015 Martin Moene. All rights reserved.
* *
* Distributed under the Boost Software License, Version 1.0. (See accompanying * 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) * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/ */
#ifndef TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
#define 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 // Don't #include any Catch headers here - we can assume they are already
// included before this header. // included before this header.
// This is not good practice in general but is necessary in this case so this // 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 // file can be distributed as a single header that works with the main
// Catch single header. // Catch single header.
#include <algorithm> #include <algorithm>
namespace Catch { namespace Catch {
struct TAPReporter : StreamingReporterBase<TAPReporter> { struct TAPReporter : StreamingReporterBase<TAPReporter> {
using StreamingReporterBase::StreamingReporterBase; using StreamingReporterBase::StreamingReporterBase;
TAPReporter( ReporterConfig const& config ): TAPReporter( ReporterConfig const& config ):
StreamingReporterBase( config ) { StreamingReporterBase( config ) {
m_reporterPrefs.shouldReportAllAssertions = true; m_reporterPrefs.shouldReportAllAssertions = true;
} }
~TAPReporter() override; ~TAPReporter() override;
static std::string getDescription() { static std::string getDescription() {
return "Reports test results in TAP format, suitable for test harnesses"; return "Reports test results in TAP format, suitable for test harnesses";
} }
void noMatchingTestCases( std::string const& spec ) override { void noMatchingTestCases( std::string const& spec ) override {
stream << "# No test cases matched '" << spec << "'" << std::endl; stream << "# No test cases matched '" << spec << "'" << std::endl;
} }
void assertionStarting( AssertionInfo const& ) override {} void assertionStarting( AssertionInfo const& ) override {}
bool assertionEnded( AssertionStats const& _assertionStats ) override { bool assertionEnded( AssertionStats const& _assertionStats ) override {
++counter; ++counter;
stream << "# " << currentTestCaseInfo->name << std::endl; stream << "# " << currentTestCaseInfo->name << std::endl;
AssertionPrinter printer( stream, _assertionStats, counter ); AssertionPrinter printer( stream, _assertionStats, counter );
printer.print(); printer.print();
stream << std::endl; stream << std::endl;
return true; return true;
} }
void testRunEnded( TestRunStats const& _testRunStats ) override { void testRunEnded( TestRunStats const& _testRunStats ) override {
printTotals( _testRunStats.totals ); printTotals( _testRunStats.totals );
stream << "\n" << std::endl; stream << "\n" << std::endl;
StreamingReporterBase::testRunEnded( _testRunStats ); StreamingReporterBase::testRunEnded( _testRunStats );
} }
private: private:
std::size_t counter = 0; std::size_t counter = 0;
class AssertionPrinter { class AssertionPrinter {
public: public:
AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; AssertionPrinter& operator= ( AssertionPrinter const& ) = delete;
AssertionPrinter( AssertionPrinter const& ) = delete; AssertionPrinter( AssertionPrinter const& ) = delete;
AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter ) AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter )
: stream( _stream ) : stream( _stream )
, result( _stats.assertionResult ) , result( _stats.assertionResult )
, messages( _stats.infoMessages ) , messages( _stats.infoMessages )
, itMessage( _stats.infoMessages.begin() ) , itMessage( _stats.infoMessages.begin() )
, printInfoMessages( true ) , printInfoMessages( true )
, counter(_counter) , counter(_counter)
{} {}
void print() { void print() {
itMessage = messages.begin(); itMessage = messages.begin();
switch( result.getResultType() ) { switch( result.getResultType() ) {
case ResultWas::Ok: case ResultWas::Ok:
printResultType( passedString() ); printResultType( passedString() );
printOriginalExpression(); printOriginalExpression();
printReconstructedExpression(); printReconstructedExpression();
if ( ! result.hasExpression() ) if ( ! result.hasExpression() )
printRemainingMessages( Colour::None ); printRemainingMessages( Colour::None );
else else
printRemainingMessages(); printRemainingMessages();
break; break;
case ResultWas::ExpressionFailed: case ResultWas::ExpressionFailed:
if (result.isOk()) { if (result.isOk()) {
printResultType(passedString()); printResultType(passedString());
} else { } else {
printResultType(failedString()); printResultType(failedString());
} }
printOriginalExpression(); printOriginalExpression();
printReconstructedExpression(); printReconstructedExpression();
if (result.isOk()) { if (result.isOk()) {
printIssue(" # TODO"); printIssue(" # TODO");
} }
printRemainingMessages(); printRemainingMessages();
break; break;
case ResultWas::ThrewException: case ResultWas::ThrewException:
printResultType( failedString() ); printResultType( failedString() );
printIssue( "unexpected exception with message:" ); printIssue( "unexpected exception with message:" );
printMessage(); printMessage();
printExpressionWas(); printExpressionWas();
printRemainingMessages(); printRemainingMessages();
break; break;
case ResultWas::FatalErrorCondition: case ResultWas::FatalErrorCondition:
printResultType( failedString() ); printResultType( failedString() );
printIssue( "fatal error condition with message:" ); printIssue( "fatal error condition with message:" );
printMessage(); printMessage();
printExpressionWas(); printExpressionWas();
printRemainingMessages(); printRemainingMessages();
break; break;
case ResultWas::DidntThrowException: case ResultWas::DidntThrowException:
printResultType( failedString() ); printResultType( failedString() );
printIssue( "expected exception, got none" ); printIssue( "expected exception, got none" );
printExpressionWas(); printExpressionWas();
printRemainingMessages(); printRemainingMessages();
break; break;
case ResultWas::Info: case ResultWas::Info:
printResultType( "info" ); printResultType( "info" );
printMessage(); printMessage();
printRemainingMessages(); printRemainingMessages();
break; break;
case ResultWas::Warning: case ResultWas::Warning:
printResultType( "warning" ); printResultType( "warning" );
printMessage(); printMessage();
printRemainingMessages(); printRemainingMessages();
break; break;
case ResultWas::ExplicitFailure: case ResultWas::ExplicitFailure:
printResultType( failedString() ); printResultType( failedString() );
printIssue( "explicitly" ); printIssue( "explicitly" );
printRemainingMessages( Colour::None ); printRemainingMessages( Colour::None );
break; break;
// These cases are here to prevent compiler warnings // These cases are here to prevent compiler warnings
case ResultWas::Unknown: case ResultWas::Unknown:
case ResultWas::FailureBit: case ResultWas::FailureBit:
case ResultWas::Exception: case ResultWas::Exception:
printResultType( "** internal error **" ); printResultType( "** internal error **" );
break; break;
} }
} }
private: private:
static Colour::Code dimColour() { return Colour::FileName; } static Colour::Code dimColour() { return Colour::FileName; }
static const char* failedString() { return "not ok"; } static const char* failedString() { return "not ok"; }
static const char* passedString() { return "ok"; } static const char* passedString() { return "ok"; }
void printSourceInfo() const { void printSourceInfo() const {
Colour colourGuard( dimColour() ); Colour colourGuard( dimColour() );
stream << result.getSourceInfo() << ":"; stream << result.getSourceInfo() << ":";
} }
void printResultType( std::string const& passOrFail ) const { void printResultType( std::string const& passOrFail ) const {
if( !passOrFail.empty() ) { if( !passOrFail.empty() ) {
stream << passOrFail << ' ' << counter << " -"; stream << passOrFail << ' ' << counter << " -";
} }
} }
void printIssue( std::string const& issue ) const { void printIssue( std::string const& issue ) const {
stream << " " << issue; stream << " " << issue;
} }
void printExpressionWas() { void printExpressionWas() {
if( result.hasExpression() ) { if( result.hasExpression() ) {
stream << ";"; stream << ";";
{ {
Colour colour( dimColour() ); Colour colour( dimColour() );
stream << " expression was:"; stream << " expression was:";
} }
printOriginalExpression(); printOriginalExpression();
} }
} }
void printOriginalExpression() const { void printOriginalExpression() const {
if( result.hasExpression() ) { if( result.hasExpression() ) {
stream << " " << result.getExpression(); stream << " " << result.getExpression();
} }
} }
void printReconstructedExpression() const { void printReconstructedExpression() const {
if( result.hasExpandedExpression() ) { if( result.hasExpandedExpression() ) {
{ {
Colour colour( dimColour() ); Colour colour( dimColour() );
stream << " for: "; stream << " for: ";
} }
std::string expr = result.getExpandedExpression(); std::string expr = result.getExpandedExpression();
std::replace( expr.begin(), expr.end(), '\n', ' '); std::replace( expr.begin(), expr.end(), '\n', ' ');
stream << expr; stream << expr;
} }
} }
void printMessage() { void printMessage() {
if ( itMessage != messages.end() ) { if ( itMessage != messages.end() ) {
stream << " '" << itMessage->message << "'"; stream << " '" << itMessage->message << "'";
++itMessage; ++itMessage;
} }
} }
void printRemainingMessages( Colour::Code colour = dimColour() ) { void printRemainingMessages( Colour::Code colour = dimColour() ) {
if (itMessage == messages.end()) { if (itMessage == messages.end()) {
return; return;
} }
const auto itEnd = messages.cend(); const auto itEnd = messages.cend();
const auto N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) ); const auto N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
{ {
Colour colourGuard( colour ); Colour colourGuard( colour );
stream << " with " << pluralise( N, "message" ) << ":"; stream << " with " << pluralise( N, "message" ) << ":";
} }
while( itMessage != itEnd ) { while( itMessage != itEnd ) {
// If this assertion is a warning ignore any INFO messages // If this assertion is a warning ignore any INFO messages
if( printInfoMessages || itMessage->type != ResultWas::Info ) { if( printInfoMessages || itMessage->type != ResultWas::Info ) {
stream << " '" << itMessage->message << "'"; stream << " '" << itMessage->message << "'";
if ( ++itMessage != itEnd ) { if ( ++itMessage != itEnd ) {
Colour colourGuard( dimColour() ); Colour colourGuard( dimColour() );
stream << " and"; stream << " and";
} }
continue; continue;
} }
++itMessage; ++itMessage;
} }
} }
private: private:
std::ostream& stream; std::ostream& stream;
AssertionResult const& result; AssertionResult const& result;
std::vector<MessageInfo> messages; std::vector<MessageInfo> messages;
std::vector<MessageInfo>::const_iterator itMessage; std::vector<MessageInfo>::const_iterator itMessage;
bool printInfoMessages; bool printInfoMessages;
std::size_t counter; std::size_t counter;
}; };
void printTotals( const Totals& totals ) const { void printTotals( const Totals& totals ) const {
stream << "1.." << totals.assertions.total(); stream << "1.." << totals.assertions.total();
if( totals.testCases.total() == 0 ) { if( totals.testCases.total() == 0 ) {
stream << " # Skipped: No tests ran."; stream << " # Skipped: No tests ran.";
} }
} }
}; };
#ifdef CATCH_IMPL #ifdef CATCH_IMPL
TAPReporter::~TAPReporter() {} TAPReporter::~TAPReporter() {}
#endif #endif
CATCH_REGISTER_REPORTER( "tap", TAPReporter ) CATCH_REGISTER_REPORTER( "tap", TAPReporter )
} // end namespace Catch } // end namespace Catch
#endif // TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED

View file

@ -1,219 +1,219 @@
/* /*
* Created by Phil Nash on 19th December 2014 * Created by Phil Nash on 19th December 2014
* Copyright 2014 Two Blue Cubes Ltd. All rights reserved. * Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
* *
* Distributed under the Boost Software License, Version 1.0. (See accompanying * 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) * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/ */
#ifndef TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
#define 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 // Don't #include any Catch headers here - we can assume they are already
// included before this header. // included before this header.
// This is not good practice in general but is necessary in this case so this // 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 // file can be distributed as a single header that works with the main
// Catch single header. // Catch single header.
#include <cstring> #include <cstring>
#ifdef __clang__ #ifdef __clang__
# pragma clang diagnostic push # pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wpadded"
#endif #endif
namespace Catch { namespace Catch {
struct TeamCityReporter : StreamingReporterBase<TeamCityReporter> { struct TeamCityReporter : StreamingReporterBase<TeamCityReporter> {
TeamCityReporter( ReporterConfig const& _config ) TeamCityReporter( ReporterConfig const& _config )
: StreamingReporterBase( _config ) : StreamingReporterBase( _config )
{ {
m_reporterPrefs.shouldRedirectStdOut = true; m_reporterPrefs.shouldRedirectStdOut = true;
} }
static std::string escape( std::string const& str ) { static std::string escape( std::string const& str ) {
std::string escaped = str; std::string escaped = str;
replaceInPlace( escaped, "|", "||" ); replaceInPlace( escaped, "|", "||" );
replaceInPlace( escaped, "'", "|'" ); replaceInPlace( escaped, "'", "|'" );
replaceInPlace( escaped, "\n", "|n" ); replaceInPlace( escaped, "\n", "|n" );
replaceInPlace( escaped, "\r", "|r" ); replaceInPlace( escaped, "\r", "|r" );
replaceInPlace( escaped, "[", "|[" ); replaceInPlace( escaped, "[", "|[" );
replaceInPlace( escaped, "]", "|]" ); replaceInPlace( escaped, "]", "|]" );
return escaped; return escaped;
} }
~TeamCityReporter() override; ~TeamCityReporter() override;
static std::string getDescription() { static std::string getDescription() {
return "Reports test results as TeamCity service messages"; return "Reports test results as TeamCity service messages";
} }
void skipTest( TestCaseInfo const& /* testInfo */ ) override { void skipTest( TestCaseInfo const& /* testInfo */ ) override {
} }
void noMatchingTestCases( std::string const& /* spec */ ) override {} void noMatchingTestCases( std::string const& /* spec */ ) override {}
void testGroupStarting( GroupInfo const& groupInfo ) override { void testGroupStarting( GroupInfo const& groupInfo ) override {
StreamingReporterBase::testGroupStarting( groupInfo ); StreamingReporterBase::testGroupStarting( groupInfo );
stream << "##teamcity[testSuiteStarted name='" stream << "##teamcity[testSuiteStarted name='"
<< escape( groupInfo.name ) << "']\n"; << escape( groupInfo.name ) << "']\n";
} }
void testGroupEnded( TestGroupStats const& testGroupStats ) override { void testGroupEnded( TestGroupStats const& testGroupStats ) override {
StreamingReporterBase::testGroupEnded( testGroupStats ); StreamingReporterBase::testGroupEnded( testGroupStats );
stream << "##teamcity[testSuiteFinished name='" stream << "##teamcity[testSuiteFinished name='"
<< escape( testGroupStats.groupInfo.name ) << "']\n"; << escape( testGroupStats.groupInfo.name ) << "']\n";
} }
void assertionStarting( AssertionInfo const& ) override {} void assertionStarting( AssertionInfo const& ) override {}
bool assertionEnded( AssertionStats const& assertionStats ) override { bool assertionEnded( AssertionStats const& assertionStats ) override {
AssertionResult const& result = assertionStats.assertionResult; AssertionResult const& result = assertionStats.assertionResult;
if( !result.isOk() ) { if( !result.isOk() ) {
ReusableStringStream msg; ReusableStringStream msg;
if( !m_headerPrintedForThisSection ) if( !m_headerPrintedForThisSection )
printSectionHeader( msg.get() ); printSectionHeader( msg.get() );
m_headerPrintedForThisSection = true; m_headerPrintedForThisSection = true;
msg << result.getSourceInfo() << "\n"; msg << result.getSourceInfo() << "\n";
switch( result.getResultType() ) { switch( result.getResultType() ) {
case ResultWas::ExpressionFailed: case ResultWas::ExpressionFailed:
msg << "expression failed"; msg << "expression failed";
break; break;
case ResultWas::ThrewException: case ResultWas::ThrewException:
msg << "unexpected exception"; msg << "unexpected exception";
break; break;
case ResultWas::FatalErrorCondition: case ResultWas::FatalErrorCondition:
msg << "fatal error condition"; msg << "fatal error condition";
break; break;
case ResultWas::DidntThrowException: case ResultWas::DidntThrowException:
msg << "no exception was thrown where one was expected"; msg << "no exception was thrown where one was expected";
break; break;
case ResultWas::ExplicitFailure: case ResultWas::ExplicitFailure:
msg << "explicit failure"; msg << "explicit failure";
break; break;
// We shouldn't get here because of the isOk() test // We shouldn't get here because of the isOk() test
case ResultWas::Ok: case ResultWas::Ok:
case ResultWas::Info: case ResultWas::Info:
case ResultWas::Warning: case ResultWas::Warning:
CATCH_ERROR( "Internal error in TeamCity reporter" ); CATCH_ERROR( "Internal error in TeamCity reporter" );
// These cases are here to prevent compiler warnings // These cases are here to prevent compiler warnings
case ResultWas::Unknown: case ResultWas::Unknown:
case ResultWas::FailureBit: case ResultWas::FailureBit:
case ResultWas::Exception: case ResultWas::Exception:
CATCH_ERROR( "Not implemented" ); CATCH_ERROR( "Not implemented" );
} }
if( assertionStats.infoMessages.size() == 1 ) if( assertionStats.infoMessages.size() == 1 )
msg << " with message:"; msg << " with message:";
if( assertionStats.infoMessages.size() > 1 ) if( assertionStats.infoMessages.size() > 1 )
msg << " with messages:"; msg << " with messages:";
for( auto const& messageInfo : assertionStats.infoMessages ) for( auto const& messageInfo : assertionStats.infoMessages )
msg << "\n \"" << messageInfo.message << "\""; msg << "\n \"" << messageInfo.message << "\"";
if( result.hasExpression() ) { if( result.hasExpression() ) {
msg << msg <<
"\n " << result.getExpressionInMacro() << "\n" "\n " << result.getExpressionInMacro() << "\n"
"with expansion:\n" << "with expansion:\n" <<
" " << result.getExpandedExpression() << "\n"; " " << result.getExpandedExpression() << "\n";
} }
if( currentTestCaseInfo->okToFail() ) { if( currentTestCaseInfo->okToFail() ) {
msg << "- failure ignore as test marked as 'ok to fail'\n"; msg << "- failure ignore as test marked as 'ok to fail'\n";
stream << "##teamcity[testIgnored" stream << "##teamcity[testIgnored"
<< " name='" << escape( currentTestCaseInfo->name )<< "'" << " name='" << escape( currentTestCaseInfo->name )<< "'"
<< " message='" << escape( msg.str() ) << "'" << " message='" << escape( msg.str() ) << "'"
<< "]\n"; << "]\n";
} }
else { else {
stream << "##teamcity[testFailed" stream << "##teamcity[testFailed"
<< " name='" << escape( currentTestCaseInfo->name )<< "'" << " name='" << escape( currentTestCaseInfo->name )<< "'"
<< " message='" << escape( msg.str() ) << "'" << " message='" << escape( msg.str() ) << "'"
<< "]\n"; << "]\n";
} }
} }
stream.flush(); stream.flush();
return true; return true;
} }
void sectionStarting( SectionInfo const& sectionInfo ) override { void sectionStarting( SectionInfo const& sectionInfo ) override {
m_headerPrintedForThisSection = false; m_headerPrintedForThisSection = false;
StreamingReporterBase::sectionStarting( sectionInfo ); StreamingReporterBase::sectionStarting( sectionInfo );
} }
void testCaseStarting( TestCaseInfo const& testInfo ) override { void testCaseStarting( TestCaseInfo const& testInfo ) override {
m_testTimer.start(); m_testTimer.start();
StreamingReporterBase::testCaseStarting( testInfo ); StreamingReporterBase::testCaseStarting( testInfo );
stream << "##teamcity[testStarted name='" stream << "##teamcity[testStarted name='"
<< escape( testInfo.name ) << "']\n"; << escape( testInfo.name ) << "']\n";
stream.flush(); stream.flush();
} }
void testCaseEnded( TestCaseStats const& testCaseStats ) override { void testCaseEnded( TestCaseStats const& testCaseStats ) override {
StreamingReporterBase::testCaseEnded( testCaseStats ); StreamingReporterBase::testCaseEnded( testCaseStats );
if( !testCaseStats.stdOut.empty() ) if( !testCaseStats.stdOut.empty() )
stream << "##teamcity[testStdOut name='" stream << "##teamcity[testStdOut name='"
<< escape( testCaseStats.testInfo.name ) << escape( testCaseStats.testInfo.name )
<< "' out='" << escape( testCaseStats.stdOut ) << "']\n"; << "' out='" << escape( testCaseStats.stdOut ) << "']\n";
if( !testCaseStats.stdErr.empty() ) if( !testCaseStats.stdErr.empty() )
stream << "##teamcity[testStdErr name='" stream << "##teamcity[testStdErr name='"
<< escape( testCaseStats.testInfo.name ) << escape( testCaseStats.testInfo.name )
<< "' out='" << escape( testCaseStats.stdErr ) << "']\n"; << "' out='" << escape( testCaseStats.stdErr ) << "']\n";
stream << "##teamcity[testFinished name='" stream << "##teamcity[testFinished name='"
<< escape( testCaseStats.testInfo.name ) << "' duration='" << escape( testCaseStats.testInfo.name ) << "' duration='"
<< m_testTimer.getElapsedMilliseconds() << "']\n"; << m_testTimer.getElapsedMilliseconds() << "']\n";
stream.flush(); stream.flush();
} }
private: private:
void printSectionHeader( std::ostream& os ) { void printSectionHeader( std::ostream& os ) {
assert( !m_sectionStack.empty() ); assert( !m_sectionStack.empty() );
if( m_sectionStack.size() > 1 ) { if( m_sectionStack.size() > 1 ) {
os << getLineOfChars<'-'>() << "\n"; os << getLineOfChars<'-'>() << "\n";
std::vector<SectionInfo>::const_iterator std::vector<SectionInfo>::const_iterator
it = m_sectionStack.begin()+1, // Skip first section (test case) it = m_sectionStack.begin()+1, // Skip first section (test case)
itEnd = m_sectionStack.end(); itEnd = m_sectionStack.end();
for( ; it != itEnd; ++it ) for( ; it != itEnd; ++it )
printHeaderString( os, it->name ); printHeaderString( os, it->name );
os << getLineOfChars<'-'>() << "\n"; os << getLineOfChars<'-'>() << "\n";
} }
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
os << lineInfo << "\n"; os << lineInfo << "\n";
os << getLineOfChars<'.'>() << "\n\n"; os << getLineOfChars<'.'>() << "\n\n";
} }
// if string has a : in first line will set indent to follow it on // if string has a : in first line will set indent to follow it on
// subsequent lines // subsequent lines
static void printHeaderString( std::ostream& os, std::string const& _string, std::size_t indent = 0 ) { static void printHeaderString( std::ostream& os, std::string const& _string, std::size_t indent = 0 ) {
std::size_t i = _string.find( ": " ); std::size_t i = _string.find( ": " );
if( i != std::string::npos ) if( i != std::string::npos )
i+=2; i+=2;
else else
i = 0; i = 0;
os << Column( _string ) os << Column( _string )
.indent( indent+i) .indent( indent+i)
.initialIndent( indent ) << "\n"; .initialIndent( indent ) << "\n";
} }
private: private:
bool m_headerPrintedForThisSection = false; bool m_headerPrintedForThisSection = false;
Timer m_testTimer; Timer m_testTimer;
}; };
#ifdef CATCH_IMPL #ifdef CATCH_IMPL
TeamCityReporter::~TeamCityReporter() {} TeamCityReporter::~TeamCityReporter() {}
#endif #endif
CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter ) CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter )
} // end namespace Catch } // end namespace Catch
#ifdef __clang__ #ifdef __clang__
# pragma clang diagnostic pop # pragma clang diagnostic pop
#endif #endif
#endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED