Refactored a lot of code from headers into impl headers only compiled into one TU

- also added noimpl option to single header script - which only generates the non impl code
This commit is contained in:
Phil Nash 2013-12-03 18:52:41 +00:00
parent 8ba6555acd
commit c4a089c12b
34 changed files with 978 additions and 682 deletions

View File

@ -21,7 +21,7 @@
#include "internal/catch_context.h"
#include "internal/catch_test_registry.hpp"
#include "internal/catch_capture.hpp"
#include "internal/catch_section.hpp"
#include "internal/catch_section.h"
#include "internal/catch_generators.hpp"
#include "internal/catch_interfaces_exception.h"
#include "internal/catch_approx.hpp"
@ -39,11 +39,11 @@
#if defined( CATCH_CONFIG_MAIN ) || defined( CATCH_CONFIG_RUNNER )
#include "internal/catch_impl.hpp"
#endif
#endif // CATCH_CONFIG_MAIN || CATCH_CONFIG_RUNNER
#ifdef CATCH_CONFIG_MAIN
#include "internal/catch_default_main.hpp"
#endif
#endif // CATCH_CONFIG_MAIN
//////

View File

@ -12,11 +12,12 @@
#include "catch_expressionresult_builder.h"
#include "catch_message.h"
#include "catch_interfaces_capture.h"
#include "catch_debugger.hpp"
#include "catch_debugger.h"
#include "catch_context.h"
#include "catch_common.h"
#include "catch_tostring.hpp"
#include "catch_interfaces_registry_hub.h"
#include "catch_interfaces_config.h"
#include "internal/catch_compiler_capabilities.h"
#include <ostream>
@ -66,7 +67,7 @@ struct TestFailureException{};
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ACCEPT_EXPR( evaluatedExpr, resultDisposition, originalExpr ) \
if( Catch::ResultAction::Value internal_catch_action = Catch::getResultCapture().acceptExpression( evaluatedExpr, INTERNAL_CATCH_ASSERTIONINFO_NAME ) ) { \
if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \
if( internal_catch_action & Catch::ResultAction::Debug ) CATCH_BREAK_INTO_DEBUGGER(); \
if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \
if( !Catch::shouldContinueOnFailure( resultDisposition ) ) throw Catch::TestFailureException(); \
Catch::isTrue( false && originalExpr ); \

View File

@ -67,36 +67,17 @@ namespace Catch {
std::for_each( container.begin(), container.end(), function );
}
inline bool startsWith( std::string const& s, std::string const& prefix ) {
return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
}
inline bool endsWith( std::string const& s, std::string const& suffix ) {
return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
}
inline bool contains( std::string const& s, std::string const& infix ) {
return s.find( infix ) != std::string::npos;
}
inline void toLowerInPlace( std::string& s ) {
std::transform( s.begin(), s.end(), s.begin(), ::tolower );
}
inline std::string toLower( std::string const& s ) {
std::string lc = s;
toLowerInPlace( lc );
return lc;
}
bool startsWith( std::string const& s, std::string const& prefix );
bool endsWith( std::string const& s, std::string const& suffix );
bool contains( std::string const& s, std::string const& infix );
void toLowerInPlace( std::string& s );
std::string toLower( std::string const& s );
std::string trim( std::string const& str );
struct pluralise {
pluralise( std::size_t count, std::string const& label )
: m_count( count ),
m_label( label )
{}
pluralise( std::size_t count, std::string const& label );
friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
os << pluraliser.m_count << " " << pluraliser.m_label;
if( pluraliser.m_count != 1 )
os << "s";
return os;
}
friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
std::size_t m_count;
std::string m_label;
@ -104,43 +85,22 @@ namespace Catch {
struct SourceLineInfo {
SourceLineInfo() : line( 0 ){}
SourceLineInfo( std::string const& _file, std::size_t _line )
: file( _file ),
line( _line )
{}
SourceLineInfo( SourceLineInfo const& other )
: file( other.file ),
line( other.line )
{}
bool empty() const {
return file.empty();
}
bool operator == ( SourceLineInfo const& other ) const {
return line == other.line && file == other.file;
}
SourceLineInfo();
SourceLineInfo( std::string const& _file, std::size_t _line );
SourceLineInfo( SourceLineInfo const& other );
bool empty() const;
bool operator == ( SourceLineInfo const& other ) const;
std::string file;
std::size_t line;
};
inline std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
#ifndef __GNUG__
os << info.file << "(" << info.line << ")";
#else
os << info.file << ":" << info.line;
#endif
return os;
}
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
// This is just here to avoid compiler warnings with macro constants and boolean literals
inline bool isTrue( bool value ){ return value; }
inline void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
std::ostringstream oss;
oss << locationInfo << ": Internal Catch error: '" << message << "'";
if( isTrue( true ))
throw std::logic_error( oss.str() );
}
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
}
#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )

View File

