mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 21:36:11 +01:00
More method bodies moved out of line
This commit is contained in:
parent
d7ff62430a
commit
4a1e898eae
@ -197,6 +197,7 @@ set(IMPL_SOURCES
|
|||||||
${HEADER_DIR}/internal/catch_assertionresult.cpp
|
${HEADER_DIR}/internal/catch_assertionresult.cpp
|
||||||
${HEADER_DIR}/internal/catch_commandline.cpp
|
${HEADER_DIR}/internal/catch_commandline.cpp
|
||||||
${HEADER_DIR}/internal/catch_common.cpp
|
${HEADER_DIR}/internal/catch_common.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_config.cpp
|
||||||
${HEADER_DIR}/internal/catch_console_colour.cpp
|
${HEADER_DIR}/internal/catch_console_colour.cpp
|
||||||
${HEADER_DIR}/internal/catch_context.cpp
|
${HEADER_DIR}/internal/catch_context.cpp
|
||||||
${HEADER_DIR}/internal/catch_debugger.cpp
|
${HEADER_DIR}/internal/catch_debugger.cpp
|
||||||
@ -209,6 +210,7 @@ set(IMPL_SOURCES
|
|||||||
${HEADER_DIR}/internal/catch_message.cpp
|
${HEADER_DIR}/internal/catch_message.cpp
|
||||||
${HEADER_DIR}/internal/catch_notimplemented_exception.cpp
|
${HEADER_DIR}/internal/catch_notimplemented_exception.cpp
|
||||||
${HEADER_DIR}/internal/catch_registry_hub.cpp
|
${HEADER_DIR}/internal/catch_registry_hub.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_interfaces_reporter.cpp
|
||||||
${HEADER_DIR}/internal/catch_result_builder.cpp
|
${HEADER_DIR}/internal/catch_result_builder.cpp
|
||||||
${HEADER_DIR}/internal/catch_result_type.cpp
|
${HEADER_DIR}/internal/catch_result_type.cpp
|
||||||
${HEADER_DIR}/internal/catch_run_context.cpp
|
${HEADER_DIR}/internal/catch_run_context.cpp
|
||||||
@ -221,9 +223,15 @@ set(IMPL_SOURCES
|
|||||||
${HEADER_DIR}/internal/catch_stringref.cpp
|
${HEADER_DIR}/internal/catch_stringref.cpp
|
||||||
${HEADER_DIR}/internal/catch_tag_alias_registry.cpp
|
${HEADER_DIR}/internal/catch_tag_alias_registry.cpp
|
||||||
${HEADER_DIR}/internal/catch_test_case_info.cpp
|
${HEADER_DIR}/internal/catch_test_case_info.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_test_case_tracker.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_test_spec.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_test_spec_parser.cpp
|
||||||
${HEADER_DIR}/internal/catch_timer.cpp
|
${HEADER_DIR}/internal/catch_timer.cpp
|
||||||
${HEADER_DIR}/internal/catch_tostring.cpp
|
${HEADER_DIR}/internal/catch_tostring.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_totals.cpp
|
||||||
${HEADER_DIR}/internal/catch_version.cpp
|
${HEADER_DIR}/internal/catch_version.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_wildcard_pattern.cpp
|
||||||
|
${HEADER_DIR}/internal/catch_xmlwriter.cpp
|
||||||
)
|
)
|
||||||
set(INTERNAL_FILES ${IMPL_SOURCES} ${INTERNAL_HEADERS})
|
set(INTERNAL_FILES ${IMPL_SOURCES} ${INTERNAL_HEADERS})
|
||||||
CheckFileList(INTERNAL_FILES ${HEADER_DIR}/internal)
|
CheckFileList(INTERNAL_FILES ${HEADER_DIR}/internal)
|
||||||
@ -232,6 +240,7 @@ CheckFileList(INTERNAL_FILES ${HEADER_DIR}/internal)
|
|||||||
set(REPORTER_HEADERS
|
set(REPORTER_HEADERS
|
||||||
${HEADER_DIR}/reporters/catch_reporter_automake.hpp
|
${HEADER_DIR}/reporters/catch_reporter_automake.hpp
|
||||||
${HEADER_DIR}/reporters/catch_reporter_bases.hpp
|
${HEADER_DIR}/reporters/catch_reporter_bases.hpp
|
||||||
|
${HEADER_DIR}/reporters/catch_reporter_multi.h
|
||||||
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
|
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
|
||||||
${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
|
${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
|
||||||
)
|
)
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
|
|
||||||
|
bool DecomposedExpression::isBinaryExpression() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
AssertionInfo::AssertionInfo( char const * _macroName,
|
AssertionInfo::AssertionInfo( char const * _macroName,
|
||||||
SourceLineInfo const& _lineInfo,
|
SourceLineInfo const& _lineInfo,
|
||||||
char const * _capturedExpression,
|
char const * _capturedExpression,
|
||||||
@ -21,6 +25,30 @@ namespace Catch {
|
|||||||
resultDisposition( _resultDisposition )
|
resultDisposition( _resultDisposition )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void AssertionResultData::negate( bool parenthesize ) {
|
||||||
|
negated = !negated;
|
||||||
|
parenthesized = parenthesize;
|
||||||
|
if( resultType == ResultWas::Ok )
|
||||||
|
resultType = ResultWas::ExpressionFailed;
|
||||||
|
else if( resultType == ResultWas::ExpressionFailed )
|
||||||
|
resultType = ResultWas::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const& AssertionResultData::reconstructExpression() const {
|
||||||
|
if( decomposedExpression != nullptr ) {
|
||||||
|
decomposedExpression->reconstructExpression( reconstructedExpression );
|
||||||
|
if( parenthesized ) {
|
||||||
|
reconstructedExpression.insert( 0, 1, '(' );
|
||||||
|
reconstructedExpression.append( 1, ')' );
|
||||||
|
}
|
||||||
|
if( negated ) {
|
||||||
|
reconstructedExpression.insert( 0, 1, '!' );
|
||||||
|
}
|
||||||
|
decomposedExpression = nullptr;
|
||||||
|
}
|
||||||
|
return reconstructedExpression;
|
||||||
|
}
|
||||||
|
|
||||||
AssertionResult::AssertionResult() {}
|
AssertionResult::AssertionResult() {}
|
||||||
|
|
||||||
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
|
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
|
||||||
|
@ -18,10 +18,12 @@ namespace Catch {
|
|||||||
|
|
||||||
struct DecomposedExpression
|
struct DecomposedExpression
|
||||||
{
|
{
|
||||||
virtual ~DecomposedExpression() {}
|
DecomposedExpression() = default;
|
||||||
virtual bool isBinaryExpression() const {
|
DecomposedExpression( DecomposedExpression const& ) = default;
|
||||||
return false;
|
DecomposedExpression& operator = ( DecomposedExpression const& ) = delete;
|
||||||
}
|
|
||||||
|
virtual ~DecomposedExpression() = default;
|
||||||
|
virtual bool isBinaryExpression() const;
|
||||||
virtual void reconstructExpression( std::string& dest ) const = 0;
|
virtual void reconstructExpression( std::string& dest ) const = 0;
|
||||||
|
|
||||||
// Only simple binary comparisons can be decomposed.
|
// Only simple binary comparisons can be decomposed.
|
||||||
@ -33,50 +35,26 @@ namespace Catch {
|
|||||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
|
||||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
|
||||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
|
||||||
|
|
||||||
private:
|
|
||||||
DecomposedExpression& operator = (DecomposedExpression const&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AssertionInfo
|
struct AssertionInfo
|
||||||
{
|
{
|
||||||
AssertionInfo() {}
|
AssertionInfo() = default;
|
||||||
AssertionInfo( char const * _macroName,
|
AssertionInfo( char const * _macroName,
|
||||||
SourceLineInfo const& _lineInfo,
|
SourceLineInfo const& _lineInfo,
|
||||||
char const * _capturedExpression,
|
char const * _capturedExpression,
|
||||||
ResultDisposition::Flags _resultDisposition);
|
ResultDisposition::Flags _resultDisposition);
|
||||||
|
|
||||||
char const * macroName;
|
char const * macroName = nullptr;
|
||||||
SourceLineInfo lineInfo;
|
SourceLineInfo lineInfo;
|
||||||
char const * capturedExpression;
|
char const * capturedExpression = nullptr;
|
||||||
ResultDisposition::Flags resultDisposition;
|
ResultDisposition::Flags resultDisposition;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AssertionResultData
|
struct AssertionResultData
|
||||||
{
|
{
|
||||||
void negate( bool parenthesize ) {
|
void negate( bool parenthesize );
|
||||||
negated = !negated;
|
std::string const& reconstructExpression() const;
|
||||||
parenthesized = parenthesize;
|
|
||||||
if( resultType == ResultWas::Ok )
|
|
||||||
resultType = ResultWas::ExpressionFailed;
|
|
||||||
else if( resultType == ResultWas::ExpressionFailed )
|
|
||||||
resultType = ResultWas::Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const& reconstructExpression() const {
|
|
||||||
if( decomposedExpression != nullptr ) {
|
|
||||||
decomposedExpression->reconstructExpression( reconstructedExpression );
|
|
||||||
if( parenthesized ) {
|
|
||||||
reconstructedExpression.insert( 0, 1, '(' );
|
|
||||||
reconstructedExpression.append( 1, ')' );
|
|
||||||
}
|
|
||||||
if( negated ) {
|
|
||||||
reconstructedExpression.insert( 0, 1, '!' );
|
|
||||||
}
|
|
||||||
decomposedExpression = nullptr;
|
|
||||||
}
|
|
||||||
return reconstructedExpression;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutable DecomposedExpression const* decomposedExpression = nullptr;
|
mutable DecomposedExpression const* decomposedExpression = nullptr;
|
||||||
mutable std::string reconstructedExpression;
|
mutable std::string reconstructedExpression;
|
||||||
|
71
include/internal/catch_config.cpp
Normal file
71
include/internal/catch_config.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_config.hpp"
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
Config::Config( ConfigData const& data )
|
||||||
|
: m_data( data ),
|
||||||
|
m_stream( openStream() )
|
||||||
|
{
|
||||||
|
if( !data.testsOrTags.empty() ) {
|
||||||
|
TestSpecParser parser( ITagAliasRegistry::get() );
|
||||||
|
for( auto const& testOrTags : data.testsOrTags )
|
||||||
|
parser.parse( testOrTags );
|
||||||
|
m_testSpec = parser.testSpec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const& Config::getFilename() const {
|
||||||
|
return m_data.outputFilename ;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Config::listTests() const { return m_data.listTests; }
|
||||||
|
bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; }
|
||||||
|
bool Config::listTags() const { return m_data.listTags; }
|
||||||
|
bool Config::listReporters() const { return m_data.listReporters; }
|
||||||
|
|
||||||
|
Verbosity Config::verbosity() const { return m_data.verbosity; }
|
||||||
|
|
||||||
|
std::string Config::getProcessName() const { return m_data.processName; }
|
||||||
|
|
||||||
|
std::vector<std::string> const& Config::getReporterNames() const { return m_data.reporterNames; }
|
||||||
|
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||||
|
|
||||||
|
TestSpec const& Config::testSpec() const { return m_testSpec; }
|
||||||
|
|
||||||
|
bool Config::showHelp() const { return m_data.showHelp; }
|
||||||
|
|
||||||
|
// IConfig interface
|
||||||
|
bool Config::allowThrows() const { return !m_data.noThrow; }
|
||||||
|
std::ostream& Config::stream() const { return m_stream->stream(); }
|
||||||
|
std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||||
|
bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
||||||
|
bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
|
||||||
|
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
|
||||||
|
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
|
||||||
|
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
|
||||||
|
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
|
||||||
|
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
||||||
|
int Config::abortAfter() const { return m_data.abortAfter; }
|
||||||
|
bool Config::showInvisibles() const { return m_data.showInvisibles; }
|
||||||
|
|
||||||
|
IStream const* Config::openStream() {
|
||||||
|
if( m_data.outputFilename.empty() )
|
||||||
|
return new CoutStream();
|
||||||
|
else if( m_data.outputFilename[0] == '%' ) {
|
||||||
|
if( m_data.outputFilename == "%debug" )
|
||||||
|
return new DebugOutStream();
|
||||||
|
else
|
||||||
|
CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return new FileStream( m_data.outputFilename );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
@ -16,7 +16,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#ifndef CATCH_CONFIG_CONSOLE_WIDTH
|
#ifndef CATCH_CONFIG_CONSOLE_WIDTH
|
||||||
#define CATCH_CONFIG_CONSOLE_WIDTH 80
|
#define CATCH_CONFIG_CONSOLE_WIDTH 80
|
||||||
@ -60,71 +59,45 @@ namespace Catch {
|
|||||||
virtual void dummy();
|
virtual void dummy();
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Config()
|
Config() = default;
|
||||||
{}
|
Config( ConfigData const& data );
|
||||||
|
virtual ~Config() = default;
|
||||||
|
|
||||||
Config( ConfigData const& data )
|
std::string const& getFilename() const;
|
||||||
: m_data( data ),
|
|
||||||
m_stream( openStream() )
|
|
||||||
{
|
|
||||||
if( !data.testsOrTags.empty() ) {
|
|
||||||
TestSpecParser parser( ITagAliasRegistry::get() );
|
|
||||||
for( auto const& testOrTags : data.testsOrTags )
|
|
||||||
parser.parse( testOrTags );
|
|
||||||
m_testSpec = parser.testSpec();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~Config() {}
|
bool listTests() const;
|
||||||
|
bool listTestNamesOnly() const;
|
||||||
|
bool listTags() const;
|
||||||
|
bool listReporters() const;
|
||||||
|
|
||||||
std::string const& getFilename() const {
|
Verbosity verbosity() const;
|
||||||
return m_data.outputFilename ;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool listTests() const { return m_data.listTests; }
|
std::string getProcessName() const;
|
||||||
bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
|
|
||||||
bool listTags() const { return m_data.listTags; }
|
|
||||||
bool listReporters() const { return m_data.listReporters; }
|
|
||||||
|
|
||||||
Verbosity verbosity() const { return m_data.verbosity; }
|
std::vector<std::string> const& getReporterNames() const;
|
||||||
|
std::vector<std::string> const& getSectionsToRun() const override;
|
||||||
|
|
||||||
std::string getProcessName() const { return m_data.processName; }
|
virtual TestSpec const& testSpec() const override;
|
||||||
|
|
||||||
std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
|
bool showHelp() const;
|
||||||
std::vector<std::string> const& getSectionsToRun() const override { return m_data.sectionsToRun; }
|
|
||||||
|
|
||||||
virtual TestSpec const& testSpec() const override { return m_testSpec; }
|
|
||||||
|
|
||||||
bool showHelp() const { return m_data.showHelp; }
|
|
||||||
|
|
||||||
// IConfig interface
|
// IConfig interface
|
||||||
virtual bool allowThrows() const override { return !m_data.noThrow; }
|
virtual bool allowThrows() const override;
|
||||||
virtual std::ostream& stream() const override { return m_stream->stream(); }
|
virtual std::ostream& stream() const override;
|
||||||
virtual std::string name() const override { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
virtual std::string name() const override;
|
||||||
virtual bool includeSuccessfulResults() const override { return m_data.showSuccessfulTests; }
|
virtual bool includeSuccessfulResults() const override;
|
||||||
virtual bool warnAboutMissingAssertions() const override { return m_data.warnings & WarnAbout::NoAssertions; }
|
virtual bool warnAboutMissingAssertions() const override;
|
||||||
virtual ShowDurations::OrNot showDurations() const override { return m_data.showDurations; }
|
virtual ShowDurations::OrNot showDurations() const override;
|
||||||
virtual RunTests::InWhatOrder runOrder() const override { return m_data.runOrder; }
|
virtual RunTests::InWhatOrder runOrder() const override;
|
||||||
virtual unsigned int rngSeed() const override { return m_data.rngSeed; }
|
virtual unsigned int rngSeed() const override;
|
||||||
virtual UseColour::YesOrNo useColour() const override { return m_data.useColour; }
|
virtual UseColour::YesOrNo useColour() const override;
|
||||||
virtual bool shouldDebugBreak() const override { return m_data.shouldDebugBreak; }
|
virtual bool shouldDebugBreak() const override;
|
||||||
virtual int abortAfter() const override { return m_data.abortAfter; }
|
virtual int abortAfter() const override;
|
||||||
virtual bool showInvisibles() const override { return m_data.showInvisibles; }
|
virtual bool showInvisibles() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
IStream const* openStream() {
|
IStream const* openStream();
|
||||||
if( m_data.outputFilename.empty() )
|
|
||||||
return new CoutStream();
|
|
||||||
else if( m_data.outputFilename[0] == '%' ) {
|
|
||||||
if( m_data.outputFilename == "%debug" )
|
|
||||||
return new DebugOutStream();
|
|
||||||
else
|
|
||||||
CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return new FileStream( m_data.outputFilename );
|
|
||||||
}
|
|
||||||
ConfigData m_data;
|
ConfigData m_data;
|
||||||
|
|
||||||
std::unique_ptr<IStream const> m_stream;
|
std::unique_ptr<IStream const> m_stream;
|
||||||
|
@ -55,33 +55,13 @@ namespace Catch {
|
|||||||
IMutableRegistryHub::~IMutableRegistryHub() {}
|
IMutableRegistryHub::~IMutableRegistryHub() {}
|
||||||
IExceptionTranslator::~IExceptionTranslator() {}
|
IExceptionTranslator::~IExceptionTranslator() {}
|
||||||
IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
|
IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
|
||||||
IReporterFactory::~IReporterFactory() {}
|
|
||||||
IReporterRegistry::~IReporterRegistry() {}
|
|
||||||
IStreamingReporter::~IStreamingReporter() {}
|
|
||||||
AssertionStats::~AssertionStats() {}
|
|
||||||
SectionStats::~SectionStats() {}
|
|
||||||
TestCaseStats::~TestCaseStats() {}
|
|
||||||
TestGroupStats::~TestGroupStats() {}
|
|
||||||
TestRunStats::~TestRunStats() {}
|
|
||||||
|
|
||||||
IRunner::~IRunner() {}
|
IRunner::~IRunner() {}
|
||||||
IMutableContext::~IMutableContext() {}
|
IMutableContext::~IMutableContext() {}
|
||||||
IConfig::~IConfig() {}
|
IConfig::~IConfig() {}
|
||||||
WildcardPattern::~WildcardPattern() {}
|
|
||||||
TestSpec::Pattern::~Pattern() {}
|
|
||||||
TestSpec::NamePattern::~NamePattern() {}
|
|
||||||
TestSpec::TagPattern::~TagPattern() {}
|
|
||||||
TestSpec::ExcludedPattern::~ExcludedPattern() {}
|
|
||||||
Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {}
|
Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {}
|
||||||
|
|
||||||
void Config::dummy() {}
|
void Config::dummy() {}
|
||||||
|
|
||||||
namespace TestCaseTracking {
|
|
||||||
ITracker::~ITracker() {}
|
|
||||||
TrackerBase::~TrackerBase() {}
|
|
||||||
SectionTracker::~SectionTracker() {}
|
|
||||||
IndexTracker::~IndexTracker() {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
|
120
include/internal/catch_interfaces_reporter.cpp
Normal file
120
include/internal/catch_interfaces_reporter.cpp
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_interfaces_reporter.h"
|
||||||
|
#include "../reporters/catch_reporter_multi.h"
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig )
|
||||||
|
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
|
||||||
|
|
||||||
|
ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream )
|
||||||
|
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
|
||||||
|
|
||||||
|
std::ostream& ReporterConfig::stream() const { return *m_stream; }
|
||||||
|
IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; }
|
||||||
|
|
||||||
|
|
||||||
|
TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {}
|
||||||
|
|
||||||
|
GroupInfo::GroupInfo( std::string const& _name,
|
||||||
|
std::size_t _groupIndex,
|
||||||
|
std::size_t _groupsCount )
|
||||||
|
: name( _name ),
|
||||||
|
groupIndex( _groupIndex ),
|
||||||
|
groupsCounts( _groupsCount )
|
||||||
|
{}
|
||||||
|
|
||||||
|
AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
|
||||||
|
std::vector<MessageInfo> const& _infoMessages,
|
||||||
|
Totals const& _totals )
|
||||||
|
: assertionResult( _assertionResult ),
|
||||||
|
infoMessages( _infoMessages ),
|
||||||
|
totals( _totals )
|
||||||
|
{
|
||||||
|
if( assertionResult.hasMessage() ) {
|
||||||
|
// Copy message into messages list.
|
||||||
|
// !TBD This should have been done earlier, somewhere
|
||||||
|
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
|
||||||
|
builder << assertionResult.getMessage();
|
||||||
|
builder.m_info.message = builder.m_stream.str();
|
||||||
|
|
||||||
|
infoMessages.push_back( builder.m_info );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionStats::SectionStats( SectionInfo const& _sectionInfo,
|
||||||
|
Counts const& _assertions,
|
||||||
|
double _durationInSeconds,
|
||||||
|
bool _missingAssertions )
|
||||||
|
: sectionInfo( _sectionInfo ),
|
||||||
|
assertions( _assertions ),
|
||||||
|
durationInSeconds( _durationInSeconds ),
|
||||||
|
missingAssertions( _missingAssertions )
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
|
||||||
|
Totals const& _totals,
|
||||||
|
std::string const& _stdOut,
|
||||||
|
std::string const& _stdErr,
|
||||||
|
bool _aborting )
|
||||||
|
: testInfo( _testInfo ),
|
||||||
|
totals( _totals ),
|
||||||
|
stdOut( _stdOut ),
|
||||||
|
stdErr( _stdErr ),
|
||||||
|
aborting( _aborting )
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo,
|
||||||
|
Totals const& _totals,
|
||||||
|
bool _aborting )
|
||||||
|
: groupInfo( _groupInfo ),
|
||||||
|
totals( _totals ),
|
||||||
|
aborting( _aborting )
|
||||||
|
{}
|
||||||
|
|
||||||
|
TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo )
|
||||||
|
: groupInfo( _groupInfo ),
|
||||||
|
aborting( false )
|
||||||
|
{}
|
||||||
|
|
||||||
|
TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
|
||||||
|
Totals const& _totals,
|
||||||
|
bool _aborting )
|
||||||
|
: runInfo( _runInfo ),
|
||||||
|
totals( _totals ),
|
||||||
|
aborting( _aborting )
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
bool IStreamingReporter::isMulti() const { return false; }
|
||||||
|
|
||||||
|
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) {
|
||||||
|
|
||||||
|
if( !existingReporter ) {
|
||||||
|
existingReporter = std::move( additionalReporter );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultipleReporters* multi = nullptr;
|
||||||
|
|
||||||
|
if( existingReporter->isMulti() ) {
|
||||||
|
multi = static_cast<MultipleReporters*>( existingReporter.get() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto newMulti = std::unique_ptr<MultipleReporters>( new MultipleReporters );
|
||||||
|
newMulti->add( std::move( existingReporter ) );
|
||||||
|
multi = newMulti.get();
|
||||||
|
existingReporter = std::move( newMulti );
|
||||||
|
}
|
||||||
|
multi->add( std::move( additionalReporter ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Catch
|
@ -10,29 +10,29 @@
|
|||||||
|
|
||||||
#include "catch_section_info.h"
|
#include "catch_section_info.h"
|
||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
#include "catch_totals.hpp"
|
|
||||||
#include "catch_config.hpp"
|
#include "catch_config.hpp"
|
||||||
|
#include "catch_context.h"
|
||||||
|
#include "catch_totals.hpp"
|
||||||
#include "catch_test_case_info.h"
|
#include "catch_test_case_info.h"
|
||||||
#include "catch_assertionresult.h"
|
#include "catch_assertionresult.h"
|
||||||
#include "catch_message.h"
|
#include "catch_message.h"
|
||||||
#include "catch_option.hpp"
|
#include "catch_option.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
#include <iosfwd>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace Catch
|
namespace Catch {
|
||||||
{
|
|
||||||
struct ReporterConfig {
|
struct ReporterConfig {
|
||||||
explicit ReporterConfig( IConfigPtr const& _fullConfig )
|
explicit ReporterConfig( IConfigPtr const& _fullConfig );
|
||||||
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
|
|
||||||
|
|
||||||
ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream )
|
ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream );
|
||||||
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
|
|
||||||
|
|
||||||
std::ostream& stream() const { return *m_stream; }
|
std::ostream& stream() const;
|
||||||
IConfigPtr fullConfig() const { return m_fullConfig; }
|
IConfigPtr fullConfig() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::ostream* m_stream;
|
std::ostream* m_stream;
|
||||||
@ -40,16 +40,11 @@ namespace Catch
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ReporterPreferences {
|
struct ReporterPreferences {
|
||||||
ReporterPreferences()
|
bool shouldRedirectStdOut = false;
|
||||||
: shouldRedirectStdOut( false )
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool shouldRedirectStdOut;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct LazyStat : Option<T> {
|
struct LazyStat : Option<T> {
|
||||||
LazyStat() : used( false ) {}
|
|
||||||
LazyStat& operator=( T const& _value ) {
|
LazyStat& operator=( T const& _value ) {
|
||||||
Option<T>::operator=( _value );
|
Option<T>::operator=( _value );
|
||||||
used = false;
|
used = false;
|
||||||
@ -59,21 +54,17 @@ namespace Catch
|
|||||||
Option<T>::reset();
|
Option<T>::reset();
|
||||||
used = false;
|
used = false;
|
||||||
}
|
}
|
||||||
bool used;
|
bool used = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestRunInfo {
|
struct TestRunInfo {
|
||||||
TestRunInfo( std::string const& _name ) : name( _name ) {}
|
TestRunInfo( std::string const& _name );
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
struct GroupInfo {
|
struct GroupInfo {
|
||||||
GroupInfo( std::string const& _name,
|
GroupInfo( std::string const& _name,
|
||||||
std::size_t _groupIndex,
|
std::size_t _groupIndex,
|
||||||
std::size_t _groupsCount )
|
std::size_t _groupsCount );
|
||||||
: name( _name ),
|
|
||||||
groupIndex( _groupIndex ),
|
|
||||||
groupsCounts( _groupsCount )
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::size_t groupIndex;
|
std::size_t groupIndex;
|
||||||
@ -83,27 +74,13 @@ namespace Catch
|
|||||||
struct AssertionStats {
|
struct AssertionStats {
|
||||||
AssertionStats( AssertionResult const& _assertionResult,
|
AssertionStats( AssertionResult const& _assertionResult,
|
||||||
std::vector<MessageInfo> const& _infoMessages,
|
std::vector<MessageInfo> const& _infoMessages,
|
||||||
Totals const& _totals )
|
Totals const& _totals );
|
||||||
: assertionResult( _assertionResult ),
|
|
||||||
infoMessages( _infoMessages ),
|
|
||||||
totals( _totals )
|
|
||||||
{
|
|
||||||
if( assertionResult.hasMessage() ) {
|
|
||||||
// Copy message into messages list.
|
|
||||||
// !TBD This should have been done earlier, somewhere
|
|
||||||
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
|
|
||||||
builder << assertionResult.getMessage();
|
|
||||||
builder.m_info.message = builder.m_stream.str();
|
|
||||||
|
|
||||||
infoMessages.push_back( builder.m_info );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual ~AssertionStats();
|
|
||||||
|
|
||||||
AssertionStats( AssertionStats const& ) = default;
|
AssertionStats( AssertionStats const& ) = default;
|
||||||
AssertionStats( AssertionStats && ) = default;
|
AssertionStats( AssertionStats && ) = default;
|
||||||
AssertionStats& operator = ( AssertionStats const& ) = default;
|
AssertionStats& operator = ( AssertionStats const& ) = default;
|
||||||
AssertionStats& operator = ( AssertionStats && ) = default;
|
AssertionStats& operator = ( AssertionStats && ) = default;
|
||||||
|
virtual ~AssertionStats() = default;
|
||||||
|
|
||||||
AssertionResult assertionResult;
|
AssertionResult assertionResult;
|
||||||
std::vector<MessageInfo> infoMessages;
|
std::vector<MessageInfo> infoMessages;
|
||||||
@ -114,17 +91,12 @@ namespace Catch
|
|||||||
SectionStats( SectionInfo const& _sectionInfo,
|
SectionStats( SectionInfo const& _sectionInfo,
|
||||||
Counts const& _assertions,
|
Counts const& _assertions,
|
||||||
double _durationInSeconds,
|
double _durationInSeconds,
|
||||||
bool _missingAssertions )
|
bool _missingAssertions );
|
||||||
: sectionInfo( _sectionInfo ),
|
|
||||||
assertions( _assertions ),
|
|
||||||
durationInSeconds( _durationInSeconds ),
|
|
||||||
missingAssertions( _missingAssertions )
|
|
||||||
{}
|
|
||||||
virtual ~SectionStats();
|
|
||||||
SectionStats( SectionStats const& ) = default;
|
SectionStats( SectionStats const& ) = default;
|
||||||
SectionStats( SectionStats && ) = default;
|
SectionStats( SectionStats && ) = default;
|
||||||
SectionStats& operator = ( SectionStats const& ) = default;
|
SectionStats& operator = ( SectionStats const& ) = default;
|
||||||
SectionStats& operator = ( SectionStats && ) = default;
|
SectionStats& operator = ( SectionStats && ) = default;
|
||||||
|
virtual ~SectionStats() = default;
|
||||||
|
|
||||||
SectionInfo sectionInfo;
|
SectionInfo sectionInfo;
|
||||||
Counts assertions;
|
Counts assertions;
|
||||||
@ -137,19 +109,13 @@ namespace Catch
|
|||||||
Totals const& _totals,
|
Totals const& _totals,
|
||||||
std::string const& _stdOut,
|
std::string const& _stdOut,
|
||||||
std::string const& _stdErr,
|
std::string const& _stdErr,
|
||||||
bool _aborting )
|
bool _aborting );
|
||||||
: testInfo( _testInfo ),
|
|
||||||
totals( _totals ),
|
|
||||||
stdOut( _stdOut ),
|
|
||||||
stdErr( _stdErr ),
|
|
||||||
aborting( _aborting )
|
|
||||||
{}
|
|
||||||
virtual ~TestCaseStats();
|
|
||||||
|
|
||||||
TestCaseStats( TestCaseStats const& ) = default;
|
TestCaseStats( TestCaseStats const& ) = default;
|
||||||
TestCaseStats( TestCaseStats && ) = default;
|
TestCaseStats( TestCaseStats && ) = default;
|
||||||
TestCaseStats& operator = ( TestCaseStats const& ) = default;
|
TestCaseStats& operator = ( TestCaseStats const& ) = default;
|
||||||
TestCaseStats& operator = ( TestCaseStats && ) = default;
|
TestCaseStats& operator = ( TestCaseStats && ) = default;
|
||||||
|
virtual ~TestCaseStats() = default;
|
||||||
|
|
||||||
TestCaseInfo testInfo;
|
TestCaseInfo testInfo;
|
||||||
Totals totals;
|
Totals totals;
|
||||||
@ -161,21 +127,14 @@ namespace Catch
|
|||||||
struct TestGroupStats {
|
struct TestGroupStats {
|
||||||
TestGroupStats( GroupInfo const& _groupInfo,
|
TestGroupStats( GroupInfo const& _groupInfo,
|
||||||
Totals const& _totals,
|
Totals const& _totals,
|
||||||
bool _aborting )
|
bool _aborting );
|
||||||
: groupInfo( _groupInfo ),
|
TestGroupStats( GroupInfo const& _groupInfo );
|
||||||
totals( _totals ),
|
|
||||||
aborting( _aborting )
|
|
||||||
{}
|
|
||||||
TestGroupStats( GroupInfo const& _groupInfo )
|
|
||||||
: groupInfo( _groupInfo ),
|
|
||||||
aborting( false )
|
|
||||||
{}
|
|
||||||
virtual ~TestGroupStats();
|
|
||||||
|
|
||||||
TestGroupStats( TestGroupStats const& ) = default;
|
TestGroupStats( TestGroupStats const& ) = default;
|
||||||
TestGroupStats( TestGroupStats && ) = default;
|
TestGroupStats( TestGroupStats && ) = default;
|
||||||
TestGroupStats& operator = ( TestGroupStats const& ) = default;
|
TestGroupStats& operator = ( TestGroupStats const& ) = default;
|
||||||
TestGroupStats& operator = ( TestGroupStats && ) = default;
|
TestGroupStats& operator = ( TestGroupStats && ) = default;
|
||||||
|
virtual ~TestGroupStats() = default;
|
||||||
|
|
||||||
GroupInfo groupInfo;
|
GroupInfo groupInfo;
|
||||||
Totals totals;
|
Totals totals;
|
||||||
@ -185,17 +144,13 @@ namespace Catch
|
|||||||
struct TestRunStats {
|
struct TestRunStats {
|
||||||
TestRunStats( TestRunInfo const& _runInfo,
|
TestRunStats( TestRunInfo const& _runInfo,
|
||||||
Totals const& _totals,
|
Totals const& _totals,
|
||||||
bool _aborting )
|
bool _aborting );
|
||||||
: runInfo( _runInfo ),
|
|
||||||
totals( _totals ),
|
|
||||||
aborting( _aborting )
|
|
||||||
{}
|
|
||||||
virtual ~TestRunStats();
|
|
||||||
|
|
||||||
TestRunStats( TestRunStats const& ) = default;
|
TestRunStats( TestRunStats const& ) = default;
|
||||||
TestRunStats( TestRunStats && ) = default;
|
TestRunStats( TestRunStats && ) = default;
|
||||||
TestRunStats& operator = ( TestRunStats const& ) = default;
|
TestRunStats& operator = ( TestRunStats const& ) = default;
|
||||||
TestRunStats& operator = ( TestRunStats && ) = default;
|
TestRunStats& operator = ( TestRunStats && ) = default;
|
||||||
|
virtual ~TestRunStats() = default;
|
||||||
|
|
||||||
TestRunInfo runInfo;
|
TestRunInfo runInfo;
|
||||||
Totals totals;
|
Totals totals;
|
||||||
@ -205,7 +160,7 @@ namespace Catch
|
|||||||
class MultipleReporters;
|
class MultipleReporters;
|
||||||
|
|
||||||
struct IStreamingReporter {
|
struct IStreamingReporter {
|
||||||
virtual ~IStreamingReporter();
|
virtual ~IStreamingReporter() = default;
|
||||||
|
|
||||||
// Implementing class must also provide the following static method:
|
// Implementing class must also provide the following static method:
|
||||||
// static std::string getDescription();
|
// static std::string getDescription();
|
||||||
@ -232,12 +187,12 @@ namespace Catch
|
|||||||
|
|
||||||
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
|
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
|
||||||
|
|
||||||
virtual bool isMulti() const { return false; }
|
virtual bool isMulti() const;
|
||||||
};
|
};
|
||||||
using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>;
|
using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>;
|
||||||
|
|
||||||
struct IReporterFactory {
|
struct IReporterFactory {
|
||||||
virtual ~IReporterFactory();
|
virtual ~IReporterFactory() = default;
|
||||||
virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0;
|
virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0;
|
||||||
virtual std::string getDescription() const = 0;
|
virtual std::string getDescription() const = 0;
|
||||||
};
|
};
|
||||||
@ -247,13 +202,14 @@ namespace Catch
|
|||||||
using FactoryMap = std::map<std::string, IReporterFactoryPtr>;
|
using FactoryMap = std::map<std::string, IReporterFactoryPtr>;
|
||||||
using Listeners = std::vector<IReporterFactoryPtr>;
|
using Listeners = std::vector<IReporterFactoryPtr>;
|
||||||
|
|
||||||
virtual ~IReporterRegistry();
|
virtual ~IReporterRegistry() = default;
|
||||||
virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0;
|
virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0;
|
||||||
virtual FactoryMap const& getFactories() const = 0;
|
virtual FactoryMap const& getFactories() const = 0;
|
||||||
virtual Listeners const& getListeners() const = 0;
|
virtual Listeners const& getListeners() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
|
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
|
||||||
}
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
||||||
|
@ -19,6 +19,16 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
|
CopyableStream::CopyableStream( CopyableStream const& other ) {
|
||||||
|
oss << other.oss.str();
|
||||||
|
}
|
||||||
|
CopyableStream& CopyableStream::operator=( CopyableStream const& other ) {
|
||||||
|
oss.str(std::string());
|
||||||
|
oss << other.oss.str();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ResultBuilder::ResultBuilder( char const* macroName,
|
ResultBuilder::ResultBuilder( char const* macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
char const* capturedExpression,
|
char const* capturedExpression,
|
||||||
|
@ -21,14 +21,9 @@ namespace Catch {
|
|||||||
|
|
||||||
struct CopyableStream {
|
struct CopyableStream {
|
||||||
CopyableStream() = default;
|
CopyableStream() = default;
|
||||||
CopyableStream( CopyableStream const& other ) {
|
CopyableStream( CopyableStream const& other );
|
||||||
oss << other.oss.str();
|
CopyableStream& operator=( CopyableStream const& other );
|
||||||
}
|
|
||||||
CopyableStream& operator=( CopyableStream const& other ) {
|
|
||||||
oss.str(std::string());
|
|
||||||
oss << other.oss.str();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "catch_run_context.hpp"
|
#include "catch_run_context.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString)
|
StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString)
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include "catch_result_builder.h"
|
#include "catch_result_builder.h"
|
||||||
#include "catch_fatal_condition.h"
|
#include "catch_fatal_condition.h"
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
277
include/internal/catch_test_case_tracker.cpp
Normal file
277
include/internal/catch_test_case_tracker.cpp
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_test_case_tracker.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace TestCaseTracking {
|
||||||
|
|
||||||
|
NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
|
||||||
|
: name( _name ),
|
||||||
|
location( _location )
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TrackerContext& TrackerContext::instance() {
|
||||||
|
static TrackerContext s_instance;
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITracker& TrackerContext::startRun() {
|
||||||
|
m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr );
|
||||||
|
m_currentTracker = nullptr;
|
||||||
|
m_runState = Executing;
|
||||||
|
return *m_rootTracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackerContext::endRun() {
|
||||||
|
m_rootTracker.reset();
|
||||||
|
m_currentTracker = nullptr;
|
||||||
|
m_runState = NotStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackerContext::startCycle() {
|
||||||
|
m_currentTracker = m_rootTracker.get();
|
||||||
|
m_runState = Executing;
|
||||||
|
}
|
||||||
|
void TrackerContext::completeCycle() {
|
||||||
|
m_runState = CompletedCycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TrackerContext::completedCycle() const {
|
||||||
|
return m_runState == CompletedCycle;
|
||||||
|
}
|
||||||
|
ITracker& TrackerContext::currentTracker() {
|
||||||
|
return *m_currentTracker;
|
||||||
|
}
|
||||||
|
void TrackerContext::setCurrentTracker( ITracker* tracker ) {
|
||||||
|
m_currentTracker = tracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
|
||||||
|
bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) {
|
||||||
|
return
|
||||||
|
tracker->nameAndLocation().name == m_nameAndLocation.name &&
|
||||||
|
tracker->nameAndLocation().location == m_nameAndLocation.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||||
|
: m_nameAndLocation( nameAndLocation ),
|
||||||
|
m_ctx( ctx ),
|
||||||
|
m_parent( parent )
|
||||||
|
{}
|
||||||
|
|
||||||
|
NameAndLocation const& TrackerBase::nameAndLocation() const {
|
||||||
|
return m_nameAndLocation;
|
||||||
|
}
|
||||||
|
bool TrackerBase::isComplete() const {
|
||||||
|
return m_runState == CompletedSuccessfully || m_runState == Failed;
|
||||||
|
}
|
||||||
|
bool TrackerBase::isSuccessfullyCompleted() const {
|
||||||
|
return m_runState == CompletedSuccessfully;
|
||||||
|
}
|
||||||
|
bool TrackerBase::isOpen() const {
|
||||||
|
return m_runState != NotStarted && !isComplete();
|
||||||
|
}
|
||||||
|
bool TrackerBase::hasChildren() const {
|
||||||
|
return !m_children.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TrackerBase::addChild( ITrackerPtr const& child ) {
|
||||||
|
m_children.push_back( child );
|
||||||
|
}
|
||||||
|
|
||||||
|
ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) {
|
||||||
|
auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
|
||||||
|
return( it != m_children.end() )
|
||||||
|
? *it
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
ITracker& TrackerBase::parent() {
|
||||||
|
assert( m_parent ); // Should always be non-null except for root
|
||||||
|
return *m_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackerBase::openChild() {
|
||||||
|
if( m_runState != ExecutingChildren ) {
|
||||||
|
m_runState = ExecutingChildren;
|
||||||
|
if( m_parent )
|
||||||
|
m_parent->openChild();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TrackerBase::isSectionTracker() const { return false; }
|
||||||
|
bool TrackerBase::isIndexTracker() const { return false; }
|
||||||
|
|
||||||
|
void TrackerBase::open() {
|
||||||
|
m_runState = Executing;
|
||||||
|
moveToThis();
|
||||||
|
if( m_parent )
|
||||||
|
m_parent->openChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackerBase::close() {
|
||||||
|
|
||||||
|
// Close any still open children (e.g. generators)
|
||||||
|
while( &m_ctx.currentTracker() != this )
|
||||||
|
m_ctx.currentTracker().close();
|
||||||
|
|
||||||
|
switch( m_runState ) {
|
||||||
|
case NeedsAnotherRun:
|
||||||
|
break;;
|
||||||
|
|
||||||
|
case Executing:
|
||||||
|
m_runState = CompletedSuccessfully;
|
||||||
|
break;
|
||||||
|
case ExecutingChildren:
|
||||||
|
if( m_children.empty() || m_children.back()->isComplete() )
|
||||||
|
m_runState = CompletedSuccessfully;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotStarted:
|
||||||
|
case CompletedSuccessfully:
|
||||||
|
case Failed:
|
||||||
|
CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
|
||||||
|
|
||||||
|
default:
|
||||||
|
CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
|
||||||
|
}
|
||||||
|
moveToParent();
|
||||||
|
m_ctx.completeCycle();
|
||||||
|
}
|
||||||
|
void TrackerBase::fail() {
|
||||||
|
m_runState = Failed;
|
||||||
|
if( m_parent )
|
||||||
|
m_parent->markAsNeedingAnotherRun();
|
||||||
|
moveToParent();
|
||||||
|
m_ctx.completeCycle();
|
||||||
|
}
|
||||||
|
void TrackerBase::markAsNeedingAnotherRun() {
|
||||||
|
m_runState = NeedsAnotherRun;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackerBase::moveToParent() {
|
||||||
|
assert( m_parent );
|
||||||
|
m_ctx.setCurrentTracker( m_parent );
|
||||||
|
}
|
||||||
|
void TrackerBase::moveToThis() {
|
||||||
|
m_ctx.setCurrentTracker( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||||
|
: TrackerBase( nameAndLocation, ctx, parent )
|
||||||
|
{
|
||||||
|
if( parent ) {
|
||||||
|
while( !parent->isSectionTracker() )
|
||||||
|
parent = &parent->parent();
|
||||||
|
|
||||||
|
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
|
||||||
|
addNextFilters( parentSection.m_filters );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SectionTracker::isSectionTracker() const { return true; }
|
||||||
|
|
||||||
|
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
|
||||||
|
std::shared_ptr<SectionTracker> section;
|
||||||
|
|
||||||
|
ITracker& currentTracker = ctx.currentTracker();
|
||||||
|
if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||||
|
assert( childTracker );
|
||||||
|
assert( childTracker->isSectionTracker() );
|
||||||
|
section = std::static_pointer_cast<SectionTracker>( childTracker );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker );
|
||||||
|
currentTracker.addChild( section );
|
||||||
|
}
|
||||||
|
if( !ctx.completedCycle() )
|
||||||
|
section->tryOpen();
|
||||||
|
return *section;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SectionTracker::tryOpen() {
|
||||||
|
if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
|
||||||
|
if( !filters.empty() ) {
|
||||||
|
m_filters.push_back(""); // Root - should never be consulted
|
||||||
|
m_filters.push_back(""); // Test Case - not a section filter
|
||||||
|
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {
|
||||||
|
if( filters.size() > 1 )
|
||||||
|
m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
|
||||||
|
: TrackerBase( nameAndLocation, ctx, parent ),
|
||||||
|
m_size( size )
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool IndexTracker::isIndexTracker() const { return true; }
|
||||||
|
|
||||||
|
IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
|
||||||
|
std::shared_ptr<IndexTracker> tracker;
|
||||||
|
|
||||||
|
ITracker& currentTracker = ctx.currentTracker();
|
||||||
|
if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||||
|
assert( childTracker );
|
||||||
|
assert( childTracker->isIndexTracker() );
|
||||||
|
tracker = std::static_pointer_cast<IndexTracker>( childTracker );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, ¤tTracker, size );
|
||||||
|
currentTracker.addChild( tracker );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !ctx.completedCycle() && !tracker->isComplete() ) {
|
||||||
|
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
|
||||||
|
tracker->moveNext();
|
||||||
|
tracker->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *tracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IndexTracker::index() const { return m_index; }
|
||||||
|
|
||||||
|
void IndexTracker::moveNext() {
|
||||||
|
m_index++;
|
||||||
|
m_children.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexTracker::close() {
|
||||||
|
TrackerBase::close();
|
||||||
|
if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
|
||||||
|
m_runState = Executing;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace TestCaseTracking
|
||||||
|
|
||||||
|
using TestCaseTracking::ITracker;
|
||||||
|
using TestCaseTracking::TrackerContext;
|
||||||
|
using TestCaseTracking::SectionTracker;
|
||||||
|
using TestCaseTracking::IndexTracker;
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
|
@ -11,11 +11,8 @@
|
|||||||
#include "catch_compiler_capabilities.h"
|
#include "catch_compiler_capabilities.h"
|
||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <assert.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdexcept>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
|
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
|
||||||
@ -27,10 +24,7 @@ namespace TestCaseTracking {
|
|||||||
std::string name;
|
std::string name;
|
||||||
SourceLineInfo location;
|
SourceLineInfo location;
|
||||||
|
|
||||||
NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
|
NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
|
||||||
: name( _name ),
|
|
||||||
location( _location )
|
|
||||||
{}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ITracker;
|
struct ITracker;
|
||||||
@ -38,7 +32,7 @@ namespace TestCaseTracking {
|
|||||||
using ITrackerPtr = std::shared_ptr<ITracker>;
|
using ITrackerPtr = std::shared_ptr<ITracker>;
|
||||||
|
|
||||||
struct ITracker {
|
struct ITracker {
|
||||||
virtual ~ITracker();
|
virtual ~ITracker() = default;
|
||||||
|
|
||||||
// static queries
|
// static queries
|
||||||
virtual NameAndLocation const& nameAndLocation() const = 0;
|
virtual NameAndLocation const& nameAndLocation() const = 0;
|
||||||
@ -79,36 +73,17 @@ namespace TestCaseTracking {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static TrackerContext& instance() {
|
static TrackerContext& instance();
|
||||||
static TrackerContext s_instance;
|
|
||||||
return s_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
ITracker& startRun();
|
ITracker& startRun();
|
||||||
|
void endRun();
|
||||||
|
|
||||||
void endRun() {
|
void startCycle();
|
||||||
m_rootTracker.reset();
|
void completeCycle();
|
||||||
m_currentTracker = nullptr;
|
|
||||||
m_runState = NotStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
void startCycle() {
|
bool completedCycle() const;
|
||||||
m_currentTracker = m_rootTracker.get();
|
ITracker& currentTracker();
|
||||||
m_runState = Executing;
|
void setCurrentTracker( ITracker* tracker );
|
||||||
}
|
|
||||||
void completeCycle() {
|
|
||||||
m_runState = CompletedCycle;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool completedCycle() const {
|
|
||||||
return m_runState == CompletedCycle;
|
|
||||||
}
|
|
||||||
ITracker& currentTracker() {
|
|
||||||
return *m_currentTracker;
|
|
||||||
}
|
|
||||||
void setCurrentTracker( ITracker* tracker ) {
|
|
||||||
m_currentTracker = tracker;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TrackerBase : public ITracker {
|
class TrackerBase : public ITracker {
|
||||||
@ -121,239 +96,87 @@ namespace TestCaseTracking {
|
|||||||
CompletedSuccessfully,
|
CompletedSuccessfully,
|
||||||
Failed
|
Failed
|
||||||
};
|
};
|
||||||
|
|
||||||
class TrackerHasName {
|
class TrackerHasName {
|
||||||
NameAndLocation m_nameAndLocation;
|
NameAndLocation m_nameAndLocation;
|
||||||
public:
|
public:
|
||||||
TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
|
TrackerHasName( NameAndLocation const& nameAndLocation );
|
||||||
bool operator ()( ITrackerPtr const& tracker ) {
|
bool operator ()( ITrackerPtr const& tracker );
|
||||||
return
|
|
||||||
tracker->nameAndLocation().name == m_nameAndLocation.name &&
|
|
||||||
tracker->nameAndLocation().location == m_nameAndLocation.location;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<ITrackerPtr> Children;
|
typedef std::vector<ITrackerPtr> Children;
|
||||||
NameAndLocation m_nameAndLocation;
|
NameAndLocation m_nameAndLocation;
|
||||||
TrackerContext& m_ctx;
|
TrackerContext& m_ctx;
|
||||||
ITracker* m_parent;
|
ITracker* m_parent;
|
||||||
Children m_children;
|
Children m_children;
|
||||||
CycleState m_runState = NotStarted;
|
CycleState m_runState = NotStarted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
|
||||||
: m_nameAndLocation( nameAndLocation ),
|
virtual ~TrackerBase() = default;
|
||||||
m_ctx( ctx ),
|
|
||||||
m_parent( parent )
|
|
||||||
{}
|
|
||||||
virtual ~TrackerBase();
|
|
||||||
|
|
||||||
virtual NameAndLocation const& nameAndLocation() const override {
|
virtual NameAndLocation const& nameAndLocation() const override;
|
||||||
return m_nameAndLocation;
|
virtual bool isComplete() const override;
|
||||||
}
|
virtual bool isSuccessfullyCompleted() const override;
|
||||||
virtual bool isComplete() const override {
|
virtual bool isOpen() const override;
|
||||||
return m_runState == CompletedSuccessfully || m_runState == Failed;
|
virtual bool hasChildren() const override;
|
||||||
}
|
|
||||||
virtual bool isSuccessfullyCompleted() const override {
|
|
||||||
return m_runState == CompletedSuccessfully;
|
|
||||||
}
|
|
||||||
virtual bool isOpen() const override {
|
|
||||||
return m_runState != NotStarted && !isComplete();
|
|
||||||
}
|
|
||||||
virtual bool hasChildren() const override {
|
|
||||||
return !m_children.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
virtual void addChild( ITrackerPtr const& child ) override {
|
virtual void addChild( ITrackerPtr const& child ) override;
|
||||||
m_children.push_back( child );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override {
|
virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override;
|
||||||
auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
|
virtual ITracker& parent() override;
|
||||||
return( it != m_children.end() )
|
|
||||||
? *it
|
|
||||||
: nullptr;
|
|
||||||
}
|
|
||||||
virtual ITracker& parent() override {
|
|
||||||
assert( m_parent ); // Should always be non-null except for root
|
|
||||||
return *m_parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void openChild() override {
|
virtual void openChild() override;
|
||||||
if( m_runState != ExecutingChildren ) {
|
|
||||||
m_runState = ExecutingChildren;
|
|
||||||
if( m_parent )
|
|
||||||
m_parent->openChild();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool isSectionTracker() const override { return false; }
|
virtual bool isSectionTracker() const override;
|
||||||
virtual bool isIndexTracker() const override { return false; }
|
virtual bool isIndexTracker() const override;
|
||||||
|
|
||||||
void open() {
|
void open();
|
||||||
m_runState = Executing;
|
|
||||||
moveToThis();
|
|
||||||
if( m_parent )
|
|
||||||
m_parent->openChild();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void close() override {
|
virtual void close() override;
|
||||||
|
virtual void fail() override;
|
||||||
|
virtual void markAsNeedingAnotherRun() override;
|
||||||
|
|
||||||
// Close any still open children (e.g. generators)
|
|
||||||
while( &m_ctx.currentTracker() != this )
|
|
||||||
m_ctx.currentTracker().close();
|
|
||||||
|
|
||||||
switch( m_runState ) {
|
|
||||||
case NeedsAnotherRun:
|
|
||||||
break;;
|
|
||||||
|
|
||||||
case Executing:
|
|
||||||
m_runState = CompletedSuccessfully;
|
|
||||||
break;
|
|
||||||
case ExecutingChildren:
|
|
||||||
if( m_children.empty() || m_children.back()->isComplete() )
|
|
||||||
m_runState = CompletedSuccessfully;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NotStarted:
|
|
||||||
case CompletedSuccessfully:
|
|
||||||
case Failed:
|
|
||||||
CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
|
|
||||||
|
|
||||||
default:
|
|
||||||
CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
|
|
||||||
}
|
|
||||||
moveToParent();
|
|
||||||
m_ctx.completeCycle();
|
|
||||||
}
|
|
||||||
virtual void fail() override {
|
|
||||||
m_runState = Failed;
|
|
||||||
if( m_parent )
|
|
||||||
m_parent->markAsNeedingAnotherRun();
|
|
||||||
moveToParent();
|
|
||||||
m_ctx.completeCycle();
|
|
||||||
}
|
|
||||||
virtual void markAsNeedingAnotherRun() override {
|
|
||||||
m_runState = NeedsAnotherRun;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
void moveToParent() {
|
void moveToParent();
|
||||||
assert( m_parent );
|
void moveToThis();
|
||||||
m_ctx.setCurrentTracker( m_parent );
|
|
||||||
}
|
|
||||||
void moveToThis() {
|
|
||||||
m_ctx.setCurrentTracker( this );
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SectionTracker : public TrackerBase {
|
class SectionTracker : public TrackerBase {
|
||||||
std::vector<std::string> m_filters;
|
std::vector<std::string> m_filters;
|
||||||
public:
|
public:
|
||||||
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
|
||||||
: TrackerBase( nameAndLocation, ctx, parent )
|
virtual ~SectionTracker() = default;
|
||||||
{
|
|
||||||
if( parent ) {
|
|
||||||
while( !parent->isSectionTracker() )
|
|
||||||
parent = &parent->parent();
|
|
||||||
|
|
||||||
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
|
virtual bool isSectionTracker() const override;
|
||||||
addNextFilters( parentSection.m_filters );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual ~SectionTracker();
|
|
||||||
|
|
||||||
virtual bool isSectionTracker() const override { return true; }
|
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
|
||||||
|
|
||||||
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
|
void tryOpen();
|
||||||
std::shared_ptr<SectionTracker> section;
|
|
||||||
|
|
||||||
ITracker& currentTracker = ctx.currentTracker();
|
void addInitialFilters( std::vector<std::string> const& filters );
|
||||||
if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
void addNextFilters( std::vector<std::string> const& filters );
|
||||||
assert( childTracker );
|
|
||||||
assert( childTracker->isSectionTracker() );
|
|
||||||
section = std::static_pointer_cast<SectionTracker>( childTracker );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker );
|
|
||||||
currentTracker.addChild( section );
|
|
||||||
}
|
|
||||||
if( !ctx.completedCycle() )
|
|
||||||
section->tryOpen();
|
|
||||||
return *section;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tryOpen() {
|
|
||||||
if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
|
|
||||||
open();
|
|
||||||
}
|
|
||||||
|
|
||||||
void addInitialFilters( std::vector<std::string> const& filters ) {
|
|
||||||
if( !filters.empty() ) {
|
|
||||||
m_filters.push_back(""); // Root - should never be consulted
|
|
||||||
m_filters.push_back(""); // Test Case - not a section filter
|
|
||||||
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void addNextFilters( std::vector<std::string> const& filters ) {
|
|
||||||
if( filters.size() > 1 )
|
|
||||||
m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IndexTracker : public TrackerBase {
|
class IndexTracker : public TrackerBase {
|
||||||
int m_size;
|
int m_size;
|
||||||
int m_index = -1;
|
int m_index = -1;
|
||||||
public:
|
public:
|
||||||
IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
|
IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size );
|
||||||
: TrackerBase( nameAndLocation, ctx, parent ),
|
virtual ~IndexTracker() = default;
|
||||||
m_size( size )
|
|
||||||
{}
|
|
||||||
virtual ~IndexTracker();
|
|
||||||
|
|
||||||
virtual bool isIndexTracker() const override { return true; }
|
virtual bool isIndexTracker() const override;
|
||||||
|
|
||||||
static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
|
static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size );
|
||||||
std::shared_ptr<IndexTracker> tracker;
|
|
||||||
|
|
||||||
ITracker& currentTracker = ctx.currentTracker();
|
int index() const;
|
||||||
if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
|
||||||
assert( childTracker );
|
|
||||||
assert( childTracker->isIndexTracker() );
|
|
||||||
tracker = std::static_pointer_cast<IndexTracker>( childTracker );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, ¤tTracker, size );
|
|
||||||
currentTracker.addChild( tracker );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !ctx.completedCycle() && !tracker->isComplete() ) {
|
void moveNext();
|
||||||
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
|
|
||||||
tracker->moveNext();
|
|
||||||
tracker->open();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *tracker;
|
virtual void close() override;
|
||||||
}
|
|
||||||
|
|
||||||
int index() const { return m_index; }
|
|
||||||
|
|
||||||
void moveNext() {
|
|
||||||
m_index++;
|
|
||||||
m_children.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void close() override {
|
|
||||||
TrackerBase::close();
|
|
||||||
if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
|
|
||||||
m_runState = Executing;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline ITracker& TrackerContext::startRun() {
|
|
||||||
m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr );
|
|
||||||
m_currentTracker = nullptr;
|
|
||||||
m_runState = Executing;
|
|
||||||
return *m_rootTracker;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace TestCaseTracking
|
} // namespace TestCaseTracking
|
||||||
|
|
||||||
using TestCaseTracking::ITracker;
|
using TestCaseTracking::ITracker;
|
||||||
|
50
include/internal/catch_test_spec.cpp
Normal file
50
include/internal/catch_test_spec.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_test_spec.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
TestSpec::NamePattern::NamePattern( std::string const& name )
|
||||||
|
: m_wildcardPattern( toLower( name ), CaseSensitive::No )
|
||||||
|
{}
|
||||||
|
bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
|
||||||
|
return m_wildcardPattern.matches( toLower( testCase.name ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
|
||||||
|
bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
|
||||||
|
return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
|
||||||
|
bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
|
||||||
|
|
||||||
|
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
|
||||||
|
// All patterns in a filter must match for the filter to be a match
|
||||||
|
for( auto const& pattern : m_patterns ) {
|
||||||
|
if( !pattern->matches( testCase ) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestSpec::hasFilters() const {
|
||||||
|
return !m_filters.empty();
|
||||||
|
}
|
||||||
|
bool TestSpec::matches( TestCaseInfo const& testCase ) const {
|
||||||
|
// A TestSpec matches if any filter matches
|
||||||
|
for( auto const& filter : m_filters )
|
||||||
|
if( filter.matches( testCase ) )
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -24,40 +24,34 @@ namespace Catch {
|
|||||||
|
|
||||||
class TestSpec {
|
class TestSpec {
|
||||||
struct Pattern {
|
struct Pattern {
|
||||||
virtual ~Pattern();
|
virtual ~Pattern() = default;
|
||||||
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
|
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
|
||||||
};
|
};
|
||||||
using PatternPtr = std::shared_ptr<Pattern>;
|
using PatternPtr = std::shared_ptr<Pattern>;
|
||||||
|
|
||||||
class NamePattern : public Pattern {
|
class NamePattern : public Pattern {
|
||||||
public:
|
public:
|
||||||
NamePattern( std::string const& name )
|
NamePattern( std::string const& name );
|
||||||
: m_wildcardPattern( toLower( name ), CaseSensitive::No )
|
virtual ~NamePattern() = default;
|
||||||
{}
|
virtual bool matches( TestCaseInfo const& testCase ) const;
|
||||||
virtual ~NamePattern();
|
|
||||||
virtual bool matches( TestCaseInfo const& testCase ) const {
|
|
||||||
return m_wildcardPattern.matches( toLower( testCase.name ) );
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
WildcardPattern m_wildcardPattern;
|
WildcardPattern m_wildcardPattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TagPattern : public Pattern {
|
class TagPattern : public Pattern {
|
||||||
public:
|
public:
|
||||||
TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
|
TagPattern( std::string const& tag );
|
||||||
virtual ~TagPattern();
|
virtual ~TagPattern() = default;
|
||||||
virtual bool matches( TestCaseInfo const& testCase ) const {
|
virtual bool matches( TestCaseInfo const& testCase ) const;
|
||||||
return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
std::string m_tag;
|
std::string m_tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExcludedPattern : public Pattern {
|
class ExcludedPattern : public Pattern {
|
||||||
public:
|
public:
|
||||||
ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
|
ExcludedPattern( PatternPtr const& underlyingPattern );
|
||||||
virtual ~ExcludedPattern();
|
virtual ~ExcludedPattern() = default;
|
||||||
virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
|
virtual bool matches( TestCaseInfo const& testCase ) const;
|
||||||
private:
|
private:
|
||||||
PatternPtr m_underlyingPattern;
|
PatternPtr m_underlyingPattern;
|
||||||
};
|
};
|
||||||
@ -65,27 +59,12 @@ namespace Catch {
|
|||||||
struct Filter {
|
struct Filter {
|
||||||
std::vector<PatternPtr> m_patterns;
|
std::vector<PatternPtr> m_patterns;
|
||||||
|
|
||||||
bool matches( TestCaseInfo const& testCase ) const {
|
bool matches( TestCaseInfo const& testCase ) const;
|
||||||
// All patterns in a filter must match for the filter to be a match
|
|
||||||
for( auto const& pattern : m_patterns ) {
|
|
||||||
if( !pattern->matches( testCase ) )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool hasFilters() const {
|
bool hasFilters() const;
|
||||||
return !m_filters.empty();
|
bool matches( TestCaseInfo const& testCase ) const;
|
||||||
}
|
|
||||||
bool matches( TestCaseInfo const& testCase ) const {
|
|
||||||
// A TestSpec matches if any filter matches
|
|
||||||
for( auto const& filter : m_filters )
|
|
||||||
if( filter.matches( testCase ) )
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Filter> m_filters;
|
std::vector<Filter> m_filters;
|
||||||
|
87
include/internal/catch_test_spec_parser.cpp
Normal file
87
include/internal/catch_test_spec_parser.cpp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_test_spec_parser.hpp"
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
|
||||||
|
|
||||||
|
TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
|
||||||
|
m_mode = None;
|
||||||
|
m_exclusion = false;
|
||||||
|
m_start = std::string::npos;
|
||||||
|
m_arg = m_tagAliases->expandAliases( arg );
|
||||||
|
m_escapeChars.clear();
|
||||||
|
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
|
||||||
|
visitChar( m_arg[m_pos] );
|
||||||
|
if( m_mode == Name )
|
||||||
|
addPattern<TestSpec::NamePattern>();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
TestSpec TestSpecParser::testSpec() {
|
||||||
|
addFilter();
|
||||||
|
return m_testSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSpecParser::visitChar( char c ) {
|
||||||
|
if( m_mode == None ) {
|
||||||
|
switch( c ) {
|
||||||
|
case ' ': return;
|
||||||
|
case '~': m_exclusion = true; return;
|
||||||
|
case '[': return startNewMode( Tag, ++m_pos );
|
||||||
|
case '"': return startNewMode( QuotedName, ++m_pos );
|
||||||
|
case '\\': return escape();
|
||||||
|
default: startNewMode( Name, m_pos ); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( m_mode == Name ) {
|
||||||
|
if( c == ',' ) {
|
||||||
|
addPattern<TestSpec::NamePattern>();
|
||||||
|
addFilter();
|
||||||
|
}
|
||||||
|
else if( c == '[' ) {
|
||||||
|
if( subString() == "exclude:" )
|
||||||
|
m_exclusion = true;
|
||||||
|
else
|
||||||
|
addPattern<TestSpec::NamePattern>();
|
||||||
|
startNewMode( Tag, ++m_pos );
|
||||||
|
}
|
||||||
|
else if( c == '\\' )
|
||||||
|
escape();
|
||||||
|
}
|
||||||
|
else if( m_mode == EscapedName )
|
||||||
|
m_mode = Name;
|
||||||
|
else if( m_mode == QuotedName && c == '"' )
|
||||||
|
addPattern<TestSpec::NamePattern>();
|
||||||
|
else if( m_mode == Tag && c == ']' )
|
||||||
|
addPattern<TestSpec::TagPattern>();
|
||||||
|
}
|
||||||
|
void TestSpecParser::startNewMode( Mode mode, std::size_t start ) {
|
||||||
|
m_mode = mode;
|
||||||
|
m_start = start;
|
||||||
|
}
|
||||||
|
void TestSpecParser::escape() {
|
||||||
|
if( m_mode == None )
|
||||||
|
m_start = m_pos;
|
||||||
|
m_mode = EscapedName;
|
||||||
|
m_escapeChars.push_back( m_pos );
|
||||||
|
}
|
||||||
|
std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
|
||||||
|
|
||||||
|
void TestSpecParser::addFilter() {
|
||||||
|
if( !m_currentFilter.m_patterns.empty() ) {
|
||||||
|
m_testSpec.m_filters.push_back( m_currentFilter );
|
||||||
|
m_currentFilter = TestSpec::Filter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSpec parseTestSpec( std::string const& arg ) {
|
||||||
|
return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Catch
|
@ -30,69 +30,17 @@ namespace Catch {
|
|||||||
ITagAliasRegistry const* m_tagAliases;
|
ITagAliasRegistry const* m_tagAliases;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
|
TestSpecParser( ITagAliasRegistry const& tagAliases );
|
||||||
|
|
||||||
|
TestSpecParser& parse( std::string const& arg );
|
||||||
|
TestSpec testSpec();
|
||||||
|
|
||||||
TestSpecParser& parse( std::string const& arg ) {
|
|
||||||
m_mode = None;
|
|
||||||
m_exclusion = false;
|
|
||||||
m_start = std::string::npos;
|
|
||||||
m_arg = m_tagAliases->expandAliases( arg );
|
|
||||||
m_escapeChars.clear();
|
|
||||||
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
|
|
||||||
visitChar( m_arg[m_pos] );
|
|
||||||
if( m_mode == Name )
|
|
||||||
addPattern<TestSpec::NamePattern>();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
TestSpec testSpec() {
|
|
||||||
addFilter();
|
|
||||||
return m_testSpec;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
void visitChar( char c ) {
|
void visitChar( char c );
|
||||||
if( m_mode == None ) {
|
void startNewMode( Mode mode, std::size_t start );
|
||||||
switch( c ) {
|
void escape();
|
||||||
case ' ': return;
|
std::string subString() const;
|
||||||
case '~': m_exclusion = true; return;
|
|
||||||
case '[': return startNewMode( Tag, ++m_pos );
|
|
||||||
case '"': return startNewMode( QuotedName, ++m_pos );
|
|
||||||
case '\\': return escape();
|
|
||||||
default: startNewMode( Name, m_pos ); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( m_mode == Name ) {
|
|
||||||
if( c == ',' ) {
|
|
||||||
addPattern<TestSpec::NamePattern>();
|
|
||||||
addFilter();
|
|
||||||
}
|
|
||||||
else if( c == '[' ) {
|
|
||||||
if( subString() == "exclude:" )
|
|
||||||
m_exclusion = true;
|
|
||||||
else
|
|
||||||
addPattern<TestSpec::NamePattern>();
|
|
||||||
startNewMode( Tag, ++m_pos );
|
|
||||||
}
|
|
||||||
else if( c == '\\' )
|
|
||||||
escape();
|
|
||||||
}
|
|
||||||
else if( m_mode == EscapedName )
|
|
||||||
m_mode = Name;
|
|
||||||
else if( m_mode == QuotedName && c == '"' )
|
|
||||||
addPattern<TestSpec::NamePattern>();
|
|
||||||
else if( m_mode == Tag && c == ']' )
|
|
||||||
addPattern<TestSpec::TagPattern>();
|
|
||||||
}
|
|
||||||
void startNewMode( Mode mode, std::size_t start ) {
|
|
||||||
m_mode = mode;
|
|
||||||
m_start = start;
|
|
||||||
}
|
|
||||||
void escape() {
|
|
||||||
if( m_mode == None )
|
|
||||||
m_start = m_pos;
|
|
||||||
m_mode = EscapedName;
|
|
||||||
m_escapeChars.push_back( m_pos );
|
|
||||||
}
|
|
||||||
std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void addPattern() {
|
void addPattern() {
|
||||||
std::string token = subString();
|
std::string token = subString();
|
||||||
@ -112,16 +60,10 @@ namespace Catch {
|
|||||||
m_exclusion = false;
|
m_exclusion = false;
|
||||||
m_mode = None;
|
m_mode = None;
|
||||||
}
|
}
|
||||||
void addFilter() {
|
|
||||||
if( !m_currentFilter.m_patterns.empty() ) {
|
void addFilter();
|
||||||
m_testSpec.m_filters.push_back( m_currentFilter );
|
|
||||||
m_currentFilter = TestSpec::Filter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
inline TestSpec parseTestSpec( std::string const& arg ) {
|
TestSpec parseTestSpec( std::string const& arg );
|
||||||
return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
|
61
include/internal/catch_totals.cpp
Normal file
61
include/internal/catch_totals.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_totals.hpp"
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
Counts Counts::operator - ( Counts const& other ) const {
|
||||||
|
Counts diff;
|
||||||
|
diff.passed = passed - other.passed;
|
||||||
|
diff.failed = failed - other.failed;
|
||||||
|
diff.failedButOk = failedButOk - other.failedButOk;
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
Counts& Counts::operator += ( Counts const& other ) {
|
||||||
|
passed += other.passed;
|
||||||
|
failed += other.failed;
|
||||||
|
failedButOk += other.failedButOk;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t Counts::total() const {
|
||||||
|
return passed + failed + failedButOk;
|
||||||
|
}
|
||||||
|
bool Counts::allPassed() const {
|
||||||
|
return failed == 0 && failedButOk == 0;
|
||||||
|
}
|
||||||
|
bool Counts::allOk() const {
|
||||||
|
return failed == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Totals Totals::operator - ( Totals const& other ) const {
|
||||||
|
Totals diff;
|
||||||
|
diff.assertions = assertions - other.assertions;
|
||||||
|
diff.testCases = testCases - other.testCases;
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
Totals& Totals::operator += ( Totals const& other ) {
|
||||||
|
assertions += other.assertions;
|
||||||
|
testCases += other.testCases;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Totals Totals::delta( Totals const& prevTotals ) const {
|
||||||
|
Totals diff = *this - prevTotals;
|
||||||
|
if( diff.assertions.failed > 0 )
|
||||||
|
++diff.testCases.failed;
|
||||||
|
else if( diff.assertions.failedButOk > 0 )
|
||||||
|
++diff.testCases.failedButOk;
|
||||||
|
else
|
||||||
|
++diff.testCases.passed;
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -13,29 +13,12 @@
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
struct Counts {
|
struct Counts {
|
||||||
Counts operator - ( Counts const& other ) const {
|
Counts operator - ( Counts const& other ) const;
|
||||||
Counts diff;
|
Counts& operator += ( Counts const& other );
|
||||||
diff.passed = passed - other.passed;
|
|
||||||
diff.failed = failed - other.failed;
|
|
||||||
diff.failedButOk = failedButOk - other.failedButOk;
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
Counts& operator += ( Counts const& other ) {
|
|
||||||
passed += other.passed;
|
|
||||||
failed += other.failed;
|
|
||||||
failedButOk += other.failedButOk;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t total() const {
|
std::size_t total() const;
|
||||||
return passed + failed + failedButOk;
|
bool allPassed() const;
|
||||||
}
|
bool allOk() const;
|
||||||
bool allPassed() const {
|
|
||||||
return failed == 0 && failedButOk == 0;
|
|
||||||
}
|
|
||||||
bool allOk() const {
|
|
||||||
return failed == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t passed = 0;
|
std::size_t passed = 0;
|
||||||
std::size_t failed = 0;
|
std::size_t failed = 0;
|
||||||
@ -44,29 +27,11 @@ namespace Catch {
|
|||||||
|
|
||||||
struct Totals {
|
struct Totals {
|
||||||
|
|
||||||
Totals operator - ( Totals const& other ) const {
|
Totals operator - ( Totals const& other ) const;
|
||||||
Totals diff;
|
Totals& operator += ( Totals const& other );
|
||||||
diff.assertions = assertions - other.assertions;
|
|
||||||
diff.testCases = testCases - other.testCases;
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
Totals delta( Totals const& prevTotals ) const {
|
Totals delta( Totals const& prevTotals ) const;
|
||||||
Totals diff = *this - prevTotals;
|
|
||||||
if( diff.assertions.failed > 0 )
|
|
||||||
++diff.testCases.failed;
|
|
||||||
else if( diff.assertions.failedButOk > 0 )
|
|
||||||
++diff.testCases.failedButOk;
|
|
||||||
else
|
|
||||||
++diff.testCases.passed;
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
Totals& operator += ( Totals const& other ) {
|
|
||||||
assertions += other.assertions;
|
|
||||||
testCases += other.testCases;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Counts assertions;
|
Counts assertions;
|
||||||
Counts testCases;
|
Counts testCases;
|
||||||
|
46
include/internal/catch_wildcard_pattern.cpp
Normal file
46
include/internal/catch_wildcard_pattern.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_wildcard_pattern.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
WildcardPattern::WildcardPattern( std::string const& pattern,
|
||||||
|
CaseSensitive::Choice caseSensitivity )
|
||||||
|
: m_caseSensitivity( caseSensitivity ),
|
||||||
|
m_pattern( adjustCase( pattern ) )
|
||||||
|
{
|
||||||
|
if( startsWith( m_pattern, '*' ) ) {
|
||||||
|
m_pattern = m_pattern.substr( 1 );
|
||||||
|
m_wildcard = WildcardAtStart;
|
||||||
|
}
|
||||||
|
if( endsWith( m_pattern, '*' ) ) {
|
||||||
|
m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
|
||||||
|
m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WildcardPattern::matches( std::string const& str ) const {
|
||||||
|
switch( m_wildcard ) {
|
||||||
|
case NoWildcard:
|
||||||
|
return m_pattern == adjustCase( str );
|
||||||
|
case WildcardAtStart:
|
||||||
|
return endsWith( adjustCase( str ), m_pattern );
|
||||||
|
case WildcardAtEnd:
|
||||||
|
return startsWith( adjustCase( str ), m_pattern );
|
||||||
|
case WildcardAtBothEnds:
|
||||||
|
return contains( adjustCase( str ), m_pattern );
|
||||||
|
default:
|
||||||
|
CATCH_INTERNAL_ERROR( "Unknown enum" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string WildcardPattern::adjustCase( std::string const& str ) const {
|
||||||
|
return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
|
||||||
|
}
|
||||||
|
}
|
@ -25,38 +25,12 @@ namespace Catch
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity )
|
WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity );
|
||||||
: m_caseSensitivity( caseSensitivity ),
|
virtual ~WildcardPattern() = default;
|
||||||
m_pattern( adjustCase( pattern ) )
|
virtual bool matches( std::string const& str ) const;
|
||||||
{
|
|
||||||
if( startsWith( m_pattern, '*' ) ) {
|
|
||||||
m_pattern = m_pattern.substr( 1 );
|
|
||||||
m_wildcard = WildcardAtStart;
|
|
||||||
}
|
|
||||||
if( endsWith( m_pattern, '*' ) ) {
|
|
||||||
m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
|
|
||||||
m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual ~WildcardPattern();
|
|
||||||
virtual bool matches( std::string const& str ) const {
|
|
||||||
switch( m_wildcard ) {
|
|
||||||
case NoWildcard:
|
|
||||||
return m_pattern == adjustCase( str );
|
|
||||||
case WildcardAtStart:
|
|
||||||
return endsWith( adjustCase( str ), m_pattern );
|
|
||||||
case WildcardAtEnd:
|
|
||||||
return startsWith( adjustCase( str ), m_pattern );
|
|
||||||
case WildcardAtBothEnds:
|
|
||||||
return contains( adjustCase( str ), m_pattern );
|
|
||||||
default:
|
|
||||||
CATCH_INTERNAL_ERROR( "Unknown enum" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
std::string adjustCase( std::string const& str ) const {
|
std::string adjustCase( std::string const& str ) const;
|
||||||
return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
|
|
||||||
}
|
|
||||||
CaseSensitive::Choice m_caseSensitivity;
|
CaseSensitive::Choice m_caseSensitivity;
|
||||||
WildcardPosition m_wildcard = NoWildcard;
|
WildcardPosition m_wildcard = NoWildcard;
|
||||||
std::string m_pattern;
|
std::string m_pattern;
|
||||||
|
181
include/internal/catch_xmlwriter.cpp
Normal file
181
include/internal/catch_xmlwriter.cpp
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_xmlwriter.hpp"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
|
||||||
|
: m_str( str ),
|
||||||
|
m_forWhat( forWhat )
|
||||||
|
{}
|
||||||
|
|
||||||
|
void XmlEncode::encodeTo( std::ostream& os ) const {
|
||||||
|
|
||||||
|
// Apostrophe escaping not necessary if we always use " to write attributes
|
||||||
|
// (see: http://www.w3.org/TR/xml/#syntax)
|
||||||
|
|
||||||
|
for( std::size_t i = 0; i < m_str.size(); ++ i ) {
|
||||||
|
char c = m_str[i];
|
||||||
|
switch( c ) {
|
||||||
|
case '<': os << "<"; break;
|
||||||
|
case '&': os << "&"; break;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
// See: http://www.w3.org/TR/xml/#syntax
|
||||||
|
if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
|
||||||
|
os << ">";
|
||||||
|
else
|
||||||
|
os << c;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\"':
|
||||||
|
if( m_forWhat == ForAttributes )
|
||||||
|
os << """;
|
||||||
|
else
|
||||||
|
os << c;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Escape control chars - based on contribution by @espenalb in PR #465 and
|
||||||
|
// by @mrpi PR #588
|
||||||
|
if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
|
||||||
|
// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
|
||||||
|
os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
|
||||||
|
<< static_cast<int>( c );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
os << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
|
||||||
|
xmlEncode.encodeTo( os );
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
|
||||||
|
: m_writer( writer )
|
||||||
|
{}
|
||||||
|
|
||||||
|
XmlWriter::ScopedElement::ScopedElement( ScopedElement const& other )
|
||||||
|
: m_writer( other.m_writer ){
|
||||||
|
other.m_writer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter::ScopedElement::~ScopedElement() {
|
||||||
|
if( m_writer )
|
||||||
|
m_writer->endElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
|
||||||
|
m_writer->writeText( text, indent );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
|
||||||
|
{
|
||||||
|
writeDeclaration();
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter::~XmlWriter() {
|
||||||
|
while( !m_tags.empty() )
|
||||||
|
endElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter& XmlWriter::startElement( std::string const& name ) {
|
||||||
|
ensureTagClosed();
|
||||||
|
newlineIfNecessary();
|
||||||
|
m_os << m_indent << '<' << name;
|
||||||
|
m_tags.push_back( name );
|
||||||
|
m_indent += " ";
|
||||||
|
m_tagIsOpen = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
|
||||||
|
ScopedElement scoped( this );
|
||||||
|
startElement( name );
|
||||||
|
return scoped;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter& XmlWriter::endElement() {
|
||||||
|
newlineIfNecessary();
|
||||||
|
m_indent = m_indent.substr( 0, m_indent.size()-2 );
|
||||||
|
if( m_tagIsOpen ) {
|
||||||
|
m_os << "/>";
|
||||||
|
m_tagIsOpen = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_os << m_indent << "</" << m_tags.back() << ">";
|
||||||
|
}
|
||||||
|
m_os << std::endl;
|
||||||
|
m_tags.pop_back();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {
|
||||||
|
if( !name.empty() && !attribute.empty() )
|
||||||
|
m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {
|
||||||
|
m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
|
||||||
|
if( !text.empty() ){
|
||||||
|
bool tagWasOpen = m_tagIsOpen;
|
||||||
|
ensureTagClosed();
|
||||||
|
if( tagWasOpen && indent )
|
||||||
|
m_os << m_indent;
|
||||||
|
m_os << XmlEncode( text );
|
||||||
|
m_needsNewline = true;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter& XmlWriter::writeComment( std::string const& text ) {
|
||||||
|
ensureTagClosed();
|
||||||
|
m_os << m_indent << "<!--" << text << "-->";
|
||||||
|
m_needsNewline = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XmlWriter::writeStylesheetRef( std::string const& url ) {
|
||||||
|
m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter& XmlWriter::writeBlankLine() {
|
||||||
|
ensureTagClosed();
|
||||||
|
m_os << '\n';
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XmlWriter::ensureTagClosed() {
|
||||||
|
if( m_tagIsOpen ) {
|
||||||
|
m_os << ">" << std::endl;
|
||||||
|
m_tagIsOpen = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XmlWriter::writeDeclaration() {
|
||||||
|
m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void XmlWriter::newlineIfNecessary() {
|
||||||
|
if( m_needsNewline ) {
|
||||||
|
m_os << std::endl;
|
||||||
|
m_needsNewline = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,9 +12,7 @@
|
|||||||
#include "catch_compiler_capabilities.h"
|
#include "catch_compiler_capabilities.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
@ -22,55 +20,11 @@ namespace Catch {
|
|||||||
public:
|
public:
|
||||||
enum ForWhat { ForTextNodes, ForAttributes };
|
enum ForWhat { ForTextNodes, ForAttributes };
|
||||||
|
|
||||||
XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes )
|
XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );
|
||||||
: m_str( str ),
|
|
||||||
m_forWhat( forWhat )
|
|
||||||
{}
|
|
||||||
|
|
||||||
void encodeTo( std::ostream& os ) const {
|
void encodeTo( std::ostream& os ) const;
|
||||||
|
|
||||||
// Apostrophe escaping not necessary if we always use " to write attributes
|
friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
|
||||||
// (see: http://www.w3.org/TR/xml/#syntax)
|
|
||||||
|
|
||||||
for( std::size_t i = 0; i < m_str.size(); ++ i ) {
|
|
||||||
char c = m_str[i];
|
|
||||||
switch( c ) {
|
|
||||||
case '<': os << "<"; break;
|
|
||||||
case '&': os << "&"; break;
|
|
||||||
|
|
||||||
case '>':
|
|
||||||
// See: http://www.w3.org/TR/xml/#syntax
|
|
||||||
if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
|
|
||||||
os << ">";
|
|
||||||
else
|
|
||||||
os << c;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\"':
|
|
||||||
if( m_forWhat == ForAttributes )
|
|
||||||
os << """;
|
|
||||||
else
|
|
||||||
os << c;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Escape control chars - based on contribution by @espenalb in PR #465 and
|
|
||||||
// by @mrpi PR #588
|
|
||||||
if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
|
|
||||||
// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
|
|
||||||
os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
|
|
||||||
<< static_cast<int>( c );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
os << c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
|
|
||||||
xmlEncode.encodeTo( os );
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_str;
|
std::string m_str;
|
||||||
@ -82,24 +36,13 @@ namespace Catch {
|
|||||||
|
|
||||||
class ScopedElement {
|
class ScopedElement {
|
||||||
public:
|
public:
|
||||||
ScopedElement( XmlWriter* writer )
|
ScopedElement( XmlWriter* writer );
|
||||||
: m_writer( writer )
|
|
||||||
{}
|
|
||||||
|
|
||||||
ScopedElement( ScopedElement const& other )
|
ScopedElement( ScopedElement const& other );
|
||||||
: m_writer( other.m_writer ){
|
|
||||||
other.m_writer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
~ScopedElement() {
|
~ScopedElement();
|
||||||
if( m_writer )
|
|
||||||
m_writer->endElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedElement& writeText( std::string const& text, bool indent = true ) {
|
ScopedElement& writeText( std::string const& text, bool indent = true );
|
||||||
m_writer->writeText( text, indent );
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
|
ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
|
||||||
@ -111,57 +54,21 @@ namespace Catch {
|
|||||||
mutable XmlWriter* m_writer;
|
mutable XmlWriter* m_writer;
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlWriter( std::ostream& os = Catch::cout() ) : m_os( os )
|
XmlWriter( std::ostream& os = Catch::cout() );
|
||||||
{
|
~XmlWriter();
|
||||||
writeDeclaration();
|
|
||||||
}
|
XmlWriter( XmlWriter const& ) = delete;
|
||||||
|
XmlWriter& operator=( XmlWriter const& ) = delete;
|
||||||
|
|
||||||
~XmlWriter() {
|
XmlWriter& startElement( std::string const& name );
|
||||||
while( !m_tags.empty() )
|
|
||||||
endElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlWriter& startElement( std::string const& name ) {
|
ScopedElement scopedElement( std::string const& name );
|
||||||
ensureTagClosed();
|
|
||||||
newlineIfNecessary();
|
|
||||||
m_os << m_indent << '<' << name;
|
|
||||||
m_tags.push_back( name );
|
|
||||||
m_indent += " ";
|
|
||||||
m_tagIsOpen = true;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedElement scopedElement( std::string const& name ) {
|
XmlWriter& endElement();
|
||||||
ScopedElement scoped( this );
|
|
||||||
startElement( name );
|
|
||||||
return scoped;
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlWriter& endElement() {
|
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
|
||||||
newlineIfNecessary();
|
|
||||||
m_indent = m_indent.substr( 0, m_indent.size()-2 );
|
|
||||||
if( m_tagIsOpen ) {
|
|
||||||
m_os << "/>";
|
|
||||||
m_tagIsOpen = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_os << m_indent << "</" << m_tags.back() << ">";
|
|
||||||
}
|
|
||||||
m_os << std::endl;
|
|
||||||
m_tags.pop_back();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
|
XmlWriter& writeAttribute( std::string const& name, bool attribute );
|
||||||
if( !name.empty() && !attribute.empty() )
|
|
||||||
m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
|
|
||||||
m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
|
XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
|
||||||
@ -171,56 +78,21 @@ namespace Catch {
|
|||||||
return writeAttribute( name, m_oss.str() );
|
return writeAttribute( name, m_oss.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlWriter& writeText( std::string const& text, bool indent = true ) {
|
XmlWriter& writeText( std::string const& text, bool indent = true );
|
||||||
if( !text.empty() ){
|
|
||||||
bool tagWasOpen = m_tagIsOpen;
|
|
||||||
ensureTagClosed();
|
|
||||||
if( tagWasOpen && indent )
|
|
||||||
m_os << m_indent;
|
|
||||||
m_os << XmlEncode( text );
|
|
||||||
m_needsNewline = true;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlWriter& writeComment( std::string const& text ) {
|
XmlWriter& writeComment( std::string const& text );
|
||||||
ensureTagClosed();
|
|
||||||
m_os << m_indent << "<!--" << text << "-->";
|
|
||||||
m_needsNewline = true;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeStylesheetRef( std::string const& url ) {
|
void writeStylesheetRef( std::string const& url );
|
||||||
m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlWriter& writeBlankLine() {
|
XmlWriter& writeBlankLine();
|
||||||
ensureTagClosed();
|
|
||||||
m_os << '\n';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ensureTagClosed() {
|
void ensureTagClosed();
|
||||||
if( m_tagIsOpen ) {
|
|
||||||
m_os << ">" << std::endl;
|
|
||||||
m_tagIsOpen = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XmlWriter( XmlWriter const& );
|
|
||||||
void operator=( XmlWriter const& );
|
|
||||||
|
|
||||||
void writeDeclaration() {
|
void writeDeclaration();
|
||||||
m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void newlineIfNecessary() {
|
void newlineIfNecessary();
|
||||||
if( m_needsNewline ) {
|
|
||||||
m_os << std::endl;
|
|
||||||
m_needsNewline = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool m_tagIsOpen = false;
|
bool m_tagIsOpen = false;
|
||||||
bool m_needsNewline = false;
|
bool m_needsNewline = false;
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -6,119 +6,86 @@
|
|||||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../internal/catch_interfaces_reporter.h"
|
#include "catch_reporter_multi.h"
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
class MultipleReporters : public IStreamingReporter {
|
void MultipleReporters::add( IStreamingReporterPtr&& reporter ) {
|
||||||
typedef std::vector<IStreamingReporterPtr> Reporters;
|
|
||||||
Reporters m_reporters;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void add( IStreamingReporterPtr&& reporter ) {
|
|
||||||
m_reporters.push_back( std::move( reporter ) );
|
m_reporters.push_back( std::move( reporter ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public: // IStreamingReporter
|
ReporterPreferences MultipleReporters::getPreferences() const {
|
||||||
|
|
||||||
virtual ReporterPreferences getPreferences() const override {
|
|
||||||
return m_reporters[0]->getPreferences();
|
return m_reporters[0]->getPreferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void noMatchingTestCases( std::string const& spec ) override {
|
void MultipleReporters::noMatchingTestCases( std::string const& spec ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->noMatchingTestCases( spec );
|
reporter->noMatchingTestCases( spec );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void testRunStarting( TestRunInfo const& testRunInfo ) override {
|
void MultipleReporters::testRunStarting( TestRunInfo const& testRunInfo ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->testRunStarting( testRunInfo );
|
reporter->testRunStarting( testRunInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void testGroupStarting( GroupInfo const& groupInfo ) override {
|
void MultipleReporters::testGroupStarting( GroupInfo const& groupInfo ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->testGroupStarting( groupInfo );
|
reporter->testGroupStarting( groupInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void testCaseStarting( TestCaseInfo const& testInfo ) override {
|
void MultipleReporters::testCaseStarting( TestCaseInfo const& testInfo ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->testCaseStarting( testInfo );
|
reporter->testCaseStarting( testInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void sectionStarting( SectionInfo const& sectionInfo ) override {
|
void MultipleReporters::sectionStarting( SectionInfo const& sectionInfo ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->sectionStarting( sectionInfo );
|
reporter->sectionStarting( sectionInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultipleReporters::assertionStarting( AssertionInfo const& assertionInfo ) {
|
||||||
virtual void assertionStarting( AssertionInfo const& assertionInfo ) override {
|
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->assertionStarting( assertionInfo );
|
reporter->assertionStarting( assertionInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The return value indicates if the messages buffer should be cleared:
|
// The return value indicates if the messages buffer should be cleared:
|
||||||
virtual bool assertionEnded( AssertionStats const& assertionStats ) override {
|
bool MultipleReporters::assertionEnded( AssertionStats const& assertionStats ) {
|
||||||
bool clearBuffer = false;
|
bool clearBuffer = false;
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
clearBuffer |= reporter->assertionEnded( assertionStats );
|
clearBuffer |= reporter->assertionEnded( assertionStats );
|
||||||
return clearBuffer;
|
return clearBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void sectionEnded( SectionStats const& sectionStats ) override {
|
void MultipleReporters::sectionEnded( SectionStats const& sectionStats ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->sectionEnded( sectionStats );
|
reporter->sectionEnded( sectionStats );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) override {
|
void MultipleReporters::testCaseEnded( TestCaseStats const& testCaseStats ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->testCaseEnded( testCaseStats );
|
reporter->testCaseEnded( testCaseStats );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) override {
|
void MultipleReporters::testGroupEnded( TestGroupStats const& testGroupStats ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->testGroupEnded( testGroupStats );
|
reporter->testGroupEnded( testGroupStats );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void testRunEnded( TestRunStats const& testRunStats ) override {
|
void MultipleReporters::testRunEnded( TestRunStats const& testRunStats ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->testRunEnded( testRunStats );
|
reporter->testRunEnded( testRunStats );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void skipTest( TestCaseInfo const& testInfo ) override {
|
void MultipleReporters::skipTest( TestCaseInfo const& testInfo ) {
|
||||||
for( auto const& reporter : m_reporters )
|
for( auto const& reporter : m_reporters )
|
||||||
reporter->skipTest( testInfo );
|
reporter->skipTest( testInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool isMulti() const override {
|
bool MultipleReporters::isMulti() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) {
|
|
||||||
|
|
||||||
if( !existingReporter ) {
|
|
||||||
existingReporter = std::move( additionalReporter );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MultipleReporters* multi = nullptr;
|
|
||||||
|
|
||||||
if( existingReporter->isMulti() ) {
|
|
||||||
multi = static_cast<MultipleReporters*>( existingReporter.get() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto newMulti = std::unique_ptr<MultipleReporters>( new MultipleReporters );
|
|
||||||
newMulti->add( std::move( existingReporter ) );
|
|
||||||
multi = newMulti.get();
|
|
||||||
existingReporter = std::move( newMulti );
|
|
||||||
}
|
|
||||||
multi->add( std::move( additionalReporter ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
57
include/reporters/catch_reporter_multi.h
Normal file
57
include/reporters/catch_reporter_multi.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../internal/catch_interfaces_reporter.h"
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class MultipleReporters : public IStreamingReporter {
|
||||||
|
typedef std::vector<IStreamingReporterPtr> Reporters;
|
||||||
|
Reporters m_reporters;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void add( IStreamingReporterPtr&& reporter );
|
||||||
|
|
||||||
|
public: // IStreamingReporter
|
||||||
|
|
||||||
|
virtual ReporterPreferences getPreferences() const override;
|
||||||
|
|
||||||
|
virtual void noMatchingTestCases( std::string const& spec ) override;
|
||||||
|
|
||||||
|
|
||||||
|
virtual void testRunStarting( TestRunInfo const& testRunInfo ) override;
|
||||||
|
|
||||||
|
virtual void testGroupStarting( GroupInfo const& groupInfo ) override;
|
||||||
|
|
||||||
|
|
||||||
|
virtual void testCaseStarting( TestCaseInfo const& testInfo ) override;
|
||||||
|
|
||||||
|
virtual void sectionStarting( SectionInfo const& sectionInfo ) override;
|
||||||
|
|
||||||
|
|
||||||
|
virtual void assertionStarting( AssertionInfo const& assertionInfo ) override;
|
||||||
|
|
||||||
|
|
||||||
|
// The return value indicates if the messages buffer should be cleared:
|
||||||
|
virtual bool assertionEnded( AssertionStats const& assertionStats ) override;
|
||||||
|
|
||||||
|
virtual void sectionEnded( SectionStats const& sectionStats ) override;
|
||||||
|
|
||||||
|
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) override;
|
||||||
|
|
||||||
|
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) override;
|
||||||
|
|
||||||
|
virtual void testRunEnded( TestRunStats const& testRunStats ) override;
|
||||||
|
|
||||||
|
|
||||||
|
virtual void skipTest( TestCaseInfo const& testInfo ) override;
|
||||||
|
|
||||||
|
virtual bool isMulti() const override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace Catch
|
Loading…
Reference in New Issue
Block a user