initial commit
This commit is contained in:
62
libs/Catch2/include/reporters/catch_reporter_automake.hpp
Normal file
62
libs/Catch2/include/reporters/catch_reporter_automake.hpp
Normal file
@@ -0,0 +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
|
||||
84
libs/Catch2/include/reporters/catch_reporter_bases.cpp
Normal file
84
libs/Catch2/include/reporters/catch_reporter_bases.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Created by Phil on 27/11/2013.
|
||||
* Copyright 2013 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)
|
||||
*/
|
||||
|
||||
#include "../internal/catch_interfaces_reporter.h"
|
||||
#include "../internal/catch_errno_guard.h"
|
||||
#include "catch_reporter_bases.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <cfloat>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
namespace Catch {
|
||||
void prepareExpandedExpression(AssertionResult& result) {
|
||||
result.getExpandedExpression();
|
||||
}
|
||||
|
||||
// Because formatting using c++ streams is stateful, drop down to C is required
|
||||
// Alternatively we could use stringstream, but its performance is... not good.
|
||||
std::string getFormattedDuration( double duration ) {
|
||||
// Max exponent + 1 is required to represent the whole part
|
||||
// + 1 for decimal point
|
||||
// + 3 for the 3 decimal places
|
||||
// + 1 for null terminator
|
||||
const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
|
||||
char buffer[maxDoubleSize];
|
||||
|
||||
// Save previous errno, to prevent sprintf from overwriting it
|
||||
ErrnoGuard guard;
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buffer, "%.3f", duration);
|
||||
#else
|
||||
std::sprintf(buffer, "%.3f", duration);
|
||||
#endif
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
bool shouldShowDuration( IConfig const& config, double duration ) {
|
||||
if ( config.showDurations() == ShowDurations::Always ) {
|
||||
return true;
|
||||
}
|
||||
if ( config.showDurations() == ShowDurations::Never ) {
|
||||
return false;
|
||||
}
|
||||
const double min = config.minDuration();
|
||||
return min >= 0 && duration >= min;
|
||||
}
|
||||
|
||||
std::string serializeFilters( std::vector<std::string> const& container ) {
|
||||
ReusableStringStream oss;
|
||||
bool first = true;
|
||||
for (auto&& filter : container)
|
||||
{
|
||||
if (!first)
|
||||
oss << ' ';
|
||||
else
|
||||
first = false;
|
||||
|
||||
oss << filter;
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)
|
||||
:StreamingReporterBase(_config) {}
|
||||
|
||||
std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() {
|
||||
return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High };
|
||||
}
|
||||
|
||||
void TestEventListenerBase::assertionStarting(AssertionInfo const &) {}
|
||||
|
||||
bool TestEventListenerBase::assertionEnded(AssertionStats const &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
285
libs/Catch2/include/reporters/catch_reporter_bases.hpp
Normal file
285
libs/Catch2/include/reporters/catch_reporter_bases.hpp
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Created by Phil on 27/11/2013.
|
||||
* Copyright 2013 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_BASES_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
|
||||
|
||||
#include "../internal/catch_enforce.h"
|
||||
#include "../internal/catch_interfaces_reporter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <cfloat>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
namespace Catch {
|
||||
void prepareExpandedExpression(AssertionResult& result);
|
||||
|
||||
// Returns double formatted as %.3f (format expected on output)
|
||||
std::string getFormattedDuration( double duration );
|
||||
|
||||
//! Should the reporter show
|
||||
bool shouldShowDuration( IConfig const& config, double duration );
|
||||
|
||||
std::string serializeFilters( std::vector<std::string> const& container );
|
||||
|
||||
template<typename DerivedT>
|
||||
struct StreamingReporterBase : IStreamingReporter {
|
||||
|
||||
StreamingReporterBase( ReporterConfig const& _config )
|
||||
: m_config( _config.fullConfig() ),
|
||||
stream( _config.stream() )
|
||||
{
|
||||
m_reporterPrefs.shouldRedirectStdOut = false;
|
||||
if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
|
||||
CATCH_ERROR( "Verbosity level not supported by this reporter" );
|
||||
}
|
||||
|
||||
ReporterPreferences getPreferences() const override {
|
||||
return m_reporterPrefs;
|
||||
}
|
||||
|
||||
static std::set<Verbosity> getSupportedVerbosities() {
|
||||
return { Verbosity::Normal };
|
||||
}
|
||||
|
||||
~StreamingReporterBase() override = default;
|
||||
|
||||
void noMatchingTestCases(std::string const&) override {}
|
||||
|
||||
void reportInvalidArguments(std::string const&) override {}
|
||||
|
||||
void testRunStarting(TestRunInfo const& _testRunInfo) override {
|
||||
currentTestRunInfo = _testRunInfo;
|
||||
}
|
||||
|
||||
void testGroupStarting(GroupInfo const& _groupInfo) override {
|
||||
currentGroupInfo = _groupInfo;
|
||||
}
|
||||
|
||||
void testCaseStarting(TestCaseInfo const& _testInfo) override {
|
||||
currentTestCaseInfo = _testInfo;
|
||||
}
|
||||
void sectionStarting(SectionInfo const& _sectionInfo) override {
|
||||
m_sectionStack.push_back(_sectionInfo);
|
||||
}
|
||||
|
||||
void sectionEnded(SectionStats const& /* _sectionStats */) override {
|
||||
m_sectionStack.pop_back();
|
||||
}
|
||||
void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
|
||||
currentTestCaseInfo.reset();
|
||||
}
|
||||
void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override {
|
||||
currentGroupInfo.reset();
|
||||
}
|
||||
void testRunEnded(TestRunStats const& /* _testRunStats */) override {
|
||||
currentTestCaseInfo.reset();
|
||||
currentGroupInfo.reset();
|
||||
currentTestRunInfo.reset();
|
||||
}
|
||||
|
||||
void skipTest(TestCaseInfo const&) override {
|
||||
// Don't do anything with this by default.
|
||||
// It can optionally be overridden in the derived class.
|
||||
}
|
||||
|
||||
IConfigPtr m_config;
|
||||
std::ostream& stream;
|
||||
|
||||
LazyStat<TestRunInfo> currentTestRunInfo;
|
||||
LazyStat<GroupInfo> currentGroupInfo;
|
||||
LazyStat<TestCaseInfo> currentTestCaseInfo;
|
||||
|
||||
std::vector<SectionInfo> m_sectionStack;
|
||||
ReporterPreferences m_reporterPrefs;
|
||||
};
|
||||
|
||||
template<typename DerivedT>
|
||||
struct CumulativeReporterBase : IStreamingReporter {
|
||||
template<typename T, typename ChildNodeT>
|
||||
struct Node {
|
||||
explicit Node( T const& _value ) : value( _value ) {}
|
||||
virtual ~Node() {}
|
||||
|
||||
using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>;
|
||||
T value;
|
||||
ChildNodes children;
|
||||
};
|
||||
struct SectionNode {
|
||||
explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
|
||||
virtual ~SectionNode() = default;
|
||||
|
||||
bool operator == (SectionNode const& other) const {
|
||||
return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
|
||||
}
|
||||
bool operator == (std::shared_ptr<SectionNode> const& other) const {
|
||||
return operator==(*other);
|
||||
}
|
||||
|
||||
SectionStats stats;
|
||||
using ChildSections = std::vector<std::shared_ptr<SectionNode>>;
|
||||
using Assertions = std::vector<AssertionStats>;
|
||||
ChildSections childSections;
|
||||
Assertions assertions;
|
||||
std::string stdOut;
|
||||
std::string stdErr;
|
||||
};
|
||||
|
||||
struct BySectionInfo {
|
||||
BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
|
||||
BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
|
||||
bool operator() (std::shared_ptr<SectionNode> const& node) const {
|
||||
return ((node->stats.sectionInfo.name == m_other.name) &&
|
||||
(node->stats.sectionInfo.lineInfo == m_other.lineInfo));
|
||||
}
|
||||
void operator=(BySectionInfo const&) = delete;
|
||||
|
||||
private:
|
||||
SectionInfo const& m_other;
|
||||
};
|
||||
|
||||
|
||||
using TestCaseNode = Node<TestCaseStats, SectionNode>;
|
||||
using TestGroupNode = Node<TestGroupStats, TestCaseNode>;
|
||||
using TestRunNode = Node<TestRunStats, TestGroupNode>;
|
||||
|
||||
CumulativeReporterBase( ReporterConfig const& _config )
|
||||
: m_config( _config.fullConfig() ),
|
||||
stream( _config.stream() )
|
||||
{
|
||||
m_reporterPrefs.shouldRedirectStdOut = false;
|
||||
if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
|
||||
CATCH_ERROR( "Verbosity level not supported by this reporter" );
|
||||
}
|
||||
~CumulativeReporterBase() override = default;
|
||||
|
||||
ReporterPreferences getPreferences() const override {
|
||||
return m_reporterPrefs;
|
||||
}
|
||||
|
||||
static std::set<Verbosity> getSupportedVerbosities() {
|
||||
return { Verbosity::Normal };
|
||||
}
|
||||
|
||||
void testRunStarting( TestRunInfo const& ) override {}
|
||||
void testGroupStarting( GroupInfo const& ) override {}
|
||||
|
||||
void testCaseStarting( TestCaseInfo const& ) override {}
|
||||
|
||||
void sectionStarting( SectionInfo const& sectionInfo ) override {
|
||||
SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
|
||||
std::shared_ptr<SectionNode> node;
|
||||
if( m_sectionStack.empty() ) {
|
||||
if( !m_rootSection )
|
||||
m_rootSection = std::make_shared<SectionNode>( incompleteStats );
|
||||
node = m_rootSection;
|
||||
}
|
||||
else {
|
||||
SectionNode& parentNode = *m_sectionStack.back();
|
||||
auto it =
|
||||
std::find_if( parentNode.childSections.begin(),
|
||||
parentNode.childSections.end(),
|
||||
BySectionInfo( sectionInfo ) );
|
||||
if( it == parentNode.childSections.end() ) {
|
||||
node = std::make_shared<SectionNode>( incompleteStats );
|
||||
parentNode.childSections.push_back( node );
|
||||
}
|
||||
else
|
||||
node = *it;
|
||||
}
|
||||
m_sectionStack.push_back( node );
|
||||
m_deepestSection = std::move(node);
|
||||
}
|
||||
|
||||
void assertionStarting(AssertionInfo const&) override {}
|
||||
|
||||
bool assertionEnded(AssertionStats const& assertionStats) override {
|
||||
assert(!m_sectionStack.empty());
|
||||
// AssertionResult holds a pointer to a temporary DecomposedExpression,
|
||||
// which getExpandedExpression() calls to build the expression string.
|
||||
// Our section stack copy of the assertionResult will likely outlive the
|
||||
// temporary, so it must be expanded or discarded now to avoid calling
|
||||
// a destroyed object later.
|
||||
prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) );
|
||||
SectionNode& sectionNode = *m_sectionStack.back();
|
||||
sectionNode.assertions.push_back(assertionStats);
|
||||
return true;
|
||||
}
|
||||
void sectionEnded(SectionStats const& sectionStats) override {
|
||||
assert(!m_sectionStack.empty());
|
||||
SectionNode& node = *m_sectionStack.back();
|
||||
node.stats = sectionStats;
|
||||
m_sectionStack.pop_back();
|
||||
}
|
||||
void testCaseEnded(TestCaseStats const& testCaseStats) override {
|
||||
auto node = std::make_shared<TestCaseNode>(testCaseStats);
|
||||
assert(m_sectionStack.size() == 0);
|
||||
node->children.push_back(m_rootSection);
|
||||
m_testCases.push_back(node);
|
||||
m_rootSection.reset();
|
||||
|
||||
assert(m_deepestSection);
|
||||
m_deepestSection->stdOut = testCaseStats.stdOut;
|
||||
m_deepestSection->stdErr = testCaseStats.stdErr;
|
||||
}
|
||||
void testGroupEnded(TestGroupStats const& testGroupStats) override {
|
||||
auto node = std::make_shared<TestGroupNode>(testGroupStats);
|
||||
node->children.swap(m_testCases);
|
||||
m_testGroups.push_back(node);
|
||||
}
|
||||
void testRunEnded(TestRunStats const& testRunStats) override {
|
||||
auto node = std::make_shared<TestRunNode>(testRunStats);
|
||||
node->children.swap(m_testGroups);
|
||||
m_testRuns.push_back(node);
|
||||
testRunEndedCumulative();
|
||||
}
|
||||
virtual void testRunEndedCumulative() = 0;
|
||||
|
||||
void skipTest(TestCaseInfo const&) override {}
|
||||
|
||||
IConfigPtr m_config;
|
||||
std::ostream& stream;
|
||||
std::vector<AssertionStats> m_assertions;
|
||||
std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections;
|
||||
std::vector<std::shared_ptr<TestCaseNode>> m_testCases;
|
||||
std::vector<std::shared_ptr<TestGroupNode>> m_testGroups;
|
||||
|
||||
std::vector<std::shared_ptr<TestRunNode>> m_testRuns;
|
||||
|
||||
std::shared_ptr<SectionNode> m_rootSection;
|
||||
std::shared_ptr<SectionNode> m_deepestSection;
|
||||
std::vector<std::shared_ptr<SectionNode>> m_sectionStack;
|
||||
ReporterPreferences m_reporterPrefs;
|
||||
};
|
||||
|
||||
template<char C>
|
||||
char const* getLineOfChars() {
|
||||
static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
|
||||
if( !*line ) {
|
||||
std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
|
||||
line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {
|
||||
TestEventListenerBase( ReporterConfig const& _config );
|
||||
|
||||
static std::set<Verbosity> getSupportedVerbosities();
|
||||
|
||||
void assertionStarting(AssertionInfo const&) override;
|
||||
bool assertionEnded(AssertionStats const&) override;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
|
||||
290
libs/Catch2/include/reporters/catch_reporter_compact.cpp
Normal file
290
libs/Catch2/include/reporters/catch_reporter_compact.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Created by Martin on 2017-11-14.
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
|
||||
#include "catch_reporter_compact.h"
|
||||
|
||||
#include "../internal/catch_reporter_registrars.hpp"
|
||||
#include "../internal/catch_console_colour.h"
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef CATCH_PLATFORM_MAC
|
||||
const char* failedString() { return "FAILED"; }
|
||||
const char* passedString() { return "PASSED"; }
|
||||
#else
|
||||
const char* failedString() { return "failed"; }
|
||||
const char* passedString() { return "passed"; }
|
||||
#endif
|
||||
|
||||
// Colour::LightGrey
|
||||
Catch::Colour::Code dimColour() { return Catch::Colour::FileName; }
|
||||
|
||||
std::string bothOrAll( std::size_t count ) {
|
||||
return count == 1 ? std::string() :
|
||||
count == 2 ? "both " : "all " ;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
|
||||
namespace Catch {
|
||||
namespace {
|
||||
// Colour, message variants:
|
||||
// - white: No tests ran.
|
||||
// - red: Failed [both/all] N test cases, failed [both/all] M assertions.
|
||||
// - white: Passed [both/all] N test cases (no assertions).
|
||||
// - red: Failed N tests cases, failed M assertions.
|
||||
// - green: Passed [both/all] N tests cases with M assertions.
|
||||
void printTotals(std::ostream& out, const Totals& totals) {
|
||||
if (totals.testCases.total() == 0) {
|
||||
out << "No tests ran.";
|
||||
} else if (totals.testCases.failed == totals.testCases.total()) {
|
||||
Colour colour(Colour::ResultError);
|
||||
const std::string qualify_assertions_failed =
|
||||
totals.assertions.failed == totals.assertions.total() ?
|
||||
bothOrAll(totals.assertions.failed) : std::string();
|
||||
out <<
|
||||
"Failed " << bothOrAll(totals.testCases.failed)
|
||||
<< pluralise(totals.testCases.failed, "test case") << ", "
|
||||
"failed " << qualify_assertions_failed <<
|
||||
pluralise(totals.assertions.failed, "assertion") << '.';
|
||||
} else if (totals.assertions.total() == 0) {
|
||||
out <<
|
||||
"Passed " << bothOrAll(totals.testCases.total())
|
||||
<< pluralise(totals.testCases.total(), "test case")
|
||||
<< " (no assertions).";
|
||||
} else if (totals.assertions.failed) {
|
||||
Colour colour(Colour::ResultError);
|
||||
out <<
|
||||
"Failed " << pluralise(totals.testCases.failed, "test case") << ", "
|
||||
"failed " << pluralise(totals.assertions.failed, "assertion") << '.';
|
||||
} else {
|
||||
Colour colour(Colour::ResultSuccess);
|
||||
out <<
|
||||
"Passed " << bothOrAll(totals.testCases.passed)
|
||||
<< pluralise(totals.testCases.passed, "test case") <<
|
||||
" with " << pluralise(totals.assertions.passed, "assertion") << '.';
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of CompactReporter formatting
|
||||
class AssertionPrinter {
|
||||
public:
|
||||
AssertionPrinter& operator= (AssertionPrinter const&) = delete;
|
||||
AssertionPrinter(AssertionPrinter const&) = delete;
|
||||
AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
|
||||
: stream(_stream)
|
||||
, result(_stats.assertionResult)
|
||||
, messages(_stats.infoMessages)
|
||||
, itMessage(_stats.infoMessages.begin())
|
||||
, printInfoMessages(_printInfoMessages) {}
|
||||
|
||||
void print() {
|
||||
printSourceInfo();
|
||||
|
||||
itMessage = messages.begin();
|
||||
|
||||
switch (result.getResultType()) {
|
||||
case ResultWas::Ok:
|
||||
printResultType(Colour::ResultSuccess, passedString());
|
||||
printOriginalExpression();
|
||||
printReconstructedExpression();
|
||||
if (!result.hasExpression())
|
||||
printRemainingMessages(Colour::None);
|
||||
else
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::ExpressionFailed:
|
||||
if (result.isOk())
|
||||
printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok"));
|
||||
else
|
||||
printResultType(Colour::Error, failedString());
|
||||
printOriginalExpression();
|
||||
printReconstructedExpression();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::ThrewException:
|
||||
printResultType(Colour::Error, failedString());
|
||||
printIssue("unexpected exception with message:");
|
||||
printMessage();
|
||||
printExpressionWas();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::FatalErrorCondition:
|
||||
printResultType(Colour::Error, failedString());
|
||||
printIssue("fatal error condition with message:");
|
||||
printMessage();
|
||||
printExpressionWas();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::DidntThrowException:
|
||||
printResultType(Colour::Error, failedString());
|
||||
printIssue("expected exception, got none");
|
||||
printExpressionWas();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::Info:
|
||||
printResultType(Colour::None, "info");
|
||||
printMessage();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::Warning:
|
||||
printResultType(Colour::None, "warning");
|
||||
printMessage();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
printResultType(Colour::Error, 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(Colour::Error, "** internal error **");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void printSourceInfo() const {
|
||||
Colour colourGuard(Colour::FileName);
|
||||
stream << result.getSourceInfo() << ':';
|
||||
}
|
||||
|
||||
void printResultType(Colour::Code colour, std::string const& passOrFail) const {
|
||||
if (!passOrFail.empty()) {
|
||||
{
|
||||
Colour colourGuard(colour);
|
||||
stream << ' ' << passOrFail;
|
||||
}
|
||||
stream << ':';
|
||||
}
|
||||
}
|
||||
|
||||
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: ";
|
||||
}
|
||||
stream << result.getExpandedExpression();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
printMessage();
|
||||
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;
|
||||
};
|
||||
|
||||
} // anon namespace
|
||||
|
||||
std::string CompactReporter::getDescription() {
|
||||
return "Reports test results on a single line, suitable for IDEs";
|
||||
}
|
||||
|
||||
void CompactReporter::noMatchingTestCases( std::string const& spec ) {
|
||||
stream << "No test cases matched '" << spec << '\'' << std::endl;
|
||||
}
|
||||
|
||||
void CompactReporter::assertionStarting( AssertionInfo const& ) {}
|
||||
|
||||
bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
|
||||
AssertionResult const& result = _assertionStats.assertionResult;
|
||||
|
||||
bool printInfoMessages = true;
|
||||
|
||||
// Drop out if result was successful and we're not printing those
|
||||
if( !m_config->includeSuccessfulResults() && result.isOk() ) {
|
||||
if( result.getResultType() != ResultWas::Warning )
|
||||
return false;
|
||||
printInfoMessages = false;
|
||||
}
|
||||
|
||||
AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
|
||||
printer.print();
|
||||
|
||||
stream << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
|
||||
double dur = _sectionStats.durationInSeconds;
|
||||
if ( shouldShowDuration( *m_config, dur ) ) {
|
||||
stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {
|
||||
printTotals( stream, _testRunStats.totals );
|
||||
stream << '\n' << std::endl;
|
||||
StreamingReporterBase::testRunEnded( _testRunStats );
|
||||
}
|
||||
|
||||
CompactReporter::~CompactReporter() {}
|
||||
|
||||
CATCH_REGISTER_REPORTER( "compact", CompactReporter )
|
||||
|
||||
} // end namespace Catch
|
||||
39
libs/Catch2/include/reporters/catch_reporter_compact.h
Normal file
39
libs/Catch2/include/reporters/catch_reporter_compact.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Created by Martin Moene on 2013-12-05.
|
||||
* Copyright 2012 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_COMPACT_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_H_INCLUDED
|
||||
|
||||
|
||||
#include "catch_reporter_bases.hpp"
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct CompactReporter : StreamingReporterBase<CompactReporter> {
|
||||
|
||||
using StreamingReporterBase::StreamingReporterBase;
|
||||
|
||||
~CompactReporter() override;
|
||||
|
||||
static std::string getDescription();
|
||||
|
||||
void noMatchingTestCases(std::string const& spec) override;
|
||||
|
||||
void assertionStarting(AssertionInfo const&) override;
|
||||
|
||||
bool assertionEnded(AssertionStats const& _assertionStats) override;
|
||||
|
||||
void sectionEnded(SectionStats const& _sectionStats) override;
|
||||
|
||||
void testRunEnded(TestRunStats const& _testRunStats) override;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_COMPACT_H_INCLUDED
|
||||
700
libs/Catch2/include/reporters/catch_reporter_console.cpp
Normal file
700
libs/Catch2/include/reporters/catch_reporter_console.cpp
Normal file
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
* Created by Phil on 5/12/2012.
|
||||
* Copyright 2012 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)
|
||||
*/
|
||||
|
||||
#include "catch_reporter_console.h"
|
||||
|
||||
#include "../internal/catch_reporter_registrars.hpp"
|
||||
#include "../internal/catch_console_colour.h"
|
||||
#include "../internal/catch_version.h"
|
||||
#include "../internal/catch_text.h"
|
||||
#include "../internal/catch_stringref.h"
|
||||
|
||||
#include <cfloat>
|
||||
#include <cstdio>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
|
||||
// Note that 4062 (not all labels are handled and default is missing) is enabled
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
// For simplicity, benchmarking-only helpers are always enabled
|
||||
# pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
|
||||
// Formatter impl for ConsoleReporter
|
||||
class ConsoleAssertionPrinter {
|
||||
public:
|
||||
ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;
|
||||
ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;
|
||||
ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
|
||||
: stream(_stream),
|
||||
stats(_stats),
|
||||
result(_stats.assertionResult),
|
||||
colour(Colour::None),
|
||||
message(result.getMessage()),
|
||||
messages(_stats.infoMessages),
|
||||
printInfoMessages(_printInfoMessages) {
|
||||
switch (result.getResultType()) {
|
||||
case ResultWas::Ok:
|
||||
colour = Colour::Success;
|
||||
passOrFail = "PASSED";
|
||||
//if( result.hasMessage() )
|
||||
if (_stats.infoMessages.size() == 1)
|
||||
messageLabel = "with message";
|
||||
if (_stats.infoMessages.size() > 1)
|
||||
messageLabel = "with messages";
|
||||
break;
|
||||
case ResultWas::ExpressionFailed:
|
||||
if (result.isOk()) {
|
||||
colour = Colour::Success;
|
||||
passOrFail = "FAILED - but was ok";
|
||||
} else {
|
||||
colour = Colour::Error;
|
||||
passOrFail = "FAILED";
|
||||
}
|
||||
if (_stats.infoMessages.size() == 1)
|
||||
messageLabel = "with message";
|
||||
if (_stats.infoMessages.size() > 1)
|
||||
messageLabel = "with messages";
|
||||
break;
|
||||
case ResultWas::ThrewException:
|
||||
colour = Colour::Error;
|
||||
passOrFail = "FAILED";
|
||||
messageLabel = "due to unexpected exception with ";
|
||||
if (_stats.infoMessages.size() == 1)
|
||||
messageLabel += "message";
|
||||
if (_stats.infoMessages.size() > 1)
|
||||
messageLabel += "messages";
|
||||
break;
|
||||
case ResultWas::FatalErrorCondition:
|
||||
colour = Colour::Error;
|
||||
passOrFail = "FAILED";
|
||||
messageLabel = "due to a fatal error condition";
|
||||
break;
|
||||
case ResultWas::DidntThrowException:
|
||||
colour = Colour::Error;
|
||||
passOrFail = "FAILED";
|
||||
messageLabel = "because no exception was thrown where one was expected";
|
||||
break;
|
||||
case ResultWas::Info:
|
||||
messageLabel = "info";
|
||||
break;
|
||||
case ResultWas::Warning:
|
||||
messageLabel = "warning";
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
passOrFail = "FAILED";
|
||||
colour = Colour::Error;
|
||||
if (_stats.infoMessages.size() == 1)
|
||||
messageLabel = "explicitly with message";
|
||||
if (_stats.infoMessages.size() > 1)
|
||||
messageLabel = "explicitly with messages";
|
||||
break;
|
||||
// These cases are here to prevent compiler warnings
|
||||
case ResultWas::Unknown:
|
||||
case ResultWas::FailureBit:
|
||||
case ResultWas::Exception:
|
||||
passOrFail = "** internal error **";
|
||||
colour = Colour::Error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print() const {
|
||||
printSourceInfo();
|
||||
if (stats.totals.assertions.total() > 0) {
|
||||
printResultType();
|
||||
printOriginalExpression();
|
||||
printReconstructedExpression();
|
||||
} else {
|
||||
stream << '\n';
|
||||
}
|
||||
printMessage();
|
||||
}
|
||||
|
||||
private:
|
||||
void printResultType() const {
|
||||
if (!passOrFail.empty()) {
|
||||
Colour colourGuard(colour);
|
||||
stream << passOrFail << ":\n";
|
||||
}
|
||||
}
|
||||
void printOriginalExpression() const {
|
||||
if (result.hasExpression()) {
|
||||
Colour colourGuard(Colour::OriginalExpression);
|
||||
stream << " ";
|
||||
stream << result.getExpressionInMacro();
|
||||
stream << '\n';
|
||||
}
|
||||
}
|
||||
void printReconstructedExpression() const {
|
||||
if (result.hasExpandedExpression()) {
|
||||
stream << "with expansion:\n";
|
||||
Colour colourGuard(Colour::ReconstructedExpression);
|
||||
stream << Column(result.getExpandedExpression()).indent(2) << '\n';
|
||||
}
|
||||
}
|
||||
void printMessage() const {
|
||||
if (!messageLabel.empty())
|
||||
stream << messageLabel << ':' << '\n';
|
||||
for (auto const& msg : messages) {
|
||||
// If this assertion is a warning ignore any INFO messages
|
||||
if (printInfoMessages || msg.type != ResultWas::Info)
|
||||
stream << Column(msg.message).indent(2) << '\n';
|
||||
}
|
||||
}
|
||||
void printSourceInfo() const {
|
||||
Colour colourGuard(Colour::FileName);
|
||||
stream << result.getSourceInfo() << ": ";
|
||||
}
|
||||
|
||||
std::ostream& stream;
|
||||
AssertionStats const& stats;
|
||||
AssertionResult const& result;
|
||||
Colour::Code colour;
|
||||
std::string passOrFail;
|
||||
std::string messageLabel;
|
||||
std::string message;
|
||||
std::vector<MessageInfo> messages;
|
||||
bool printInfoMessages;
|
||||
};
|
||||
|
||||
std::size_t makeRatio(std::size_t number, std::size_t total) {
|
||||
std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
|
||||
return (ratio == 0 && number > 0) ? 1 : ratio;
|
||||
}
|
||||
|
||||
std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) {
|
||||
if (i > j && i > k)
|
||||
return i;
|
||||
else if (j > k)
|
||||
return j;
|
||||
else
|
||||
return k;
|
||||
}
|
||||
|
||||
struct ColumnInfo {
|
||||
enum Justification { Left, Right };
|
||||
std::string name;
|
||||
int width;
|
||||
Justification justification;
|
||||
};
|
||||
struct ColumnBreak {};
|
||||
struct RowBreak {};
|
||||
|
||||
class Duration {
|
||||
enum class Unit {
|
||||
Auto,
|
||||
Nanoseconds,
|
||||
Microseconds,
|
||||
Milliseconds,
|
||||
Seconds,
|
||||
Minutes
|
||||
};
|
||||
static const uint64_t s_nanosecondsInAMicrosecond = 1000;
|
||||
static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
|
||||
static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
|
||||
static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
|
||||
|
||||
double m_inNanoseconds;
|
||||
Unit m_units;
|
||||
|
||||
public:
|
||||
explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
|
||||
: m_inNanoseconds(inNanoseconds),
|
||||
m_units(units) {
|
||||
if (m_units == Unit::Auto) {
|
||||
if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
|
||||
m_units = Unit::Nanoseconds;
|
||||
else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
|
||||
m_units = Unit::Microseconds;
|
||||
else if (m_inNanoseconds < s_nanosecondsInASecond)
|
||||
m_units = Unit::Milliseconds;
|
||||
else if (m_inNanoseconds < s_nanosecondsInAMinute)
|
||||
m_units = Unit::Seconds;
|
||||
else
|
||||
m_units = Unit::Minutes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
auto value() const -> double {
|
||||
switch (m_units) {
|
||||
case Unit::Microseconds:
|
||||
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);
|
||||
case Unit::Milliseconds:
|
||||
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);
|
||||
case Unit::Seconds:
|
||||
return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);
|
||||
case Unit::Minutes:
|
||||
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
|
||||
default:
|
||||
return m_inNanoseconds;
|
||||
}
|
||||
}
|
||||
auto unitsAsString() const -> std::string {
|
||||
switch (m_units) {
|
||||
case Unit::Nanoseconds:
|
||||
return "ns";
|
||||
case Unit::Microseconds:
|
||||
return "us";
|
||||
case Unit::Milliseconds:
|
||||
return "ms";
|
||||
case Unit::Seconds:
|
||||
return "s";
|
||||
case Unit::Minutes:
|
||||
return "m";
|
||||
default:
|
||||
return "** internal error **";
|
||||
}
|
||||
|
||||
}
|
||||
friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
|
||||
return os << duration.value() << ' ' << duration.unitsAsString();
|
||||
}
|
||||
};
|
||||
} // end anon namespace
|
||||
|
||||
class TablePrinter {
|
||||
std::ostream& m_os;
|
||||
std::vector<ColumnInfo> m_columnInfos;
|
||||
std::ostringstream m_oss;
|
||||
int m_currentColumn = -1;
|
||||
bool m_isOpen = false;
|
||||
|
||||
public:
|
||||
TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
|
||||
: m_os( os ),
|
||||
m_columnInfos( std::move( columnInfos ) ) {}
|
||||
|
||||
auto columnInfos() const -> std::vector<ColumnInfo> const& {
|
||||
return m_columnInfos;
|
||||
}
|
||||
|
||||
void open() {
|
||||
if (!m_isOpen) {
|
||||
m_isOpen = true;
|
||||
*this << RowBreak();
|
||||
|
||||
Columns headerCols;
|
||||
Spacer spacer(2);
|
||||
for (auto const& info : m_columnInfos) {
|
||||
headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2));
|
||||
headerCols += spacer;
|
||||
}
|
||||
m_os << headerCols << '\n';
|
||||
|
||||
m_os << Catch::getLineOfChars<'-'>() << '\n';
|
||||
}
|
||||
}
|
||||
void close() {
|
||||
if (m_isOpen) {
|
||||
*this << RowBreak();
|
||||
m_os << std::endl;
|
||||
m_isOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
friend TablePrinter& operator << (TablePrinter& tp, T const& value) {
|
||||
tp.m_oss << value;
|
||||
return tp;
|
||||
}
|
||||
|
||||
friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
|
||||
auto colStr = tp.m_oss.str();
|
||||
const auto strSize = colStr.size();
|
||||
tp.m_oss.str("");
|
||||
tp.open();
|
||||
if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
|
||||
tp.m_currentColumn = -1;
|
||||
tp.m_os << '\n';
|
||||
}
|
||||
tp.m_currentColumn++;
|
||||
|
||||
auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
|
||||
auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width))
|
||||
? std::string(colInfo.width - (strSize + 1), ' ')
|
||||
: std::string();
|
||||
if (colInfo.justification == ColumnInfo::Left)
|
||||
tp.m_os << colStr << padding << ' ';
|
||||
else
|
||||
tp.m_os << padding << colStr << ' ';
|
||||
return tp;
|
||||
}
|
||||
|
||||
friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
|
||||
if (tp.m_currentColumn > 0) {
|
||||
tp.m_os << '\n';
|
||||
tp.m_currentColumn = -1;
|
||||
}
|
||||
return tp;
|
||||
}
|
||||
};
|
||||
|
||||
ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
|
||||
: StreamingReporterBase(config),
|
||||
m_tablePrinter(new TablePrinter(config.stream(),
|
||||
[&config]() -> std::vector<ColumnInfo> {
|
||||
if (config.fullConfig()->benchmarkNoAnalysis())
|
||||
{
|
||||
return{
|
||||
{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
|
||||
{ " samples", 14, ColumnInfo::Right },
|
||||
{ " iterations", 14, ColumnInfo::Right },
|
||||
{ " mean", 14, ColumnInfo::Right }
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return{
|
||||
{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
|
||||
{ "samples mean std dev", 14, ColumnInfo::Right },
|
||||
{ "iterations low mean low std dev", 14, ColumnInfo::Right },
|
||||
{ "estimated high mean high std dev", 14, ColumnInfo::Right }
|
||||
};
|
||||
}
|
||||
}())) {}
|
||||
ConsoleReporter::~ConsoleReporter() = default;
|
||||
|
||||
std::string ConsoleReporter::getDescription() {
|
||||
return "Reports test results as plain lines of text";
|
||||
}
|
||||
|
||||
void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
|
||||
stream << "No test cases matched '" << spec << '\'' << std::endl;
|
||||
}
|
||||
|
||||
void ConsoleReporter::reportInvalidArguments(std::string const&arg){
|
||||
stream << "Invalid Filter: " << arg << std::endl;
|
||||
}
|
||||
|
||||
void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
|
||||
|
||||
bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
|
||||
AssertionResult const& result = _assertionStats.assertionResult;
|
||||
|
||||
bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
|
||||
|
||||
// Drop out if result was successful but we're not printing them.
|
||||
if (!includeResults && result.getResultType() != ResultWas::Warning)
|
||||
return false;
|
||||
|
||||
lazyPrint();
|
||||
|
||||
ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults);
|
||||
printer.print();
|
||||
stream << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
|
||||
m_tablePrinter->close();
|
||||
m_headerPrinted = false;
|
||||
StreamingReporterBase::sectionStarting(_sectionInfo);
|
||||
}
|
||||
void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
|
||||
m_tablePrinter->close();
|
||||
if (_sectionStats.missingAssertions) {
|
||||
lazyPrint();
|
||||
Colour colour(Colour::ResultError);
|
||||
if (m_sectionStack.size() > 1)
|
||||
stream << "\nNo assertions in section";
|
||||
else
|
||||
stream << "\nNo assertions in test case";
|
||||
stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
|
||||
}
|
||||
double dur = _sectionStats.durationInSeconds;
|
||||
if (shouldShowDuration(*m_config, dur)) {
|
||||
stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl;
|
||||
}
|
||||
if (m_headerPrinted) {
|
||||
m_headerPrinted = false;
|
||||
}
|
||||
StreamingReporterBase::sectionEnded(_sectionStats);
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
void ConsoleReporter::benchmarkPreparing(std::string const& name) {
|
||||
lazyPrintWithoutClosingBenchmarkTable();
|
||||
|
||||
auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2));
|
||||
|
||||
bool firstLine = true;
|
||||
for (auto line : nameCol) {
|
||||
if (!firstLine)
|
||||
(*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
|
||||
else
|
||||
firstLine = false;
|
||||
|
||||
(*m_tablePrinter) << line << ColumnBreak();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
|
||||
(*m_tablePrinter) << info.samples << ColumnBreak()
|
||||
<< info.iterations << ColumnBreak();
|
||||
if (!m_config->benchmarkNoAnalysis())
|
||||
(*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();
|
||||
}
|
||||
void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
|
||||
if (m_config->benchmarkNoAnalysis())
|
||||
{
|
||||
(*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
|
||||
}
|
||||
else
|
||||
{
|
||||
(*m_tablePrinter) << ColumnBreak()
|
||||
<< Duration(stats.mean.point.count()) << ColumnBreak()
|
||||
<< Duration(stats.mean.lower_bound.count()) << ColumnBreak()
|
||||
<< Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
|
||||
<< Duration(stats.standardDeviation.point.count()) << ColumnBreak()
|
||||
<< Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
|
||||
<< Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleReporter::benchmarkFailed(std::string const& error) {
|
||||
Colour colour(Colour::Red);
|
||||
(*m_tablePrinter)
|
||||
<< "Benchmark failed (" << error << ')'
|
||||
<< ColumnBreak() << RowBreak();
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
||||
|
||||
void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
|
||||
m_tablePrinter->close();
|
||||
StreamingReporterBase::testCaseEnded(_testCaseStats);
|
||||
m_headerPrinted = false;
|
||||
}
|
||||
void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) {
|
||||
if (currentGroupInfo.used) {
|
||||
printSummaryDivider();
|
||||
stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
|
||||
printTotals(_testGroupStats.totals);
|
||||
stream << '\n' << std::endl;
|
||||
}
|
||||
StreamingReporterBase::testGroupEnded(_testGroupStats);
|
||||
}
|
||||
void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
|
||||
printTotalsDivider(_testRunStats.totals);
|
||||
printTotals(_testRunStats.totals);
|
||||
stream << std::endl;
|
||||
StreamingReporterBase::testRunEnded(_testRunStats);
|
||||
}
|
||||
void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {
|
||||
StreamingReporterBase::testRunStarting(_testInfo);
|
||||
printTestFilters();
|
||||
}
|
||||
|
||||
void ConsoleReporter::lazyPrint() {
|
||||
|
||||
m_tablePrinter->close();
|
||||
lazyPrintWithoutClosingBenchmarkTable();
|
||||
}
|
||||
|
||||
void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
|
||||
|
||||
if (!currentTestRunInfo.used)
|
||||
lazyPrintRunInfo();
|
||||
if (!currentGroupInfo.used)
|
||||
lazyPrintGroupInfo();
|
||||
|
||||
if (!m_headerPrinted) {
|
||||
printTestCaseAndSectionHeader();
|
||||
m_headerPrinted = true;
|
||||
}
|
||||
}
|
||||
void ConsoleReporter::lazyPrintRunInfo() {
|
||||
stream << '\n' << getLineOfChars<'~'>() << '\n';
|
||||
Colour colour(Colour::SecondaryText);
|
||||
stream << currentTestRunInfo->name
|
||||
<< " is a Catch v" << libraryVersion() << " host application.\n"
|
||||
<< "Run with -? for options\n\n";
|
||||
|
||||
if (m_config->rngSeed() != 0)
|
||||
stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
|
||||
|
||||
currentTestRunInfo.used = true;
|
||||
}
|
||||
void ConsoleReporter::lazyPrintGroupInfo() {
|
||||
if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) {
|
||||
printClosedHeader("Group: " + currentGroupInfo->name);
|
||||
currentGroupInfo.used = true;
|
||||
}
|
||||
}
|
||||
void ConsoleReporter::printTestCaseAndSectionHeader() {
|
||||
assert(!m_sectionStack.empty());
|
||||
printOpenHeader(currentTestCaseInfo->name);
|
||||
|
||||
if (m_sectionStack.size() > 1) {
|
||||
Colour colourGuard(Colour::Headers);
|
||||
|
||||
auto
|
||||
it = m_sectionStack.begin() + 1, // Skip first section (test case)
|
||||
itEnd = m_sectionStack.end();
|
||||
for (; it != itEnd; ++it)
|
||||
printHeaderString(it->name, 2);
|
||||
}
|
||||
|
||||
SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
|
||||
|
||||
|
||||
stream << getLineOfChars<'-'>() << '\n';
|
||||
Colour colourGuard(Colour::FileName);
|
||||
stream << lineInfo << '\n';
|
||||
stream << getLineOfChars<'.'>() << '\n' << std::endl;
|
||||
}
|
||||
|
||||
void ConsoleReporter::printClosedHeader(std::string const& _name) {
|
||||
printOpenHeader(_name);
|
||||
stream << getLineOfChars<'.'>() << '\n';
|
||||
}
|
||||
void ConsoleReporter::printOpenHeader(std::string const& _name) {
|
||||
stream << getLineOfChars<'-'>() << '\n';
|
||||
{
|
||||
Colour colourGuard(Colour::Headers);
|
||||
printHeaderString(_name);
|
||||
}
|
||||
}
|
||||
|
||||
// if string has a : in first line will set indent to follow it on
|
||||
// subsequent lines
|
||||
void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {
|
||||
std::size_t i = _string.find(": ");
|
||||
if (i != std::string::npos)
|
||||
i += 2;
|
||||
else
|
||||
i = 0;
|
||||
stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n';
|
||||
}
|
||||
|
||||
struct SummaryColumn {
|
||||
|
||||
SummaryColumn( std::string _label, Colour::Code _colour )
|
||||
: label( std::move( _label ) ),
|
||||
colour( _colour ) {}
|
||||
SummaryColumn addRow( std::size_t count ) {
|
||||
ReusableStringStream rss;
|
||||
rss << count;
|
||||
std::string row = rss.str();
|
||||
for (auto& oldRow : rows) {
|
||||
while (oldRow.size() < row.size())
|
||||
oldRow = ' ' + oldRow;
|
||||
while (oldRow.size() > row.size())
|
||||
row = ' ' + row;
|
||||
}
|
||||
rows.push_back(row);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string label;
|
||||
Colour::Code colour;
|
||||
std::vector<std::string> rows;
|
||||
|
||||
};
|
||||
|
||||
void ConsoleReporter::printTotals( Totals const& totals ) {
|
||||
if (totals.testCases.total() == 0) {
|
||||
stream << Colour(Colour::Warning) << "No tests ran\n";
|
||||
} else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) {
|
||||
stream << Colour(Colour::ResultSuccess) << "All tests passed";
|
||||
stream << " ("
|
||||
<< pluralise(totals.assertions.passed, "assertion") << " in "
|
||||
<< pluralise(totals.testCases.passed, "test case") << ')'
|
||||
<< '\n';
|
||||
} else {
|
||||
|
||||
std::vector<SummaryColumn> columns;
|
||||
columns.push_back(SummaryColumn("", Colour::None)
|
||||
.addRow(totals.testCases.total())
|
||||
.addRow(totals.assertions.total()));
|
||||
columns.push_back(SummaryColumn("passed", Colour::Success)
|
||||
.addRow(totals.testCases.passed)
|
||||
.addRow(totals.assertions.passed));
|
||||
columns.push_back(SummaryColumn("failed", Colour::ResultError)
|
||||
.addRow(totals.testCases.failed)
|
||||
.addRow(totals.assertions.failed));
|
||||
columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure)
|
||||
.addRow(totals.testCases.failedButOk)
|
||||
.addRow(totals.assertions.failedButOk));
|
||||
|
||||
printSummaryRow("test cases", columns, 0);
|
||||
printSummaryRow("assertions", columns, 1);
|
||||
}
|
||||
}
|
||||
void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) {
|
||||
for (auto col : cols) {
|
||||
std::string value = col.rows[row];
|
||||
if (col.label.empty()) {
|
||||
stream << label << ": ";
|
||||
if (value != "0")
|
||||
stream << value;
|
||||
else
|
||||
stream << Colour(Colour::Warning) << "- none -";
|
||||
} else if (value != "0") {
|
||||
stream << Colour(Colour::LightGrey) << " | ";
|
||||
stream << Colour(col.colour)
|
||||
<< value << ' ' << col.label;
|
||||
}
|
||||
}
|
||||
stream << '\n';
|
||||
}
|
||||
|
||||
void ConsoleReporter::printTotalsDivider(Totals const& totals) {
|
||||
if (totals.testCases.total() > 0) {
|
||||
std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
|
||||
std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
|
||||
std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
|
||||
while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
|
||||
findMax(failedRatio, failedButOkRatio, passedRatio)++;
|
||||
while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
|
||||
findMax(failedRatio, failedButOkRatio, passedRatio)--;
|
||||
|
||||
stream << Colour(Colour::Error) << std::string(failedRatio, '=');
|
||||
stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');
|
||||
if (totals.testCases.allPassed())
|
||||
stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
|
||||
else
|
||||
stream << Colour(Colour::Success) << std::string(passedRatio, '=');
|
||||
} else {
|
||||
stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
|
||||
}
|
||||
stream << '\n';
|
||||
}
|
||||
void ConsoleReporter::printSummaryDivider() {
|
||||
stream << getLineOfChars<'-'>() << '\n';
|
||||
}
|
||||
|
||||
void ConsoleReporter::printTestFilters() {
|
||||
if (m_config->testSpec().hasFilters()) {
|
||||
Colour guard(Colour::BrightYellow);
|
||||
stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
89
libs/Catch2/include/reporters/catch_reporter_console.h
Normal file
89
libs/Catch2/include/reporters/catch_reporter_console.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Created by Phil on 5/12/2012.
|
||||
* Copyright 2012 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_CONSOLE_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_H_INCLUDED
|
||||
|
||||
#include "catch_reporter_bases.hpp"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
|
||||
// Note that 4062 (not all labels are handled
|
||||
// and default is missing) is enabled
|
||||
#endif
|
||||
|
||||
|
||||
namespace Catch {
|
||||
// Fwd decls
|
||||
struct SummaryColumn;
|
||||
class TablePrinter;
|
||||
|
||||
struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> {
|
||||
std::unique_ptr<TablePrinter> m_tablePrinter;
|
||||
|
||||
ConsoleReporter(ReporterConfig const& config);
|
||||
~ConsoleReporter() override;
|
||||
static std::string getDescription();
|
||||
|
||||
void noMatchingTestCases(std::string const& spec) override;
|
||||
|
||||
void reportInvalidArguments(std::string const&arg) override;
|
||||
|
||||
void assertionStarting(AssertionInfo const&) override;
|
||||
|
||||
bool assertionEnded(AssertionStats const& _assertionStats) override;
|
||||
|
||||
void sectionStarting(SectionInfo const& _sectionInfo) override;
|
||||
void sectionEnded(SectionStats const& _sectionStats) override;
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
void benchmarkPreparing(std::string const& name) override;
|
||||
void benchmarkStarting(BenchmarkInfo const& info) override;
|
||||
void benchmarkEnded(BenchmarkStats<> const& stats) override;
|
||||
void benchmarkFailed(std::string const& error) override;
|
||||
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
||||
|
||||
void testCaseEnded(TestCaseStats const& _testCaseStats) override;
|
||||
void testGroupEnded(TestGroupStats const& _testGroupStats) override;
|
||||
void testRunEnded(TestRunStats const& _testRunStats) override;
|
||||
void testRunStarting(TestRunInfo const& _testRunInfo) override;
|
||||
private:
|
||||
|
||||
void lazyPrint();
|
||||
|
||||
void lazyPrintWithoutClosingBenchmarkTable();
|
||||
void lazyPrintRunInfo();
|
||||
void lazyPrintGroupInfo();
|
||||
void printTestCaseAndSectionHeader();
|
||||
|
||||
void printClosedHeader(std::string const& _name);
|
||||
void printOpenHeader(std::string const& _name);
|
||||
|
||||
// if string has a : in first line will set indent to follow it on
|
||||
// subsequent lines
|
||||
void printHeaderString(std::string const& _string, std::size_t indent = 0);
|
||||
|
||||
|
||||
void printTotals(Totals const& totals);
|
||||
void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row);
|
||||
|
||||
void printTotalsDivider(Totals const& totals);
|
||||
void printSummaryDivider();
|
||||
void printTestFilters();
|
||||
|
||||
private:
|
||||
bool m_headerPrinted = false;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_CONSOLE_H_INCLUDED
|
||||
300
libs/Catch2/include/reporters/catch_reporter_junit.cpp
Normal file
300
libs/Catch2/include/reporters/catch_reporter_junit.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Created by Phil on 26/11/2010.
|
||||
* Copyright 2010 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)
|
||||
*/
|
||||
|
||||
#include "catch_reporter_bases.hpp"
|
||||
|
||||
#include "catch_reporter_junit.h"
|
||||
|
||||
#include "../internal/catch_tostring.h"
|
||||
#include "../internal/catch_reporter_registrars.hpp"
|
||||
#include "../internal/catch_text.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
std::string getCurrentTimestamp() {
|
||||
// Beware, this is not reentrant because of backward compatibility issues
|
||||
// Also, UTC only, again because of backward compatibility (%z is C++11)
|
||||
time_t rawtime;
|
||||
std::time(&rawtime);
|
||||
auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::tm timeInfo = {};
|
||||
gmtime_s(&timeInfo, &rawtime);
|
||||
#else
|
||||
std::tm* timeInfo;
|
||||
timeInfo = std::gmtime(&rawtime);
|
||||
#endif
|
||||
|
||||
char timeStamp[timeStampSize];
|
||||
const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
|
||||
#else
|
||||
std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
|
||||
#endif
|
||||
return std::string(timeStamp, timeStampSize-1);
|
||||
}
|
||||
|
||||
std::string fileNameTag(const std::vector<std::string> &tags) {
|
||||
auto it = std::find_if(begin(tags),
|
||||
end(tags),
|
||||
[] (std::string const& tag) {return tag.front() == '#'; });
|
||||
if (it != tags.end())
|
||||
return it->substr(1);
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// Formats the duration in seconds to 3 decimal places.
|
||||
// This is done because some genius defined Maven Surefire schema
|
||||
// in a way that only accepts 3 decimal places, and tools like
|
||||
// Jenkins use that schema for validation JUnit reporter output.
|
||||
std::string formatDuration( double seconds ) {
|
||||
ReusableStringStream rss;
|
||||
rss << std::fixed << std::setprecision( 3 ) << seconds;
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
JunitReporter::JunitReporter( ReporterConfig const& _config )
|
||||
: CumulativeReporterBase( _config ),
|
||||
xml( _config.stream() )
|
||||
{
|
||||
m_reporterPrefs.shouldRedirectStdOut = true;
|
||||
m_reporterPrefs.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
JunitReporter::~JunitReporter() {}
|
||||
|
||||
std::string JunitReporter::getDescription() {
|
||||
return "Reports test results in an XML format that looks like Ant's junitreport target";
|
||||
}
|
||||
|
||||
void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {}
|
||||
|
||||
void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
|
||||
CumulativeReporterBase::testRunStarting( runInfo );
|
||||
xml.startElement( "testsuites" );
|
||||
}
|
||||
|
||||
void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {
|
||||
suiteTimer.start();
|
||||
stdOutForSuite.clear();
|
||||
stdErrForSuite.clear();
|
||||
unexpectedExceptions = 0;
|
||||
CumulativeReporterBase::testGroupStarting( groupInfo );
|
||||
}
|
||||
|
||||
void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {
|
||||
m_okToFail = testCaseInfo.okToFail();
|
||||
}
|
||||
|
||||
bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {
|
||||
if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
|
||||
unexpectedExceptions++;
|
||||
return CumulativeReporterBase::assertionEnded( assertionStats );
|
||||
}
|
||||
|
||||
void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
|
||||
stdOutForSuite += testCaseStats.stdOut;
|
||||
stdErrForSuite += testCaseStats.stdErr;
|
||||
CumulativeReporterBase::testCaseEnded( testCaseStats );
|
||||
}
|
||||
|
||||
void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
|
||||
double suiteTime = suiteTimer.getElapsedSeconds();
|
||||
CumulativeReporterBase::testGroupEnded( testGroupStats );
|
||||
writeGroup( *m_testGroups.back(), suiteTime );
|
||||
}
|
||||
|
||||
void JunitReporter::testRunEndedCumulative() {
|
||||
xml.endElement();
|
||||
}
|
||||
|
||||
void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
|
||||
XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
|
||||
|
||||
TestGroupStats const& stats = groupNode.value;
|
||||
xml.writeAttribute( "name", stats.groupInfo.name );
|
||||
xml.writeAttribute( "errors", unexpectedExceptions );
|
||||
xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
|
||||
xml.writeAttribute( "tests", stats.totals.assertions.total() );
|
||||
xml.writeAttribute( "hostname", "tbd" ); // !TBD
|
||||
if( m_config->showDurations() == ShowDurations::Never )
|
||||
xml.writeAttribute( "time", "" );
|
||||
else
|
||||
xml.writeAttribute( "time", formatDuration( suiteTime ) );
|
||||
xml.writeAttribute( "timestamp", getCurrentTimestamp() );
|
||||
|
||||
// Write properties if there are any
|
||||
if (m_config->hasTestFilters() || m_config->rngSeed() != 0) {
|
||||
auto properties = xml.scopedElement("properties");
|
||||
if (m_config->hasTestFilters()) {
|
||||
xml.scopedElement("property")
|
||||
.writeAttribute("name", "filters")
|
||||
.writeAttribute("value", serializeFilters(m_config->getTestsOrTags()));
|
||||
}
|
||||
if (m_config->rngSeed() != 0) {
|
||||
xml.scopedElement("property")
|
||||
.writeAttribute("name", "random-seed")
|
||||
.writeAttribute("value", m_config->rngSeed());
|
||||
}
|
||||
}
|
||||
|
||||
// Write test cases
|
||||
for( auto const& child : groupNode.children )
|
||||
writeTestCase( *child );
|
||||
|
||||
xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
|
||||
xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
|
||||
}
|
||||
|
||||
void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
|
||||
TestCaseStats const& stats = testCaseNode.value;
|
||||
|
||||
// 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();
|
||||
|
||||
std::string className = stats.testInfo.className;
|
||||
|
||||
if( className.empty() ) {
|
||||
className = fileNameTag(stats.testInfo.tags);
|
||||
if ( className.empty() )
|
||||
className = "global";
|
||||
}
|
||||
|
||||
if ( !m_config->name().empty() )
|
||||
className = m_config->name() + "." + className;
|
||||
|
||||
writeSection( className, "", rootSection, stats.testInfo.okToFail() );
|
||||
}
|
||||
|
||||
void JunitReporter::writeSection( std::string const& className,
|
||||
std::string const& rootName,
|
||||
SectionNode const& sectionNode,
|
||||
bool testOkToFail) {
|
||||
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" );
|
||||
if( className.empty() ) {
|
||||
xml.writeAttribute( "classname", name );
|
||||
xml.writeAttribute( "name", "root" );
|
||||
}
|
||||
else {
|
||||
xml.writeAttribute( "classname", className );
|
||||
xml.writeAttribute( "name", name );
|
||||
}
|
||||
xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) );
|
||||
// This is not ideal, but it should be enough to mimic gtest's
|
||||
// junit output.
|
||||
// Ideally the JUnit reporter would also handle `skipTest`
|
||||
// events and write those out appropriately.
|
||||
xml.writeAttribute( "status", "run" );
|
||||
|
||||
if (sectionNode.stats.assertions.failedButOk) {
|
||||
xml.scopedElement("skipped")
|
||||
.writeAttribute("message", "TEST_CASE tagged with !mayfail");
|
||||
}
|
||||
|
||||
writeAssertions( sectionNode );
|
||||
|
||||
|
||||
if( !sectionNode.stdOut.empty() )
|
||||
xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
|
||||
if( !sectionNode.stdErr.empty() )
|
||||
xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
|
||||
}
|
||||
for( auto const& childNode : sectionNode.childSections )
|
||||
if( className.empty() )
|
||||
writeSection( name, "", *childNode, testOkToFail );
|
||||
else
|
||||
writeSection( className, name, *childNode, testOkToFail );
|
||||
}
|
||||
|
||||
void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
|
||||
for( auto const& assertion : sectionNode.assertions )
|
||||
writeAssertion( assertion );
|
||||
}
|
||||
|
||||
void JunitReporter::writeAssertion( AssertionStats const& stats ) {
|
||||
AssertionResult const& result = stats.assertionResult;
|
||||
if( !result.isOk() ) {
|
||||
std::string elementName;
|
||||
switch( result.getResultType() ) {
|
||||
case ResultWas::ThrewException:
|
||||
case ResultWas::FatalErrorCondition:
|
||||
elementName = "error";
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
case ResultWas::ExpressionFailed:
|
||||
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 );
|
||||
|
||||
xml.writeAttribute( "message", result.getExpression() );
|
||||
xml.writeAttribute( "type", result.getTestMacroName() );
|
||||
|
||||
ReusableStringStream rss;
|
||||
if (stats.totals.assertions.total() > 0) {
|
||||
rss << "FAILED" << ":\n";
|
||||
if (result.hasExpression()) {
|
||||
rss << " ";
|
||||
rss << result.getExpressionInMacro();
|
||||
rss << '\n';
|
||||
}
|
||||
if (result.hasExpandedExpression()) {
|
||||
rss << "with expansion:\n";
|
||||
rss << Column(result.getExpandedExpression()).indent(2) << '\n';
|
||||
}
|
||||
} else {
|
||||
rss << '\n';
|
||||
}
|
||||
|
||||
if( !result.getMessage().empty() )
|
||||
rss << result.getMessage() << '\n';
|
||||
for( auto const& msg : stats.infoMessages )
|
||||
if( msg.type == ResultWas::Info )
|
||||
rss << msg.message << '\n';
|
||||
|
||||
rss << "at " << result.getSourceInfo();
|
||||
xml.writeText( rss.str(), XmlFormatting::Newline );
|
||||
}
|
||||
}
|
||||
|
||||
CATCH_REGISTER_REPORTER( "junit", JunitReporter )
|
||||
|
||||
} // end namespace Catch
|
||||
62
libs/Catch2/include/reporters/catch_reporter_junit.h
Normal file
62
libs/Catch2/include/reporters/catch_reporter_junit.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Created by Martin on 14/11/2017.
|
||||
*
|
||||
* 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_JUNIT_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_H_INCLUDED
|
||||
|
||||
|
||||
#include "catch_reporter_bases.hpp"
|
||||
#include "../internal/catch_xmlwriter.h"
|
||||
#include "../internal/catch_timer.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class JunitReporter : public CumulativeReporterBase<JunitReporter> {
|
||||
public:
|
||||
JunitReporter(ReporterConfig const& _config);
|
||||
|
||||
~JunitReporter() override;
|
||||
|
||||
static std::string getDescription();
|
||||
|
||||
void noMatchingTestCases(std::string const& /*spec*/) override;
|
||||
|
||||
void testRunStarting(TestRunInfo const& runInfo) override;
|
||||
|
||||
void testGroupStarting(GroupInfo const& groupInfo) override;
|
||||
|
||||
void testCaseStarting(TestCaseInfo const& testCaseInfo) override;
|
||||
bool assertionEnded(AssertionStats const& assertionStats) override;
|
||||
|
||||
void testCaseEnded(TestCaseStats const& testCaseStats) override;
|
||||
|
||||
void testGroupEnded(TestGroupStats const& testGroupStats) override;
|
||||
|
||||
void testRunEndedCumulative() override;
|
||||
|
||||
void writeGroup(TestGroupNode const& groupNode, double suiteTime);
|
||||
|
||||
void writeTestCase(TestCaseNode const& testCaseNode);
|
||||
|
||||
void writeSection( std::string const& className,
|
||||
std::string const& rootName,
|
||||
SectionNode const& sectionNode,
|
||||
bool testOkToFail );
|
||||
|
||||
void writeAssertions(SectionNode const& sectionNode);
|
||||
void writeAssertion(AssertionStats const& stats);
|
||||
|
||||
XmlWriter xml;
|
||||
Timer suiteTimer;
|
||||
std::string stdOutForSuite;
|
||||
std::string stdErrForSuite;
|
||||
unsigned int unexpectedExceptions = 0;
|
||||
bool m_okToFail = false;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_JUNIT_H_INCLUDED
|
||||
164
libs/Catch2/include/reporters/catch_reporter_listening.cpp
Normal file
164
libs/Catch2/include/reporters/catch_reporter_listening.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Created by Phil on 5/08/2015.
|
||||
* Copyright 2015 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)
|
||||
*/
|
||||
|
||||
#include "catch_reporter_listening.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
ListeningReporter::ListeningReporter() {
|
||||
// We will assume that listeners will always want all assertions
|
||||
m_preferences.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) {
|
||||
m_listeners.push_back( std::move( listener ) );
|
||||
}
|
||||
|
||||
void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) {
|
||||
assert(!m_reporter && "Listening reporter can wrap only 1 real reporter");
|
||||
m_reporter = std::move( reporter );
|
||||
m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut;
|
||||
}
|
||||
|
||||
ReporterPreferences ListeningReporter::getPreferences() const {
|
||||
return m_preferences;
|
||||
}
|
||||
|
||||
std::set<Verbosity> ListeningReporter::getSupportedVerbosities() {
|
||||
return std::set<Verbosity>{ };
|
||||
}
|
||||
|
||||
|
||||
void ListeningReporter::noMatchingTestCases( std::string const& spec ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->noMatchingTestCases( spec );
|
||||
}
|
||||
m_reporter->noMatchingTestCases( spec );
|
||||
}
|
||||
|
||||
void ListeningReporter::reportInvalidArguments(std::string const&arg){
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->reportInvalidArguments( arg );
|
||||
}
|
||||
m_reporter->reportInvalidArguments( arg );
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
void ListeningReporter::benchmarkPreparing( std::string const& name ) {
|
||||
for (auto const& listener : m_listeners) {
|
||||
listener->benchmarkPreparing(name);
|
||||
}
|
||||
m_reporter->benchmarkPreparing(name);
|
||||
}
|
||||
void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->benchmarkStarting( benchmarkInfo );
|
||||
}
|
||||
m_reporter->benchmarkStarting( benchmarkInfo );
|
||||
}
|
||||
void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->benchmarkEnded( benchmarkStats );
|
||||
}
|
||||
m_reporter->benchmarkEnded( benchmarkStats );
|
||||
}
|
||||
|
||||
void ListeningReporter::benchmarkFailed( std::string const& error ) {
|
||||
for (auto const& listener : m_listeners) {
|
||||
listener->benchmarkFailed(error);
|
||||
}
|
||||
m_reporter->benchmarkFailed(error);
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
||||
|
||||
void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->testRunStarting( testRunInfo );
|
||||
}
|
||||
m_reporter->testRunStarting( testRunInfo );
|
||||
}
|
||||
|
||||
void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->testGroupStarting( groupInfo );
|
||||
}
|
||||
m_reporter->testGroupStarting( groupInfo );
|
||||
}
|
||||
|
||||
|
||||
void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->testCaseStarting( testInfo );
|
||||
}
|
||||
m_reporter->testCaseStarting( testInfo );
|
||||
}
|
||||
|
||||
void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->sectionStarting( sectionInfo );
|
||||
}
|
||||
m_reporter->sectionStarting( sectionInfo );
|
||||
}
|
||||
|
||||
void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->assertionStarting( assertionInfo );
|
||||
}
|
||||
m_reporter->assertionStarting( assertionInfo );
|
||||
}
|
||||
|
||||
// The return value indicates if the messages buffer should be cleared:
|
||||
bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) {
|
||||
for( auto const& listener : m_listeners ) {
|
||||
static_cast<void>( listener->assertionEnded( assertionStats ) );
|
||||
}
|
||||
return m_reporter->assertionEnded( assertionStats );
|
||||
}
|
||||
|
||||
void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->sectionEnded( sectionStats );
|
||||
}
|
||||
m_reporter->sectionEnded( sectionStats );
|
||||
}
|
||||
|
||||
void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->testCaseEnded( testCaseStats );
|
||||
}
|
||||
m_reporter->testCaseEnded( testCaseStats );
|
||||
}
|
||||
|
||||
void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->testGroupEnded( testGroupStats );
|
||||
}
|
||||
m_reporter->testGroupEnded( testGroupStats );
|
||||
}
|
||||
|
||||
void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->testRunEnded( testRunStats );
|
||||
}
|
||||
m_reporter->testRunEnded( testRunStats );
|
||||
}
|
||||
|
||||
|
||||
void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) {
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->skipTest( testInfo );
|
||||
}
|
||||
m_reporter->skipTest( testInfo );
|
||||
}
|
||||
|
||||
bool ListeningReporter::isMulti() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
63
libs/Catch2/include/reporters/catch_reporter_listening.h
Normal file
63
libs/Catch2/include/reporters/catch_reporter_listening.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Created by Martin on 19/07/2017.
|
||||
*
|
||||
* 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_MULTI_REPORTER_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MULTI_REPORTER_H_INCLUDED
|
||||
|
||||
#include "../internal/catch_interfaces_reporter.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class ListeningReporter : public IStreamingReporter {
|
||||
using Reporters = std::vector<IStreamingReporterPtr>;
|
||||
Reporters m_listeners;
|
||||
IStreamingReporterPtr m_reporter = nullptr;
|
||||
ReporterPreferences m_preferences;
|
||||
|
||||
public:
|
||||
ListeningReporter();
|
||||
|
||||
void addListener( IStreamingReporterPtr&& listener );
|
||||
void addReporter( IStreamingReporterPtr&& reporter );
|
||||
|
||||
public: // IStreamingReporter
|
||||
|
||||
ReporterPreferences getPreferences() const override;
|
||||
|
||||
void noMatchingTestCases( std::string const& spec ) override;
|
||||
|
||||
void reportInvalidArguments(std::string const&arg) override;
|
||||
|
||||
static std::set<Verbosity> getSupportedVerbosities();
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
void benchmarkPreparing(std::string const& name) override;
|
||||
void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
|
||||
void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
|
||||
void benchmarkFailed(std::string const&) override;
|
||||
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
||||
|
||||
void testRunStarting( TestRunInfo const& testRunInfo ) override;
|
||||
void testGroupStarting( GroupInfo const& groupInfo ) override;
|
||||
void testCaseStarting( TestCaseInfo const& testInfo ) override;
|
||||
void sectionStarting( SectionInfo const& sectionInfo ) override;
|
||||
void assertionStarting( AssertionInfo const& assertionInfo ) override;
|
||||
|
||||
// The return value indicates if the messages buffer should be cleared:
|
||||
bool assertionEnded( AssertionStats const& assertionStats ) override;
|
||||
void sectionEnded( SectionStats const& sectionStats ) override;
|
||||
void testCaseEnded( TestCaseStats const& testCaseStats ) override;
|
||||
void testGroupEnded( TestGroupStats const& testGroupStats ) override;
|
||||
void testRunEnded( TestRunStats const& testRunStats ) override;
|
||||
|
||||
void skipTest( TestCaseInfo const& testInfo ) override;
|
||||
bool isMulti() const override;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_MULTI_REPORTER_H_INCLUDED
|
||||
181
libs/Catch2/include/reporters/catch_reporter_sonarqube.hpp
Normal file
181
libs/Catch2/include/reporters/catch_reporter_sonarqube.hpp
Normal file
@@ -0,0 +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
|
||||
|
||||
#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
||||
254
libs/Catch2/include/reporters/catch_reporter_tap.hpp
Normal file
254
libs/Catch2/include/reporters/catch_reporter_tap.hpp
Normal file
@@ -0,0 +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
|
||||
219
libs/Catch2/include/reporters/catch_reporter_teamcity.hpp
Normal file
219
libs/Catch2/include/reporters/catch_reporter_teamcity.hpp
Normal file
@@ -0,0 +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
|
||||
281
libs/Catch2/include/reporters/catch_reporter_xml.cpp
Normal file
281
libs/Catch2/include/reporters/catch_reporter_xml.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Created by Phil on 28/10/2010.
|
||||
* Copyright 2010 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)
|
||||
*/
|
||||
|
||||
#include "catch_reporter_xml.h"
|
||||
|
||||
#include "../internal/catch_capture.hpp"
|
||||
#include "../internal/catch_reporter_registrars.hpp"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
|
||||
// Note that 4062 (not all labels are handled
|
||||
// and default is missing) is enabled
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
XmlReporter::XmlReporter( ReporterConfig const& _config )
|
||||
: StreamingReporterBase( _config ),
|
||||
m_xml(_config.stream())
|
||||
{
|
||||
m_reporterPrefs.shouldRedirectStdOut = true;
|
||||
m_reporterPrefs.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
XmlReporter::~XmlReporter() = default;
|
||||
|
||||
std::string XmlReporter::getDescription() {
|
||||
return "Reports test results as an XML document";
|
||||
}
|
||||
|
||||
std::string XmlReporter::getStylesheetRef() const {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {
|
||||
m_xml
|
||||
.writeAttribute( "filename", sourceInfo.file )
|
||||
.writeAttribute( "line", sourceInfo.line );
|
||||
}
|
||||
|
||||
void XmlReporter::noMatchingTestCases( std::string const& s ) {
|
||||
StreamingReporterBase::noMatchingTestCases( s );
|
||||
}
|
||||
|
||||
void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {
|
||||
StreamingReporterBase::testRunStarting( testInfo );
|
||||
std::string stylesheetRef = getStylesheetRef();
|
||||
if( !stylesheetRef.empty() )
|
||||
m_xml.writeStylesheetRef( stylesheetRef );
|
||||
m_xml.startElement( "Catch" );
|
||||
if( !m_config->name().empty() )
|
||||
m_xml.writeAttribute( "name", m_config->name() );
|
||||
if (m_config->testSpec().hasFilters())
|
||||
m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) );
|
||||
if( m_config->rngSeed() != 0 )
|
||||
m_xml.scopedElement( "Randomness" )
|
||||
.writeAttribute( "seed", m_config->rngSeed() );
|
||||
}
|
||||
|
||||
void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) {
|
||||
StreamingReporterBase::testGroupStarting( groupInfo );
|
||||
m_xml.startElement( "Group" )
|
||||
.writeAttribute( "name", groupInfo.name );
|
||||
}
|
||||
|
||||
void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
|
||||
StreamingReporterBase::testCaseStarting(testInfo);
|
||||
m_xml.startElement( "TestCase" )
|
||||
.writeAttribute( "name", trim( testInfo.name ) )
|
||||
.writeAttribute( "description", testInfo.description )
|
||||
.writeAttribute( "tags", testInfo.tagsAsString() );
|
||||
|
||||
writeSourceInfo( testInfo.lineInfo );
|
||||
|
||||
if ( m_config->showDurations() == ShowDurations::Always )
|
||||
m_testCaseTimer.start();
|
||||
m_xml.ensureTagClosed();
|
||||
}
|
||||
|
||||
void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {
|
||||
StreamingReporterBase::sectionStarting( sectionInfo );
|
||||
if( m_sectionDepth++ > 0 ) {
|
||||
m_xml.startElement( "Section" )
|
||||
.writeAttribute( "name", trim( sectionInfo.name ) );
|
||||
writeSourceInfo( sectionInfo.lineInfo );
|
||||
m_xml.ensureTagClosed();
|
||||
}
|
||||
}
|
||||
|
||||
void XmlReporter::assertionStarting( AssertionInfo const& ) { }
|
||||
|
||||
bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {
|
||||
|
||||
AssertionResult const& result = assertionStats.assertionResult;
|
||||
|
||||
bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
|
||||
|
||||
if( includeResults || result.getResultType() == ResultWas::Warning ) {
|
||||
// Print any info messages in <Info> tags.
|
||||
for( auto const& msg : assertionStats.infoMessages ) {
|
||||
if( msg.type == ResultWas::Info && includeResults ) {
|
||||
m_xml.scopedElement( "Info" )
|
||||
.writeText( msg.message );
|
||||
} else if ( msg.type == ResultWas::Warning ) {
|
||||
m_xml.scopedElement( "Warning" )
|
||||
.writeText( msg.message );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drop out if result was successful but we're not printing them.
|
||||
if( !includeResults && result.getResultType() != ResultWas::Warning )
|
||||
return true;
|
||||
|
||||
|
||||
// Print the expression if there is one.
|
||||
if( result.hasExpression() ) {
|
||||
m_xml.startElement( "Expression" )
|
||||
.writeAttribute( "success", result.succeeded() )
|
||||
.writeAttribute( "type", result.getTestMacroName() );
|
||||
|
||||
writeSourceInfo( result.getSourceInfo() );
|
||||
|
||||
m_xml.scopedElement( "Original" )
|
||||
.writeText( result.getExpression() );
|
||||
m_xml.scopedElement( "Expanded" )
|
||||
.writeText( result.getExpandedExpression() );
|
||||
}
|
||||
|
||||
// And... Print a result applicable to each result type.
|
||||
switch( result.getResultType() ) {
|
||||
case ResultWas::ThrewException:
|
||||
m_xml.startElement( "Exception" );
|
||||
writeSourceInfo( result.getSourceInfo() );
|
||||
m_xml.writeText( result.getMessage() );
|
||||
m_xml.endElement();
|
||||
break;
|
||||
case ResultWas::FatalErrorCondition:
|
||||
m_xml.startElement( "FatalErrorCondition" );
|
||||
writeSourceInfo( result.getSourceInfo() );
|
||||
m_xml.writeText( result.getMessage() );
|
||||
m_xml.endElement();
|
||||
break;
|
||||
case ResultWas::Info:
|
||||
m_xml.scopedElement( "Info" )
|
||||
.writeText( result.getMessage() );
|
||||
break;
|
||||
case ResultWas::Warning:
|
||||
// Warning will already have been written
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
m_xml.startElement( "Failure" );
|
||||
writeSourceInfo( result.getSourceInfo() );
|
||||
m_xml.writeText( result.getMessage() );
|
||||
m_xml.endElement();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( result.hasExpression() )
|
||||
m_xml.endElement();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {
|
||||
StreamingReporterBase::sectionEnded( sectionStats );
|
||||
if( --m_sectionDepth > 0 ) {
|
||||
XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
|
||||
e.writeAttribute( "successes", sectionStats.assertions.passed );
|
||||
e.writeAttribute( "failures", sectionStats.assertions.failed );
|
||||
e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
|
||||
|
||||
if ( m_config->showDurations() == ShowDurations::Always )
|
||||
e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
|
||||
|
||||
m_xml.endElement();
|
||||
}
|
||||
}
|
||||
|
||||
void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
|
||||
StreamingReporterBase::testCaseEnded( testCaseStats );
|
||||
XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
|
||||
e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
|
||||
|
||||
if ( m_config->showDurations() == ShowDurations::Always )
|
||||
e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
|
||||
|
||||
if( !testCaseStats.stdOut.empty() )
|
||||
m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
|
||||
if( !testCaseStats.stdErr.empty() )
|
||||
m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
|
||||
|
||||
m_xml.endElement();
|
||||
}
|
||||
|
||||
void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
|
||||
StreamingReporterBase::testGroupEnded( testGroupStats );
|
||||
// TODO: Check testGroupStats.aborting and act accordingly.
|
||||
m_xml.scopedElement( "OverallResults" )
|
||||
.writeAttribute( "successes", testGroupStats.totals.assertions.passed )
|
||||
.writeAttribute( "failures", testGroupStats.totals.assertions.failed )
|
||||
.writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
|
||||
m_xml.scopedElement( "OverallResultsCases")
|
||||
.writeAttribute( "successes", testGroupStats.totals.testCases.passed )
|
||||
.writeAttribute( "failures", testGroupStats.totals.testCases.failed )
|
||||
.writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk );
|
||||
m_xml.endElement();
|
||||
}
|
||||
|
||||
void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {
|
||||
StreamingReporterBase::testRunEnded( testRunStats );
|
||||
m_xml.scopedElement( "OverallResults" )
|
||||
.writeAttribute( "successes", testRunStats.totals.assertions.passed )
|
||||
.writeAttribute( "failures", testRunStats.totals.assertions.failed )
|
||||
.writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
|
||||
m_xml.scopedElement( "OverallResultsCases")
|
||||
.writeAttribute( "successes", testRunStats.totals.testCases.passed )
|
||||
.writeAttribute( "failures", testRunStats.totals.testCases.failed )
|
||||
.writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk );
|
||||
m_xml.endElement();
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
void XmlReporter::benchmarkPreparing(std::string const& name) {
|
||||
m_xml.startElement("BenchmarkResults")
|
||||
.writeAttribute("name", name);
|
||||
}
|
||||
|
||||
void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
|
||||
m_xml.writeAttribute("samples", info.samples)
|
||||
.writeAttribute("resamples", info.resamples)
|
||||
.writeAttribute("iterations", info.iterations)
|
||||
.writeAttribute("clockResolution", info.clockResolution)
|
||||
.writeAttribute("estimatedDuration", info.estimatedDuration)
|
||||
.writeComment("All values in nano seconds");
|
||||
}
|
||||
|
||||
void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
|
||||
m_xml.startElement("mean")
|
||||
.writeAttribute("value", benchmarkStats.mean.point.count())
|
||||
.writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count())
|
||||
.writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count())
|
||||
.writeAttribute("ci", benchmarkStats.mean.confidence_interval);
|
||||
m_xml.endElement();
|
||||
m_xml.startElement("standardDeviation")
|
||||
.writeAttribute("value", benchmarkStats.standardDeviation.point.count())
|
||||
.writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count())
|
||||
.writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count())
|
||||
.writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval);
|
||||
m_xml.endElement();
|
||||
m_xml.startElement("outliers")
|
||||
.writeAttribute("variance", benchmarkStats.outlierVariance)
|
||||
.writeAttribute("lowMild", benchmarkStats.outliers.low_mild)
|
||||
.writeAttribute("lowSevere", benchmarkStats.outliers.low_severe)
|
||||
.writeAttribute("highMild", benchmarkStats.outliers.high_mild)
|
||||
.writeAttribute("highSevere", benchmarkStats.outliers.high_severe);
|
||||
m_xml.endElement();
|
||||
m_xml.endElement();
|
||||
}
|
||||
|
||||
void XmlReporter::benchmarkFailed(std::string const &error) {
|
||||
m_xml.scopedElement("failed").
|
||||
writeAttribute("message", error);
|
||||
m_xml.endElement();
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
||||
|
||||
CATCH_REGISTER_REPORTER( "xml", XmlReporter )
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
68
libs/Catch2/include/reporters/catch_reporter_xml.h
Normal file
68
libs/Catch2/include/reporters/catch_reporter_xml.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Created by Martin on 14/11/2017.
|
||||
*
|
||||
* 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_XML_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REPORTER_XML_H_INCLUDED
|
||||
|
||||
#include "catch_reporter_bases.hpp"
|
||||
|
||||
#include "../internal/catch_xmlwriter.h"
|
||||
#include "../internal/catch_timer.h"
|
||||
|
||||
|
||||
namespace Catch {
|
||||
class XmlReporter : public StreamingReporterBase<XmlReporter> {
|
||||
public:
|
||||
XmlReporter(ReporterConfig const& _config);
|
||||
|
||||
~XmlReporter() override;
|
||||
|
||||
static std::string getDescription();
|
||||
|
||||
virtual std::string getStylesheetRef() const;
|
||||
|
||||
void writeSourceInfo(SourceLineInfo const& sourceInfo);
|
||||
|
||||
public: // StreamingReporterBase
|
||||
|
||||
void noMatchingTestCases(std::string const& s) override;
|
||||
|
||||
void testRunStarting(TestRunInfo const& testInfo) override;
|
||||
|
||||
void testGroupStarting(GroupInfo const& groupInfo) override;
|
||||
|
||||
void testCaseStarting(TestCaseInfo const& testInfo) override;
|
||||
|
||||
void sectionStarting(SectionInfo const& sectionInfo) override;
|
||||
|
||||
void assertionStarting(AssertionInfo const&) override;
|
||||
|
||||
bool assertionEnded(AssertionStats const& assertionStats) override;
|
||||
|
||||
void sectionEnded(SectionStats const& sectionStats) override;
|
||||
|
||||
void testCaseEnded(TestCaseStats const& testCaseStats) override;
|
||||
|
||||
void testGroupEnded(TestGroupStats const& testGroupStats) override;
|
||||
|
||||
void testRunEnded(TestRunStats const& testRunStats) override;
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
void benchmarkPreparing(std::string const& name) override;
|
||||
void benchmarkStarting(BenchmarkInfo const&) override;
|
||||
void benchmarkEnded(BenchmarkStats<> const&) override;
|
||||
void benchmarkFailed(std::string const&) override;
|
||||
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
||||
|
||||
private:
|
||||
Timer m_testCaseTimer;
|
||||
XmlWriter m_xml;
|
||||
int m_sectionDepth = 0;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_XML_H_INCLUDED
|
||||
Reference in New Issue
Block a user