@ -0,0 +1,86 @@
/*
* Created by Phil on 27/11/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
#include "catch_common.h"
namespace Catch {
bool startsWith( std::string const& s, std::string const& prefix ) {
return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
}
bool endsWith( std::string const& s, std::string const& suffix ) {
return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
}
bool contains( std::string const& s, std::string const& infix ) {
return s.find( infix ) != std::string::npos;
}
void toLowerInPlace( std::string& s ) {
std::transform( s.begin(), s.end(), s.begin(), ::tolower );
}
std::string toLower( std::string const& s ) {
std::string lc = s;
toLowerInPlace( lc );
return lc;
}
std::string trim( std::string const& str ) {
static char const* whitespaceChars = "\n\r\t ";
std::string::size_type start = str.find_first_not_of( whitespaceChars );
std::string::size_type end = str.find_last_not_of( whitespaceChars );
return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
}
pluralise::pluralise( std::size_t count, std::string const& label )
: m_count( count ),
m_label( label )
{}
std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
os << pluraliser.m_count << " " << pluraliser.m_label;
if( pluraliser.m_count != 1 )
os << "s";
return os;
}
SourceLineInfo::SourceLineInfo() : line( 0 ){}
SourceLineInfo::SourceLineInfo( std::string const& _file, std::size_t _line )
: file( _file ),
line( _line )
{}
SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
: file( other.file ),
line( other.line )
{}
bool SourceLineInfo::empty() const {
return file.empty();
}
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
return line == other.line && file == other.file;
}
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
#ifndef __GNUG__
os << info.file << "(" << info.line << ")";
#else
os << info.file << ":" << info.line;
#endif
return os;
}
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
std::ostringstream oss;
oss << locationInfo << ": Internal Catch error: '" << message << "'";
if( isTrue( true ))
throw std::logic_error( oss.str() );
}
}
#endif // TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED

View File

@ -11,7 +11,7 @@
#include "catch_test_spec.h"
#include "catch_context.h"
#include "catch_interfaces_config.h"
#include "catch_stream.hpp"
#include "catch_stream.h"
#include <memory>
#include <vector>

View File

@ -0,0 +1,49 @@
/*
* Created by Phil on 3/12/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#ifndef TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
#include "catch_platform.h"
#include <string>
namespace Catch{
bool isDebuggerActive();
void writeToDebugConsole( std::string const& text );
}
#ifdef CATCH_PLATFORM_MAC
// The following code snippet based on:
// http://cocoawithlove.com/2008/03/break-into-debugger.html
#ifdef DEBUG
#if defined(__ppc64__) || defined(__ppc__)
#define CATCH_BREAK_INTO_DEBUGGER() \
if( Catch::isDebuggerActive() ) { \
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
: : : "memory","r0","r3","r4" ); \
}
#else
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
#endif
#endif
#elif defined(_MSC_VER)
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
#elif defined(__MINGW32__)
extern "C" __declspec(dllimport) void __stdcall DebugBreak();
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
#endif
#ifndef CATCH_BREAK_INTO_DEBUGGER
#define CATCH_BREAK_INTO_DEBUGGER()
#endif
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED

View File

@ -5,14 +5,13 @@
* 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)
*
* Provides a BreakIntoDebugger() macro for Windows and Mac (so far)
*/
#ifndef TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
#include <iostream>
#include "catch_debugger.h"
#include "catch_platform.h"
#include <iostream>
#ifdef CATCH_PLATFORM_MAC
@ -29,7 +28,7 @@
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
inline bool isDebuggerActive(){
bool isDebuggerActive(){
int junk;
int mib[4];
@ -59,52 +58,42 @@
return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
}
}
// The following code snippet taken from:
// http://cocoawithlove.com/2008/03/break-into-debugger.html
#ifdef DEBUG
#if defined(__ppc64__) || defined(__ppc__)
#define BreakIntoDebugger() \
if( Catch::isDebuggerActive() ) { \
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
: : : "memory","r0","r3","r4" ); \
}
#else
#define BreakIntoDebugger() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
#endif
#else
inline void BreakIntoDebugger(){}
#endif
} // namespace Catch
#elif defined(_MSC_VER)
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
#define BreakIntoDebugger() if (IsDebuggerPresent() ) { __debugbreak(); }
inline bool isDebuggerActive() {
return IsDebuggerPresent() != 0;
namespace Catch {
bool isDebuggerActive() {
return IsDebuggerPresent() != 0;
}
}
#elif defined(__MINGW32__)
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
extern "C" __declspec(dllimport) void __stdcall DebugBreak();
#define BreakIntoDebugger() if (IsDebuggerPresent() ) { DebugBreak(); }
inline bool isDebuggerActive() {
return IsDebuggerPresent() != 0;
namespace Catch {
bool isDebuggerActive() {
return IsDebuggerPresent() != 0;
}
}
#else
inline void BreakIntoDebugger(){}
namespace Catch {
inline bool isDebuggerActive() { return false; }
#endif
}
#endif // Platform
#ifdef CATCH_PLATFORM_WINDOWS
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
inline void writeToDebugConsole( std::string const& text ) {
::OutputDebugStringA( text.c_str() );
}
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
::OutputDebugStringA( text.c_str() );
}
}
#else
inline void writeToDebugConsole( std::string const& text ) {
// !TBD: Need a version for Mac/ XCode and other IDEs
std::cout << text;
}
#endif // CATCH_PLATFORM_WINDOWS
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
// !TBD: Need a version for Mac/ XCode and other IDEs
std::cout << text;
}
}
#endif // Platform
#endif // TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED

View File

