Merge from mainline

This commit is contained in:
Malcolm Noyes
2013-12-09 16:01:23 +00:00
71 changed files with 4125 additions and 4921 deletions

View File

@@ -12,11 +12,13 @@
#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_reporter.h"
//#include "catch_interfaces_registry_hub.h"
//#include "catch_interfaces_config.h"
#include "internal/catch_compiler_capabilities.h"
#include <ostream>
@@ -117,7 +119,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 ) { INTERNAL_CATCH_TEST_THROW_FAILURE } \
if( !Catch::shouldContinueOnFailure( resultDisposition ) ) { INTERNAL_CATCH_TEST_THROW_FAILURE } \
Catch::isTrue( false && originalExpr ); \

View File

@@ -12,6 +12,8 @@
#include "catch_common.h"
#include "clara.h"
#include <fstream>
namespace Catch {
inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
@@ -38,7 +40,18 @@ namespace Catch {
? ShowDurations::Always
: ShowDurations::Never;
}
inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
std::ifstream f( _filename.c_str() );
if( !f.is_open() )
throw std::domain_error( "Unable to load input file: " + _filename );
std::string line;
while( std::getline( f, line ) ) {
line = trim(line);
if( !line.empty() && !startsWith( line, "#" ) )
addTestOrTags( config, line );
}
}
inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
@@ -53,19 +66,15 @@ namespace Catch {
.longOpt( "help" );
cli.bind( &ConfigData::listTests )
.describe( "list all (or matching) test cases" )
.describe( "list all/matching test cases" )
.shortOpt( "l")
.longOpt( "list-tests" );
cli.bind( &ConfigData::listTags )
.describe( "list all (or matching) tags" )
.describe( "list all/matching tags" )
.shortOpt( "t")
.longOpt( "list-tags" );
cli.bind( &ConfigData::listReporters )
.describe( "list all reporters" )
.longOpt( "list-reporters" );
cli.bind( &ConfigData::showSuccessfulTests )
.describe( "include successful tests in output" )
.shortOpt( "s")
@@ -88,7 +97,7 @@ namespace Catch {
.hint( "filename" );
cli.bind( &ConfigData::reporterName )
.describe( "reporter to use - defaults to console" )
.describe( "reporter to use (defaults to console)" )
.shortOpt( "r")
.longOpt( "reporter" )
// .hint( "name[:filename]" );
@@ -133,6 +142,22 @@ namespace Catch {
.longOpt( "durations" )
.hint( "yes/no" );
cli.bind( &loadTestNamesFromFile )
.describe( "load test names to run from a file" )
.shortOpt( "f")
.longOpt( "input-file" )
.hint( "filename" );
// Less common commands which don't have a short form
cli.bind( &ConfigData::listTestNamesOnly )
.describe( "list all/matching test cases names only" )
.longOpt( "list-test-names-only" );
cli.bind( &ConfigData::listReporters )
.describe( "list all reporters" )
.longOpt( "list-reporters" );
return cli;
}

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( char 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 {
INTERNAL_CATCH_INLINE bool startsWith( std::string const& s, std::string const& prefix ) {
return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
}
INTERNAL_CATCH_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;
}
INTERNAL_CATCH_INLINE bool contains( std::string const& s, std::string const& infix ) {
return s.find( infix ) != std::string::npos;
}
INTERNAL_CATCH_INLINE void toLowerInPlace( std::string& s ) {
std::transform( s.begin(), s.end(), s.begin(), ::tolower );
}
INTERNAL_CATCH_INLINE std::string toLower( std::string const& s ) {
std::string lc = s;
toLowerInPlace( lc );
return lc;
}
INTERNAL_CATCH_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 ) : "";
}
INTERNAL_CATCH_INLINE pluralise::pluralise( std::size_t count, std::string const& label )
: m_count( count ),
m_label( label )
{}
INTERNAL_CATCH_INLINE 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;
}
INTERNAL_CATCH_INLINE SourceLineInfo::SourceLineInfo() : line( 0 ){}
INTERNAL_CATCH_INLINE SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
: file( _file ),
line( _line )
{}
INTERNAL_CATCH_INLINE SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
: file( other.file ),
line( other.line )
{}
INTERNAL_CATCH_INLINE bool SourceLineInfo::empty() const {
return file.empty();
}
INTERNAL_CATCH_INLINE bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
return line == other.line && file == other.file;
}
INTERNAL_CATCH_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;
}
INTERNAL_CATCH_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() );
}
}
#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>
@@ -30,6 +30,7 @@ namespace Catch {
: listTests( false ),
listTags( false ),
listReporters( false ),
listTestNamesOnly( false ),
showSuccessfulTests( false ),
shouldDebugBreak( false ),
noThrow( false ),
@@ -43,6 +44,7 @@ namespace Catch {
bool listTests;
bool listTags;
bool listReporters;
bool listTestNamesOnly;
bool showSuccessfulTests;
bool shouldDebugBreak;
@@ -112,6 +114,7 @@ namespace Catch {
}
bool listTests() const { return m_data.listTests; }
bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
bool listTags() const { return m_data.listTags; }
bool listReporters() const { return m_data.listReporters; }

View File

@@ -117,7 +117,7 @@ namespace {
};
inline bool shouldUseColourForPlatform() {
return isatty( fileno(stdout) );
return isatty(STDOUT_FILENO);
}
PosixColourImpl platformColourImpl;

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(){
INTERNAL_CATCH_INLINE 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 {
INTERNAL_CATCH_INLINE 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 {
INTERNAL_CATCH_INLINE 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 {
INTERNAL_CATCH_INLINE 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 {
INTERNAL_CATCH_INLINE 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>
@@ -60,6 +61,20 @@ namespace Catch {
return matchedTests;
}
inline std::size_t listTestsNamesOnly( Config const& config ) {
std::size_t matchedTests = 0;
std::vector<TestCase> const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests();
for( std::vector<TestCase>::const_iterator it = allTests.begin(), itEnd = allTests.end();
it != itEnd;
++it )
if( matchesFilters( config.filters(), *it ) ) {
matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
std::cout << testCaseInfo.name << std::endl;
}
return matchedTests;
}
inline std::size_t listTags( Config const& config ) {
if( config.filters().empty() )
std::cout << "All available tags:\n";
@@ -131,6 +146,8 @@ namespace Catch {
Option<std::size_t> listedCount;
if( config.listTests() )
listedCount = listedCount.valueOr(0) + listTests( config );
if( config.listTestNamesOnly() )
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
if( config.listTags() )
listedCount = listedCount.valueOr(0) + listTags( config );
if( config.listReporters() )

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();
}
INTERNAL_CATCH_INLINE 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() );
}
INTERNAL_CATCH_INLINE 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
INTERNAL_CATCH_INLINE 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 )
{}
INTERNAL_CATCH_INLINE Stream::Stream()
: streamBuf( NULL ), isOwned( false )
{}
Stream( std::streambuf* _streamBuf, bool _isOwned )
: streamBuf( _streamBuf ), isOwned( _isOwned )
{}
INTERNAL_CATCH_INLINE Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
: streamBuf( _streamBuf ), isOwned( _isOwned )
{}
void release() {
if( isOwned ) {
delete streamBuf;
streamBuf = NULL;
isOwned = false;
}
INTERNAL_CATCH_INLINE 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();
INTERNAL_CATCH_INLINE 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++;
}
INTERNAL_CATCH_INLINE 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();
}
INTERNAL_CATCH_INLINE TagExtracter::TagExtracter( std::set<std::string>& tags )
: m_tags( tags )
{}
INTERNAL_CATCH_INLINE TagExtracter::~TagExtracter() {}
INTERNAL_CATCH_INLINE void TagExtracter::parse( std::string& description ) {
TagParser::parse( description );
description = m_remainder;
}
INTERNAL_CATCH_INLINE void TagExtracter::acceptTag( std::string const& tag ) {
m_tags.insert( toLower( tag ) );
}
INTERNAL_CATCH_INLINE void TagExtracter::acceptChar( char c ) {
m_remainder += c;
}
INTERNAL_CATCH_INLINE Tag::Tag() : m_isNegated( false ) {}
INTERNAL_CATCH_INLINE Tag::Tag( std::string const& name, bool isNegated )
: m_name( name ),
m_isNegated( isNegated )
{}
INTERNAL_CATCH_INLINE std::string Tag::getName() const {
return m_name;
}
INTERNAL_CATCH_INLINE bool Tag::isNegated() const {
return m_isNegated;
}
INTERNAL_CATCH_INLINE bool Tag::operator ! () const {
return m_name.empty();
}
INTERNAL_CATCH_INLINE void TagSet::add( Tag const& tag ) {
m_tags.insert( std::make_pair( toLower( tag.getName() ), tag ) );
}
INTERNAL_CATCH_INLINE bool TagSet::empty() const {
return m_tags.empty();
}
INTERNAL_CATCH_INLINE 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;
}
INTERNAL_CATCH_INLINE 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;
}
INTERNAL_CATCH_INLINE TagExpressionParser::TagExpressionParser( TagExpression& exp )
: m_isNegated( false ),
m_exp( exp )
{}
INTERNAL_CATCH_INLINE TagExpressionParser::~TagExpressionParser() {}
INTERNAL_CATCH_INLINE void TagExpressionParser::acceptTag( std::string const& tag ) {
m_currentTagSet.add( Tag( tag, m_isNegated ) );
m_isNegated = false;
}
INTERNAL_CATCH_INLINE 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;
};
INTERNAL_CATCH_INLINE 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"
@@ -22,12 +22,16 @@ namespace Catch {
SourceLineInfo const& _lineInfo )
{
std::string desc = _descOrTags;
bool isHidden( startsWith( _name, "./" ) );
bool isHidden( startsWith( _name, "./" ) ); // Legacy support
std::set<std::string> tags;
TagExtracter( tags ).parse( desc );
if( tags.find( "hide" ) != tags.end() || tags.find( "." ) != tags.end() )
isHidden = true;
if( isHidden ) {
tags.insert( "hide" );
tags.insert( "." );
}
TestCaseInfo info( _name, _className, desc, tags, isHidden, _lineInfo );
return TestCase( _testCase, info );
}

View File

@@ -42,8 +42,8 @@ namespace Catch {
else {
TestCase const& prev = *m_functions.find( testCase );
std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n"
<< "\tFirst seen at " << SourceLineInfo( prev.getTestCaseInfo().lineInfo ) << "\n"
<< "\tRedefined at " << SourceLineInfo( testCase.getTestCaseInfo().lineInfo ) << std::endl;
<< "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n"
<< "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
exit(1);
}
}

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 {
INTERNAL_CATCH_INLINE 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 );
}
}
INTERNAL_CATCH_INLINE IfFilterMatches::DoWhat TestCaseFilter::getFilterType() const {
return m_filterType;
}
INTERNAL_CATCH_INLINE 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
INTERNAL_CATCH_INLINE 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
INTERNAL_CATCH_INLINE TestCaseFilters::TestCaseFilters( std::string const& name ) : m_name( name ) {}
INTERNAL_CATCH_INLINE std::string TestCaseFilters::getName() const {
return m_name;
}
INTERNAL_CATCH_INLINE void TestCaseFilters::addFilter( TestCaseFilter const& filter ) {
if( filter.getFilterType() == IfFilterMatches::ExcludeTests )
m_exclusionFilters.push_back( filter );
else
m_inclusionFilters.push_back( filter );
}
INTERNAL_CATCH_INLINE void TestCaseFilters::addTags( std::string const& tagPattern ) {
TagExpression exp;
TagExpressionParser( exp ).parse( tagPattern );
m_tagExpressions.push_back( exp );
}
INTERNAL_CATCH_INLINE 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