@ -26,11 +26,15 @@
#include "catch_expressionresult_builder.hpp"
#include "catch_test_case_info.hpp"
#include "catch_tags.hpp"
#include "catch_test_spec.hpp"
#include "catch_version.hpp"
#include "catch_text.hpp"
#include "catch_message.hpp"
#include "catch_legacy_reporter_adapter.hpp"
#include "catch_timer.hpp"
#include "catch_common.hpp"
#include "catch_section.hpp"
#include "catch_debugger.hpp"
#include "../reporters/catch_reporter_xml.hpp"
#include "../reporters/catch_reporter_junit.hpp"
@ -71,9 +75,6 @@ namespace Catch {
FreeFunctionTestCase::~FreeFunctionTestCase() {}
IGeneratorInfo::~IGeneratorInfo() {}
IGeneratorsForTest::~IGeneratorsForTest() {}
TagParser::~TagParser() {}
TagExtracter::~TagExtracter() {}
TagExpressionParser::~TagExpressionParser() {}
Matchers::Impl::StdString::Equals::~Equals() {}
Matchers::Impl::StdString::Contains::~Contains() {}

View File

@ -10,7 +10,6 @@
#include <string>
#include "catch_result_type.h"
#include "catch_totals.hpp"
#include "catch_common.h"
namespace Catch {
@ -22,6 +21,7 @@ namespace Catch {
struct SectionInfo;
struct MessageInfo;
class ScopedMessageBuilder;
struct Counts;
struct IResultCapture {

View File

@ -8,10 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
#include "catch_interfaces_reporter.h"
#include "catch_interfaces_config.h"
#include <vector>
#include <string>
namespace Catch {
@ -19,6 +16,8 @@ namespace Catch {
struct ITestCaseRegistry;
struct IExceptionTranslatorRegistry;
struct IExceptionTranslator;
struct IReporterRegistry;
struct IReporterFactory;
struct IRegistryHub {
virtual ~IRegistryHub();

View File

@ -8,6 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
#include "catch_section_info.h"
#include "catch_common.h"
#include "catch_totals.hpp"
#include "catch_ptr.hpp"
@ -80,20 +81,6 @@ namespace Catch
std::size_t groupsCounts;
};
struct SectionInfo {
SectionInfo( std::string const& _name,
std::string const& _description,
SourceLineInfo const& _lineInfo )
: name( _name ),
description( _description ),
lineInfo( _lineInfo )
{}
std::string name;
std::string description;
SourceLineInfo lineInfo;
};
struct AssertionStats {
AssertionStats( AssertionResult const& _assertionResult,
std::vector<MessageInfo> const& _infoMessages,
@ -223,201 +210,6 @@ namespace Catch
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
};
struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
StreamingReporterBase( ReporterConfig const& _config )
: m_config( _config.fullConfig() ),
stream( _config.stream() )
{}
virtual ~StreamingReporterBase();
virtual void noMatchingTestCases( std::string const& ) {}
virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
currentTestRunInfo = _testRunInfo;
}
virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
currentGroupInfo = _groupInfo;
}
virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
currentTestCaseInfo = _testInfo;
}
virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
m_sectionStack.push_back( _sectionInfo );
}
virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
m_sectionStack.pop_back();
}
virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
currentTestCaseInfo.reset();
assert( m_sectionStack.empty() );
}
virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
currentGroupInfo.reset();
}
virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
currentTestCaseInfo.reset();
currentGroupInfo.reset();
currentTestRunInfo.reset();
}
Ptr<IConfig> m_config;
std::ostream& stream;
LazyStat<TestRunInfo> currentTestRunInfo;
LazyStat<GroupInfo> currentGroupInfo;
LazyStat<TestCaseInfo> currentTestCaseInfo;
std::vector<SectionInfo> m_sectionStack;
};
struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
template<typename T, typename ChildNodeT>
struct Node : SharedImpl<> {
explicit Node( T const& _value ) : value( _value ) {}
virtual ~Node() {}
typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
T value;
ChildNodes children;
};
struct SectionNode : SharedImpl<> {
explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
virtual ~SectionNode();
bool operator == ( SectionNode const& other ) const {
return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
}
bool operator == ( Ptr<SectionNode> const& other ) const {
return operator==( *other );
}
SectionStats stats;
typedef std::vector<Ptr<SectionNode> > ChildSections;
typedef std::vector<AssertionStats> Assertions;
ChildSections childSections;
Assertions assertions;
std::string stdOut;
std::string stdErr;
};
friend bool operator == ( Ptr<SectionNode> const& node, SectionInfo const& other ) {
return node->stats.sectionInfo.lineInfo == other.lineInfo;
}
typedef Node<TestCaseStats, SectionNode> TestCaseNode;
typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
typedef Node<TestRunStats, TestGroupNode> TestRunNode;
CumulativeReporterBase( ReporterConfig const& _config )
: m_config( _config.fullConfig() ),
stream( _config.stream() )
{}
~CumulativeReporterBase();
virtual void testRunStarting( TestRunInfo const& ) {}
virtual void testGroupStarting( GroupInfo const& ) {}
virtual void testCaseStarting( TestCaseInfo const& ) {}
virtual void sectionStarting( SectionInfo const& sectionInfo ) {
SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
Ptr<SectionNode> node;
if( m_sectionStack.empty() ) {
if( !m_rootSection )
m_rootSection = new SectionNode( incompleteStats );
node = m_rootSection;
}
else {
SectionNode& parentNode = *m_sectionStack.back();
SectionNode::ChildSections::const_iterator it =
std::find( parentNode.childSections.begin(), parentNode.childSections.end(), sectionInfo );
if( it == parentNode.childSections.end() ) {
node = new SectionNode( incompleteStats );
parentNode.childSections.push_back( node );
}
else
node = *it;
}
m_sectionStack.push_back( node );
m_deepestSection = node;
}
virtual void assertionStarting( AssertionInfo const& ) {}
virtual bool assertionEnded( AssertionStats const& assertionStats ) {
assert( !m_sectionStack.empty() );
SectionNode& sectionNode = *m_sectionStack.back();
sectionNode.assertions.push_back( assertionStats );
return true;
}
virtual void sectionEnded( SectionStats const& sectionStats ) {
assert( !m_sectionStack.empty() );
SectionNode& node = *m_sectionStack.back();
node.stats = sectionStats;
m_sectionStack.pop_back();
}
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
assert( m_sectionStack.size() == 0 );
node->children.push_back( m_rootSection );
m_testCases.push_back( node );
m_rootSection.reset();
assert( m_deepestSection );
m_deepestSection->stdOut = testCaseStats.stdOut;
m_deepestSection->stdErr = testCaseStats.stdErr;
}
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
node->children.swap( m_testCases );
m_testGroups.push_back( node );
}
virtual void testRunEnded( TestRunStats const& testRunStats ) {
Ptr<TestRunNode> node = new TestRunNode( testRunStats );
node->children.swap( m_testGroups );
m_testRuns.push_back( node );
testRunEnded();
}
virtual void testRunEnded() = 0;
Ptr<IConfig> m_config;
std::ostream& stream;
std::vector<AssertionStats> m_assertions;
std::vector<std::vector<Ptr<SectionNode> > > m_sections;
std::vector<Ptr<TestCaseNode> > m_testCases;
std::vector<Ptr<TestGroupNode> > m_testGroups;
std::vector<Ptr<TestRunNode> > m_testRuns;
Ptr<SectionNode> m_rootSection;
Ptr<SectionNode> m_deepestSection;
std::vector<Ptr<SectionNode> > m_sectionStack;
};
// Deprecated
struct IReporter : IShared {
virtual ~IReporter();
virtual bool shouldRedirectStdout() const = 0;
virtual void StartTesting() = 0;
virtual void EndTesting( Totals const& totals ) = 0;
virtual void StartGroup( std::string const& groupName ) = 0;
virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
virtual void Aborted() = 0;
virtual void Result( AssertionResult const& result ) = 0;
};
struct IReporterFactory {
virtual ~IReporterFactory();
@ -433,13 +225,6 @@ namespace Catch
virtual FactoryMap const& getFactories() const = 0;
};
inline std::string trim( std::string const& str ) {
static char const* whitespaceChars = "\n\r\t ";
std::string::size_type start = str.find_first_not_of( whitespaceChars );
std::string::size_type end = str.find_last_not_of( whitespaceChars );
return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
}
}
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED

View File

@ -8,10 +8,6 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
#include "catch_totals.hpp"
#include <string>
namespace Catch {
class TestCase;

View File

@ -12,6 +12,26 @@
namespace Catch
{
// Deprecated
struct IReporter : IShared {
virtual ~IReporter();
virtual bool shouldRedirectStdout() const = 0;
virtual void StartTesting() = 0;
virtual void EndTesting( Totals const& totals ) = 0;
virtual void StartGroup( std::string const& groupName ) = 0;
virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
virtual void Aborted() = 0;
virtual void Result( AssertionResult const& result ) = 0;
};
class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
{
public:

View File

@ -11,6 +11,7 @@
#include "catch_commandline.hpp"
#include "catch_text.h"
#include "catch_console_colour.hpp"
#include "catch_interfaces_reporter.h"
#include <limits>
#include <algorithm>

View File

@ -56,9 +56,6 @@ namespace Catch {
namespace Detail{
inline bool startsWith( std::string const& str, std::string const& sub ) {
return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
}
inline std::string getAnnotation( Class cls,
std::string const& annotationName,
@ -88,7 +85,7 @@ namespace Catch {
for( u_int m = 0; m < count ; m++ ) {
SEL selector = method_getName(methods[m]);
std::string methodName = sel_getName(selector);
if( Detail::startsWith( methodName, "Catch_TestCase_" ) ) {
if( startsWith( methodName, "Catch_TestCase_" ) ) {
std::string testCaseName = methodName.substr( 15 );
std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );

View File

@ -0,0 +1,49 @@
/*
* Created by Phil on 03/12/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
#include "catch_section_info.h"
#include "catch_totals.hpp"
#include "catch_timer.h"
#include <string>
namespace Catch {
class Section {
public:
Section( SourceLineInfo const& lineInfo,
std::string const& name,
std::string const& description = "" );
~Section();
// This indicates whether the section should be executed or not
operator bool();
private:
SectionInfo m_info;
std::string m_name;
Counts m_assertions;
bool m_sectionIncluded;
Timer m_timer;
};
} // end namespace Catch
#ifdef CATCH_CONFIG_VARIADIC_MACROS
#define INTERNAL_CATCH_SECTION( ... ) \
if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
#else
#define INTERNAL_CATCH_SECTION( name, desc ) \
if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, name, desc ) )
#endif
#endif // TWOBLUECUBES_CATCH_SECTION_H_INCLUDED

View File

@ -8,53 +8,33 @@
#ifndef TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
#include "catch_section.h"
#include "catch_capture.hpp"
#include "catch_totals.hpp"
#include "catch_compiler_capabilities.h"
#include "catch_timer.h"
#include <string>
namespace Catch {
class Section {
public:
Section( SourceLineInfo const& lineInfo,
std::string const& name,
std::string const& description = "" )
: m_info( name, description, lineInfo ),
m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( m_info, m_assertions ) )
{
m_timer.start();
}
Section::Section( SourceLineInfo const& lineInfo,
std::string const& name,
std::string const& description )
: m_info( name, description, lineInfo ),
m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( m_info, m_assertions ) )
{
m_timer.start();
}
~Section() {
if( m_sectionIncluded )
getCurrentContext().getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
}
Section::~Section() {
if( m_sectionIncluded )
getCurrentContext().getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
}
// This indicates whether the section should be executed or not
operator bool() {
return m_sectionIncluded;
}
// This indicates whether the section should be executed or not
Section::operator bool() {
return m_sectionIncluded;
}
private:
SectionInfo m_info;
std::string m_name;
Counts m_assertions;
bool m_sectionIncluded;
Timer m_timer;
};
} // end namespace Catch
#ifdef CATCH_CONFIG_VARIADIC_MACROS
#define INTERNAL_CATCH_SECTION( ... ) \
if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
#else
#define INTERNAL_CATCH_SECTION( name, desc ) \
if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, name, desc ) )
#endif
#endif // TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED

View File

@ -0,0 +1,31 @@
/*
* Created by Phil on 03/11/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
#include "catch_common.h"
namespace Catch {
struct SectionInfo {
SectionInfo( std::string const& _name,
std::string const& _description,
SourceLineInfo const& _lineInfo )
: name( _name ),
description( _description ),
lineInfo( _lineInfo )
{}
std::string name;
std::string description;
SourceLineInfo lineInfo;
};
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED

View File

@ -0,0 +1,33 @@
/*
* Created by Phil on 2/12/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#include <streambuf>
#ifdef __clang__
#pragma clang diagnostic ignored "-Wpadded"
#endif
namespace Catch {
class Stream {
public:
Stream();
Stream( std::streambuf* _streamBuf, bool _isOwned );
void release();
std::streambuf* streamBuf;
private:
bool isOwned;
};
}
#endif // TWOBLUECUBES_CATCH_STREAM_H_INCLUDED

View File

@ -9,8 +9,9 @@
#ifndef TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
#include "catch_stream.h"
#include "catch_streambuf.h"
#include "catch_debugger.hpp"
#include "catch_debugger.h"
#include <stdexcept>
#include <cstdio>
@ -62,29 +63,21 @@ namespace Catch {
}
};
class Stream {
public:
Stream()
: streamBuf( NULL ), isOwned( false )
{}
Stream::Stream()
: streamBuf( NULL ), isOwned( false )
{}
Stream( std::streambuf* _streamBuf, bool _isOwned )
: streamBuf( _streamBuf ), isOwned( _isOwned )
{}
Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
: streamBuf( _streamBuf ), isOwned( _isOwned )
{}
void release() {
if( isOwned ) {
delete streamBuf;
streamBuf = NULL;
isOwned = false;
}
void Stream::release() {
if( isOwned ) {
delete streamBuf;
streamBuf = NULL;
isOwned = false;
}
std::streambuf* streamBuf;
private:
bool isOwned;
};
}
}
#endif // TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED

View File

@ -0,0 +1,109 @@
/*
* Created by Phil on 2/12/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_TAGS_H_INCLUDED
#define TWOBLUECUBES_CATCH_TAGS_H_INCLUDED
#include "catch_common.h"
#include <string>
#include <set>
#include <map>
#include <vector>
#ifdef __clang__
#pragma clang diagnostic ignored "-Wpadded"
#endif
namespace Catch {
class TagParser {
public:
virtual ~TagParser();
void parse( std::string const& str );
protected:
virtual void acceptTag( std::string const& tag ) = 0;
virtual void acceptChar( char c ) = 0;
virtual void endParse() {}
private:
};
class TagExtracter : public TagParser {
public:
TagExtracter( std::set<std::string>& tags );
virtual ~TagExtracter();
void parse( std::string& description );
private:
virtual void acceptTag( std::string const& tag );
virtual void acceptChar( char c );
TagExtracter& operator=(TagExtracter const&);
std::set<std::string>& m_tags;
std::string m_remainder;
};
class Tag {
public:
Tag();
Tag( std::string const& name, bool isNegated );
std::string getName() const;
bool isNegated() const;
bool operator ! () const;
private:
std::string m_name;
bool m_isNegated;
};
class TagSet {
typedef std::map<std::string, Tag> TagMap;
public:
void add( Tag const& tag );
bool empty() const;
bool matches( std::set<std::string> const& tags ) const;
private:
TagMap m_tags;
};
class TagExpression {
public:
bool matches( std::set<std::string> const& tags ) const;
private:
friend class TagExpressionParser;
std::vector<TagSet> m_tagSets;
};
class TagExpressionParser : public TagParser {
public:
TagExpressionParser( TagExpression& exp );
~TagExpressionParser();
private:
virtual void acceptTag( std::string const& tag );
virtual void acceptChar( char c );
virtual void endParse();
TagExpressionParser& operator=(TagExpressionParser const&);
bool m_isNegated;
TagSet m_currentTagSet;
TagExpression& m_exp;
};
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED

View File

@ -8,188 +8,129 @@
#ifndef TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED
#include "catch_common.h"
#include <string>
#include <set>
#include <map>
#include <vector>
#ifdef __clang__
#pragma clang diagnostic ignored "-Wpadded"
#endif
#include "catch_tags.h"
namespace Catch {
class TagParser {
public:
virtual ~TagParser();
TagParser::~TagParser() {}
void parse( std::string const& str ) {
std::size_t pos = 0;
while( pos < str.size() ) {
char c = str[pos];
if( c == '[' ) {
std::size_t end = str.find_first_of( ']', pos );
if( end != std::string::npos ) {
acceptTag( str.substr( pos+1, end-pos-1 ) );
pos = end+1;
}
else {
acceptChar( c );
pos++;
}
void TagParser::parse( std::string const& str ) {
std::size_t pos = 0;
while( pos < str.size() ) {
char c = str[pos];
if( c == '[' ) {
std::size_t end = str.find_first_of( ']', pos );
if( end != std::string::npos ) {
acceptTag( str.substr( pos+1, end-pos-1 ) );
pos = end+1;
}
else {
acceptChar( c );
pos++;
}
}
endParse();
}
protected:
virtual void acceptTag( std::string const& tag ) = 0;
virtual void acceptChar( char c ) = 0;
virtual void endParse() {}
private:
};
class TagExtracter : public TagParser {
public:
TagExtracter( std::set<std::string>& tags )
: m_tags( tags )
{}
virtual ~TagExtracter();
void parse( std::string& description ) {
TagParser::parse( description );
description = m_remainder;
}
private:
virtual void acceptTag( std::string const& tag ) {
m_tags.insert( toLower( tag ) );
}
virtual void acceptChar( char c ) {
m_remainder += c;
}
TagExtracter& operator=(TagExtracter const&);
std::set<std::string>& m_tags;
std::string m_remainder;
};
class Tag {
public:
Tag()
: m_isNegated( false )
{}
Tag( std::string const& name, bool isNegated )
: m_name( name ),
m_isNegated( isNegated )
{}
std::string getName() const {
return m_name;
}
bool isNegated() const {
return m_isNegated;
}
bool operator ! () const {
return m_name.empty();
}
private:
std::string m_name;
bool m_isNegated;
};
class TagSet {
typedef std::map<std::string, Tag> TagMap;
public:
void add( Tag const& tag ) {
m_tags.insert( std::make_pair( toLower( tag.getName() ), tag ) );
}
bool empty() const {
return m_tags.empty();
}
bool matches( std::set<std::string> const& tags ) const {
for( TagMap::const_iterator
it = m_tags.begin(), itEnd = m_tags.end();
it != itEnd;
++it ) {
bool found = tags.find( it->first ) != tags.end();
if( found == it->second.isNegated() )
return false;
}
return true;
}
private:
TagMap m_tags;
};
class TagExpression {
public:
bool matches( std::set<std::string> const& tags ) const {
for( std::vector<TagSet>::const_iterator
it = m_tagSets.begin(), itEnd = m_tagSets.end();
it != itEnd;
++it )
if( it->matches( tags ) )
return true;
return false;
}
private:
friend class TagExpressionParser;
std::vector<TagSet> m_tagSets;
};
class TagExpressionParser : public TagParser {
public:
TagExpressionParser( TagExpression& exp )
: m_isNegated( false ),
m_exp( exp )
{}
~TagExpressionParser();
private:
virtual void acceptTag( std::string const& tag ) {
m_currentTagSet.add( Tag( tag, m_isNegated ) );
m_isNegated = false;
}
virtual void acceptChar( char c ) {
switch( c ) {
case '~':
m_isNegated = true;
break;
case ',':
m_exp.m_tagSets.push_back( m_currentTagSet );
m_currentTagSet = TagSet();
break;
else {
acceptChar( c );
pos++;
}
}
virtual void endParse() {
if( !m_currentTagSet.empty() )
endParse();
}
TagExtracter::TagExtracter( std::set<std::string>& tags )
: m_tags( tags )
{}
TagExtracter::~TagExtracter() {}
void TagExtracter::parse( std::string& description ) {
TagParser::parse( description );
description = m_remainder;
}
void TagExtracter::acceptTag( std::string const& tag ) {
m_tags.insert( toLower( tag ) );
}
void TagExtracter::acceptChar( char c ) {
m_remainder += c;
}
Tag::Tag() : m_isNegated( false ) {}
Tag::Tag( std::string const& name, bool isNegated )
: m_name( name ),
m_isNegated( isNegated )
{}
std::string Tag::getName() const {
return m_name;
}
bool Tag::isNegated() const {
return m_isNegated;
}
bool Tag::operator ! () const {
return m_name.empty();
}
void TagSet::add( Tag const& tag ) {
m_tags.insert( std::make_pair( toLower( tag.getName() ), tag ) );
}
bool TagSet::empty() const {
return m_tags.empty();
}
bool TagSet::matches( std::set<std::string> const& tags ) const {
for( TagMap::const_iterator
it = m_tags.begin(), itEnd = m_tags.end();
it != itEnd;
++it ) {
bool found = tags.find( it->first ) != tags.end();
if( found == it->second.isNegated() )
return false;
}
return true;
}
bool TagExpression::matches( std::set<std::string> const& tags ) const {
for( std::vector<TagSet>::const_iterator
it = m_tagSets.begin(), itEnd = m_tagSets.end();
it != itEnd;
++it )
if( it->matches( tags ) )
return true;
return false;
}
TagExpressionParser::TagExpressionParser( TagExpression& exp )
: m_isNegated( false ),
m_exp( exp )
{}
TagExpressionParser::~TagExpressionParser() {}
void TagExpressionParser::acceptTag( std::string const& tag ) {
m_currentTagSet.add( Tag( tag, m_isNegated ) );
m_isNegated = false;
}
void TagExpressionParser::acceptChar( char c ) {
switch( c ) {
case '~':
m_isNegated = true;
break;
case ',':
m_exp.m_tagSets.push_back( m_currentTagSet );
m_currentTagSet = TagSet();
break;
}
}
TagExpressionParser& operator=(TagExpressionParser const&);
bool m_isNegated;
TagSet m_currentTagSet;
TagExpression& m_exp;
};
void TagExpressionParser::endParse() {
if( !m_currentTagSet.empty() )
m_exp.m_tagSets.push_back( m_currentTagSet );
}
} // end namespace Catch

View File

@ -8,7 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
#include "catch_tags.hpp"
#include "catch_tags.h"
#include "catch_test_case_info.h"
#include "catch_interfaces_testcase.h"
#include "catch_common.h"

View File

@ -8,15 +8,15 @@
#ifndef TWOBLUECUBES_CATCH_TEST_SPEC_H_INCLUDED
#define TWOBLUECUBES_CATCH_TEST_SPEC_H_INCLUDED
#include "catch_test_case_info.h"
#include "catch_tags.hpp"
#include "catch_common.h"
#include "catch_tags.h"
#include <string>
#include <vector>
namespace Catch {
class TestCase;
struct IfFilterMatches{ enum DoWhat {
AutoDetectBehaviour,
IncludeTests,
@ -32,69 +32,13 @@ namespace Catch {
};
public:
TestCaseFilter( std::string const& testSpec, IfFilterMatches::DoWhat matchBehaviour = IfFilterMatches::AutoDetectBehaviour )
: m_stringToMatch( toLower( testSpec ) ),
m_filterType( matchBehaviour ),
m_wildcardPosition( NoWildcard )
{
if( m_filterType == IfFilterMatches::AutoDetectBehaviour ) {
if( startsWith( m_stringToMatch, "exclude:" ) ) {
m_stringToMatch = m_stringToMatch.substr( 8 );
m_filterType = IfFilterMatches::ExcludeTests;
}
else if( startsWith( m_stringToMatch, "~" ) ) {
m_stringToMatch = m_stringToMatch.substr( 1 );
m_filterType = IfFilterMatches::ExcludeTests;
}
else {
m_filterType = IfFilterMatches::IncludeTests;
}
}
TestCaseFilter( std::string const& testSpec, IfFilterMatches::DoWhat matchBehaviour = IfFilterMatches::AutoDetectBehaviour );
if( startsWith( m_stringToMatch, "*" ) ) {
m_stringToMatch = m_stringToMatch.substr( 1 );
m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtStart );
}
if( endsWith( m_stringToMatch, "*" ) ) {
m_stringToMatch = m_stringToMatch.substr( 0, m_stringToMatch.size()-1 );
m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtEnd );
}
}
IfFilterMatches::DoWhat getFilterType() const;
bool shouldInclude( TestCase const& testCase ) const;
IfFilterMatches::DoWhat getFilterType() const {
return m_filterType;
}
bool shouldInclude( TestCase const& testCase ) const {
return isMatch( testCase ) == (m_filterType == IfFilterMatches::IncludeTests);
}
private:
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
#endif
bool isMatch( TestCase const& testCase ) const {
std::string name = testCase.getTestCaseInfo().name;
toLowerInPlace( name );
switch( m_wildcardPosition ) {
case NoWildcard:
return m_stringToMatch == name;
case WildcardAtStart:
return endsWith( name, m_stringToMatch );
case WildcardAtEnd:
return startsWith( name, m_stringToMatch );
case WildcardAtBothEnds:
return contains( name, m_stringToMatch );
}
throw std::logic_error( "Unhandled wildcard type" );
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
bool isMatch( TestCase const& testCase ) const;
std::string m_stringToMatch;
IfFilterMatches::DoWhat m_filterType;
@ -103,57 +47,12 @@ namespace Catch {
class TestCaseFilters {
public:
TestCaseFilters( std::string const& name ) : m_name( name ) {}
TestCaseFilters( std::string const& name );
std::string getName() const;
void addFilter( TestCaseFilter const& filter );
void addTags( std::string const& tagPattern );
bool shouldInclude( TestCase const& testCase ) const;
std::string getName() const {
return m_name;
}
void addFilter( TestCaseFilter const& filter ) {
if( filter.getFilterType() == IfFilterMatches::ExcludeTests )
m_exclusionFilters.push_back( filter );
else
m_inclusionFilters.push_back( filter );
}
void addTags( std::string const& tagPattern ) {
TagExpression exp;
TagExpressionParser( exp ).parse( tagPattern );
m_tagExpressions.push_back( exp );
}
bool shouldInclude( TestCase const& testCase ) const {
if( !m_tagExpressions.empty() ) {
std::vector<TagExpression>::const_iterator it = m_tagExpressions.begin();
std::vector<TagExpression>::const_iterator itEnd = m_tagExpressions.end();
for(; it != itEnd; ++it )
if( it->matches( testCase.getTags() ) )
break;
if( it == itEnd )
return false;
}
if( !m_inclusionFilters.empty() ) {
std::vector<TestCaseFilter>::const_iterator it = m_inclusionFilters.begin();
std::vector<TestCaseFilter>::const_iterator itEnd = m_inclusionFilters.end();
for(; it != itEnd; ++it )
if( it->shouldInclude( testCase ) )
break;
if( it == itEnd )
return false;
}
else if( m_exclusionFilters.empty() && m_tagExpressions.empty() ) {
return !testCase.isHidden();
}
std::vector<TestCaseFilter>::const_iterator it = m_exclusionFilters.begin();
std::vector<TestCaseFilter>::const_iterator itEnd = m_exclusionFilters.end();
for(; it != itEnd; ++it )
if( !it->shouldInclude( testCase ) )
return false;
return true;
}
private:
std::vector<TagExpression> m_tagExpressions;
std::vector<TestCaseFilter> m_inclusionFilters;

View File

@ -0,0 +1,133 @@
/*
* Created by Phil on 2/12/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
#include "catch_test_spec.hpp"
#include "catch_test_case_info.h"
#include "catch_common.h"
namespace Catch {
TestCaseFilter::TestCaseFilter( std::string const& testSpec, IfFilterMatches::DoWhat matchBehaviour )
: m_stringToMatch( toLower( testSpec ) ),
m_filterType( matchBehaviour ),
m_wildcardPosition( NoWildcard )
{
if( m_filterType == IfFilterMatches::AutoDetectBehaviour ) {
if( startsWith( m_stringToMatch, "exclude:" ) ) {
m_stringToMatch = m_stringToMatch.substr( 8 );
m_filterType = IfFilterMatches::ExcludeTests;
}
else if( startsWith( m_stringToMatch, "~" ) ) {
m_stringToMatch = m_stringToMatch.substr( 1 );
m_filterType = IfFilterMatches::ExcludeTests;
}
else {
m_filterType = IfFilterMatches::IncludeTests;
}
}
if( startsWith( m_stringToMatch, "*" ) ) {
m_stringToMatch = m_stringToMatch.substr( 1 );
m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtStart );
}
if( endsWith( m_stringToMatch, "*" ) ) {
m_stringToMatch = m_stringToMatch.substr( 0, m_stringToMatch.size()-1 );
m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtEnd );
}
}
IfFilterMatches::DoWhat TestCaseFilter::getFilterType() const {
return m_filterType;
}
bool TestCaseFilter::shouldInclude( TestCase const& testCase ) const {
return isMatch( testCase ) == (m_filterType == IfFilterMatches::IncludeTests);
}
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
#endif
bool TestCaseFilter::isMatch( TestCase const& testCase ) const {
std::string name = testCase.getTestCaseInfo().name;
toLowerInPlace( name );
switch( m_wildcardPosition ) {
case NoWildcard:
return m_stringToMatch == name;
case WildcardAtStart:
return endsWith( name, m_stringToMatch );
case WildcardAtEnd:
return startsWith( name, m_stringToMatch );
case WildcardAtBothEnds:
return contains( name, m_stringToMatch );
}
throw std::logic_error( "Unhandled wildcard type" );
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
TestCaseFilters::TestCaseFilters( std::string const& name ) : m_name( name ) {}
std::string TestCaseFilters::getName() const {
return m_name;
}
void TestCaseFilters::addFilter( TestCaseFilter const& filter ) {
if( filter.getFilterType() == IfFilterMatches::ExcludeTests )
m_exclusionFilters.push_back( filter );
else
m_inclusionFilters.push_back( filter );
}
void TestCaseFilters::addTags( std::string const& tagPattern ) {
TagExpression exp;
TagExpressionParser( exp ).parse( tagPattern );
m_tagExpressions.push_back( exp );
}
bool TestCaseFilters::shouldInclude( TestCase const& testCase ) const {
if( !m_tagExpressions.empty() ) {
std::vector<TagExpression>::const_iterator it = m_tagExpressions.begin();
std::vector<TagExpression>::const_iterator itEnd = m_tagExpressions.end();
for(; it != itEnd; ++it )
if( it->matches( testCase.getTags() ) )
break;
if( it == itEnd )
return false;
}
if( !m_inclusionFilters.empty() ) {
std::vector<TestCaseFilter>::const_iterator it = m_inclusionFilters.begin();
std::vector<TestCaseFilter>::const_iterator itEnd = m_inclusionFilters.end();
for(; it != itEnd; ++it )
if( it->shouldInclude( testCase ) )
break;
if( it == itEnd )
return false;
}
else if( m_exclusionFilters.empty() && m_tagExpressions.empty() ) {
return !testCase.isHidden();
}
std::vector<TestCaseFilter>::const_iterator it = m_exclusionFilters.begin();
std::vector<TestCaseFilter>::const_iterator itEnd = m_exclusionFilters.end();
for(; it != itEnd; ++it )
if( !it->shouldInclude( testCase ) )
return false;
return true;
}
}
#endif // TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED

View File

@ -0,0 +1,192 @@
/*
* Created by Phil on 27/11/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
#include "../internal/catch_interfaces_reporter.h"
namespace Catch {
struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
StreamingReporterBase( ReporterConfig const& _config )
: m_config( _config.fullConfig() ),
stream( _config.stream() )
{}
virtual ~StreamingReporterBase();
virtual void noMatchingTestCases( std::string const& ) {}
virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
currentTestRunInfo = _testRunInfo;
}
virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
currentGroupInfo = _groupInfo;
}
virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
currentTestCaseInfo = _testInfo;
}
virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
m_sectionStack.push_back( _sectionInfo );
}
virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
m_sectionStack.pop_back();
}
virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
currentTestCaseInfo.reset();
assert( m_sectionStack.empty() );
}
virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
currentGroupInfo.reset();
}
virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
currentTestCaseInfo.reset();
currentGroupInfo.reset();
currentTestRunInfo.reset();
}
Ptr<IConfig> m_config;
std::ostream& stream;
LazyStat<TestRunInfo> currentTestRunInfo;
LazyStat<GroupInfo> currentGroupInfo;
LazyStat<TestCaseInfo> currentTestCaseInfo;
std::vector<SectionInfo> m_sectionStack;
};
struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
template<typename T, typename ChildNodeT>
struct Node : SharedImpl<> {
explicit Node( T const& _value ) : value( _value ) {}
virtual ~Node() {}
typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
T value;
ChildNodes children;
};
struct SectionNode : SharedImpl<> {
explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
virtual ~SectionNode();
bool operator == ( SectionNode const& other ) const {
return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
}
bool operator == ( Ptr<SectionNode> const& other ) const {
return operator==( *other );
}
SectionStats stats;
typedef std::vector<Ptr<SectionNode> > ChildSections;
typedef std::vector<AssertionStats> Assertions;
ChildSections childSections;
Assertions assertions;
std::string stdOut;
std::string stdErr;
};
friend bool operator == ( Ptr<SectionNode> const& node, SectionInfo const& other ) {
return node->stats.sectionInfo.lineInfo == other.lineInfo;
}
typedef Node<TestCaseStats, SectionNode> TestCaseNode;
typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
typedef Node<TestRunStats, TestGroupNode> TestRunNode;
CumulativeReporterBase( ReporterConfig const& _config )
: m_config( _config.fullConfig() ),
stream( _config.stream() )
{}
~CumulativeReporterBase();
virtual void testRunStarting( TestRunInfo const& ) {}
virtual void testGroupStarting( GroupInfo const& ) {}
virtual void testCaseStarting( TestCaseInfo const& ) {}
virtual void sectionStarting( SectionInfo const& sectionInfo ) {
SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
Ptr<SectionNode> node;
if( m_sectionStack.empty() ) {
if( !m_rootSection )
m_rootSection = new SectionNode( incompleteStats );
node = m_rootSection;
}
else {
SectionNode& parentNode = *m_sectionStack.back();
SectionNode::ChildSections::const_iterator it =
std::find( parentNode.childSections.begin(), parentNode.childSections.end(), sectionInfo );
if( it == parentNode.childSections.end() ) {
node = new SectionNode( incompleteStats );
parentNode.childSections.push_back( node );
}
else
node = *it;
}
m_sectionStack.push_back( node );
m_deepestSection = node;
}
virtual void assertionStarting( AssertionInfo const& ) {}
virtual bool assertionEnded( AssertionStats const& assertionStats ) {
assert( !m_sectionStack.empty() );
SectionNode& sectionNode = *m_sectionStack.back();
sectionNode.assertions.push_back( assertionStats );
return true;
}
virtual void sectionEnded( SectionStats const& sectionStats ) {
assert( !m_sectionStack.empty() );
SectionNode& node = *m_sectionStack.back();
node.stats = sectionStats;
m_sectionStack.pop_back();
}
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
assert( m_sectionStack.size() == 0 );
node->children.push_back( m_rootSection );
m_testCases.push_back( node );
m_rootSection.reset();
assert( m_deepestSection );
m_deepestSection->stdOut = testCaseStats.stdOut;
m_deepestSection->stdErr = testCaseStats.stdErr;
}
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
node->children.swap( m_testCases );
m_testGroups.push_back( node );
}
virtual void testRunEnded( TestRunStats const& testRunStats ) {
Ptr<TestRunNode> node = new TestRunNode( testRunStats );
node->children.swap( m_testGroups );
m_testRuns.push_back( node );
testRunEnded();
}
virtual void testRunEnded() = 0;
Ptr<IConfig> m_config;
std::ostream& stream;
std::vector<AssertionStats> m_assertions;
std::vector<std::vector<Ptr<SectionNode> > > m_sections;
std::vector<Ptr<TestCaseNode> > m_testCases;
std::vector<Ptr<TestGroupNode> > m_testGroups;
std::vector<Ptr<TestRunNode> > m_testRuns;
Ptr<SectionNode> m_rootSection;
Ptr<SectionNode> m_deepestSection;
std::vector<Ptr<SectionNode> > m_sectionStack;
};
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED

View File

@ -8,7 +8,8 @@
#ifndef TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
#include "../internal/catch_interfaces_reporter.h"
#include "catch_reporter_bases.hpp"
#include "../internal/catch_reporter_registrars.hpp"
#include "../internal/catch_console_colour.hpp"

View File

@ -8,8 +8,9 @@
#ifndef TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
#include "catch_reporter_bases.hpp"
#include "../internal/catch_tostring.hpp"
#include "../internal/catch_interfaces_reporter.h"
#include "../internal/catch_reporter_registrars.hpp"
#include "../internal/catch_xmlwriter.hpp"

View File

@ -8,8 +8,9 @@
#ifndef TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
#include "catch_reporter_bases.hpp"
#include "../internal/catch_capture.hpp"
#include "../internal/catch_interfaces_reporter.h"
#include "../internal/catch_reporter_registrars.hpp"
#include "../internal/catch_xmlwriter.hpp"

View File

@ -1,2 +1,2 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_debugger.hpp"
#include "catch_debugger.h"

View File

@ -1,2 +1,2 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_stream.hpp"
#include "catch_stream.h"

View File

@ -1,2 +1,2 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header
#include "catch_tags.hpp"
#include "catch_tags.h"

View File

@ -56,6 +56,14 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
261488FA184C81130041FBEB /* catch_test_spec.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_spec.hpp; sourceTree = "<group>"; };
261488FB184C83EA0041FBEB /* catch_tags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_tags.h; sourceTree = "<group>"; };
261488FC184D1DC10041FBEB /* catch_stream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_stream.h; sourceTree = "<group>"; };
261488FD184D21290041FBEB /* catch_section_info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_section_info.h; sourceTree = "<group>"; };
261488FE184DC32F0041FBEB /* catch_section.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_section.h; sourceTree = "<group>"; };
261488FF184DC4A20041FBEB /* catch_debugger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_debugger.h; sourceTree = "<group>"; };
262E7399184673A800CAC268 /* catch_reporter_bases.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_bases.hpp; sourceTree = "<group>"; };
262E739A1846759000CAC268 /* catch_common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_common.hpp; sourceTree = "<group>"; };
263FD06017AF8DF200988A20 /* catch_timer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_timer.hpp; sourceTree = "<group>"; };
263FD06117AF8DF200988A20 /* catch_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_timer.h; sourceTree = "<group>"; };
266B06B616F3A60A004ED264 /* VariadicMacrosTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VariadicMacrosTests.cpp; path = ../../../SelfTest/VariadicMacrosTests.cpp; sourceTree = "<group>"; };
@ -277,6 +285,7 @@
4A6D0C65149B3E3D00DB3EAA /* reporters */ = {
isa = PBXGroup;
children = (
262E7399184673A800CAC268 /* catch_reporter_bases.hpp */,
4A6D0C67149B3E3D00DB3EAA /* catch_reporter_junit.hpp */,
4A6D0C68149B3E3D00DB3EAA /* catch_reporter_xml.hpp */,
4AB42F84166F3E1A0099F2C8 /* catch_reporter_console.hpp */,
@ -314,6 +323,7 @@
4AC91CB4155B9EBF00DC5117 /* impl */ = {
isa = PBXGroup;
children = (
261488FA184C81130041FBEB /* catch_test_spec.hpp */,
263FD06017AF8DF200988A20 /* catch_timer.hpp */,
266E9AD117230ACF0061DAB2 /* catch_text.hpp */,
4A4B0F9C15CEFA8300AE2392 /* catch_impl.hpp */,
@ -341,6 +351,7 @@
4A6D0C5D149B3E3D00DB3EAA /* catch_assertionresult.h */,
4A9D84B315599AC900FBB209 /* catch_expressionresult_builder.h */,
4A6D0C5F149B3E3D00DB3EAA /* catch_section.hpp */,
261488FE184DC32F0041FBEB /* catch_section.h */,
4A3D7DD01503869D005F9203 /* catch_matchers.hpp */,
4A9D84B11558FC0400FBB209 /* catch_tostring.hpp */,
4A6D0C46149B3E3D00DB3EAA /* catch_approx.hpp */,
@ -349,6 +360,7 @@
4AC91CD0155D8DA600DC5117 /* catch_expression_decomposer.hpp */,
4A4B0F9A15CEF84800AE2392 /* catch_notimplemented_exception.h */,
26847E5B16BBAB790043B9C1 /* catch_message.h */,
261488FD184D21290041FBEB /* catch_section_info.h */,
);
name = Assertions;
sourceTree = "<group>";
@ -375,6 +387,7 @@
4A084F1D15DAD15F0027E631 /* catch_test_spec.h */,
4A8E4DCC160A344100194CBD /* catch_tags.hpp */,
26948287179EF7F900ED166E /* catch_test_case_tracker.hpp */,
261488FB184C83EA0041FBEB /* catch_tags.h */,
);
name = "Test execution";
sourceTree = "<group>";
@ -411,6 +424,7 @@
266ECD8D1713614B0030D735 /* catch_legacy_reporter_adapter.h */,
4A6D0C49149B3E3D00DB3EAA /* catch_common.h */,
4A6D0C4B149B3E3D00DB3EAA /* catch_debugger.hpp */,
261488FF184DC4A20041FBEB /* catch_debugger.h */,
4A6D0C60149B3E3D00DB3EAA /* catch_stream.hpp */,
4A6D0C64149B3E3D00DB3EAA /* catch_xmlwriter.hpp */,
4AB1C73714F97C1300F31DF7 /* catch_console_colour.hpp */,
@ -422,6 +436,8 @@
26DACF2F17206D3400A21326 /* catch_text.h */,
263FD06117AF8DF200988A20 /* catch_timer.h */,
26AEAF1617BEA18E009E32C9 /* catch_platform.h */,
262E739A1846759000CAC268 /* catch_common.hpp */,
261488FC184D1DC10041FBEB /* catch_stream.h */,
);
name = Infrastructure;
sourceTree = "<group>";

View File

@ -2,6 +2,7 @@ import os
import sys
import re
import datetime
import string
from scriptCommon import catchPath
@ -9,6 +10,9 @@ versionParser = re.compile( r'(\s*Version\slibraryVersion)\s*\(\s*(.*)\s*,\s*(.*
includesParser = re.compile( r'\s*#include\s*"(.*)"' )
guardParser = re.compile( r'\s*#.*_INCLUDED')
defineParser = re.compile( r'\s*#define')
ifParser = re.compile( r'\s*#if')
endIfParser = re.compile( r'\s*#endif')
ifImplParser = re.compile( r'\s*#if.*(CATCH_CONFIG_MAIN|CATCH_CONFIG_RUNNER)')
commentParser1 = re.compile( r'^\s*/\*')
commentParser2 = re.compile( r'^\s*\*')
blankParser = re.compile( r'^\s*$')
@ -18,21 +22,48 @@ versionPath = os.path.join( rootPath, "internal/catch_version.hpp" )
readmePath = os.path.join( catchPath, "README.md" )
outputPath = os.path.join( catchPath, 'single_include/catch.hpp' )
bumpVersion = len(sys.argv) < 2 or sys.argv[1] <> "nobump"
bumpVersion = True
includeImpl = True
for arg in sys.argv[1:]:
arg = string.lower(arg)
if arg == "nobump":
bumpVersion = False
print "Not bumping version number"
elif arg == "noimpl":
includeImpl = False
bumpVersion = False
print "Not including impl code (and not bumping version)"
else:
print "\n** Unrecognised argument: " + arg + " **\n"
exit(1)
out = open( outputPath, 'w' )
ifdefs = 0
implIfDefs = -1
def write( line ):
if includeImpl or implIfDefs == -1:
out.write( line )
def parseFile( path, filename ):
global ifdefs
global implIfDefs
f = open( path + filename, 'r' )
blanks = 0
for line in f:
if ifParser.match( line ):
ifdefs = ifdefs + 1
elif endIfParser.match( line ):
ifdefs = ifdefs - 1
m = includesParser.match( line )
if m:
header = m.group(1)
headerPath, sep, headerFile = header.rpartition( "/" )
if not headerFile in seenHeaders:
seenHeaders.add( headerFile )
out.write( "// #included from: {0}\n".format( header ) )
write( "// #included from: {0}\n".format( header ) )
if( headerPath == "internal" and path.endswith( "internal/" ) ):
headerPath = ""
sep = ""
@ -40,13 +71,15 @@ def parseFile( path, filename ):
parseFile( path + headerPath + sep, headerFile )
else:
parseFile( rootPath + headerPath + sep, headerFile )
elif ifImplParser.match(line):
implIfDefs = ifdefs
elif (not guardParser.match( line ) or defineParser.match( line ) ) and not commentParser1.match( line )and not commentParser2.match( line ):
if blankParser.match( line ):
blanks = blanks + 1
else:
blanks = 0
if blanks < 2:
out.write( line.rstrip() + "\n" )
write( line.rstrip() + "\n" )
class Version:
def __init__(self):