@@ -14,7 +14,7 @@ namespace Catch {
// These numbers are maintained by a script
template <typename T>
const T LibraryVersionInfo<T>::value( 1, 0, 13, "master" );
const T LibraryVersionInfo<T>::value( 1, 0, 16, "master" );
}
#endif // TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED

View File

@@ -26,6 +26,11 @@ namespace Catch {
}
#include "catch_common.hpp"
#include "catch_debugger.hpp"
#include "catch_tags.hpp"
#include "catch_test_spec.hpp"
#include "catch_section.hpp"
#include "internal/catch_timer.hpp"
#include "internal/catch_vs_test_registry.hpp"
#include "reporters/catch_vs_reporter.hpp"

View File

@@ -21,6 +21,11 @@ using Microsoft::VisualStudio::CppUnitTestFramework::__LineInfo;
#include <cvt/wstring>
#include <codecvt>
#include "catch_common.hpp"
#include "catch_debugger.hpp"
#include "catch_tags.hpp"
#include "catch_test_spec.hpp"
#include "catch_section.hpp"
#include "internal/catch_timer.hpp"
#include "internal/catch_vs_test_registry.hpp"
#include "reporters/catch_vs_reporter.hpp"

View File

@@ -332,7 +332,6 @@ namespace Catch {
inline IMutableRegistryHub::~IMutableRegistryHub() {}
inline IExceptionTranslator::~IExceptionTranslator() {}
inline IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
inline IReporter::~IReporter() {}
inline IReporterFactory::~IReporterFactory() {}
inline IReporterRegistry::~IReporterRegistry() {}
inline IStreamingReporter::~IStreamingReporter() {}
@@ -355,9 +354,6 @@ namespace Catch {
inline FreeFunctionTestCase::~FreeFunctionTestCase() {}
inline IGeneratorInfo::~IGeneratorInfo() {}
inline IGeneratorsForTest::~IGeneratorsForTest() {}
inline TagParser::~TagParser() {}
inline TagExtracter::~TagExtracter() {}
inline TagExpressionParser::~TagExpressionParser() {}
inline Matchers::Impl::StdString::Equals::~Equals() {}
inline Matchers::Impl::StdString::Contains::~Contains() {}