Merge branch 'catch2'

This commit is contained in:
Phil Nash
2017-11-03 12:05:38 +00:00
264 changed files with 25287 additions and 23762 deletions

View File

@@ -0,0 +1,56 @@
/*
* Created by Martin on 19/07/2017.
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_approx.h"
#include <cmath>
#include <limits>
namespace {
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
// But without the subtraction to allow for INFINITY in comparison
bool marginComparison(double lhs, double rhs, double margin) {
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
}
}
namespace Catch {
namespace Detail {
Approx::Approx ( double value )
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
m_margin( 0.0 ),
m_scale( 0.0 ),
m_value( value )
{}
Approx Approx::custom() {
return Approx( 0 );
}
std::string Approx::toString() const {
std::ostringstream oss;
oss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
return oss.str();
}
bool Approx::equalityComparisonImpl(const double other) const {
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
// Thanks to Richard Harris for his help refining the scaled margin value
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
}
} // end namespace Detail
std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
return value.toString();
}
} // end namespace Catch

View File

@@ -0,0 +1,126 @@
/*
* Created by Phil on 28/04/2011.
* 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_APPROX_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
#include "catch_enforce.h"
#include "catch_tostring.h"
#include <type_traits>
namespace Catch {
namespace Detail {
class Approx {
private:
bool equalityComparisonImpl(double other) const;
public:
explicit Approx ( double value );
static Approx custom();
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx operator()( T const& value ) {
Approx approx( static_cast<double>(value) );
approx.epsilon( m_epsilon );
approx.margin( m_margin );
approx.scale( m_scale );
return approx;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
explicit Approx( T const& value ): Approx(static_cast<double>(value))
{}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator == ( const T& lhs, Approx const& rhs ) {
auto lhs_v = static_cast<double>(lhs);
return rhs.equalityComparisonImpl(lhs_v);
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator == ( Approx const& lhs, const T& rhs ) {
return operator==( rhs, lhs );
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator != ( T const& lhs, Approx const& rhs ) {
return !operator==( lhs, rhs );
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator != ( Approx const& lhs, T const& rhs ) {
return !operator==( rhs, lhs );
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator <= ( T const& lhs, Approx const& rhs ) {
return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator <= ( Approx const& lhs, T const& rhs ) {
return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator >= ( T const& lhs, Approx const& rhs ) {
return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator >= ( Approx const& lhs, T const& rhs ) {
return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& epsilon( T const& newEpsilon ) {
double epsilonAsDouble = static_cast<double>(newEpsilon);
CATCH_ENFORCE(epsilonAsDouble >= 0 && epsilonAsDouble <= 1.0,
"Invalid Approx::epsilon: " << epsilonAsDouble
<< ", Approx::epsilon has to be between 0 and 1");
m_epsilon = epsilonAsDouble;
return *this;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& margin( T const& newMargin ) {
double marginAsDouble = static_cast<double>(newMargin);
CATCH_ENFORCE(marginAsDouble >= 0,
"Invalid Approx::margin: " << marginAsDouble
<< ", Approx::Margin has to be non-negative.");
m_margin = marginAsDouble;
return *this;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& scale( T const& newScale ) {
m_scale = static_cast<double>(newScale);
return *this;
}
std::string toString() const;
private:
double m_epsilon;
double m_margin;
double m_scale;
double m_value;
};
}
template<>
struct StringMaker<Catch::Detail::Approx> {
static std::string convert(Catch::Detail::Approx const& value);
};
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED

View File

@@ -0,0 +1,147 @@
/*
* Created by Phil on 8/8/2017.
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_assertionhandler.h"
#include "catch_assertionresult.h"
#include "catch_interfaces_capture.h"
#include "catch_interfaces_runner.h"
#include "catch_interfaces_config.h"
#include "catch_context.h"
#include "catch_debugger.h"
#include "catch_interfaces_registry_hub.h"
#include "catch_capture_matchers.h"
#include <cassert>
namespace Catch {
auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
expr.streamReconstructedExpression( os );
return os;
}
LazyExpression::LazyExpression( bool isNegated )
: m_isNegated( isNegated )
{}
LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {}
LazyExpression::operator bool() const {
return m_transientExpression != nullptr;
}
auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& {
if( lazyExpr.m_isNegated )
os << "!";
if( lazyExpr ) {
if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() )
os << "(" << *lazyExpr.m_transientExpression << ")";
else
os << *lazyExpr.m_transientExpression;
}
else {
os << "{** error - unchecked empty expression requested **}";
}
return os;
}
AssertionHandler::AssertionHandler
( StringRef macroName,
SourceLineInfo const& lineInfo,
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition )
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }
{
getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo );
}
AssertionHandler::~AssertionHandler() {
if ( m_inExceptionGuard ) {
handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" );
getCurrentContext().getResultCapture()->exceptionEarlyReported();
}
}
void AssertionHandler::handle( ITransientExpression const& expr ) {
bool negated = isFalseTest( m_assertionInfo.resultDisposition );
bool result = expr.getResult() != negated;
handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated );
}
void AssertionHandler::handle( ResultWas::OfType resultType ) {
handle( resultType, nullptr, false );
}
void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) {
AssertionResultData data( resultType, LazyExpression( false ) );
data.message = message;
handle( data, nullptr );
}
void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) {
AssertionResultData data( resultType, LazyExpression( negated ) );
handle( data, expr );
}
void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) {
getResultCapture().assertionRun();
AssertionResult assertionResult{ m_assertionInfo, resultData };
assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
getResultCapture().assertionEnded( assertionResult );
if( !assertionResult.isOk() ) {
m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak();
m_shouldThrow =
getCurrentContext().getRunner()->aborting() ||
(m_assertionInfo.resultDisposition & ResultDisposition::Normal);
}
}
auto AssertionHandler::allowThrows() const -> bool {
return getCurrentContext().getConfig()->allowThrows();
}
auto AssertionHandler::shouldDebugBreak() const -> bool {
return m_shouldDebugBreak;
}
void AssertionHandler::reactWithDebugBreak() const {
if (m_shouldDebugBreak) {
///////////////////////////////////////////////////////////////////
// To inspect the state during test, you need to go one level up the callstack
// To go back to the test and change execution, jump over the reactWithoutDebugBreak() call
///////////////////////////////////////////////////////////////////
CATCH_BREAK_INTO_DEBUGGER();
}
reactWithoutDebugBreak();
}
void AssertionHandler::reactWithoutDebugBreak() const {
if( m_shouldThrow )
throw Catch::TestFailureException();
}
void AssertionHandler::useActiveException() {
handle( ResultWas::ThrewException, Catch::translateActiveException() );
}
void AssertionHandler::setExceptionGuard() {
assert( m_inExceptionGuard == false );
m_inExceptionGuard = true;
}
void AssertionHandler::unsetExceptionGuard() {
assert( m_inExceptionGuard == true );
m_inExceptionGuard = false;
}
// This is the overload that takes a string and infers the Equals matcher from it
// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) {
handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
}
} // namespace Catch

View File

@@ -0,0 +1,73 @@
/*
* Created by Phil on 8/8/2017.
* Copyright 2017 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_ASSERTIONHANDLER_H_INCLUDED
#define TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED
#include "catch_decomposer.h"
#include "catch_assertioninfo.h"
namespace Catch {
struct TestFailureException{};
struct AssertionResultData;
class LazyExpression {
friend class AssertionHandler;
friend struct AssertionStats;
ITransientExpression const* m_transientExpression = nullptr;
bool m_isNegated;
public:
LazyExpression( bool isNegated );
LazyExpression( LazyExpression const& other );
LazyExpression& operator = ( LazyExpression const& ) = delete;
explicit operator bool() const;
friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
};
class AssertionHandler {
AssertionInfo m_assertionInfo;
bool m_shouldDebugBreak = false;
bool m_shouldThrow = false;
bool m_inExceptionGuard = false;
public:
AssertionHandler
( StringRef macroName,
SourceLineInfo const& lineInfo,
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition );
~AssertionHandler();
void handle( ITransientExpression const& expr );
template<typename T>
void handle( ExprLhs<T> const& expr ) {
handle( expr.makeUnaryExpr() );
}
void handle( ResultWas::OfType resultType );
void handle( ResultWas::OfType resultType, StringRef const& message );
void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated );
void handle( AssertionResultData const& resultData, ITransientExpression const* expr );
auto shouldDebugBreak() const -> bool;
auto allowThrows() const -> bool;
void reactWithDebugBreak() const;
void reactWithoutDebugBreak() const;
void useActiveException();
void setExceptionGuard();
void unsetExceptionGuard();
};
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED

View File

@@ -0,0 +1,31 @@
/*
* Created by Phil on 8/8/2017.
* Copyright 2017 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_ASSERTIONINFO_H_INCLUDED
#define TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED
#include "catch_result_type.h"
#include "catch_common.h"
#include "catch_stringref.h"
namespace Catch {
struct AssertionInfo
{
StringRef macroName;
SourceLineInfo lineInfo;
StringRef capturedExpression;
ResultDisposition::Flags resultDisposition;
// We want to delete this constructor but a compiler bug in 4.8 means
// the struct is then treated as non-aggregate
//AssertionInfo() = delete;
};
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED

View File

@@ -0,0 +1,99 @@
/*
* Created by Phil on 8/8/12
* Copyright 2012 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_assertionresult.h"
namespace Catch {
AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):
lazyExpression(_lazyExpression),
resultType(_resultType) {}
std::string AssertionResultData::reconstructExpression() const {
if( reconstructedExpression.empty() ) {
if( lazyExpression ) {
// !TBD Use stringstream for now, but rework above to pass stream in
std::ostringstream oss;
oss << lazyExpression;
reconstructedExpression = oss.str();
}
}
return reconstructedExpression;
}
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
: m_info( info ),
m_resultData( data )
{}
// Result was a success
bool AssertionResult::succeeded() const {
return Catch::isOk( m_resultData.resultType );
}
// Result was a success, or failure is suppressed
bool AssertionResult::isOk() const {
return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
}
ResultWas::OfType AssertionResult::getResultType() const {
return m_resultData.resultType;
}
bool AssertionResult::hasExpression() const {
return m_info.capturedExpression[0] != 0;
}
bool AssertionResult::hasMessage() const {
return !m_resultData.message.empty();
}
std::string AssertionResult::getExpression() const {
if( isFalseTest( m_info.resultDisposition ) )
return "!(" + std::string(m_info.capturedExpression) + ")";
else
return m_info.capturedExpression;
}
std::string AssertionResult::getExpressionInMacro() const {
std::string expr;
if( m_info.macroName[0] == 0 )
expr = m_info.capturedExpression;
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName;
expr += "( ";
expr += m_info.capturedExpression;
expr += " )";
}
return expr;
}
bool AssertionResult::hasExpandedExpression() const {
return hasExpression() && getExpandedExpression() != getExpression();
}
std::string AssertionResult::getExpandedExpression() const {
std::string expr = m_resultData.reconstructExpression();
return expr.empty()
? getExpression()
: expr;
}
std::string AssertionResult::getMessage() const {
return m_resultData.message;
}
SourceLineInfo AssertionResult::getSourceInfo() const {
return m_info.lineInfo;
}
std::string AssertionResult::getTestMacroName() const {
return m_info.macroName;
}
} // end namespace Catch

View File

@@ -9,100 +9,32 @@
#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
#include <string>
#include "catch_assertioninfo.h"
#include "catch_result_type.h"
#include "catch_common.h"
#include "catch_stringref.h"
#include "catch_assertionhandler.h"
namespace Catch {
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
struct DecomposedExpression
{
virtual ~DecomposedExpression() {}
virtual bool isBinaryExpression() const {
return false;
}
virtual void reconstructExpression( std::string& dest ) const = 0;
// Only simple binary comparisons can be decomposed.
// If more complex check is required then wrap sub-expressions in parentheses.
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
private:
DecomposedExpression& operator = (DecomposedExpression const&);
};
struct AssertionInfo
{
AssertionInfo();
AssertionInfo( char const * _macroName,
SourceLineInfo const& _lineInfo,
char const * _capturedExpression,
ResultDisposition::Flags _resultDisposition,
char const * _secondArg = "");
char const * macroName;
SourceLineInfo lineInfo;
char const * capturedExpression;
ResultDisposition::Flags resultDisposition;
char const * secondArg;
};
struct AssertionResultData
{
AssertionResultData() : decomposedExpression( CATCH_NULL )
, resultType( ResultWas::Unknown )
, negated( false )
, parenthesized( false ) {}
AssertionResultData() = delete;
void negate( bool parenthesize ) {
negated = !negated;
parenthesized = parenthesize;
if( resultType == ResultWas::Ok )
resultType = ResultWas::ExpressionFailed;
else if( resultType == ResultWas::ExpressionFailed )
resultType = ResultWas::Ok;
}
AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
std::string const& reconstructExpression() const {
if( decomposedExpression != CATCH_NULL ) {
decomposedExpression->reconstructExpression( reconstructedExpression );
if( parenthesized ) {
reconstructedExpression.insert( 0, 1, '(' );
reconstructedExpression.append( 1, ')' );
}
if( negated ) {
reconstructedExpression.insert( 0, 1, '!' );
}
decomposedExpression = CATCH_NULL;
}
return reconstructedExpression;
}
mutable DecomposedExpression const* decomposedExpression;
mutable std::string reconstructedExpression;
std::string message;
mutable std::string reconstructedExpression;
LazyExpression lazyExpression;
ResultWas::OfType resultType;
bool negated;
bool parenthesized;
std::string reconstructExpression() const;
};
class AssertionResult {
public:
AssertionResult();
AssertionResult() = delete;
AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
~AssertionResult();
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
AssertionResult( AssertionResult const& ) = default;
AssertionResult( AssertionResult && ) = default;
AssertionResult& operator = ( AssertionResult const& ) = default;
AssertionResult& operator = ( AssertionResult && ) = default;
# endif
bool isOk() const;
bool succeeded() const;
@@ -116,10 +48,8 @@ namespace Catch {
std::string getMessage() const;
SourceLineInfo getSourceInfo() const;
std::string getTestMacroName() const;
void discardDecomposedExpression() const;
void expandDecomposedExpression() const;
protected:
//protected:
AssertionInfo m_info;
AssertionResultData m_resultData;
};

View File

@@ -0,0 +1,36 @@
/*
* Created by Phil on 04/07/2017.
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_benchmark.h"
#include "catch_capture.hpp"
#include "catch_interfaces_reporter.h"
#include "catch_context.h"
namespace Catch {
auto BenchmarkLooper::getResolution() -> uint64_t {
return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple();
}
void BenchmarkLooper::reportStart() {
getResultCapture().benchmarkStarting( { m_name } );
}
auto BenchmarkLooper::needsMoreIterations() -> bool {
auto elapsed = m_timer.getElapsedNanoseconds();
// Exponentially increasing iterations until we're confident in our timer resolution
if( elapsed < m_resolution ) {
m_iterationsToRun *= 10;
return true;
}
getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } );
return false;
}
} // end namespace Catch

View File

@@ -0,0 +1,57 @@
/*
* Created by Phil on 04/07/2017.
* Copyright 2017 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_BENCHMARK_H_INCLUDED
#define TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED
#include "catch_stringref.h"
#include "catch_timer.h"
#include <cstdint>
#include <string>
namespace Catch {
class BenchmarkLooper {
std::string m_name;
std::size_t m_count = 0;
std::size_t m_iterationsToRun = 1;
uint64_t m_resolution;
Timer m_timer;
static auto getResolution() -> uint64_t;
public:
// Keep most of this inline as it's on the code path that is being timed
BenchmarkLooper( StringRef name )
: m_name( name ),
m_resolution( getResolution() )
{
reportStart();
m_timer.start();
}
explicit operator bool() {
if( m_count < m_iterationsToRun )
return true;
return needsMoreIterations();
}
void increment() {
++m_count;
}
void reportStart();
auto needsMoreIterations() -> bool;
};
} // end namespace Catch
#define BENCHMARK( name ) \
for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() )
#endif // TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED

View File

@@ -8,20 +8,17 @@
#ifndef TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
#include "catch_result_builder.h"
#include "catch_assertionhandler.h"
#include "catch_message.h"
#include "catch_interfaces_capture.h"
#include "catch_debugger.h"
#include "catch_common.h"
#include "catch_tostring.h"
#include "catch_interfaces_runner.h"
#include "catch_compiler_capabilities.h"
#if !defined(CATCH_CONFIG_DISABLE)
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
# define CATCH_INTERNAL_STRINGIFY(expr) #expr
#define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__
#else
# define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
#endif
#if defined(CATCH_CONFIG_FAST_COMPILE)
@@ -29,158 +26,138 @@
// We can speedup compilation significantly by breaking into debugger lower in
// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER
// macro in each assertion
#define INTERNAL_CATCH_REACT( resultBuilder ) \
resultBuilder.react();
#define INTERNAL_CATCH_REACT( handler ) \
handler.reactWithDebugBreak();
///////////////////////////////////////////////////////////////////////////////
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
// macros.
// This can potentially cause false negative, if the test code catches
// the exception before it propagates back up to the runner.
#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
__catchResult.setExceptionGuard(); \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
( __catchResult <= expr ).endExpression(); \
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
__catchResult.unsetExceptionGuard(); \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
#define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard();
#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard();
#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
__catchResult.setExceptionGuard(); \
__catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
__catchResult.unsetExceptionGuard(); \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::alwaysFalse() )
#else // CATCH_CONFIG_FAST_COMPILE
#else
///////////////////////////////////////////////////////////////////////////////
// In the event of a failure works out if the debugger needs to be invoked
// and/or an exception thrown and takes appropriate action.
// This needs to be done as a macro so the debugger will stop in the user
// source code rather than in Catch library code
#define INTERNAL_CATCH_REACT( resultBuilder ) \
if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
resultBuilder.react();
#define INTERNAL_CATCH_REACT( handler ) \
if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
handler.reactWithoutDebugBreak();
#define INTERNAL_CATCH_TRY( capturer ) try
#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); }
#endif
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
try { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
INTERNAL_CATCH_TRY( catchAssertionHandler ) { \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
( __catchResult <= expr ).endExpression(); \
catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
} \
catch( ... ) { \
__catchResult.useActiveException( resultDisposition ); \
} \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( Catch::isTrue( false && static_cast<bool>( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
if( Catch::getResultCapture().lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
if( !Catch::getResultCapture().lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
try { \
static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
static_cast<void>(__VA_ARGS__); \
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
} \
catch( ... ) { \
__catchResult.useActiveException( resultDisposition ); \
catchAssertionHandler.useActiveException(); \
} \
INTERNAL_CATCH_REACT( __catchResult ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( Catch::alwaysFalse() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \
if( __catchResult.allowThrows() ) \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
static_cast<void>(__VA_ARGS__); \
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
} \
catch( ... ) { \
__catchResult.captureExpectedException( matcher ); \
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
} \
else \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
INTERNAL_CATCH_REACT( __catchResult ) \
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( Catch::alwaysFalse() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
if( __catchResult.allowThrows() ) \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
} \
catch( exceptionType ) { \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
catch( exceptionType const& ) { \
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
} \
catch( ... ) { \
__catchResult.useActiveException( resultDisposition ); \
catchAssertionHandler.useActiveException(); \
} \
else \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
INTERNAL_CATCH_REACT( __catchResult ) \
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( Catch::alwaysFalse() )
///////////////////////////////////////////////////////////////////////////////
#ifdef CATCH_CONFIG_VARIADIC_MACROS
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
__catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
__catchResult.captureResult( messageType ); \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::alwaysFalse() )
#else
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
__catchResult << log + ::Catch::StreamEndStop(); \
__catchResult.captureResult( messageType ); \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::alwaysFalse() )
#endif
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( Catch::alwaysFalse() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_INFO( macroName, log ) \
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
// Although this is matcher-based, it can be used with just a string
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
try { \
__catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
} catch( ... ) { \
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
} \
INTERNAL_CATCH_REACT( __catchResult ) \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(__VA_ARGS__); \
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
} \
catch( ... ) { \
handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
} \
else \
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( Catch::alwaysFalse() )
#endif // CATCH_CONFIG_DISABLE
#endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED

View File

@@ -0,0 +1,24 @@
/*
* Created by Phil on 9/8/2017.
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_capture_matchers.h"
#include "catch_interfaces_registry_hub.h"
namespace Catch {
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
// This is the general overload that takes a any string matcher
// There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers
// the Equals matcher (so the header does not mention matchers)
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
std::string exceptionMessage = Catch::translateActiveException();
MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
handler.handle( expr );
}
} // namespace Catch

View File

@@ -0,0 +1,88 @@
/*
* Created by Phil on 9/8/2017
* Copyright 2017 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_CAPTURE_MATCHERS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED
#include "catch_capture.hpp"
#include "catch_matchers.h"
#include "catch_matchers_string.h"
#include "catch_matchers_vector.h"
namespace Catch {
template<typename ArgT, typename MatcherT>
class MatchExpr : public ITransientExpression {
ArgT const& m_arg;
MatcherT m_matcher;
StringRef m_matcherString;
bool m_result;
public:
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString )
: m_arg( arg ),
m_matcher( matcher ),
m_matcherString( matcherString ),
m_result( matcher.match( arg ) )
{}
auto isBinaryExpression() const -> bool override { return true; }
auto getResult() const -> bool override { return m_result; }
void streamReconstructedExpression( std::ostream &os ) const override {
auto matcherAsString = m_matcher.toString();
os << Catch::Detail::stringify( m_arg ) << ' ';
if( matcherAsString == Detail::unprintableString )
os << m_matcherString;
else
os << matcherAsString;
}
};
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString );
template<typename ArgT, typename MatcherT>
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr<ArgT, MatcherT> {
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
}
} // namespace Catch
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
INTERNAL_CATCH_TRY( catchAssertionHandler ) { \
catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( Catch::alwaysFalse() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(__VA_ARGS__ ); \
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
} \
catch( exceptionType const& ex ) { \
catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
} \
catch( ... ) { \
catchAssertionHandler.useActiveException(); \
} \
else \
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( Catch::alwaysFalse() )
#endif // TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED

View File

@@ -11,21 +11,27 @@
// Use Catch's value for console width (store Clara's off to the side, if present)
#ifdef CLARA_CONFIG_CONSOLE_WIDTH
#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
#undef CLARA_CONFIG_CONSOLE_WIDTH
#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
#endif
#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wweak-vtables"
#pragma clang diagnostic ignored "-Wexit-time-destructors"
#pragma clang diagnostic ignored "-Wshadow"
#endif
// Declare Clara inside the Catch namespace
#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
#include "../external/clara.h"
#undef STITCH_CLARA_OPEN_NAMESPACE
#include "../external/clara.hpp"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
// Restore Clara's value for console width, if present
#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
#endif

View File

@@ -0,0 +1,184 @@
/*
* Created by Phil on 02/11/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_commandline.h"
#include "catch_string_manip.h"
#include <fstream>
#include <ctime>
namespace Catch {
clara::Parser makeCommandLineParser( ConfigData& config ) {
using namespace clara;
auto const setWarning = [&]( std::string const& warning ) {
if( warning != "NoAssertions" )
return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
return ParserResult::ok( ParseResultType::Matched );
};
auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
std::ifstream f( filename.c_str() );
if( !f.is_open() )
return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" );
std::string line;
while( std::getline( f, line ) ) {
line = trim(line);
if( !line.empty() && !startsWith( line, '#' ) ) {
if( !startsWith( line, '"' ) )
line = '"' + line + '"';
config.testsOrTags.push_back( line + ',' );
}
}
return ParserResult::ok( ParseResultType::Matched );
};
auto const setTestOrder = [&]( std::string const& order ) {
if( startsWith( "declared", order ) )
config.runOrder = RunTests::InDeclarationOrder;
else if( startsWith( "lexical", order ) )
config.runOrder = RunTests::InLexicographicalOrder;
else if( startsWith( "random", order ) )
config.runOrder = RunTests::InRandomOrder;
else
return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" );
return ParserResult::ok( ParseResultType::Matched );
};
auto const setRngSeed = [&]( std::string const& seed ) {
if( seed != "time" )
return clara::detail::convertInto( seed, config.rngSeed );
config.rngSeed = static_cast<unsigned int>( std::time(nullptr) );
return ParserResult::ok( ParseResultType::Matched );
};
auto const setColourUsage = [&]( std::string const& useColour ) {
auto mode = toLower( useColour );
if( mode == "yes" )
config.useColour = UseColour::Yes;
else if( mode == "no" )
config.useColour = UseColour::No;
else if( mode == "auto" )
config.useColour = UseColour::Auto;
else
return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" );
return ParserResult::ok( ParseResultType::Matched );
};
auto const setWaitForKeypress = [&]( std::string const& keypress ) {
auto keypressLc = toLower( keypress );
if( keypressLc == "start" )
config.waitForKeypress = WaitForKeypress::BeforeStart;
else if( keypressLc == "exit" )
config.waitForKeypress = WaitForKeypress::BeforeExit;
else if( keypressLc == "both" )
config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
else
return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
return ParserResult::ok( ParseResultType::Matched );
};
auto const setVerbosity = [&]( std::string const& verbosity ) {
auto lcVerbosity = toLower( verbosity );
if( lcVerbosity == "quiet" )
config.verbosity = Verbosity::Quiet;
else if( lcVerbosity == "normal" )
config.verbosity = Verbosity::Normal;
else if( lcVerbosity == "high" )
config.verbosity = Verbosity::High;
else
return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
return ParserResult::ok( ParseResultType::Matched );
};
auto cli
= ExeName( config.processName )
| Help( config.showHelp )
| Opt( config.listTests )
["-l"]["--list-tests"]
( "list all/matching test cases" )
| Opt( config.listTags )
["-t"]["--list-tags"]
( "list all/matching tags" )
| Opt( config.showSuccessfulTests )
["-s"]["--success"]
( "include successful tests in output" )
| Opt( config.shouldDebugBreak )
["-b"]["--break"]
( "break into debugger on failure" )
| Opt( config.noThrow )
["-e"]["--nothrow"]
( "skip exception tests" )
| Opt( config.showInvisibles )
["-i"]["--invisibles"]
( "show invisibles (tabs, newlines)" )
| Opt( config.outputFilename, "filename" )
["-o"]["--out"]
( "output filename" )
| Opt( config.reporterNames, "name" )
["-r"]["--reporter"]
( "reporter to use (defaults to console)" )
| Opt( config.name, "name" )
["-n"]["--name"]
( "suite name" )
| Opt( [&]( bool ){ config.abortAfter = 1; } )
["-a"]["--abort"]
( "abort at first failure" )
| Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
["-x"]["--abortx"]
( "abort after x failures" )
| Opt( setWarning, "warning name" )
["-w"]["--warn"]
( "enable warnings" )
| Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
["-d"]["--durations"]
( "show test durations" )
| Opt( loadTestNamesFromFile, "filename" )
["-f"]["--input-file"]
( "load test names to run from a file" )
| Opt( config.filenamesAsTags )
["-#"]["--filenames-as-tags"]
( "adds a tag for the filename" )
| Opt( config.sectionsToRun, "section name" )
["-c"]["--section"]
( "specify section to run" )
| Opt( setVerbosity, "quiet|normal|high" )
["-v"]["--verbosity"]
( "set output verbosity" )
| Opt( config.listTestNamesOnly )
["--list-test-names-only"]
( "list all/matching test cases names only" )
| Opt( config.listReporters )
["--list-reporters"]
( "list all reporters" )
| Opt( setTestOrder, "decl|lex|rand" )
["--order"]
( "test case order (defaults to decl)" )
| Opt( setRngSeed, "'time'|number" )
["--rng-seed"]
( "set a specific seed for random numbers" )
| Opt( setColourUsage, "yes|no" )
["--use-colour"]
( "should output be colourised" )
| Opt( config.libIdentify )
["--libidentify"]
( "report name and version according to libidentify standard" )
| Opt( setWaitForKeypress, "start|exit|both" )
["--wait-for-keypress"]
( "waits for a keypress before exiting" )
| Opt( config.benchmarkResolutionMultiple, "multiplier" )
["--benchmark-resolution-multiple"]
( "multiple of clock resolution to run benchmarks" )
| Arg( config.testsOrTags, "test name|pattern|tags" )
( "which test or tests to use" );
return cli;
}
} // end namespace Catch

View File

@@ -0,0 +1,20 @@
/*
* Created by Phil on 02/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_COMMANDLINE_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
#include "catch_config.hpp"
#include "catch_clara.h"
namespace Catch {
clara::Parser makeCommandLineParser( ConfigData& config );
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED

View File

@@ -0,0 +1,52 @@
/*
* Created by Phil on 27/11/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_common.h"
#include "catch_context.h"
#include "catch_interfaces_config.h"
#include <cstring>
#include <ostream>
namespace Catch {
SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept
: file( _file ),
line( _line )
{}
bool SourceLineInfo::empty() const noexcept {
return file[0] == '\0';
}
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
}
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
}
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;
}
bool isTrue( bool value ){ return value; }
bool alwaysTrue() { return true; }
bool alwaysFalse() { return false; }
std::string StreamEndStop::operator+() const {
return std::string();
}
NonCopyable::NonCopyable() = default;
NonCopyable::~NonCopyable() = default;
}

View File

@@ -18,95 +18,41 @@
# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
#endif
#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
#include <sstream>
#include <algorithm>
#include <iosfwd>
#include <string>
#include <cstdint>
namespace Catch {
struct IConfig;
struct CaseSensitive { enum Choice {
Yes,
No
}; };
class NonCopyable {
#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
NonCopyable( NonCopyable const& ) = delete;
NonCopyable( NonCopyable && ) = delete;
NonCopyable& operator = ( NonCopyable const& ) = delete;
NonCopyable& operator = ( NonCopyable && ) = delete;
#else
NonCopyable( NonCopyable const& info );
NonCopyable& operator = ( NonCopyable const& );
#endif
protected:
NonCopyable() {}
NonCopyable();
virtual ~NonCopyable();
};
class SafeBool {
public:
typedef void (SafeBool::*type)() const;
static type makeSafe( bool value ) {
return value ? &SafeBool::trueValue : 0;
}
private:
void trueValue() const {}
};
template<typename ContainerT>
void deleteAll( ContainerT& container ) {
typename ContainerT::const_iterator it = container.begin();
typename ContainerT::const_iterator itEnd = container.end();
for(; it != itEnd; ++it )
delete *it;
}
template<typename AssociativeContainerT>
void deleteAllValues( AssociativeContainerT& container ) {
typename AssociativeContainerT::const_iterator it = container.begin();
typename AssociativeContainerT::const_iterator itEnd = container.end();
for(; it != itEnd; ++it )
delete it->second;
}
bool startsWith( std::string const& s, std::string const& prefix );
bool startsWith( std::string const& s, char prefix );
bool endsWith( std::string const& s, std::string const& suffix );
bool endsWith( std::string const& s, char 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 );
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
struct pluralise {
pluralise( std::size_t count, std::string const& label );
friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
std::size_t m_count;
std::string m_label;
};
struct SourceLineInfo {
SourceLineInfo();
SourceLineInfo( char const* _file, std::size_t _line );
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
SourceLineInfo(SourceLineInfo const& other) = default;
SourceLineInfo() = delete;
SourceLineInfo( char const* _file, std::size_t _line ) noexcept;
SourceLineInfo( SourceLineInfo const& other ) = default;
SourceLineInfo( SourceLineInfo && ) = default;
SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
SourceLineInfo& operator = ( SourceLineInfo && ) = default;
# endif
bool empty() const;
bool operator == ( SourceLineInfo const& other ) const;
bool operator < ( SourceLineInfo const& other ) const;
bool empty() const noexcept;
bool operator == ( SourceLineInfo const& other ) const noexcept;
bool operator < ( SourceLineInfo const& other ) const noexcept;
char const* file;
std::size_t line;
@@ -115,23 +61,16 @@ namespace Catch {
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 bool alwaysTrue() { return true; }
inline bool alwaysFalse() { return false; }
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
void seedRng( IConfig const& config );
unsigned int rngSeed();
bool isTrue( bool value );
bool alwaysTrue();
bool alwaysFalse();
// Use this in variadic streaming macros to allow
// >> +StreamEndStop
// as well as
// >> stuff +StreamEndStop
struct StreamEndStop {
std::string operator+() {
return std::string();
}
std::string operator+() const;
};
template<typename T>
T const& operator + ( T const& value, StreamEndStop ) {
@@ -139,8 +78,8 @@ namespace Catch {
}
}
#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
#define CATCH_INTERNAL_LINEINFO \
::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
#endif // TWOBLUECUBES_CATCH_COMMON_H_INCLUDED

View File

@@ -8,23 +8,9 @@
#ifndef TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
// Detect a number of compiler features - by compiler
// The following features are defined:
//
// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported?
// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported?
// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
@@ -34,18 +20,13 @@
// ****************
// In general each macro has a _NO_<feature name> form
// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature.
// Many features, at point of detection, define an _INTERNAL_ macro, so they
// can be combined, en-mass, with the _NO_ forms later.
// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
#ifdef __cplusplus
# if __cplusplus >= 201103L
# define CATCH_CPP11_OR_GREATER
# endif
# if __cplusplus >= 201402L
# define CATCH_CPP14_OR_GREATER
# endif
@@ -54,19 +35,11 @@
#ifdef __clang__
# if __has_feature(cxx_nullptr)
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
# endif
# if __has_feature(cxx_noexcept)
# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
# endif
# if defined(CATCH_CPP11_OR_GREATER)
# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
_Pragma( "clang diagnostic push" ) \
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" )
# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
_Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
_Pragma( "clang diagnostic pop" )
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
@@ -74,7 +47,6 @@
_Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
_Pragma( "clang diagnostic pop" )
# endif
#endif // __clang__
@@ -104,174 +76,34 @@
#endif // __CYGWIN__
////////////////////////////////////////////////////////////////////////////////
// Borland
#ifdef __BORLANDC__
#endif // __BORLANDC__
////////////////////////////////////////////////////////////////////////////////
// EDG
#ifdef __EDG_VERSION__
#endif // __EDG_VERSION__
////////////////////////////////////////////////////////////////////////////////
// Digital Mars
#ifdef __DMC__
#endif // __DMC__
////////////////////////////////////////////////////////////////////////////////
// GCC
#ifdef __GNUC__
# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
# endif
// - otherwise more recent versions define __cplusplus >= 201103L
// and will get picked up below
#endif // __GNUC__
////////////////////////////////////////////////////////////////////////////////
// Visual C++
#ifdef _MSC_VER
#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
#if (_MSC_VER >= 1600)
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
#endif
#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
#endif
// Universal Windows platform does not support SEH
// Or console colours (or console at all...)
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
# define CATCH_CONFIG_COLOUR_NONE
# else
# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
# endif
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
// Use variadic macros if the compiler supports them
#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
( defined __GNUC__ && __GNUC__ >= 3 ) || \
( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
#endif
// Use __COUNTER__ if the compiler supports it
#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \
( defined __clang__ && __clang_major__ >= 3 )
// Use of __COUNTER__ is suppressed during code analysis in CLion/AppCode 2017.2.x and former,
// because __COUNTER__ is not properly handled by it.
// This does not affect compilation
#if ( !defined __JETBRAINS_IDE__ || __JETBRAINS_IDE__ >= 20170300L )
// Use of __COUNTER__ is suppressed during code analysis in
// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly
// handled by it.
// Otherwise all supported compilers support COUNTER macro,
// but user still might want to turn it off
#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
#define CATCH_INTERNAL_CONFIG_COUNTER
#endif
#endif
////////////////////////////////////////////////////////////////////////////////
// C++ language feature support
// catch all support for C++11
#if defined(CATCH_CPP11_OR_GREATER)
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
# endif
# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
# endif
# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
# endif
# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
# endif
# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
# endif
# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
# endif
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
# endif
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
# endif
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
# endif
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE)
# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
# endif
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS)
# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
# endif
#endif // __cplusplus >= 201103L
// Now set the actual defines based on the above + anything the user has configured
#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_NULLPTR
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_NOEXCEPT
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_GENERATED_METHODS
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_IS_ENUM
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_TUPLE
#endif
#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
# define CATCH_CONFIG_VARIADIC_MACROS
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_LONG_LONG
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_OVERRIDE
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_UNIQUE_PTR
#endif
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
# define CATCH_CONFIG_COUNTER
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_SHUFFLE
#endif
# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_TYPE_TRAITS
# endif
#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
# define CATCH_CONFIG_WINDOWS_SEH
#endif
@@ -284,40 +116,11 @@
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
#endif
// noexcept support:
#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
# define CATCH_NOEXCEPT noexcept
# define CATCH_NOEXCEPT_IS(x) noexcept(x)
#else
# define CATCH_NOEXCEPT throw()
# define CATCH_NOEXCEPT_IS(x)
#endif
// nullptr support
#ifdef CATCH_CONFIG_CPP11_NULLPTR
# define CATCH_NULL nullptr
#else
# define CATCH_NULL NULL
#endif
// override support
#ifdef CATCH_CONFIG_CPP11_OVERRIDE
# define CATCH_OVERRIDE override
#else
# define CATCH_OVERRIDE
#endif
// unique_ptr support
#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
# define CATCH_AUTO_PTR( T ) std::unique_ptr<T>
#else
# define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
#endif
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED

View File

@@ -0,0 +1,73 @@
/*
* Created by Martin on 19/07/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_config.hpp"
#include "catch_enforce.h"
#include "catch_stream.h"
namespace Catch {
Config::Config( ConfigData const& data )
: m_data( data ),
m_stream( openStream() )
{
if( !data.testsOrTags.empty() ) {
TestSpecParser parser( ITagAliasRegistry::get() );
for( auto const& testOrTags : data.testsOrTags )
parser.parse( testOrTags );
m_testSpec = parser.testSpec();
}
}
std::string const& Config::getFilename() const {
return m_data.outputFilename ;
}
bool Config::listTests() const { return m_data.listTests; }
bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; }
bool Config::listTags() const { return m_data.listTags; }
bool Config::listReporters() const { return m_data.listReporters; }
std::string Config::getProcessName() const { return m_data.processName; }
std::vector<std::string> const& Config::getReporterNames() const { return m_data.reporterNames; }
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
TestSpec const& Config::testSpec() const { return m_testSpec; }
bool Config::showHelp() const { return m_data.showHelp; }
// IConfig interface
bool Config::allowThrows() const { return !m_data.noThrow; }
std::ostream& Config::stream() const { return m_stream->stream(); }
std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; }
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
int Config::abortAfter() const { return m_data.abortAfter; }
bool Config::showInvisibles() const { return m_data.showInvisibles; }
Verbosity Config::verbosity() const { return m_data.verbosity; }
IStream const* Config::openStream() {
if( m_data.outputFilename.empty() )
return new CoutStream();
else if( m_data.outputFilename[0] == '%' ) {
if( m_data.outputFilename == "%debug" )
return new DebugOutStream();
else
CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" );
}
else
return new FileStream( m_data.outputFilename );
}
} // end namespace Catch

View File

@@ -8,15 +8,15 @@
#ifndef TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
#include "catch_test_spec_parser.hpp"
#include "catch_context.h"
#include "catch_test_spec_parser.h"
#include "catch_interfaces_config.h"
// Libstdc++ doesn't like incomplete classes for unique_ptr
#include "catch_stream.h"
#include <memory>
#include <vector>
#include <string>
#include <stdexcept>
#ifndef CATCH_CONFIG_CONSOLE_WIDTH
#define CATCH_CONFIG_CONSOLE_WIDTH 80
@@ -24,54 +24,32 @@
namespace Catch {
struct IStream;
struct ConfigData {
bool listTests = false;
bool listTags = false;
bool listReporters = false;
bool listTestNamesOnly = false;
ConfigData()
: listTests( false ),
listTags( false ),
listReporters( false ),
listTestNamesOnly( false ),
listExtraInfo( false ),
showSuccessfulTests( false ),
shouldDebugBreak( false ),
noThrow( false ),
showHelp( false ),
showInvisibles( false ),
filenamesAsTags( false ),
libIdentify( false ),
abortAfter( -1 ),
rngSeed( 0 ),
verbosity( Verbosity::Normal ),
warnings( WarnAbout::Nothing ),
showDurations( ShowDurations::DefaultForReporter ),
runOrder( RunTests::InDeclarationOrder ),
useColour( UseColour::Auto ),
waitForKeypress( WaitForKeypress::Never )
{}
bool showSuccessfulTests = false;
bool shouldDebugBreak = false;
bool noThrow = false;
bool showHelp = false;
bool showInvisibles = false;
bool filenamesAsTags = false;
bool libIdentify = false;
bool listTests;
bool listTags;
bool listReporters;
bool listTestNamesOnly;
bool listExtraInfo;
int abortAfter = -1;
unsigned int rngSeed = 0;
int benchmarkResolutionMultiple = 100;
bool showSuccessfulTests;
bool shouldDebugBreak;
bool noThrow;
bool showHelp;
bool showInvisibles;
bool filenamesAsTags;
bool libIdentify;
int abortAfter;
unsigned int rngSeed;
Verbosity::Level verbosity;
WarnAbout::What warnings;
ShowDurations::OrNot showDurations;
RunTests::InWhatOrder runOrder;
UseColour::YesOrNo useColour;
WaitForKeypress::When waitForKeypress;
Verbosity verbosity = Verbosity::Normal;
WarnAbout::What warnings = WarnAbout::Nothing;
ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
UseColour::YesOrNo useColour = UseColour::Auto;
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
std::string outputFilename;
std::string name;
@@ -83,80 +61,51 @@ namespace Catch {
};
class Config : public SharedImpl<IConfig> {
private:
Config( Config const& other );
Config& operator = ( Config const& other );
virtual void dummy();
class Config : public IConfig {
public:
Config()
{}
Config() = default;
Config( ConfigData const& data );
virtual ~Config() = default;
Config( ConfigData const& data )
: m_data( data ),
m_stream( openStream() )
{
if( !data.testsOrTags.empty() ) {
TestSpecParser parser( ITagAliasRegistry::get() );
for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
parser.parse( data.testsOrTags[i] );
m_testSpec = parser.testSpec();
}
}
std::string const& getFilename() const;
virtual ~Config() {}
bool listTests() const;
bool listTestNamesOnly() const;
bool listTags() const;
bool listReporters() const;
std::string const& getFilename() const {
return m_data.outputFilename ;
}
std::string getProcessName() const;
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; }
bool listExtraInfo() const { return m_data.listExtraInfo; }
std::vector<std::string> const& getReporterNames() const;
std::vector<std::string> const& getSectionsToRun() const override;
std::string getProcessName() const { return m_data.processName; }
virtual TestSpec const& testSpec() const override;
std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; }
bool showHelp() const { return m_data.showHelp; }
bool showHelp() const;
// IConfig interface
virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; }
virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); }
virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; }
virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; }
virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; }
virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; }
virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; }
virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; }
virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; }
virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; }
virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; }
virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; }
bool allowThrows() const override;
std::ostream& stream() const override;
std::string name() const override;
bool includeSuccessfulResults() const override;
bool warnAboutMissingAssertions() const override;
ShowDurations::OrNot showDurations() const override;
RunTests::InWhatOrder runOrder() const override;
unsigned int rngSeed() const override;
int benchmarkResolutionMultiple() const override;
UseColour::YesOrNo useColour() const override;
bool shouldDebugBreak() const override;
int abortAfter() const override;
bool showInvisibles() const override;
Verbosity verbosity() const override;
private:
IStream const* openStream() {
if( m_data.outputFilename.empty() )
return new CoutStream();
else if( m_data.outputFilename[0] == '%' ) {
if( m_data.outputFilename == "%debug" )
return new DebugOutStream();
else
throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
}
else
return new FileStream( m_data.outputFilename );
}
IStream const* openStream();
ConfigData m_data;
CATCH_AUTO_PTR( IStream const ) m_stream;
std::unique_ptr<IStream const> m_stream;
TestSpec m_testSpec;
};

View File

@@ -5,17 +5,29 @@
* 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_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
#include "catch_console_colour.hpp"
#include "catch_errno_guard.hpp"
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wexit-time-destructors"
#endif
#include "catch_console_colour.h"
#include "catch_enforce.h"
#include "catch_errno_guard.h"
#include "catch_interfaces_config.h"
#include "catch_stream.h"
#include "catch_context.h"
#include "catch_platform.h"
#include "catch_debugger.h"
#include "catch_windows_h_proxy.h"
namespace Catch {
namespace {
struct IColourImpl {
virtual ~IColourImpl() {}
virtual ~IColourImpl() = default;
virtual void use( Colour::Code _colourCode ) = 0;
};
@@ -42,8 +54,6 @@ namespace Catch {
#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
#include "catch_windows_h_proxy.h"
namespace Catch {
namespace {
@@ -57,7 +67,7 @@ namespace {
originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
}
virtual void use( Colour::Code _colourCode ) {
virtual void use( Colour::Code _colourCode ) override {
switch( _colourCode ) {
case Colour::None: return setTextAttribute( originalForegroundAttributes );
case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
@@ -73,7 +83,7 @@ namespace {
case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
case Colour::Bright: throw std::logic_error( "not a colour" );
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
}
}
@@ -89,14 +99,12 @@ namespace {
IColourImpl* platformColourInstance() {
static Win32ColourImpl s_instance;
Ptr<IConfig const> config = getCurrentContext().getConfig();
IConfigPtr config = getCurrentContext().getConfig();
UseColour::YesOrNo colourMode = config
? config->useColour()
: UseColour::Auto;
if( colourMode == UseColour::Auto )
colourMode = !isDebuggerActive()
? UseColour::Yes
: UseColour::No;
colourMode = UseColour::Yes;
return colourMode == UseColour::Yes
? &s_instance
: NoColourImpl::instance();
@@ -118,7 +126,7 @@ namespace {
// https://github.com/philsquared/Catch/pull/131
class PosixColourImpl : public IColourImpl {
public:
virtual void use( Colour::Code _colourCode ) {
virtual void use( Colour::Code _colourCode ) override {
switch( _colourCode ) {
case Colour::None:
case Colour::White: return setColour( "[0m" );
@@ -134,7 +142,7 @@ namespace {
case Colour::BrightGreen: return setColour( "[1;32m" );
case Colour::BrightWhite: return setColour( "[1;37m" );
case Colour::Bright: throw std::logic_error( "not a colour" );
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
}
}
static IColourImpl* instance() {
@@ -148,14 +156,21 @@ namespace {
}
};
bool useColourOnPlatform() {
return
#ifdef CATCH_PLATFORM_MAC
!isDebuggerActive() &&
#endif
isatty(STDOUT_FILENO);
}
IColourImpl* platformColourInstance() {
ErrnoGuard guard;
Ptr<IConfig const> config = getCurrentContext().getConfig();
IConfigPtr config = getCurrentContext().getConfig();
UseColour::YesOrNo colourMode = config
? config->useColour()
: UseColour::Auto;
if( colourMode == UseColour::Auto )
colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
colourMode = useColourOnPlatform()
? UseColour::Yes
: UseColour::No;
return colourMode == UseColour::Yes
@@ -178,8 +193,17 @@ namespace Catch {
namespace Catch {
Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
Colour::Colour( Colour&& rhs ) noexcept {
m_moved = rhs.m_moved;
rhs.m_moved = true;
}
Colour& Colour::operator=( Colour&& rhs ) noexcept {
m_moved = rhs.m_moved;
rhs.m_moved = true;
return *this;
}
Colour::~Colour(){ if( !m_moved ) use( None ); }
void Colour::use( Code _colourCode ) {
@@ -187,6 +211,13 @@ namespace Catch {
impl->use( _colourCode );
}
std::ostream& operator << ( std::ostream& os, Colour const& ) {
return os;
}
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
#if defined(__clang__)
# pragma clang diagnostic pop
#endif

View File

@@ -50,17 +50,18 @@ namespace Catch {
// Use constructed object for RAII guard
Colour( Code _colourCode );
Colour( Colour const& other );
Colour( Colour&& other ) noexcept;
Colour& operator=( Colour&& other ) noexcept;
~Colour();
// Use static method for one-shot changes
static void use( Code _colourCode );
private:
bool m_moved;
bool m_moved = false;
};
inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
std::ostream& operator << ( std::ostream& os, Colour const& );
} // end namespace Catch

View File

@@ -0,0 +1,67 @@
/*
* Created by Phil on 31/12/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_context.h"
#include "catch_common.h"
namespace Catch {
class Context : public IMutableContext, NonCopyable {
public: // IContext
virtual IResultCapture* getResultCapture() override {
return m_resultCapture;
}
virtual IRunner* getRunner() override {
return m_runner;
}
virtual IConfigPtr getConfig() const override {
return m_config;
}
virtual ~Context() override;
public: // IMutableContext
virtual void setResultCapture( IResultCapture* resultCapture ) override {
m_resultCapture = resultCapture;
}
virtual void setRunner( IRunner* runner ) override {
m_runner = runner;
}
virtual void setConfig( IConfigPtr const& config ) override {
m_config = config;
}
friend IMutableContext& getCurrentMutableContext();
private:
IConfigPtr m_config;
IRunner* m_runner = nullptr;
IResultCapture* m_resultCapture = nullptr;
};
namespace {
Context* currentContext = nullptr;
}
IMutableContext& getCurrentMutableContext() {
if( !currentContext )
currentContext = new Context();
return *currentContext;
}
IContext& getCurrentContext() {
return getCurrentMutableContext();
}
void cleanUpContext() {
delete currentContext;
currentContext = nullptr;
}
IContext::~IContext() = default;
IMutableContext::~IMutableContext() = default;
Context::~Context() = default;
}

View File

@@ -8,28 +8,23 @@
#ifndef TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
#include "catch_interfaces_generators.h"
#include "catch_ptr.hpp"
#include <memory>
namespace Catch {
class TestCase;
class Stream;
struct IResultCapture;
struct IRunner;
struct IGeneratorsForTest;
struct IConfig;
using IConfigPtr = std::shared_ptr<IConfig const>;
struct IContext
{
virtual ~IContext();
virtual IResultCapture* getResultCapture() = 0;
virtual IRunner* getRunner() = 0;
virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
virtual bool advanceGeneratorsForCurrentTest() = 0;
virtual Ptr<IConfig const> getConfig() const = 0;
virtual IConfigPtr getConfig() const = 0;
};
struct IMutableContext : IContext
@@ -37,14 +32,12 @@ namespace Catch {
virtual ~IMutableContext();
virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
virtual void setRunner( IRunner* runner ) = 0;
virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
virtual void setConfig( IConfigPtr const& config ) = 0;
};
IContext& getCurrentContext();
IMutableContext& getCurrentMutableContext();
void cleanUpContext();
Stream createStream( std::string const& streamName );
}
#endif // TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED

View File

@@ -1,110 +0,0 @@
/*
* Created by Phil on 31/12/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_CONTEXT_IMPL_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
#include "catch_run_context.hpp"
#include "catch_context.h"
#include "catch_stream.hpp"
#include "catch_common.h"
namespace Catch {
class Context : public IMutableContext {
Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {}
Context( Context const& );
void operator=( Context const& );
public:
virtual ~Context() {
deleteAllValues( m_generatorsByTestName );
}
public: // IContext
virtual IResultCapture* getResultCapture() {
return m_resultCapture;
}
virtual IRunner* getRunner() {
return m_runner;
}
virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
return getGeneratorsForCurrentTest()
.getGeneratorInfo( fileInfo, totalSize )
.getCurrentIndex();
}
virtual bool advanceGeneratorsForCurrentTest() {
IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
return generators && generators->moveNext();
}
virtual Ptr<IConfig const> getConfig() const {
return m_config;
}
public: // IMutableContext
virtual void setResultCapture( IResultCapture* resultCapture ) {
m_resultCapture = resultCapture;
}
virtual void setRunner( IRunner* runner ) {
m_runner = runner;
}
virtual void setConfig( Ptr<IConfig const> const& config ) {
m_config = config;
}
friend IMutableContext& getCurrentMutableContext();
private:
IGeneratorsForTest* findGeneratorsForCurrentTest() {
std::string testName = getResultCapture()->getCurrentTestName();
std::map<std::string, IGeneratorsForTest*>::const_iterator it =
m_generatorsByTestName.find( testName );
return it != m_generatorsByTestName.end()
? it->second
: CATCH_NULL;
}
IGeneratorsForTest& getGeneratorsForCurrentTest() {
IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
if( !generators ) {
std::string testName = getResultCapture()->getCurrentTestName();
generators = createGeneratorsForTest();
m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
}
return *generators;
}
private:
Ptr<IConfig const> m_config;
IRunner* m_runner;
IResultCapture* m_resultCapture;
std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
};
namespace {
Context* currentContext = CATCH_NULL;
}
IMutableContext& getCurrentMutableContext() {
if( !currentContext )
currentContext = new Context();
return *currentContext;
}
IContext& getCurrentContext() {
return getCurrentMutableContext();
}
void cleanUpContext() {
delete currentContext;
currentContext = CATCH_NULL;
}
}
#endif // TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED

View File

@@ -0,0 +1,29 @@
/*
* Created by Martin on 29/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#include "catch_debug_console.h"
#include "catch_stream.h"
#include "catch_platform.h"
#ifdef CATCH_PLATFORM_WINDOWS
#include "catch_windows_h_proxy.h"
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
::OutputDebugStringA( text.c_str() );
}
}
#else
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
// !TBD: Need a version for Mac/ XCode and other IDEs
Catch::cout() << text;
}
}
#endif // Platform

View File

@@ -0,0 +1,17 @@
/*
* Created by Martin on 29/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#ifndef TWOBLUECUBES_CATCH_DEBUG_CONSOLE_H_INCLUDED
#define TWOBLUECUBES_CATCH_DEBUG_CONSOLE_H_INCLUDED
#include <string>
namespace Catch {
void writeToDebugConsole( std::string const& text );
}
#endif // TWOBLUECUBES_CATCH_DEBUG_CONSOLE_H_INCLUDED

View File

@@ -6,11 +6,11 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#ifndef TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
#include "catch_debugger.h"
#include "catch_errno_guard.hpp"
#include "catch_errno_guard.h"
#include "catch_stream.h"
#include "catch_platform.h"
#ifdef CATCH_PLATFORM_MAC
@@ -20,7 +20,7 @@
#include <unistd.h>
#include <sys/sysctl.h>
namespace Catch{
namespace Catch {
// The following function is taken directly from the following technical note:
// http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
@@ -31,7 +31,7 @@
int mib[4];
struct kinfo_proc info;
size_t size;
std::size_t size;
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
@@ -49,7 +49,7 @@
// Call sysctl.
size = sizeof(info);
if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) {
if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
return false;
}
@@ -106,26 +106,6 @@
}
#else
namespace Catch {
inline bool isDebuggerActive() { return false; }
bool isDebuggerActive() { return false; }
}
#endif // Platform
#ifdef CATCH_PLATFORM_WINDOWS
#include "catch_windows_h_proxy.h"
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
::OutputDebugStringA( text.c_str() );
}
}
#else
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
// !TBD: Need a version for Mac/ XCode and other IDEs
Catch::cout() << text;
}
}
#endif // Platform
#endif // TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED

View File

@@ -11,25 +11,13 @@
#include "catch_platform.h"
#include <string>
namespace Catch{
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
#if defined(__ppc64__) || defined(__ppc__)
#define CATCH_TRAP() \
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
: : : "memory","r0","r3","r4" ) /* NOLINT */
#else
#define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ )
#endif
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
#elif defined(CATCH_PLATFORM_LINUX)
// If we can use inline assembler, do it because this allows us to break

View File

@@ -0,0 +1,24 @@
/*
* Created by Phil Nash on 8/8/2017.
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_decomposer.h"
#include "catch_config.hpp"
namespace Catch {
ITransientExpression::~ITransientExpression() = default;
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
if( lhs.size() + rhs.size() < 40 &&
lhs.find('\n') == std::string::npos &&
rhs.find('\n') == std::string::npos )
os << lhs << " " << op << " " << rhs;
else
os << lhs << "\n" << op << "\n" << rhs;
}
}

View File

@@ -0,0 +1,169 @@
/*
* Created by Phil Nash on 8/8/2017.
* Copyright 2017 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_DECOMPOSER_H_INCLUDED
#define TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED
#include "catch_tostring.h"
#include "catch_stringref.h"
#include <ostream>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
#pragma warning(disable:4018) // more "signed/unsigned mismatch"
#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
#pragma warning(disable:4180) // qualifier applied to function type has no meaning
#endif
namespace Catch {
struct ITransientExpression {
virtual auto isBinaryExpression() const -> bool = 0;
virtual auto getResult() const -> bool = 0;
virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
// We don't actually need a virtual destructore, but many static analysers
// complain if it's not here :-(
virtual ~ITransientExpression();
};
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
template<typename LhsT, typename RhsT>
class BinaryExpr : public ITransientExpression {
bool m_result;
LhsT m_lhs;
StringRef m_op;
RhsT m_rhs;
auto isBinaryExpression() const -> bool override { return true; }
auto getResult() const -> bool override { return m_result; }
void streamReconstructedExpression( std::ostream &os ) const override {
formatReconstructedExpression
( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
}
public:
BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
: m_result( comparisonResult ),
m_lhs( lhs ),
m_op( op ),
m_rhs( rhs )
{}
};
template<typename LhsT>
class UnaryExpr : public ITransientExpression {
LhsT m_lhs;
auto isBinaryExpression() const -> bool override { return false; }
auto getResult() const -> bool override { return m_lhs ? true : false; }
void streamReconstructedExpression( std::ostream &os ) const override {
os << Catch::Detail::stringify( m_lhs );
}
public:
UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {}
};
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
template<typename LhsT, typename RhsT>
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; };
template<typename T>
auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
template<typename T>
auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
template<typename T>
auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
template<typename T>
auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
template<typename LhsT, typename RhsT>
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; };
template<typename T>
auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
template<typename T>
auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
template<typename T>
auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
template<typename T>
auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
template<typename LhsT>
class ExprLhs {
LhsT m_lhs;
public:
ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
template<typename RhsT>
auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return BinaryExpr<LhsT, RhsT const&>( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs );
}
auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
return BinaryExpr<LhsT, bool>( m_lhs == rhs, m_lhs, "==", rhs );
}
template<typename RhsT>
auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return BinaryExpr<LhsT, RhsT const&>( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs );
}
auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
return BinaryExpr<LhsT, bool>( m_lhs != rhs, m_lhs, "!=", rhs );
}
template<typename RhsT>
auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return BinaryExpr<LhsT, RhsT const&>( m_lhs > rhs, m_lhs, ">", rhs );
}
template<typename RhsT>
auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return BinaryExpr<LhsT, RhsT const&>( m_lhs < rhs, m_lhs, "<", rhs );
}
template<typename RhsT>
auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return BinaryExpr<LhsT, RhsT const&>( m_lhs >= rhs, m_lhs, ">=", rhs );
}
template<typename RhsT>
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return BinaryExpr<LhsT, RhsT const&>( m_lhs <= rhs, m_lhs, "<=", rhs );
}
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
return UnaryExpr<LhsT>( m_lhs );
}
};
void handleExpression( ITransientExpression const& expr );
template<typename T>
void handleExpression( ExprLhs<T> const& expr ) {
handleExpression( expr.makeUnaryExpr() );
}
struct Decomposer {
template<typename T>
auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {
return ExprLhs<T const&>( lhs );
}
auto operator <=( bool value ) -> ExprLhs<bool> {
return ExprLhs<bool>( value );
}
};
} // end namespace Catch
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED

View File

@@ -8,6 +8,8 @@
#ifndef TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
#include "catch_session.h"
#ifndef __OBJC__
#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
@@ -18,8 +20,7 @@ extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
int main (int argc, char * argv[]) {
#endif
int result = Catch::Session().run( argc, argv );
return ( result < 0xff ? result : 0xff );
return Catch::Session().run( argc, argv );
}
#else // __OBJC__
@@ -31,13 +32,13 @@ int main (int argc, char * const argv[]) {
#endif
Catch::registerTestMethods();
int result = Catch::Session().run( argc, (char* const*)argv );
int result = Catch::Session().run( argc, (char**)argv );
#if !CATCH_ARC_ENABLED
[pool drain];
#endif
return ( result < 0xff ? result : 0xff );
return result;
}
#endif // __OBJC__

View File

@@ -0,0 +1,24 @@
/*
* Created by Martin on 01/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
#define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
#include "catch_common.h"
#include <sstream>
#include <stdexcept>
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
type( static_cast<std::ostringstream&&>( std::ostringstream() << msg ).str() )
#define CATCH_INTERNAL_ERROR( msg ) \
throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
#define CATCH_ERROR( msg ) \
throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg )
#define CATCH_ENFORCE( condition, msg ) \
do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
#endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED

View File

@@ -0,0 +1,15 @@
/*
* Created by Martin on 06/03/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_errno_guard.h"
#include <cerrno>
namespace Catch {
ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
}

View File

@@ -4,22 +4,19 @@
* 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_ERRNO_GUARD_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
#include <cerrno>
#ifndef TWOBLUECUBES_CATCH_ERRNO_GUARD_H_INCLUDED
#define TWOBLUECUBES_CATCH_ERRNO_GUARD_H_INCLUDED
namespace Catch {
class ErrnoGuard {
public:
ErrnoGuard():m_oldErrno(errno){}
~ErrnoGuard() { errno = m_oldErrno; }
ErrnoGuard();
~ErrnoGuard();
private:
int m_oldErrno;
};
}
#endif // TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
#endif // TWOBLUECUBES_CATCH_ERRNO_GUARD_H_INCLUDED

View File

@@ -0,0 +1,62 @@
/*
* Created by Phil on 20/04/2011.
* Copyright 2011 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_assertionhandler.h"
#include "catch_exception_translator_registry.h"
#ifdef __OBJC__
#import "Foundation/Foundation.h"
#endif
namespace Catch {
ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
}
void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) {
m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
}
std::string ExceptionTranslatorRegistry::translateActiveException() const {
try {
#ifdef __OBJC__
// In Objective-C try objective-c exceptions first
@try {
return tryTranslators();
}
@catch (NSException *exception) {
return Catch::Detail::stringify( [exception description] );
}
#else
return tryTranslators();
#endif
}
catch( TestFailureException& ) {
std::rethrow_exception(std::current_exception());
}
catch( std::exception& ex ) {
return ex.what();
}
catch( std::string& msg ) {
return msg;
}
catch( const char* msg ) {
return msg;
}
catch(...) {
return "Unknown exception";
}
}
std::string ExceptionTranslatorRegistry::tryTranslators() const {
if( m_translators.empty() )
std::rethrow_exception(std::current_exception());
else
return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
}
}

View File

@@ -0,0 +1,30 @@
/*
* Created by Phil on 20/04/2011.
* Copyright 2011 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_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
#include "catch_interfaces_exception.h"
#include <vector>
#include <string>
#include <memory>
namespace Catch {
class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
public:
~ExceptionTranslatorRegistry();
virtual void registerTranslator( const IExceptionTranslator* translator );
virtual std::string translateActiveException() const override;
std::string tryTranslators() const;
private:
std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators;
};
}
#endif // TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED

View File

@@ -1,73 +0,0 @@
/*
* Created by Phil on 20/04/2011.
* Copyright 2011 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_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
#include "catch_interfaces_exception.h"
#include "catch_tostring.h"
#ifdef __OBJC__
#import "Foundation/Foundation.h"
#endif
namespace Catch {
class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
public:
~ExceptionTranslatorRegistry() {
deleteAll( m_translators );
}
virtual void registerTranslator( const IExceptionTranslator* translator ) {
m_translators.push_back( translator );
}
virtual std::string translateActiveException() const {
try {
#ifdef __OBJC__
// In Objective-C try objective-c exceptions first
@try {
return tryTranslators();
}
@catch (NSException *exception) {
return Catch::toString( [exception description] );
}
#else
return tryTranslators();
#endif
}
catch( TestFailureException& ) {
throw;
}
catch( std::exception& ex ) {
return ex.what();
}
catch( std::string& msg ) {
return msg;
}
catch( const char* msg ) {
return msg;
}
catch(...) {
return "Unknown exception";
}
}
std::string tryTranslators() const {
if( m_translators.empty() )
throw;
else
return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
}
private:
std::vector<const IExceptionTranslator*> m_translators;
};
}
#endif // TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED

View File

@@ -0,0 +1,14 @@
/*
* Created by Martin on 17/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H_INCLUDED
#define TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H_INCLUDED
#include "../reporters/catch_reporter_bases.hpp"
#include "catch_console_colour.h"
#include "catch_reporter_registrars.hpp"
#endif // TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H_INCLUDED

View File

@@ -0,0 +1,176 @@
/*
* Created by Phil on 21/08/2014
* Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#include "catch_fatal_condition.h"
#include "catch_context.h"
#include "catch_interfaces_capture.h"
namespace {
// Report the error condition
void reportFatal( char const * const message ) {
Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
}
}
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
void FatalConditionHandler::reset() {}
}
# else // CATCH_CONFIG_WINDOWS_SEH is defined
namespace Catch {
struct SignalDefs { DWORD id; const char* name; };
// There is no 1-1 mapping between signals and windows exceptions.
// Windows can easily distinguish between SO and SigSegV,
// but SigInt, SigTerm, etc are handled differently.
static SignalDefs signalDefs[] = {
{ EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
{ EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
{ EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
};
LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
for (auto const& def : signalDefs) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
reportFatal(def.name);
}
}
// If its not an exception we care about, pass it along.
// This stops us from eating debugger breaks etc.
return EXCEPTION_CONTINUE_SEARCH;
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
// 32k seems enough for Catch to handle stack overflow,
// but the value was found experimentally, so there is no strong guarantee
guaranteeSize = 32 * 1024;
exceptionHandlerHandle = nullptr;
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
// Pass in guarantee size to be filled
SetThreadStackGuarantee(&guaranteeSize);
}
void FatalConditionHandler::reset() {
if (isSet) {
// Unregister handler and restore the old guarantee
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
SetThreadStackGuarantee(&guaranteeSize);
exceptionHandlerHandle = nullptr;
isSet = false;
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
}
bool FatalConditionHandler::isSet = false;
ULONG FatalConditionHandler::guaranteeSize = 0;
PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
} // namespace Catch
# endif // CATCH_CONFIG_WINDOWS_SEH
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
namespace Catch {
void FatalConditionHandler::reset() {}
}
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
#include <signal.h>
namespace Catch {
struct SignalDefs {
int id;
const char* name;
};
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
{ SIGILL, "SIGILL - Illegal instruction signal" },
{ SIGFPE, "SIGFPE - Floating point error signal" },
{ SIGSEGV, "SIGSEGV - Segmentation violation signal" },
{ SIGTERM, "SIGTERM - Termination request signal" },
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
};
void FatalConditionHandler::handleSignal( int sig ) {
char const * name = "<unknown signal>";
for (auto const& def : signalDefs) {
if (sig == def.id) {
name = def.name;
break;
}
}
reset();
reportFatal(name);
raise( sig );
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
stack_t sigStack;
sigStack.ss_sp = altStackMem;
sigStack.ss_size = SIGSTKSZ;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = { };
sa.sa_handler = handleSignal;
sa.sa_flags = SA_ONSTACK;
for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
}
void FatalConditionHandler::reset() {
if( isSet ) {
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
}
// Return the old stack
sigaltstack(&oldSigStack, nullptr);
isSet = false;
}
}
bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
stack_t FatalConditionHandler::oldSigStack = {};
char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
} // namespace Catch
# endif // CATCH_CONFIG_POSIX_SIGNALS
#endif // not Windows

View File

@@ -0,0 +1,86 @@
/*
* Created by Phil on 21/08/2014
* Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
#include <string>
#include "catch_platform.h"
#include "catch_compiler_capabilities.h"
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
#include "catch_windows_h_proxy.h"
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
struct FatalConditionHandler {
void reset();
};
}
# else // CATCH_CONFIG_WINDOWS_SEH is defined
namespace Catch {
struct FatalConditionHandler {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
FatalConditionHandler();
static void reset();
~FatalConditionHandler();
private:
static bool isSet;
static ULONG guaranteeSize;
static PVOID exceptionHandlerHandle;
};
} // namespace Catch
# endif // CATCH_CONFIG_WINDOWS_SEH
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
namespace Catch {
struct FatalConditionHandler {
void reset();
};
}
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
#include <signal.h>
namespace Catch {
struct FatalConditionHandler {
static bool isSet;
static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)];
static stack_t oldSigStack;
static char altStackMem[];
static void handleSignal( int sig );
FatalConditionHandler();
~FatalConditionHandler();
static void reset();
};
} // namespace Catch
# endif // CATCH_CONFIG_POSIX_SIGNALS
#endif // not Windows
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED

View File

@@ -1,200 +0,0 @@
/*
* Created by Phil on 21/08/2014
* Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
namespace Catch {
// Report the error condition
inline void reportFatal( std::string const& message ) {
IContext& context = Catch::getCurrentContext();
IResultCapture* resultCapture = context.getResultCapture();
resultCapture->handleFatalErrorCondition( message );
}
} // namespace Catch
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
#include "catch_windows_h_proxy.h"
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
struct FatalConditionHandler {
void reset() {}
};
}
# else // CATCH_CONFIG_WINDOWS_SEH is defined
namespace Catch {
struct SignalDefs { DWORD id; const char* name; };
extern SignalDefs signalDefs[];
// There is no 1-1 mapping between signals and windows exceptions.
// Windows can easily distinguish between SO and SigSegV,
// but SigInt, SigTerm, etc are handled differently.
SignalDefs signalDefs[] = {
{ EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
{ EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
{ EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
};
struct FatalConditionHandler {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
reportFatal(signalDefs[i].name);
}
}
// If its not an exception we care about, pass it along.
// This stops us from eating debugger breaks etc.
return EXCEPTION_CONTINUE_SEARCH;
}
FatalConditionHandler() {
isSet = true;
// 32k seems enough for Catch to handle stack overflow,
// but the value was found experimentally, so there is no strong guarantee
guaranteeSize = 32 * 1024;
exceptionHandlerHandle = CATCH_NULL;
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
// Pass in guarantee size to be filled
SetThreadStackGuarantee(&guaranteeSize);
}
static void reset() {
if (isSet) {
// Unregister handler and restore the old guarantee
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
SetThreadStackGuarantee(&guaranteeSize);
exceptionHandlerHandle = CATCH_NULL;
isSet = false;
}
}
~FatalConditionHandler() {
reset();
}
private:
static bool isSet;
static ULONG guaranteeSize;
static PVOID exceptionHandlerHandle;
};
bool FatalConditionHandler::isSet = false;
ULONG FatalConditionHandler::guaranteeSize = 0;
PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
} // namespace Catch
# endif // CATCH_CONFIG_WINDOWS_SEH
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
namespace Catch {
struct FatalConditionHandler {
void reset() {}
};
}
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
#include <signal.h>
namespace Catch {
struct SignalDefs {
int id;
const char* name;
};
extern SignalDefs signalDefs[];
SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
{ SIGILL, "SIGILL - Illegal instruction signal" },
{ SIGFPE, "SIGFPE - Floating point error signal" },
{ SIGSEGV, "SIGSEGV - Segmentation violation signal" },
{ SIGTERM, "SIGTERM - Termination request signal" },
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
};
struct FatalConditionHandler {
static bool isSet;
static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
static stack_t oldSigStack;
static char altStackMem[SIGSTKSZ];
static void handleSignal( int sig ) {
std::string name = "<unknown signal>";
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
SignalDefs &def = signalDefs[i];
if (sig == def.id) {
name = def.name;
break;
}
}
reset();
reportFatal(name);
raise( sig );
}
FatalConditionHandler() {
isSet = true;
stack_t sigStack;
sigStack.ss_sp = altStackMem;
sigStack.ss_size = SIGSTKSZ;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = { 0 };
sa.sa_handler = handleSignal;
sa.sa_flags = SA_ONSTACK;
for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
}
}
~FatalConditionHandler() {
reset();
}
static void reset() {
if( isSet ) {
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
}
// Return the old stack
sigaltstack(&oldSigStack, CATCH_NULL);
isSet = false;
}
}
};
bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
stack_t FatalConditionHandler::oldSigStack = {};
char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
} // namespace Catch
# endif // CATCH_CONFIG_POSIX_SIGNALS
#endif // not Windows
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED

View File

@@ -1,189 +0,0 @@
/*
* Created by Phil on 27/01/2011.
* Copyright 2011 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_GENERATORS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
#include "catch_context.h"
#include <vector>
#include <string>
#include <stdlib.h>
namespace Catch {
template<typename T>
struct IGenerator {
virtual ~IGenerator() {}
virtual T getValue( std::size_t index ) const = 0;
virtual std::size_t size () const = 0;
};
template<typename T>
class BetweenGenerator : public IGenerator<T> {
public:
BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
virtual T getValue( std::size_t index ) const {
return m_from+static_cast<int>( index );
}
virtual std::size_t size() const {
return static_cast<std::size_t>( 1+m_to-m_from );
}
private:
T m_from;
T m_to;
};
template<typename T>
class ValuesGenerator : public IGenerator<T> {
public:
ValuesGenerator(){}
void add( T value ) {
m_values.push_back( value );
}
virtual T getValue( std::size_t index ) const {
return m_values[index];
}
virtual std::size_t size() const {
return m_values.size();
}
private:
std::vector<T> m_values;
};
template<typename T>
class CompositeGenerator {
public:
CompositeGenerator() : m_totalSize( 0 ) {}
// *** Move semantics, similar to auto_ptr ***
CompositeGenerator( CompositeGenerator& other )
: m_fileInfo( other.m_fileInfo ),
m_totalSize( 0 )
{
move( other );
}
CompositeGenerator& setFileInfo( const char* fileInfo ) {
m_fileInfo = fileInfo;
return *this;
}
~CompositeGenerator() {
deleteAll( m_composed );
}
operator T () const {
size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
for( size_t index = 0; it != itEnd; ++it )
{
const IGenerator<T>* generator = *it;
if( overallIndex >= index && overallIndex < index + generator->size() )
{
return generator->getValue( overallIndex-index );
}
index += generator->size();
}
CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
}
void add( const IGenerator<T>* generator ) {
m_totalSize += generator->size();
m_composed.push_back( generator );
}
CompositeGenerator& then( CompositeGenerator& other ) {
move( other );
return *this;
}
CompositeGenerator& then( T value ) {
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
valuesGen->add( value );
add( valuesGen );
return *this;
}
private:
void move( CompositeGenerator& other ) {
m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() );
m_totalSize += other.m_totalSize;
other.m_composed.clear();
}
std::vector<const IGenerator<T>*> m_composed;
std::string m_fileInfo;
size_t m_totalSize;
};
namespace Generators
{
template<typename T>
CompositeGenerator<T> between( T from, T to ) {
CompositeGenerator<T> generators;
generators.add( new BetweenGenerator<T>( from, to ) );
return generators;
}
template<typename T>
CompositeGenerator<T> values( T val1, T val2 ) {
CompositeGenerator<T> generators;
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
valuesGen->add( val1 );
valuesGen->add( val2 );
generators.add( valuesGen );
return generators;
}
template<typename T>
CompositeGenerator<T> values( T val1, T val2, T val3 ){
CompositeGenerator<T> generators;
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
valuesGen->add( val1 );
valuesGen->add( val2 );
valuesGen->add( val3 );
generators.add( valuesGen );
return generators;
}
template<typename T>
CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
CompositeGenerator<T> generators;
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
valuesGen->add( val1 );
valuesGen->add( val2 );
valuesGen->add( val3 );
valuesGen->add( val4 );
generators.add( valuesGen );
return generators;
}
} // end namespace Generators
using namespace Generators;
} // end namespace Catch
#define INTERNAL_CATCH_LINESTR2( line ) #line
#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED

View File

@@ -1,86 +0,0 @@
/*
* Created by Phil on 28/01/2011.
* Copyright 2011 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_GENERATORS_IMPL_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
#include "catch_interfaces_generators.h"
#include "catch_common.h"
#include <vector>
#include <string>
#include <map>
namespace Catch {
struct GeneratorInfo : IGeneratorInfo {
GeneratorInfo( std::size_t size )
: m_size( size ),
m_currentIndex( 0 )
{}
bool moveNext() {
if( ++m_currentIndex == m_size ) {
m_currentIndex = 0;
return false;
}
return true;
}
std::size_t getCurrentIndex() const {
return m_currentIndex;
}
std::size_t m_size;
std::size_t m_currentIndex;
};
///////////////////////////////////////////////////////////////////////////
class GeneratorsForTest : public IGeneratorsForTest {
public:
~GeneratorsForTest() {
deleteAll( m_generatorsInOrder );
}
IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
if( it == m_generatorsByName.end() ) {
IGeneratorInfo* info = new GeneratorInfo( size );
m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
m_generatorsInOrder.push_back( info );
return *info;
}
return *it->second;
}
bool moveNext() {
std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
for(; it != itEnd; ++it ) {
if( (*it)->moveNext() )
return true;
}
return false;
}
private:
std::map<std::string, IGeneratorInfo*> m_generatorsByName;
std::vector<IGeneratorInfo*> m_generatorsInOrder;
};
IGeneratorsForTest* createGeneratorsForTest()
{
return new GeneratorsForTest();
}
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED

View File

@@ -8,99 +8,22 @@
#ifndef TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
// Collect all the implementation files together here
// These are the equivalent of what would usually be cpp files
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wweak-vtables"
#endif
#include "../catch_session.hpp"
#include "catch_registry_hub.hpp"
#include "catch_notimplemented_exception.hpp"
#include "catch_context_impl.hpp"
#include "catch_console_colour_impl.hpp"
#include "catch_generators_impl.hpp"
#include "catch_assertionresult.hpp"
#include "catch_test_case_info.hpp"
#include "catch_test_spec.hpp"
#include "catch_version.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 "catch_tostring.hpp"
#include "catch_result_builder.hpp"
#include "catch_tag_alias_registry.hpp"
#include "catch_test_case_tracker.hpp"
#include "catch_matchers_string.hpp"
// Keep these here for external reporters
#include "catch_test_spec.h"
#include "catch_test_case_tracker.h"
#include "../reporters/catch_reporter_multi.hpp"
#include "../reporters/catch_reporter_xml.hpp"
#include "../reporters/catch_reporter_junit.hpp"
#include "../reporters/catch_reporter_console.hpp"
#include "../reporters/catch_reporter_compact.hpp"
#include "catch_leak_detector.h"
// Cpp files will be included in the single-header file here
// ~*~* CATCH_CPP_STITCH_PLACE *~*~
namespace Catch {
// These are all here to avoid warnings about not having any out of line
// virtual methods
NonCopyable::~NonCopyable() {}
IShared::~IShared() {}
IStream::~IStream() CATCH_NOEXCEPT {}
FileStream::~FileStream() CATCH_NOEXCEPT {}
CoutStream::~CoutStream() CATCH_NOEXCEPT {}
DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
IContext::~IContext() {}
IResultCapture::~IResultCapture() {}
ITestCase::~ITestCase() {}
ITestCaseRegistry::~ITestCaseRegistry() {}
IRegistryHub::~IRegistryHub() {}
IMutableRegistryHub::~IMutableRegistryHub() {}
IExceptionTranslator::~IExceptionTranslator() {}
IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
IReporter::~IReporter() {}
IReporterFactory::~IReporterFactory() {}
IReporterRegistry::~IReporterRegistry() {}
IStreamingReporter::~IStreamingReporter() {}
AssertionStats::~AssertionStats() {}
SectionStats::~SectionStats() {}
TestCaseStats::~TestCaseStats() {}
TestGroupStats::~TestGroupStats() {}
TestRunStats::~TestRunStats() {}
CumulativeReporterBase::SectionNode::~SectionNode() {}
CumulativeReporterBase::~CumulativeReporterBase() {}
StreamingReporterBase::~StreamingReporterBase() {}
ConsoleReporter::~ConsoleReporter() {}
CompactReporter::~CompactReporter() {}
IRunner::~IRunner() {}
IMutableContext::~IMutableContext() {}
IConfig::~IConfig() {}
XmlReporter::~XmlReporter() {}
JunitReporter::~JunitReporter() {}
TestRegistry::~TestRegistry() {}
FreeFunctionTestCase::~FreeFunctionTestCase() {}
IGeneratorInfo::~IGeneratorInfo() {}
IGeneratorsForTest::~IGeneratorsForTest() {}
WildcardPattern::~WildcardPattern() {}
TestSpec::Pattern::~Pattern() {}
TestSpec::NamePattern::~NamePattern() {}
TestSpec::TagPattern::~TagPattern() {}
TestSpec::ExcludedPattern::~ExcludedPattern() {}
Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {}
void Config::dummy() {}
namespace TestCaseTracking {
ITracker::~ITracker() {}
TrackerBase::~TrackerBase() {}
SectionTracker::~SectionTracker() {}
IndexTracker::~IndexTracker() {}
}
LeakDetector leakDetector;
}
#ifdef __clang__

View File

@@ -0,0 +1,5 @@
#include "catch_interfaces_capture.h"
namespace Catch {
IResultCapture::~IResultCapture() = default;
}

View File

@@ -9,29 +9,34 @@
#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
#include <string>
#include "catch_result_type.h"
#include "catch_common.h"
#include "catch_stringref.h"
namespace Catch {
class TestCase;
class AssertionResult;
struct AssertionInfo;
struct SectionInfo;
struct SectionEndInfo;
struct MessageInfo;
class ScopedMessageBuilder;
struct Counts;
struct BenchmarkInfo;
struct BenchmarkStats;
struct IResultCapture {
virtual ~IResultCapture();
virtual void assertionStarting( AssertionInfo const& info ) = 0;
virtual void assertionEnded( AssertionResult const& result ) = 0;
virtual bool sectionStarted( SectionInfo const& sectionInfo,
Counts& assertions ) = 0;
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
virtual void popScopedMessage( MessageInfo const& message ) = 0;
@@ -40,7 +45,7 @@ namespace Catch {
virtual void exceptionEarlyReported() = 0;
virtual void handleFatalErrorCondition( std::string const& message ) = 0;
virtual void handleFatalErrorCondition( StringRef message ) = 0;
virtual bool lastAssertionPassed() = 0;
virtual void assertionPassed() = 0;

View File

@@ -0,0 +1,5 @@
#include "internal/catch_interfaces_config.h"
namespace Catch {
IConfig::~IConfig() = default;
}

View File

@@ -8,19 +8,20 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
#include "catch_common.h"
#include <iosfwd>
#include <string>
#include <vector>
#include "catch_ptr.hpp"
#include <memory>
namespace Catch {
struct Verbosity { enum Level {
NoOutput = 0,
Quiet,
Normal
}; };
enum class Verbosity {
Quiet = 0,
Normal,
High
};
struct WarnAbout { enum What {
Nothing = 0x00,
@@ -51,7 +52,7 @@ namespace Catch {
class TestSpec;
struct IConfig : IShared {
struct IConfig : NonCopyable {
virtual ~IConfig();
@@ -67,10 +68,13 @@ namespace Catch {
virtual TestSpec const& testSpec() const = 0;
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
virtual int benchmarkResolutionMultiple() const = 0;
virtual UseColour::YesOrNo useColour() const = 0;
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
virtual Verbosity verbosity() const = 0;
};
using IConfigPtr = std::shared_ptr<IConfig const>;
}
#endif // TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED

View File

@@ -0,0 +1,6 @@
#include "internal/catch_interfaces_exception.h"
namespace Catch {
IExceptionTranslator::~IExceptionTranslator() = default;
IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
}

View File

@@ -8,17 +8,22 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
#include "catch_interfaces_registry_hub.h"
#if defined(CATCH_CONFIG_DISABLE)
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
static std::string translatorName( signature )
#endif
#include <exception>
#include <string>
#include <vector>
#include "catch_interfaces_registry_hub.h"
namespace Catch {
typedef std::string(*exceptionTranslateFunction)();
using exceptionTranslateFunction = std::string(*)();
struct IExceptionTranslator;
typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>;
struct IExceptionTranslator {
virtual ~IExceptionTranslator();
@@ -40,10 +45,10 @@ namespace Catch {
: m_translateFunction( translateFunction )
{}
virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
try {
if( it == itEnd )
throw;
std::rethrow_exception(std::current_exception());
else
return (*it)->translate( it+1, itEnd );
}

View File

@@ -1,32 +0,0 @@
/*
* Created by Phil on 7/8/2012.
* Copyright 2011 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_INTERFACES_GENERATORS_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
#include <string>
namespace Catch {
struct IGeneratorInfo {
virtual ~IGeneratorInfo();
virtual bool moveNext() = 0;
virtual std::size_t getCurrentIndex() const = 0;
};
struct IGeneratorsForTest {
virtual ~IGeneratorsForTest();
virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
virtual bool moveNext() = 0;
};
IGeneratorsForTest* createGeneratorsForTest();
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED

View File

@@ -0,0 +1,6 @@
#include "internal/catch_interfaces_registry_hub.h"
namespace Catch {
IRegistryHub::~IRegistryHub() = default;
IMutableRegistryHub::~IMutableRegistryHub() = default;
}

View File

@@ -8,9 +8,10 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
#include "catch_ptr.hpp"
#include "catch_common.h"
#include <string>
#include <memory>
namespace Catch {
@@ -21,6 +22,9 @@ namespace Catch {
struct IReporterRegistry;
struct IReporterFactory;
struct ITagAliasRegistry;
class StartupExceptionRegistry;
using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
struct IRegistryHub {
virtual ~IRegistryHub();
@@ -30,15 +34,19 @@ namespace Catch {
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
};
struct IMutableRegistryHub {
virtual ~IMutableRegistryHub();
virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0;
virtual void registerListener( IReporterFactoryPtr const& factory ) = 0;
virtual void registerTest( TestCase const& testInfo ) = 0;
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
virtual void registerStartupException() noexcept = 0;
};
IRegistryHub& getRegistryHub();

View File

@@ -0,0 +1,135 @@
/*
* Created by Martin on 19/07/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_interfaces_reporter.h"
#include "../reporters/catch_reporter_multi.h"
namespace Catch {
ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig )
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream )
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
std::ostream& ReporterConfig::stream() const { return *m_stream; }
IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; }
TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {}
GroupInfo::GroupInfo( std::string const& _name,
std::size_t _groupIndex,
std::size_t _groupsCount )
: name( _name ),
groupIndex( _groupIndex ),
groupsCounts( _groupsCount )
{}
AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
std::vector<MessageInfo> const& _infoMessages,
Totals const& _totals )
: assertionResult( _assertionResult ),
infoMessages( _infoMessages ),
totals( _totals )
{
assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;
if( assertionResult.hasMessage() ) {
// Copy message into messages list.
// !TBD This should have been done earlier, somewhere
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
builder << assertionResult.getMessage();
builder.m_info.message = builder.m_stream.str();
infoMessages.push_back( builder.m_info );
}
}
AssertionStats::~AssertionStats() = default;
SectionStats::SectionStats( SectionInfo const& _sectionInfo,
Counts const& _assertions,
double _durationInSeconds,
bool _missingAssertions )
: sectionInfo( _sectionInfo ),
assertions( _assertions ),
durationInSeconds( _durationInSeconds ),
missingAssertions( _missingAssertions )
{}
SectionStats::~SectionStats() = default;
TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals,
std::string const& _stdOut,
std::string const& _stdErr,
bool _aborting )
: testInfo( _testInfo ),
totals( _totals ),
stdOut( _stdOut ),
stdErr( _stdErr ),
aborting( _aborting )
{}
TestCaseStats::~TestCaseStats() = default;
TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo,
Totals const& _totals,
bool _aborting )
: groupInfo( _groupInfo ),
totals( _totals ),
aborting( _aborting )
{}
TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo )
: groupInfo( _groupInfo ),
aborting( false )
{}
TestGroupStats::~TestGroupStats() = default;
TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
Totals const& _totals,
bool _aborting )
: runInfo( _runInfo ),
totals( _totals ),
aborting( _aborting )
{}
TestRunStats::~TestRunStats() = default;
void IStreamingReporter::fatalErrorEncountered( StringRef ) {}
bool IStreamingReporter::isMulti() const { return false; }
IReporterFactory::~IReporterFactory() = default;
IReporterRegistry::~IReporterRegistry() = default;
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) {
if( !existingReporter ) {
existingReporter = std::move( additionalReporter );
return;
}
MultipleReporters* multi = nullptr;
if( existingReporter->isMulti() ) {
multi = static_cast<MultipleReporters*>( existingReporter.get() );
}
else {
auto newMulti = std::unique_ptr<MultipleReporters>( new MultipleReporters );
newMulti->add( std::move( existingReporter ) );
multi = newMulti.get();
existingReporter = std::move( newMulti );
}
multi->add( std::move( additionalReporter ) );
}
} // end namespace Catch

View File

@@ -10,46 +10,42 @@
#include "catch_section_info.h"
#include "catch_common.h"
#include "catch_totals.hpp"
#include "catch_ptr.hpp"
#include "catch_config.hpp"
#include "catch_totals.h"
#include "catch_test_case_info.h"
#include "catch_assertionresult.h"
#include "catch_message.h"
#include "catch_option.hpp"
#include "catch_stringref.h"
#include <string>
#include <ostream>
#include <iosfwd>
#include <map>
#include <set>
#include <memory>
namespace Catch {
namespace Catch
{
struct ReporterConfig {
explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
explicit ReporterConfig( IConfigPtr const& _fullConfig );
ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream );
std::ostream& stream() const { return *m_stream; }
Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
std::ostream& stream() const;
IConfigPtr fullConfig() const;
private:
std::ostream* m_stream;
Ptr<IConfig const> m_fullConfig;
IConfigPtr m_fullConfig;
};
struct ReporterPreferences {
ReporterPreferences()
: shouldRedirectStdOut( false )
{}
bool shouldRedirectStdOut;
bool shouldRedirectStdOut = false;
};
template<typename T>
struct LazyStat : Option<T> {
LazyStat() : used( false ) {}
LazyStat& operator=( T const& _value ) {
Option<T>::operator=( _value );
used = false;
@@ -59,21 +55,17 @@ namespace Catch
Option<T>::reset();
used = false;
}
bool used;
bool used = false;
};
struct TestRunInfo {
TestRunInfo( std::string const& _name ) : name( _name ) {}
TestRunInfo( std::string const& _name );
std::string name;
};
struct GroupInfo {
GroupInfo( std::string const& _name,
std::size_t _groupIndex,
std::size_t _groupsCount )
: name( _name ),
groupIndex( _groupIndex ),
groupsCounts( _groupsCount )
{}
std::size_t _groupsCount );
std::string name;
std::size_t groupIndex;
@@ -83,29 +75,13 @@ namespace Catch
struct AssertionStats {
AssertionStats( AssertionResult const& _assertionResult,
std::vector<MessageInfo> const& _infoMessages,
Totals const& _totals )
: assertionResult( _assertionResult ),
infoMessages( _infoMessages ),
totals( _totals )
{
if( assertionResult.hasMessage() ) {
// Copy message into messages list.
// !TBD This should have been done earlier, somewhere
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
builder << assertionResult.getMessage();
builder.m_info.message = builder.m_stream.str();
Totals const& _totals );
infoMessages.push_back( builder.m_info );
}
}
virtual ~AssertionStats();
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
AssertionStats( AssertionStats const& ) = default;
AssertionStats( AssertionStats && ) = default;
AssertionStats& operator = ( AssertionStats const& ) = default;
AssertionStats& operator = ( AssertionStats && ) = default;
# endif
virtual ~AssertionStats();
AssertionResult assertionResult;
std::vector<MessageInfo> infoMessages;
@@ -116,19 +92,12 @@ namespace Catch
SectionStats( SectionInfo const& _sectionInfo,
Counts const& _assertions,
double _durationInSeconds,
bool _missingAssertions )
: sectionInfo( _sectionInfo ),
assertions( _assertions ),
durationInSeconds( _durationInSeconds ),
missingAssertions( _missingAssertions )
{}
virtual ~SectionStats();
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
bool _missingAssertions );
SectionStats( SectionStats const& ) = default;
SectionStats( SectionStats && ) = default;
SectionStats& operator = ( SectionStats const& ) = default;
SectionStats& operator = ( SectionStats && ) = default;
# endif
virtual ~SectionStats();
SectionInfo sectionInfo;
Counts assertions;
@@ -141,21 +110,13 @@ namespace Catch
Totals const& _totals,
std::string const& _stdOut,
std::string const& _stdErr,
bool _aborting )
: testInfo( _testInfo ),
totals( _totals ),
stdOut( _stdOut ),
stdErr( _stdErr ),
aborting( _aborting )
{}
virtual ~TestCaseStats();
bool _aborting );
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
TestCaseStats( TestCaseStats const& ) = default;
TestCaseStats( TestCaseStats && ) = default;
TestCaseStats& operator = ( TestCaseStats const& ) = default;
TestCaseStats& operator = ( TestCaseStats && ) = default;
# endif
virtual ~TestCaseStats();
TestCaseInfo testInfo;
Totals totals;
@@ -167,23 +128,14 @@ namespace Catch
struct TestGroupStats {
TestGroupStats( GroupInfo const& _groupInfo,
Totals const& _totals,
bool _aborting )
: groupInfo( _groupInfo ),
totals( _totals ),
aborting( _aborting )
{}
TestGroupStats( GroupInfo const& _groupInfo )
: groupInfo( _groupInfo ),
aborting( false )
{}
virtual ~TestGroupStats();
bool _aborting );
TestGroupStats( GroupInfo const& _groupInfo );
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
TestGroupStats( TestGroupStats const& ) = default;
TestGroupStats( TestGroupStats && ) = default;
TestGroupStats& operator = ( TestGroupStats const& ) = default;
TestGroupStats& operator = ( TestGroupStats && ) = default;
# endif
virtual ~TestGroupStats();
GroupInfo groupInfo;
Totals totals;
@@ -193,38 +145,34 @@ namespace Catch
struct TestRunStats {
TestRunStats( TestRunInfo const& _runInfo,
Totals const& _totals,
bool _aborting )
: runInfo( _runInfo ),
totals( _totals ),
aborting( _aborting )
{}
virtual ~TestRunStats();
bool _aborting );
# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
TestRunStats( TestRunStats const& _other )
: runInfo( _other.runInfo ),
totals( _other.totals ),
aborting( _other.aborting )
{}
# else
TestRunStats( TestRunStats const& ) = default;
TestRunStats( TestRunStats && ) = default;
TestRunStats& operator = ( TestRunStats const& ) = default;
TestRunStats& operator = ( TestRunStats && ) = default;
# endif
virtual ~TestRunStats();
TestRunInfo runInfo;
Totals totals;
bool aborting;
};
class MultipleReporters;
struct BenchmarkInfo {
std::string name;
};
struct BenchmarkStats {
BenchmarkInfo info;
std::size_t iterations;
uint64_t elapsedTimeInNanoseconds;
};
struct IStreamingReporter : IShared {
virtual ~IStreamingReporter();
struct IStreamingReporter {
virtual ~IStreamingReporter() = default;
// Implementing class must also provide the following static method:
// Implementing class must also provide the following static methods:
// static std::string getDescription();
// static std::set<Verbosity> getSupportedVerbosities()
virtual ReporterPreferences getPreferences() const = 0;
@@ -236,11 +184,17 @@ namespace Catch
virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
// *** experimental ***
virtual void benchmarkStarting( BenchmarkInfo const& ) {}
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
// The return value indicates if the messages buffer should be cleared:
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
// *** experimental ***
virtual void benchmarkEnded( BenchmarkStats const& ) {}
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
@@ -248,28 +202,32 @@ namespace Catch
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
// Default empty implementation provided
virtual void fatalErrorEncountered( StringRef name );
virtual bool isMulti() const;
};
using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>;
struct IReporterFactory : IShared {
struct IReporterFactory {
virtual ~IReporterFactory();
virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0;
virtual std::string getDescription() const = 0;
};
using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
struct IReporterRegistry {
typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
typedef std::vector<Ptr<IReporterFactory> > Listeners;
using FactoryMap = std::map<std::string, IReporterFactoryPtr>;
using Listeners = std::vector<IReporterFactoryPtr>;
virtual ~IReporterRegistry();
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0;
virtual FactoryMap const& getFactories() const = 0;
virtual Listeners const& getListeners() const = 0;
};
Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
}
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED

View File

@@ -0,0 +1,5 @@
#include "internal/catch_interfaces_runner.h"
namespace Catch {
IRunner::~IRunner() = default;
}

View File

@@ -9,7 +9,6 @@
#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
namespace Catch {
class TestCase;
struct IRunner {
virtual ~IRunner();

View File

@@ -8,14 +8,16 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
#include "catch_tag_alias.h"
#include "catch_option.hpp"
#include <string>
namespace Catch {
struct TagAlias;
struct ITagAliasRegistry {
virtual ~ITagAliasRegistry();
virtual Option<TagAlias> find( std::string const& alias ) const = 0;
// Nullptr if not present
virtual TagAlias const* find( std::string const& alias ) const = 0;
virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
static ITagAliasRegistry const& get();

View File

@@ -0,0 +1,6 @@
#include "internal/catch_interfaces_testcase.h"
namespace Catch {
ITestInvoker::~ITestInvoker() = default;
ITestCaseRegistry::~ITestCaseRegistry() = default;
}

View File

@@ -8,20 +8,20 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
#include "catch_ptr.hpp"
#include <vector>
#include <memory>
namespace Catch {
class TestSpec;
struct ITestCase : IShared {
struct ITestInvoker {
virtual void invoke () const = 0;
protected:
virtual ~ITestCase();
virtual ~ITestInvoker();
};
using ITestCasePtr = std::shared_ptr<ITestInvoker>;
class TestCase;
struct IConfig;

View File

@@ -0,0 +1,33 @@
/*
* Created by Martin on 12/07/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_leak_detector.h"
namespace Catch {
#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
#include <crtdbg.h>
LeakDetector::LeakDetector() {
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flag |= _CRTDBG_LEAK_CHECK_DF;
flag |= _CRTDBG_ALLOC_MEM_DF;
_CrtSetDbgFlag(flag);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
// Change this to leaking allocation's number to break there
_CrtSetBreakAlloc(-1);
}
#else
LeakDetector::LeakDetector(){}
#endif
}

View File

@@ -0,0 +1,17 @@
/*
* Created by Martin on 12/07/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_LEAK_DETECTOR_H_INCLUDED
#define TWOBLUECUBES_CATCH_LEAK_DETECTOR_H_INCLUDED
namespace Catch {
struct LeakDetector {
LeakDetector();
};
}
#endif // TWOBLUECUBES_CATCH_LEAK_DETECTOR_H_INCLUDED

View File

@@ -1,60 +0,0 @@
/*
* Created by Phil on 6th April 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_LEGACY_REPORTER_ADAPTER_H_INCLUDED
#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
#include "catch_interfaces_reporter.h"
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:
LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
virtual ~LegacyReporterAdapter();
virtual ReporterPreferences getPreferences() const;
virtual void noMatchingTestCases( std::string const& );
virtual void testRunStarting( TestRunInfo const& );
virtual void testGroupStarting( GroupInfo const& groupInfo );
virtual void testCaseStarting( TestCaseInfo const& testInfo );
virtual void sectionStarting( SectionInfo const& sectionInfo );
virtual void assertionStarting( AssertionInfo const& );
virtual bool assertionEnded( AssertionStats const& assertionStats );
virtual void sectionEnded( SectionStats const& sectionStats );
virtual void testCaseEnded( TestCaseStats const& testCaseStats );
virtual void testGroupEnded( TestGroupStats const& testGroupStats );
virtual void testRunEnded( TestRunStats const& testRunStats );
virtual void skipTest( TestCaseInfo const& );
private:
Ptr<IReporter> m_legacyReporter;
};
}
#endif // TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED

View File

@@ -1,84 +0,0 @@
/*
* Created by Phil on 6th April 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_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
#include "catch_legacy_reporter_adapter.h"
namespace Catch
{
LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
: m_legacyReporter( legacyReporter )
{}
LegacyReporterAdapter::~LegacyReporterAdapter() {}
ReporterPreferences LegacyReporterAdapter::getPreferences() const {
ReporterPreferences prefs;
prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
return prefs;
}
void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
m_legacyReporter->StartTesting();
}
void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
m_legacyReporter->StartGroup( groupInfo.name );
}
void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
m_legacyReporter->StartTestCase( testInfo );
}
void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
}
void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
// Not on legacy interface
}
bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
it != itEnd;
++it ) {
if( it->type == ResultWas::Info ) {
ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
rb << it->message;
rb.setResultType( ResultWas::Info );
AssertionResult result = rb.build();
m_legacyReporter->Result( result );
}
}
}
m_legacyReporter->Result( assertionStats.assertionResult );
return true;
}
void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
if( sectionStats.missingAssertions )
m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
}
void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
m_legacyReporter->EndTestCase
( testCaseStats.testInfo,
testCaseStats.totals,
testCaseStats.stdOut,
testCaseStats.stdErr );
}
void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
if( testGroupStats.aborting )
m_legacyReporter->Aborted();
m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
}
void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
m_legacyReporter->EndTesting( testRunStats.totals );
}
void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
}
}
#endif // TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED

View File

@@ -0,0 +1,165 @@
/*
* Created by Phil on 5/11/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_list.h"
#include "catch_interfaces_registry_hub.h"
#include "catch_interfaces_reporter.h"
#include "catch_interfaces_testcase.h"
#include "catch_stream.h"
#include "catch_text.h"
#include "catch_console_colour.h"
#include "catch_test_spec_parser.h"
#include "catch_tostring.h"
#include "catch_string_manip.h"
#include <limits>
#include <algorithm>
#include <iomanip>
namespace Catch {
std::size_t listTests( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( config.testSpec().hasFilters() )
Catch::cout() << "Matching test cases:\n";
else {
Catch::cout() << "All available test cases:\n";
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
}
auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCaseInfo : matchedTestCases ) {
Colour::Code colour = testCaseInfo.isHidden()
? Colour::SecondaryText
: Colour::None;
Colour colourGuard( colour );
Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n";
if( config.verbosity() >= Verbosity::High ) {
Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl;
std::string description = testCaseInfo.description;
if( description.empty() )
description = "(NO DESCRIPTION)";
Catch::cout() << Column( description ).indent(4) << std::endl;
}
if( !testCaseInfo.tags.empty() )
Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
}
if( !config.testSpec().hasFilters() )
Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
else
Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
return matchedTestCases.size();
}
std::size_t listTestsNamesOnly( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( !config.testSpec().hasFilters() )
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCaseInfo : matchedTestCases ) {
matchedTests++;
if( startsWith( testCaseInfo.name, '#' ) )
Catch::cout() << '"' << testCaseInfo.name << '"';
else
Catch::cout() << testCaseInfo.name;
if ( config.verbosity() >= Verbosity::High )
Catch::cout() << "\t@" << testCaseInfo.lineInfo;
Catch::cout() << std::endl;
}
return matchedTests;
}
void TagInfo::add( std::string const& spelling ) {
++count;
spellings.insert( spelling );
}
std::string TagInfo::all() const {
std::string out;
for( auto const& spelling : spellings )
out += "[" + spelling + "]";
return out;
}
std::size_t listTags( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( config.testSpec().hasFilters() )
Catch::cout() << "Tags for matching test cases:\n";
else {
Catch::cout() << "All available tags:\n";
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
}
std::map<std::string, TagInfo> tagCounts;
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCase : matchedTestCases ) {
for( auto const& tagName : testCase.getTestCaseInfo().tags ) {
std::string lcaseTagName = toLower( tagName );
auto countIt = tagCounts.find( lcaseTagName );
if( countIt == tagCounts.end() )
countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
countIt->second.add( tagName );
}
}
for( auto const& tagCount : tagCounts ) {
std::ostringstream oss;
oss << " " << std::setw(2) << tagCount.second.count << " ";
auto wrapper = Column( tagCount.second.all() )
.initialIndent( 0 )
.indent( oss.str().size() )
.width( CATCH_CONFIG_CONSOLE_WIDTH-10 );
Catch::cout() << oss.str() << wrapper << '\n';
}
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
return tagCounts.size();
}
std::size_t listReporters( Config const& /*config*/ ) {
Catch::cout() << "Available reporters:\n";
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
std::size_t maxNameLen = 0;
for( auto const& factoryKvp : factories )
maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() );
for( auto const& factoryKvp : factories ) {
Catch::cout()
<< Column( factoryKvp.first + ":" )
.indent(2)
.width( 5+maxNameLen )
+ Column( factoryKvp.second->getDescription() )
.initialIndent(0)
.indent(2)
.width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 )
<< "\n";
}
Catch::cout() << std::endl;
return factories.size();
}
Option<std::size_t> list( Config const& config ) {
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() )
listedCount = listedCount.valueOr(0) + listReporters( config );
return listedCount;
}
} // end namespace Catch

View File

@@ -0,0 +1,38 @@
/*
* Created by Phil on 5/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_LIST_H_INCLUDED
#define TWOBLUECUBES_CATCH_LIST_H_INCLUDED
#include "catch_option.hpp"
#include "catch_config.hpp"
#include <set>
namespace Catch {
std::size_t listTests( Config const& config );
std::size_t listTestsNamesOnly( Config const& config );
struct TagInfo {
void add( std::string const& spelling );
std::string all() const;
std::set<std::string> spellings;
std::size_t count = 0;
};
std::size_t listTags( Config const& config );
std::size_t listReporters( Config const& /*config*/ );
Option<std::size_t> list( Config const& config );
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_LIST_H_INCLUDED

View File

@@ -1,190 +0,0 @@
/*
* Created by Phil on 5/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_LIST_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
#include "catch_commandline.hpp"
#include "catch_text.h"
#include "catch_console_colour.hpp"
#include "catch_interfaces_reporter.h"
#include "catch_test_spec_parser.hpp"
#include <limits>
#include <algorithm>
namespace Catch {
inline std::size_t listTests( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( config.testSpec().hasFilters() )
Catch::cout() << "Matching test cases:\n";
else {
Catch::cout() << "All available test cases:\n";
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
}
std::size_t matchedTests = 0;
TextAttributes nameAttr, descAttr, tagsAttr;
nameAttr.setInitialIndent( 2 ).setIndent( 4 );
descAttr.setIndent( 4 );
tagsAttr.setIndent( 6 );
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
it != itEnd;
++it ) {
matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
Colour::Code colour = testCaseInfo.isHidden()
? Colour::SecondaryText
: Colour::None;
Colour colourGuard( colour );
Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
if( config.listExtraInfo() ) {
Catch::cout() << " " << testCaseInfo.lineInfo << std::endl;
std::string description = testCaseInfo.description;
if( description.empty() )
description = "(NO DESCRIPTION)";
Catch::cout() << Text( description, descAttr ) << std::endl;
}
if( !testCaseInfo.tags.empty() )
Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
}
if( !config.testSpec().hasFilters() )
Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
else
Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
return matchedTests;
}
inline std::size_t listTestsNamesOnly( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( !config.testSpec().hasFilters() )
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
it != itEnd;
++it ) {
matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
if( startsWith( testCaseInfo.name, '#' ) )
Catch::cout() << '"' << testCaseInfo.name << '"';
else
Catch::cout() << testCaseInfo.name;
if ( config.listExtraInfo() )
Catch::cout() << "\t@" << testCaseInfo.lineInfo;
Catch::cout() << std::endl;
}
return matchedTests;
}
struct TagInfo {
TagInfo() : count ( 0 ) {}
void add( std::string const& spelling ) {
++count;
spellings.insert( spelling );
}
std::string all() const {
std::string out;
for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
it != itEnd;
++it )
out += "[" + *it + "]";
return out;
}
std::set<std::string> spellings;
std::size_t count;
};
inline std::size_t listTags( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( config.testSpec().hasFilters() )
Catch::cout() << "Tags for matching test cases:\n";
else {
Catch::cout() << "All available tags:\n";
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
}
std::map<std::string, TagInfo> tagCounts;
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
it != itEnd;
++it ) {
for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
tagItEnd = it->getTestCaseInfo().tags.end();
tagIt != tagItEnd;
++tagIt ) {
std::string tagName = *tagIt;
std::string lcaseTagName = toLower( tagName );
std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
if( countIt == tagCounts.end() )
countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
countIt->second.add( tagName );
}
}
for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
countItEnd = tagCounts.end();
countIt != countItEnd;
++countIt ) {
std::ostringstream oss;
oss << " " << std::setw(2) << countIt->second.count << " ";
Text wrapper( countIt->second.all(), TextAttributes()
.setInitialIndent( 0 )
.setIndent( oss.str().size() )
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
Catch::cout() << oss.str() << wrapper << '\n';
}
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
return tagCounts.size();
}
inline std::size_t listReporters( Config const& /*config*/ ) {
Catch::cout() << "Available reporters:\n";
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
std::size_t maxNameLen = 0;
for(it = itBegin; it != itEnd; ++it )
maxNameLen = (std::max)( maxNameLen, it->first.size() );
for(it = itBegin; it != itEnd; ++it ) {
Text wrapper( it->second->getDescription(), TextAttributes()
.setInitialIndent( 0 )
.setIndent( 7+maxNameLen )
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
Catch::cout() << " "
<< it->first
<< ':'
<< std::string( maxNameLen - it->first.size() + 2, ' ' )
<< wrapper << '\n';
}
Catch::cout() << std::endl;
return factories.size();
}
inline Option<std::size_t> list( Config const& config ) {
Option<std::size_t> listedCount;
if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) )
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() )
listedCount = listedCount.valueOr(0) + listReporters( config );
return listedCount;
}
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED

View File

@@ -0,0 +1,28 @@
/*
* Created by Phil Nash on 19/07/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_matchers.h"
namespace Catch {
namespace Matchers {
namespace Impl {
std::string MatcherUntypedBase::toString() const {
if( m_cachedToString.empty() )
m_cachedToString = describe();
return m_cachedToString;
}
MatcherUntypedBase::~MatcherUntypedBase() = default;
} // namespace Impl
} // namespace Matchers
using namespace Matchers;
using Matchers::Impl::MatcherBase;
} // namespace Catch

View File

@@ -10,6 +10,9 @@
#include "catch_common.h"
#include <string>
#include <vector>
namespace Catch {
namespace Matchers {
namespace Impl {
@@ -20,18 +23,15 @@ namespace Matchers {
class MatcherUntypedBase {
public:
std::string toString() const {
if( m_cachedToString.empty() )
m_cachedToString = describe();
return m_cachedToString;
}
MatcherUntypedBase() = default;
MatcherUntypedBase ( MatcherUntypedBase const& ) = default;
MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete;
std::string toString() const;
protected:
virtual ~MatcherUntypedBase();
virtual std::string describe() const = 0;
mutable std::string m_cachedToString;
private:
MatcherUntypedBase& operator = ( MatcherUntypedBase const& );
};
template<typename ObjectT>
@@ -54,21 +54,24 @@ namespace Matchers {
template<typename ArgT>
struct MatchAllOf : MatcherBase<ArgT> {
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if (!m_matchers[i]->match(arg))
bool match( ArgT const& arg ) const override {
for( auto matcher : m_matchers ) {
if (!matcher->match(arg))
return false;
}
return true;
}
virtual std::string describe() const CATCH_OVERRIDE {
std::string describe() const override {
std::string description;
description.reserve( 4 + m_matchers.size()*32 );
description += "( ";
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if( i != 0 )
bool first = true;
for( auto matcher : m_matchers ) {
if( first )
first = false;
else
description += " and ";
description += m_matchers[i]->toString();
description += matcher->toString();
}
description += " )";
return description;
@@ -84,21 +87,24 @@ namespace Matchers {
template<typename ArgT>
struct MatchAnyOf : MatcherBase<ArgT> {
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if (m_matchers[i]->match(arg))
bool match( ArgT const& arg ) const override {
for( auto matcher : m_matchers ) {
if (matcher->match(arg))
return true;
}
return false;
}
virtual std::string describe() const CATCH_OVERRIDE {
std::string describe() const override {
std::string description;
description.reserve( 4 + m_matchers.size()*32 );
description += "( ";
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if( i != 0 )
bool first = true;
for( auto matcher : m_matchers ) {
if( first )
first = false;
else
description += " or ";
description += m_matchers[i]->toString();
description += matcher->toString();
}
description += " )";
return description;
@@ -117,11 +123,11 @@ namespace Matchers {
MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
bool match( ArgT const& arg ) const override {
return !m_underlyingMatcher.match( arg );
}
virtual std::string describe() const CATCH_OVERRIDE {
std::string describe() const override {
return "not " + m_underlyingMatcher.toString();
}
MatcherBase<ArgT> const& m_underlyingMatcher;
@@ -142,31 +148,6 @@ namespace Matchers {
} // namespace Impl
// The following functions create the actual matcher objects.
// This allows the types to be inferred
// - deprecated: prefer ||, && and !
template<typename T>
Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
return Impl::MatchNotOf<T>( underlyingMatcher );
}
template<typename T>
Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
return Impl::MatchAllOf<T>() && m1 && m2;
}
template<typename T>
Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
return Impl::MatchAllOf<T>() && m1 && m2 && m3;
}
template<typename T>
Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
return Impl::MatchAnyOf<T>() || m1 || m2;
}
template<typename T>
Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
}
} // namespace Matchers
using namespace Matchers;

View File

@@ -6,7 +6,8 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_matchers.hpp"
#include "catch_matchers_string.h"
#include "catch_string_manip.h"
namespace Catch {
namespace Matchers {

View File

@@ -8,7 +8,9 @@
#ifndef TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
#include "catch_matchers.hpp"
#include "catch_matchers.h"
#include <string>
namespace Catch {
namespace Matchers {
@@ -27,7 +29,7 @@ namespace Matchers {
struct StringMatcherBase : MatcherBase<std::string> {
StringMatcherBase( std::string const& operation, CasedString const& comparator );
virtual std::string describe() const CATCH_OVERRIDE;
std::string describe() const override;
CasedString m_comparator;
std::string m_operation;
@@ -35,19 +37,19 @@ namespace Matchers {
struct EqualsMatcher : StringMatcherBase {
EqualsMatcher( CasedString const& comparator );
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
bool match( std::string const& source ) const override;
};
struct ContainsMatcher : StringMatcherBase {
ContainsMatcher( CasedString const& comparator );
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
bool match( std::string const& source ) const override;
};
struct StartsWithMatcher : StringMatcherBase {
StartsWithMatcher( CasedString const& comparator );
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
bool match( std::string const& source ) const override;
};
struct EndsWithMatcher : StringMatcherBase {
EndsWithMatcher( CasedString const& comparator );
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
bool match( std::string const& source ) const override;
};
} // namespace StdString

View File

@@ -8,7 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
#include "catch_matchers.hpp"
#include "catch_matchers.h"
namespace Catch {
namespace Matchers {
@@ -20,12 +20,17 @@ namespace Matchers {
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
return std::find(v.begin(), v.end(), m_comparator) != v.end();
bool match(std::vector<T> const &v) const override {
for (auto const& el : v) {
if (el == m_comparator) {
return true;
}
}
return false;
}
virtual std::string describe() const CATCH_OVERRIDE {
return "Contains: " + Catch::toString( m_comparator );
std::string describe() const override {
return "Contains: " + ::Catch::Detail::stringify( m_comparator );
}
T const& m_comparator;
@@ -36,17 +41,26 @@ namespace Matchers {
ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
bool match(std::vector<T> const &v) const override {
// !TBD: see note in EqualsMatcher
if (m_comparator.size() > v.size())
return false;
for (size_t i = 0; i < m_comparator.size(); ++i)
if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end())
for (auto const& comparator : m_comparator) {
auto present = false;
for (const auto& el : v) {
if (el == comparator) {
present = true;
break;
}
}
if (!present) {
return false;
}
}
return true;
}
virtual std::string describe() const CATCH_OVERRIDE {
return "Contains: " + Catch::toString( m_comparator );
std::string describe() const override {
return "Contains: " + ::Catch::Detail::stringify( m_comparator );
}
std::vector<T> const& m_comparator;
@@ -57,20 +71,20 @@ namespace Matchers {
EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
bool match(std::vector<T> const &v) const override {
// !TBD: This currently works if all elements can be compared using !=
// - a more general approach would be via a compare template that defaults
// to using !=. but could be specialised for, e.g. std::vector<T> etc
// - then just call that directly
if (m_comparator.size() != v.size())
return false;
for (size_t i = 0; i < v.size(); ++i)
for (std::size_t i = 0; i < v.size(); ++i)
if (m_comparator[i] != v[i])
return false;
return true;
}
virtual std::string describe() const CATCH_OVERRIDE {
return "Equals: " + Catch::toString( m_comparator );
std::string describe() const override {
return "Equals: " + ::Catch::Detail::stringify( m_comparator );
}
std::vector<T> const& m_comparator;
};

View File

@@ -5,10 +5,9 @@
* 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_MESSAGE_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
#include "catch_message.h"
#include "catch_interfaces_capture.h"
namespace Catch {
@@ -21,21 +20,34 @@ namespace Catch {
sequence( ++globalCount )
{}
bool MessageInfo::operator==( MessageInfo const& other ) const {
return sequence == other.sequence;
}
bool MessageInfo::operator<( MessageInfo const& other ) const {
return sequence < other.sequence;
}
// This may need protecting if threading support is added
unsigned int MessageInfo::globalCount = 0;
////////////////////////////////////////////////////////////////////////////
Catch::MessageBuilder::MessageBuilder( std::string const& macroName,
SourceLineInfo const& lineInfo,
ResultWas::OfType type )
:m_info(macroName, lineInfo, type) {}
////////////////////////////////////////////////////////////////////////////
ScopedMessage::ScopedMessage( MessageBuilder const& builder )
: m_info( builder.m_info )
{
m_info.message = builder.m_stream.str();
getResultCapture().pushScopedMessage( m_info );
}
ScopedMessage::ScopedMessage( ScopedMessage const& other )
: m_info( other.m_info )
{}
ScopedMessage::~ScopedMessage() {
if ( !std::uncaught_exception() ){
@@ -45,5 +57,3 @@ namespace Catch {
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED

View File

@@ -9,6 +9,7 @@
#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
#include <string>
#include <sstream>
#include "catch_result_type.h"
#include "catch_common.h"
@@ -20,27 +21,33 @@ namespace Catch {
ResultWas::OfType _type );
std::string macroName;
std::string message;
SourceLineInfo lineInfo;
ResultWas::OfType type;
std::string message;
unsigned int sequence;
bool operator == ( MessageInfo const& other ) const {
return sequence == other.sequence;
}
bool operator < ( MessageInfo const& other ) const {
return sequence < other.sequence;
}
bool operator == ( MessageInfo const& other ) const;
bool operator < ( MessageInfo const& other ) const;
private:
static unsigned int globalCount;
};
struct MessageBuilder {
struct MessageStream {
template<typename T>
MessageStream& operator << ( T const& value ) {
m_stream << value;
return *this;
}
// !TBD reuse a global/ thread-local stream
std::ostringstream m_stream;
};
struct MessageBuilder : MessageStream {
MessageBuilder( std::string const& macroName,
SourceLineInfo const& lineInfo,
ResultWas::OfType type )
: m_info( macroName, lineInfo, type )
{}
ResultWas::OfType type );
template<typename T>
MessageBuilder& operator << ( T const& value ) {
@@ -49,13 +56,11 @@ namespace Catch {
}
MessageInfo m_info;
std::ostringstream m_stream;
};
class ScopedMessage {
public:
ScopedMessage( MessageBuilder const& builder );
ScopedMessage( ScopedMessage const& other );
~ScopedMessage();
MessageInfo m_info;

View File

@@ -1,34 +0,0 @@
/*
* Created by Phil on 5/8/2012.
* Copyright 2012 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
#include "catch_common.h"
namespace Catch {
class NotImplementedException : public std::exception
{
public:
NotImplementedException( SourceLineInfo const& lineInfo );
virtual ~NotImplementedException() CATCH_NOEXCEPT {}
virtual const char* what() const CATCH_NOEXCEPT;
private:
std::string m_what;
SourceLineInfo m_lineInfo;
};
} // end namespace Catch
///////////////////////////////////////////////////////////////////////////////
#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
#endif // TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED

View File

@@ -1,30 +0,0 @@
/*
* Created by Phil on 5/8/2012.
* Copyright 2012 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
#include "catch_notimplemented_exception.h"
#include <sstream>
namespace Catch {
NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
: m_lineInfo( lineInfo ) {
std::ostringstream oss;
oss << lineInfo << ": function ";
oss << "not implemented";
m_what = oss.str();
}
const char* NotImplementedException::what() const CATCH_NOEXCEPT {
return m_what.c_str();
}
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED

View File

@@ -18,6 +18,8 @@
// in catch.hpp first to make sure they are included by the single
// header for non obj-usage
#include "catch_test_case_info.h"
#include "catch_string_manip.h"
#include "catch_tostring.h"
///////////////////////////////////////////////////////////////////////////////
// This protocol is really only here for (self) documenting purposes, since
@@ -33,7 +35,7 @@
namespace Catch {
class OcMethod : public SharedImpl<ITestCase> {
class OcMethod : public ITestInvoker {
public:
OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
@@ -70,9 +72,9 @@ namespace Catch {
}
}
inline size_t registerTestMethods() {
size_t noTestMethods = 0;
int noClasses = objc_getClassList( CATCH_NULL, 0 );
inline std::size_t registerTestMethods() {
std::size_t noTestMethods = 0;
int noClasses = objc_getClassList( nullptr, 0 );
Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
objc_getClassList( classes, noClasses );
@@ -91,7 +93,7 @@ namespace Catch {
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
const char* className = class_getName( cls );
getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) );
noTestMethods++;
}
}
@@ -101,6 +103,8 @@ namespace Catch {
return noTestMethods;
}
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
namespace Matchers {
namespace Impl {
namespace NSStringMatchers {
@@ -112,61 +116,61 @@ namespace Catch {
arcSafeRelease( m_substr );
}
virtual bool match( NSString* arg ) const CATCH_OVERRIDE {
bool match( NSString* arg ) const override {
return false;
}
NSString* m_substr;
NSString* CATCH_ARC_STRONG m_substr;
};
struct Equals : StringHolder {
Equals( NSString* substr ) : StringHolder( substr ){}
virtual bool match( NSString* str ) const CATCH_OVERRIDE {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str isEqualToString:m_substr];
}
virtual std::string describe() const CATCH_OVERRIDE {
return "equals string: " + Catch::toString( m_substr );
std::string describe() const override {
return "equals string: " + Catch::Detail::stringify( m_substr );
}
};
struct Contains : StringHolder {
Contains( NSString* substr ) : StringHolder( substr ){}
virtual bool match( NSString* str ) const {
bool match( NSString* str ) const {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location != NSNotFound;
}
virtual std::string describe() const CATCH_OVERRIDE {
return "contains string: " + Catch::toString( m_substr );
std::string describe() const override {
return "contains string: " + Catch::Detail::stringify( m_substr );
}
};
struct StartsWith : StringHolder {
StartsWith( NSString* substr ) : StringHolder( substr ){}
virtual bool match( NSString* str ) const {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == 0;
}
virtual std::string describe() const CATCH_OVERRIDE {
return "starts with: " + Catch::toString( m_substr );
std::string describe() const override {
return "starts with: " + Catch::Detail::stringify( m_substr );
}
};
struct EndsWith : StringHolder {
EndsWith( NSString* substr ) : StringHolder( substr ){}
virtual bool match( NSString* str ) const {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
}
virtual std::string describe() const CATCH_OVERRIDE {
return "ends with: " + Catch::toString( m_substr );
std::string describe() const override {
return "ends with: " + Catch::Detail::stringify( m_substr );
}
};
@@ -189,18 +193,23 @@ namespace Catch {
using namespace Matchers;
#endif // CATCH_CONFIG_DISABLE_MATCHERS
} // namespace Catch
///////////////////////////////////////////////////////////////////////////////
#define OC_TEST_CASE( name, desc )\
+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
{\
#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix
#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \
+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \
{ \
return @ name; \
}\
+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
} \
+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \
{ \
return @ desc; \
} \
-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix )
#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ )
#endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED

View File

@@ -8,20 +8,18 @@
#ifndef TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
#include "catch_common.h"
namespace Catch {
// An optional type
template<typename T>
class Option {
public:
Option() : nullableValue( CATCH_NULL ) {}
Option() : nullableValue( nullptr ) {}
Option( T const& _value )
: nullableValue( new( storage ) T( _value ) )
{}
Option( Option const& _other )
: nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL )
: nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
{}
~Option() {
@@ -45,7 +43,7 @@ namespace Catch {
void reset() {
if( nullableValue )
nullableValue->~T();
nullableValue = CATCH_NULL;
nullableValue = nullptr;
}
T& operator*() { return *nullableValue; }
@@ -57,27 +55,17 @@ namespace Catch {
return nullableValue ? *nullableValue : defaultValue;
}
bool some() const { return nullableValue != CATCH_NULL; }
bool none() const { return nullableValue == CATCH_NULL; }
bool some() const { return nullableValue != nullptr; }
bool none() const { return nullableValue == nullptr; }
bool operator !() const { return nullableValue == CATCH_NULL; }
operator SafeBool::type() const {
return SafeBool::makeSafe( some() );
bool operator !() const { return nullableValue == nullptr; }
explicit operator bool() const {
return some();
}
private:
T *nullableValue;
union {
char storage[sizeof(T)];
// These are here to force alignment for the storage
long double dummy1;
void (*dummy2)();
long double dummy3;
#ifdef CATCH_CONFIG_CPP11_LONG_LONG
long long dummy4;
#endif
};
alignas(alignof(T)) char storage[sizeof(T)];
};
} // end namespace Catch

View File

@@ -9,20 +9,19 @@
#ifndef TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
#ifdef __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_MAC == 1
# define CATCH_PLATFORM_MAC
#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
# elif TARGET_OS_IPHONE == 1
# define CATCH_PLATFORM_IPHONE
# endif
#elif defined(linux) || defined(__linux) || defined(__linux__)
# define CATCH_PLATFORM_LINUX
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
# define CATCH_PLATFORM_WINDOWS
# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
# define CATCH_DEFINES_NOMINMAX
# endif
# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN
# endif
#endif
#endif // TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED

View File

@@ -1,93 +0,0 @@
/*
* Created by Phil on 02/05/2012.
* Copyright 2012 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
#include "catch_common.h"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpadded"
#endif
namespace Catch {
// An intrusive reference counting smart pointer.
// T must implement addRef() and release() methods
// typically implementing the IShared interface
template<typename T>
class Ptr {
public:
Ptr() : m_p( CATCH_NULL ){}
Ptr( T* p ) : m_p( p ){
if( m_p )
m_p->addRef();
}
Ptr( Ptr const& other ) : m_p( other.m_p ){
if( m_p )
m_p->addRef();
}
~Ptr(){
if( m_p )
m_p->release();
}
void reset() {
if( m_p )
m_p->release();
m_p = CATCH_NULL;
}
Ptr& operator = ( T* p ){
Ptr temp( p );
swap( temp );
return *this;
}
Ptr& operator = ( Ptr const& other ){
Ptr temp( other );
swap( temp );
return *this;
}
void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
T* get() const{ return m_p; }
T& operator*() const { return *m_p; }
T* operator->() const { return m_p; }
bool operator !() const { return m_p == CATCH_NULL; }
operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); }
private:
T* m_p;
};
struct IShared : NonCopyable {
virtual ~IShared();
virtual void addRef() const = 0;
virtual void release() const = 0;
};
template<typename T = IShared>
struct SharedImpl : T {
SharedImpl() : m_rc( 0 ){}
virtual void addRef() const {
++m_rc;
}
virtual void release() const {
if( --m_rc == 0 )
delete this;
}
mutable unsigned int m_rc;
};
} // end namespace Catch
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif // TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED

View File

@@ -0,0 +1,31 @@
/*
* Created by Martin on 30/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_random_number_generator.h"
#include "catch_context.h"
#include "catch_interfaces_config.h"
#include <cstdlib>
namespace Catch {
void seedRng( IConfig const& config ) {
if( config.rngSeed() != 0 )
std::srand( config.rngSeed() );
}
unsigned int rngSeed() {
return getCurrentContext().getConfig()->rngSeed();
}
RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const {
return std::rand() % n;
}
RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const {
return std::rand() % (max)();
}
}

View File

@@ -0,0 +1,40 @@
/*
* Created by Martin on 30/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
#define TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
#include "catch_random_number_generator.h"
#include <algorithm>
namespace Catch {
struct IConfig;
void seedRng( IConfig const& config );
unsigned int rngSeed();
struct RandomNumberGenerator {
using result_type = unsigned int;
static constexpr result_type (min)() { return 0; }
static constexpr result_type (max)() { return 1000000; }
result_type operator()( result_type n ) const;
result_type operator()() const;
template<typename V>
static void shuffle( V& vector ) {
RandomNumberGenerator rng;
std::shuffle( vector.begin(), vector.end(), rng );
}
};
}
#endif // TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED

View File

@@ -5,69 +5,72 @@
* 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_REGISTRY_HUB_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
#include "catch_interfaces_registry_hub.h"
#include "catch_test_case_registry_impl.hpp"
#include "catch_reporter_registry.hpp"
#include "catch_exception_translator_registry.hpp"
#include "catch_context.h"
#include "catch_test_case_registry_impl.h"
#include "catch_reporter_registry.h"
#include "catch_exception_translator_registry.h"
#include "catch_tag_alias_registry.h"
#include "catch_startup_exception_registry.h"
namespace Catch {
namespace {
class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
RegistryHub( RegistryHub const& );
void operator=( RegistryHub const& );
class RegistryHub : public IRegistryHub, public IMutableRegistryHub,
private NonCopyable {
public: // IRegistryHub
RegistryHub() {
}
virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE {
RegistryHub() = default;
IReporterRegistry const& getReporterRegistry() const override {
return m_reporterRegistry;
}
virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE {
ITestCaseRegistry const& getTestCaseRegistry() const override {
return m_testCaseRegistry;
}
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override {
return m_exceptionTranslatorRegistry;
}
virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE {
ITagAliasRegistry const& getTagAliasRegistry() const override {
return m_tagAliasRegistry;
}
StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
return m_exceptionRegistry;
}
public: // IMutableRegistryHub
virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override {
m_reporterRegistry.registerReporter( name, factory );
}
virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
void registerListener( IReporterFactoryPtr const& factory ) override {
m_reporterRegistry.registerListener( factory );
}
virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE {
void registerTest( TestCase const& testInfo ) override {
m_testCaseRegistry.registerTest( testInfo );
}
virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
void registerTranslator( const IExceptionTranslator* translator ) override {
m_exceptionTranslatorRegistry.registerTranslator( translator );
}
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE {
void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
m_tagAliasRegistry.add( alias, tag, lineInfo );
}
void registerStartupException() noexcept override {
m_exceptionRegistry.add(std::current_exception());
}
private:
TestRegistry m_testCaseRegistry;
ReporterRegistry m_reporterRegistry;
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
TagAliasRegistry m_tagAliasRegistry;
StartupExceptionRegistry m_exceptionRegistry;
};
// Single, global, instance
inline RegistryHub*& getTheRegistryHub() {
static RegistryHub* theRegistryHub = CATCH_NULL;
RegistryHub*& getTheRegistryHub() {
static RegistryHub* theRegistryHub = nullptr;
if( !theRegistryHub )
theRegistryHub = new RegistryHub();
return theRegistryHub;
@@ -82,7 +85,7 @@ namespace Catch {
}
void cleanUp() {
delete getTheRegistryHub();
getTheRegistryHub() = CATCH_NULL;
getTheRegistryHub() = nullptr;
cleanUpContext();
}
std::string translateActiveException() {
@@ -91,5 +94,3 @@ namespace Catch {
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED

View File

@@ -1,3 +1,4 @@
/*
* Created by Phil on 31/12/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
@@ -9,51 +10,19 @@
#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
#include "catch_interfaces_registry_hub.h"
#include "catch_legacy_reporter_adapter.h"
namespace Catch {
template<typename T>
class LegacyReporterRegistrar {
class ReporterFactory : public IReporterFactory {
virtual IStreamingReporter* create( ReporterConfig const& config ) const {
return new LegacyReporterAdapter( new T( config ) );
}
virtual std::string getDescription() const {
return T::getDescription();
}
};
public:
LegacyReporterRegistrar( std::string const& name ) {
getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
}
};
template<typename T>
class ReporterRegistrar {
class ReporterFactory : public SharedImpl<IReporterFactory> {
class ReporterFactory : public IReporterFactory {
// *** Please Note ***:
// - If you end up here looking at a compiler error because it's trying to register
// your custom reporter class be aware that the native reporter interface has changed
// to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
// an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
// However please consider updating to the new interface as the old one is now
// deprecated and will probably be removed quite soon!
// Please contact me via github if you have any questions at all about this.
// In fact, ideally, please contact me anyway to let me know you've hit this - as I have
// no idea who is actually using custom reporters at all (possibly no-one!).
// The new interface is designed to minimise exposure to interface changes in the future.
virtual IStreamingReporter* create( ReporterConfig const& config ) const {
return new T( config );
virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override {
return std::unique_ptr<T>( new T( config ) );
}
virtual std::string getDescription() const {
virtual std::string getDescription() const override {
return T::getDescription();
}
};
@@ -61,19 +30,19 @@ namespace Catch {
public:
ReporterRegistrar( std::string const& name ) {
getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() );
}
};
template<typename T>
class ListenerRegistrar {
class ListenerFactory : public SharedImpl<IReporterFactory> {
class ListenerFactory : public IReporterFactory {
virtual IStreamingReporter* create( ReporterConfig const& config ) const {
return new T( config );
virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override {
return std::unique_ptr<T>( new T( config ) );
}
virtual std::string getDescription() const {
virtual std::string getDescription() const override {
return std::string();
}
};
@@ -81,22 +50,27 @@ namespace Catch {
public:
ListenerRegistrar() {
getMutableRegistryHub().registerListener( new ListenerFactory() );
getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() );
}
};
}
#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
#if !defined(CATCH_CONFIG_DISABLE)
#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
// Deprecated - use the form without INTERNAL_
#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
#define CATCH_REGISTER_REPORTER( name, reporterType ) \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
#define CATCH_REGISTER_LISTENER( listenerType ) \
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
#else // CATCH_CONFIG_DISABLE
#define CATCH_REGISTER_REPORTER(name, reporterType)
#define CATCH_REGISTER_LISTENER(listenerType)
#endif // CATCH_CONFIG_DISABLE
#endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED

View File

@@ -0,0 +1,34 @@
/*
* Created by Martin on 31/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_reporter_registry.h"
namespace Catch {
ReporterRegistry::~ReporterRegistry() = default;
IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const {
auto it = m_factories.find( name );
if( it == m_factories.end() )
return nullptr;
return it->second->create( ReporterConfig( config ) );
}
void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) {
m_factories.emplace(name, factory);
}
void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) {
m_listeners.push_back( factory );
}
IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const {
return m_factories;
}
IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const {
return m_listeners;
}
}

View File

@@ -0,0 +1,37 @@
/*
* Created by Phil on 29/10/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_REPORTER_REGISTRY_H_INCLUDED
#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_H_INCLUDED
#include "catch_interfaces_reporter.h"
#include <map>
namespace Catch {
class ReporterRegistry : public IReporterRegistry {
public:
~ReporterRegistry() override;
IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override;
void registerReporter( std::string const& name, IReporterFactoryPtr const& factory );
void registerListener( IReporterFactoryPtr const& factory );
FactoryMap const& getFactories() const override;
Listeners const& getListeners() const override;
private:
FactoryMap m_factories;
Listeners m_listeners;
};
}
#endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRY_H_INCLUDED

View File

@@ -1,50 +0,0 @@
/*
* Created by Phil on 29/10/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
#include "catch_interfaces_reporter.h"
#include <map>
namespace Catch {
class ReporterRegistry : public IReporterRegistry {
public:
virtual ~ReporterRegistry() CATCH_OVERRIDE {}
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
FactoryMap::const_iterator it = m_factories.find( name );
if( it == m_factories.end() )
return CATCH_NULL;
return it->second->create( ReporterConfig( config ) );
}
void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) {
m_factories.insert( std::make_pair( name, factory ) );
}
void registerListener( Ptr<IReporterFactory> const& factory ) {
m_listeners.push_back( factory );
}
virtual FactoryMap const& getFactories() const CATCH_OVERRIDE {
return m_factories;
}
virtual Listeners const& getListeners() const CATCH_OVERRIDE {
return m_listeners;
}
private:
FactoryMap m_factories;
Listeners m_listeners;
};
}
#endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED

View File

@@ -1,133 +0,0 @@
/*
* Created by Phil on 28/5/2014.
* Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
#include "catch_result_type.h"
#include "catch_assertionresult.h"
#include "catch_common.h"
#include "catch_matchers.hpp"
namespace Catch {
struct TestFailureException{};
template<typename T> class ExpressionLhs;
struct CopyableStream {
CopyableStream() {}
CopyableStream( CopyableStream const& other ) {
oss << other.oss.str();
}
CopyableStream& operator=( CopyableStream const& other ) {
oss.str(std::string());
oss << other.oss.str();
return *this;
}
std::ostringstream oss;
};
class ResultBuilder : public DecomposedExpression {
public:
ResultBuilder( char const* macroName,
SourceLineInfo const& lineInfo,
char const* capturedExpression,
ResultDisposition::Flags resultDisposition,
char const* secondArg = "" );
~ResultBuilder();
template<typename T>
ExpressionLhs<T const&> operator <= ( T const& operand );
ExpressionLhs<bool> operator <= ( bool value );
template<typename T>
ResultBuilder& operator << ( T const& value ) {
stream().oss << value;
return *this;
}
ResultBuilder& setResultType( ResultWas::OfType result );
ResultBuilder& setResultType( bool result );
void endExpression( DecomposedExpression const& expr );
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
AssertionResult build() const;
AssertionResult build( DecomposedExpression const& expr ) const;
void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
void captureResult( ResultWas::OfType resultType );
void captureExpression();
void captureExpectedException( std::string const& expectedMessage );
void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher );
void handleResult( AssertionResult const& result );
void react();
bool shouldDebugBreak() const;
bool allowThrows() const;
template<typename ArgT, typename MatcherT>
void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
void setExceptionGuard();
void unsetExceptionGuard();
private:
AssertionInfo m_assertionInfo;
AssertionResultData m_data;
CopyableStream &stream()
{
if(!m_usedStream)
{
m_usedStream = true;
m_stream().oss.str("");
}
return m_stream();
}
static CopyableStream &m_stream()
{
static CopyableStream s;
return s;
}
bool m_shouldDebugBreak;
bool m_shouldThrow;
bool m_guardException;
bool m_usedStream;
};
} // namespace Catch
// Include after due to circular dependency:
#include "catch_expression_lhs.hpp"
namespace Catch {
template<typename T>
ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
return ExpressionLhs<T const&>( *this, operand );
}
inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) {
return ExpressionLhs<bool>( *this, value );
}
template<typename ArgT, typename MatcherT>
void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
char const* matcherString ) {
MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
setResultType( matcher.match( arg ) );
endExpression( expr );
}
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED

View File

@@ -1,173 +0,0 @@
/*
* Created by Phil on 28/5/2014.
* Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
#include "catch_result_builder.h"
#include "catch_context.h"
#include "catch_interfaces_config.h"
#include "catch_interfaces_runner.h"
#include "catch_interfaces_capture.h"
#include "catch_interfaces_registry_hub.h"
#include "catch_wildcard_pattern.hpp"
namespace Catch {
ResultBuilder::ResultBuilder( char const* macroName,
SourceLineInfo const& lineInfo,
char const* capturedExpression,
ResultDisposition::Flags resultDisposition,
char const* secondArg )
: m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ),
m_shouldDebugBreak( false ),
m_shouldThrow( false ),
m_guardException( false ),
m_usedStream( false )
{}
ResultBuilder::~ResultBuilder() {
#if defined(CATCH_CONFIG_FAST_COMPILE)
if ( m_guardException ) {
stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
captureResult( ResultWas::ThrewException );
getCurrentContext().getResultCapture()->exceptionEarlyReported();
}
#endif
}
ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
m_data.resultType = result;
return *this;
}
ResultBuilder& ResultBuilder::setResultType( bool result ) {
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
return *this;
}
void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
// Flip bool results if FalseTest flag is set
if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
m_data.negate( expr.isBinaryExpression() );
}
getResultCapture().assertionRun();
if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok)
{
AssertionResult result = build( expr );
handleResult( result );
}
else
getResultCapture().assertionPassed();
}
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
m_assertionInfo.resultDisposition = resultDisposition;
stream().oss << Catch::translateActiveException();
captureResult( ResultWas::ThrewException );
}
void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
setResultType( resultType );
captureExpression();
}
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
if( expectedMessage.empty() )
captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() );
else
captureExpectedException( Matchers::Equals( expectedMessage ) );
}
void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) {
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
AssertionResultData data = m_data;
data.resultType = ResultWas::Ok;
data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
std::string actualMessage = Catch::translateActiveException();
if( !matcher.match( actualMessage ) ) {
data.resultType = ResultWas::ExpressionFailed;
data.reconstructedExpression = actualMessage;
}
AssertionResult result( m_assertionInfo, data );
handleResult( result );
}
void ResultBuilder::captureExpression() {
AssertionResult result = build();
handleResult( result );
}
void ResultBuilder::handleResult( AssertionResult const& result )
{
getResultCapture().assertionEnded( result );
if( !result.isOk() ) {
if( getCurrentContext().getConfig()->shouldDebugBreak() )
m_shouldDebugBreak = true;
if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) )
m_shouldThrow = true;
}
}
void ResultBuilder::react() {
#if defined(CATCH_CONFIG_FAST_COMPILE)
if (m_shouldDebugBreak) {
///////////////////////////////////////////////////////////////////
// To inspect the state during test, you need to go one level up the callstack
// To go back to the test and change execution, jump over the throw statement
///////////////////////////////////////////////////////////////////
CATCH_BREAK_INTO_DEBUGGER();
}
#endif
if( m_shouldThrow )
throw Catch::TestFailureException();
}
bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
AssertionResult ResultBuilder::build() const
{
return build( *this );
}
// CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
// a temporary DecomposedExpression, which in turn holds references to
// operands, possibly temporary as well.
// It should immediately be passed to handleResult; if the expression
// needs to be reported, its string expansion must be composed before
// the temporaries are destroyed.
AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
{
assert( m_data.resultType != ResultWas::Unknown );
AssertionResultData data = m_data;
if(m_usedStream)
data.message = m_stream().oss.str();
data.decomposedExpression = &expr; // for lazy reconstruction
return AssertionResult( m_assertionInfo, data );
}
void ResultBuilder::reconstructExpression( std::string& dest ) const {
dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
}
void ResultBuilder::setExceptionGuard() {
m_guardException = true;
}
void ResultBuilder::unsetExceptionGuard() {
m_guardException = false;
}
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED

View File

@@ -0,0 +1,28 @@
/*
* Created by Phil on 07/01/2011.
* Copyright 2011 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_result_type.h"
namespace Catch {
bool isOk( ResultWas::OfType resultType ) {
return ( resultType & ResultWas::FailureBit ) == 0;
}
bool isJustInfo( int flags ) {
return flags == ResultWas::Info;
}
ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
}
bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
} // end namespace Catch

View File

@@ -31,12 +31,8 @@ namespace Catch {
}; };
inline bool isOk( ResultWas::OfType resultType ) {
return ( resultType & ResultWas::FailureBit ) == 0;
}
inline bool isJustInfo( int flags ) {
return flags == ResultWas::Info;
}
bool isOk( ResultWas::OfType resultType );
bool isJustInfo( int flags );
// ResultDisposition::Flags enum
@@ -48,13 +44,11 @@ namespace Catch {
SuppressFail = 0x08 // Failures are reported but do not fail the test
}; };
inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
}
ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );
inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
bool shouldContinueOnFailure( int flags );
bool isFalseTest( int flags );
bool shouldSuppressFailure( int flags );
} // end namespace Catch

View File

@@ -0,0 +1,335 @@
#include "catch_run_context.h"
#include "catch_context.h"
#include "catch_enforce.h"
#include "catch_random_number_generator.h"
#include "catch_stream.h"
#include <cassert>
#include <algorithm>
namespace Catch {
StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString)
: m_stream(stream),
m_prevBuf(stream.rdbuf()),
m_targetString(targetString) {
stream.rdbuf(m_oss.rdbuf());
}
StreamRedirect::~StreamRedirect() {
m_targetString += m_oss.str();
m_stream.rdbuf(m_prevBuf);
}
StdErrRedirect::StdErrRedirect(std::string & targetString)
:m_cerrBuf(cerr().rdbuf()), m_clogBuf(clog().rdbuf()),
m_targetString(targetString) {
cerr().rdbuf(m_oss.rdbuf());
clog().rdbuf(m_oss.rdbuf());
}
StdErrRedirect::~StdErrRedirect() {
m_targetString += m_oss.str();
cerr().rdbuf(m_cerrBuf);
clog().rdbuf(m_clogBuf);
}
RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
: m_runInfo(_config->name()),
m_context(getCurrentMutableContext()),
m_config(_config),
m_reporter(std::move(reporter)),
m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal }
{
m_context.setRunner(this);
m_context.setConfig(m_config);
m_context.setResultCapture(this);
m_reporter->testRunStarting(m_runInfo);
}
RunContext::~RunContext() {
m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
}
void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) {
m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));
}
void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) {
m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));
}
Totals RunContext::runTest(TestCase const& testCase) {
Totals prevTotals = m_totals;
std::string redirectedCout;
std::string redirectedCerr;
TestCaseInfo testInfo = testCase.getTestCaseInfo();
m_reporter->testCaseStarting(testInfo);
m_activeTestCase = &testCase;
ITracker& rootTracker = m_trackerContext.startRun();
assert(rootTracker.isSectionTracker());
static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
do {
m_trackerContext.startCycle();
m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));
runCurrentTest(redirectedCout, redirectedCerr);
} while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
Totals deltaTotals = m_totals.delta(prevTotals);
if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
deltaTotals.assertions.failed++;
deltaTotals.testCases.passed--;
deltaTotals.testCases.failed++;
}
m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded(TestCaseStats(testInfo,
deltaTotals,
redirectedCout,
redirectedCerr,
aborting()));
m_activeTestCase = nullptr;
m_testCaseTracker = nullptr;
return deltaTotals;
}
IConfigPtr RunContext::config() const {
return m_config;
}
IStreamingReporter& RunContext::reporter() const {
return *m_reporter;
}
void RunContext::assertionStarting(AssertionInfo const& info) {
m_reporter->assertionStarting( info );
}
void RunContext::assertionEnded(AssertionResult const & result) {
if (result.getResultType() == ResultWas::Ok) {
m_totals.assertions.passed++;
} else if (!result.isOk()) {
if( m_activeTestCase->getTestCaseInfo().okToFail() )
m_totals.assertions.failedButOk++;
else
m_totals.assertions.failed++;
}
// We have no use for the return value (whether messages should be cleared), because messages were made scoped
// and should be let to clear themselves out.
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
// Reset working state
m_lastAssertionInfo = { "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition };
m_lastResult = result;
}
bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {
ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));
if (!sectionTracker.isOpen())
return false;
m_activeSections.push_back(&sectionTracker);
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
m_reporter->sectionStarting(sectionInfo);
assertions = m_totals.assertions;
return true;
}
bool RunContext::testForMissingAssertions(Counts& assertions) {
if (assertions.total() != 0)
return false;
if (!m_config->warnAboutMissingAssertions())
return false;
if (m_trackerContext.currentTracker().hasChildren())
return false;
m_totals.assertions.failed++;
assertions.failed++;
return true;
}
void RunContext::sectionEnded(SectionEndInfo const & endInfo) {
Counts assertions = m_totals.assertions - endInfo.prevAssertions;
bool missingAssertions = testForMissingAssertions(assertions);
if (!m_activeSections.empty()) {
m_activeSections.back()->close();
m_activeSections.pop_back();
}
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
m_messages.clear();
}
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
if (m_unfinishedSections.empty())
m_activeSections.back()->fail();
else
m_activeSections.back()->close();
m_activeSections.pop_back();
m_unfinishedSections.push_back(endInfo);
}
void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
m_reporter->benchmarkStarting( info );
}
void RunContext::benchmarkEnded( BenchmarkStats const& stats ) {
m_reporter->benchmarkEnded( stats );
}
void RunContext::pushScopedMessage(MessageInfo const & message) {
m_messages.push_back(message);
}
void RunContext::popScopedMessage(MessageInfo const & message) {
m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
}
std::string RunContext::getCurrentTestName() const {
return m_activeTestCase
? m_activeTestCase->getTestCaseInfo().name
: std::string();
}
const AssertionResult * RunContext::getLastResult() const {
return &(*m_lastResult);
}
void RunContext::exceptionEarlyReported() {
m_shouldReportUnexpected = false;
}
void RunContext::handleFatalErrorCondition( StringRef message ) {
// First notify reporter that bad things happened
m_reporter->fatalErrorEncountered(message);
// Don't rebuild the result -- the stringification itself can cause more fatal errors
// Instead, fake a result data.
AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
tempResult.message = message;
AssertionResult result(m_lastAssertionInfo, tempResult);
getResultCapture().assertionEnded(result);
handleUnfinishedSections();
// Recreate section for test case (as we will lose the one that was in scope)
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
Counts assertions;
assertions.failed = 1;
SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
m_reporter->sectionEnded(testCaseSectionStats);
auto const& testInfo = m_activeTestCase->getTestCaseInfo();
Totals deltaTotals;
deltaTotals.testCases.failed = 1;
deltaTotals.assertions.failed = 1;
m_reporter->testCaseEnded(TestCaseStats(testInfo,
deltaTotals,
std::string(),
std::string(),
false));
m_totals.testCases.failed++;
testGroupEnded(std::string(), m_totals, 1, 1);
m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
}
bool RunContext::lastAssertionPassed() {
return m_totals.assertions.passed == (m_prevPassed + 1);
}
void RunContext::assertionPassed() {
++m_totals.assertions.passed;
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}";
m_lastAssertionInfo.macroName = "";
}
void RunContext::assertionRun() {
m_prevPassed = m_totals.assertions.passed;
}
bool RunContext::aborting() const {
return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter());
}
void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
m_reporter->sectionStarting(testCaseSection);
Counts prevAssertions = m_totals.assertions;
double duration = 0;
m_shouldReportUnexpected = true;
try {
m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal };
seedRng(*m_config);
Timer timer;
timer.start();
if (m_reporter->getPreferences().shouldRedirectStdOut) {
StreamRedirect coutRedir(cout(), redirectedCout);
StdErrRedirect errRedir(redirectedCerr);
invokeActiveTestCase();
} else {
invokeActiveTestCase();
}
duration = timer.getElapsedSeconds();
} catch (TestFailureException&) {
// This just means the test was aborted due to failure
} catch (...) {
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
// are reported without translation at the point of origin.
if (m_shouldReportUnexpected) {
AssertionHandler
( m_lastAssertionInfo.macroName,
m_lastAssertionInfo.lineInfo,
m_lastAssertionInfo.capturedExpression,
m_lastAssertionInfo.resultDisposition ).useActiveException();
}
}
m_testCaseTracker->close();
handleUnfinishedSections();
m_messages.clear();
Counts assertions = m_totals.assertions - prevAssertions;
bool missingAssertions = testForMissingAssertions(assertions);
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
m_reporter->sectionEnded(testCaseSectionStats);
}
void RunContext::invokeActiveTestCase() {
FatalConditionHandler fatalConditionHandler; // Handle signals
m_activeTestCase->invoke();
fatalConditionHandler.reset();
}
void RunContext::handleUnfinishedSections() {
// If sections ended prematurely due to an exception we stored their
// infos here so we can tear them down outside the unwind process.
for (auto it = m_unfinishedSections.rbegin(),
itEnd = m_unfinishedSections.rend();
it != itEnd;
++it)
sectionEnded(*it);
m_unfinishedSections.clear();
}
IResultCapture& getResultCapture() {
if (auto* capture = getCurrentContext().getResultCapture())
return *capture;
else
CATCH_INTERNAL_ERROR("No result capture instance");
}
}

View File

@@ -0,0 +1,146 @@
/*
* Created by Phil on 22/10/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
#include "catch_interfaces_runner.h"
#include "catch_interfaces_reporter.h"
#include "catch_interfaces_exception.h"
#include "catch_config.hpp"
#include "catch_test_registry.h"
#include "catch_test_case_info.h"
#include "catch_capture.hpp"
#include "catch_totals.h"
#include "catch_test_spec.h"
#include "catch_test_case_tracker.h"
#include "catch_timer.h"
#include "catch_assertionhandler.h"
#include "catch_fatal_condition.h"
#include <string>
namespace Catch {
struct IMutableContext;
class StreamRedirect {
public:
StreamRedirect(std::ostream& stream, std::string& targetString);
~StreamRedirect();
private:
std::ostream& m_stream;
std::streambuf* m_prevBuf;
std::ostringstream m_oss;
std::string& m_targetString;
};
// StdErr has two constituent streams in C++, std::cerr and std::clog
// This means that we need to redirect 2 streams into 1 to keep proper
// order of writes and cannot use StreamRedirect on its own
class StdErrRedirect {
public:
StdErrRedirect(std::string& targetString);
~StdErrRedirect();
private:
std::streambuf* m_cerrBuf;
std::streambuf* m_clogBuf;
std::ostringstream m_oss;
std::string& m_targetString;
};
///////////////////////////////////////////////////////////////////////////
class RunContext : public IResultCapture, public IRunner {
public:
RunContext( RunContext const& ) = delete;
RunContext& operator =( RunContext const& ) = delete;
explicit RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter);
virtual ~RunContext();
void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount);
void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount);
Totals runTest(TestCase const& testCase);
IConfigPtr config() const;
IStreamingReporter& reporter() const;
private: // IResultCapture
void assertionStarting(AssertionInfo const& info) override;
void assertionEnded(AssertionResult const& result) override;
bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
bool testForMissingAssertions(Counts& assertions);
void sectionEnded(SectionEndInfo const& endInfo) override;
void sectionEndedEarly(SectionEndInfo const& endInfo) override;
void benchmarkStarting( BenchmarkInfo const& info ) override;
void benchmarkEnded( BenchmarkStats const& stats ) override;
void pushScopedMessage(MessageInfo const& message) override;
void popScopedMessage(MessageInfo const& message) override;
std::string getCurrentTestName() const override;
const AssertionResult* getLastResult() const override;
void exceptionEarlyReported() override;
void handleFatalErrorCondition( StringRef message ) override;
bool lastAssertionPassed() override;
void assertionPassed() override;
void assertionRun() override;
public:
// !TBD We need to do this another way!
bool aborting() const override;
private:
void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr);
void invokeActiveTestCase();
private:
void handleUnfinishedSections();
TestRunInfo m_runInfo;
IMutableContext& m_context;
TestCase const* m_activeTestCase = nullptr;
ITracker* m_testCaseTracker;
Option<AssertionResult> m_lastResult;
IConfigPtr m_config;
Totals m_totals;
IStreamingReporterPtr m_reporter;
std::vector<MessageInfo> m_messages;
AssertionInfo m_lastAssertionInfo;
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
std::size_t m_prevPassed = 0;
bool m_shouldReportUnexpected = true;
};
IResultCapture& getResultCapture();
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED

View File

@@ -5,24 +5,12 @@
* 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_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
#include "catch_section.h"
#include "catch_capture.hpp"
#include "catch_compiler_capabilities.h"
namespace Catch {
SectionInfo::SectionInfo
( SourceLineInfo const& _lineInfo,
std::string const& _name,
std::string const& _description )
: name( _name ),
description( _description ),
lineInfo( _lineInfo )
{}
Section::Section( SectionInfo const& info )
: m_info( info ),
m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
@@ -54,5 +42,3 @@ namespace Catch {
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED

View File

@@ -9,7 +9,7 @@
#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
#include "catch_section_info.h"
#include "catch_totals.hpp"
#include "catch_totals.h"
#include "catch_timer.h"
#include <string>
@@ -22,7 +22,7 @@ namespace Catch {
~Section();
// This indicates whether the section should be executed or not
operator bool() const;
explicit operator bool() const;
private:
SectionInfo m_info;
@@ -35,12 +35,7 @@ namespace Catch {
} // end namespace Catch
#ifdef CATCH_CONFIG_VARIADIC_MACROS
#define INTERNAL_CATCH_SECTION( ... ) \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
#else
#define INTERNAL_CATCH_SECTION( name, desc ) \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
#endif
#endif // TWOBLUECUBES_CATCH_SECTION_H_INCLUDED

View File

@@ -0,0 +1,25 @@
/*
* Created by Martin on 01/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_section_info.h"
namespace Catch {
SectionInfo::SectionInfo
( SourceLineInfo const& _lineInfo,
std::string const& _name,
std::string const& _description )
: name( _name ),
description( _description ),
lineInfo( _lineInfo )
{}
SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
: sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
{}
} // end namespace Catch

View File

@@ -9,7 +9,7 @@
#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
#include "catch_common.h"
#include "catch_totals.hpp"
#include "catch_totals.h"
#include <string>
@@ -27,9 +27,7 @@ namespace Catch {
};
struct SectionEndInfo {
SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
: sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
{}
SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds );
SectionInfo sectionInfo;
Counts prevAssertions;

View File

@@ -1,110 +0,0 @@
/*
* Created by Phil Nash on 4/5/2012
* Copyright 2012 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_SECTION_INFO_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_SECTION_INFO_HPP_INCLUDED
#include "catch_section_info.h"
namespace Catch {
class RunningSection {
public:
typedef std::vector<RunningSection*> SubSections;
enum State {
Root,
Unknown,
Branch,
TestedBranch,
TestedLeaf
};
RunningSection( RunningSection* parent, std::string const& name )
: m_state( Unknown ),
m_parent( parent ),
m_name( name )
{}
RunningSection( std::string const& name )
: m_state( Root ),
m_parent( CATCH_NULL ),
m_name( name )
{}
~RunningSection() {
deleteAll( m_subSections );
}
std::string getName() const {
return m_name;
}
bool shouldRun() const {
return m_state < TestedBranch;
}
bool isBranch() const {
return m_state == Branch;
}
const RunningSection* getParent() const {
return m_parent;
}
bool hasUntestedSections() const {
if( m_state == Unknown )
return true;
for( SubSections::const_iterator it = m_subSections.begin();
it != m_subSections.end();
++it)
if( (*it)->hasUntestedSections() )
return true;
return false;
}
// Mutable methods:
RunningSection* getParent() {
return m_parent;
}
RunningSection* findOrAddSubSection( std::string const& name, bool& changed ) {
for( SubSections::const_iterator it = m_subSections.begin();
it != m_subSections.end();
++it)
if( (*it)->getName() == name )
return *it;
RunningSection* subSection = new RunningSection( this, name );
m_subSections.push_back( subSection );
m_state = Branch;
changed = true;
return subSection;
}
bool ran() {
if( m_state >= Branch )
return false;
m_state = TestedLeaf;
return true;
}
void ranToCompletion() {
if( m_state == Branch && !hasUntestedSections() )
m_state = TestedBranch;
}
private:
State m_state;
RunningSection* m_parent;
std::string m_name;
SubSections m_subSections;
};
}
#endif // TWOBLUECUBES_CATCH_SECTION_INFO_HPP_INCLUDED

View File

@@ -0,0 +1,276 @@
/*
* Created by Martin on 31/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_session.h"
#include "catch_commandline.h"
#include "catch_console_colour.h"
#include "catch_enforce.h"
#include "catch_list.h"
#include "catch_run_context.h"
#include "catch_stream.h"
#include "catch_test_spec.h"
#include "catch_version.h"
#include "catch_interfaces_reporter.h"
#include "catch_random_number_generator.h"
#include "catch_startup_exception_registry.h"
#include "catch_text.h"
#include <cstdlib>
#include <iomanip>
namespace {
const int MaxExitCode = 255;
using Catch::IStreamingReporterPtr;
using Catch::IConfigPtr;
using Catch::Config;
IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) {
auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);
CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'");
return reporter;
}
#ifndef CATCH_CONFIG_DEFAULT_REPORTER
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
#endif
IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
auto const& reporterNames = config->getReporterNames();
if (reporterNames.empty())
return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config);
IStreamingReporterPtr reporter;
for (auto const& name : reporterNames)
addReporter(reporter, createReporter(name, config));
return reporter;
}
#undef CATCH_CONFIG_DEFAULT_REPORTER
void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) {
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
for (auto const& listener : listeners)
addReporter(reporters, listener->create(Catch::ReporterConfig(config)));
}
Catch::Totals runTests(std::shared_ptr<Config> const& config) {
using namespace Catch;
IStreamingReporterPtr reporter = makeReporter(config);
addListeners(reporter, config);
RunContext context(config, std::move(reporter));
Totals totals;
context.testGroupStarting(config->name(), 1, 1);
TestSpec testSpec = config->testSpec();
if (!testSpec.hasFilters())
testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests
auto const& allTestCases = getAllTestCasesSorted(*config);
for (auto const& testCase : allTestCases) {
if (!context.aborting() && matchTest(testCase, testSpec, *config))
totals += context.runTest(testCase);
else
context.reporter().skipTest(testCase);
}
context.testGroupEnded(config->name(), totals, 1, 1);
return totals;
}
void applyFilenamesAsTags(Catch::IConfig const& config) {
using namespace Catch;
auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
for (auto& testCase : tests) {
auto tags = testCase.tags;
std::string filename = testCase.lineInfo.file;
auto lastSlash = filename.find_last_of("\\/");
if (lastSlash != std::string::npos) {
filename.erase(0, lastSlash);
filename[0] = '#';
}
auto lastDot = filename.find_last_of('.');
if (lastDot != std::string::npos) {
filename.erase(lastDot);
}
tags.push_back(std::move(filename));
setTags(testCase, tags);
}
}
}
namespace Catch {
Session::Session() {
static bool alreadyInstantiated = false;
if( alreadyInstantiated ) {
try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
catch(...) { getMutableRegistryHub().registerStartupException(); }
}
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
if ( !exceptions.empty() ) {
m_startupExceptions = true;
Colour colourGuard( Colour::Red );
Catch::cerr() << "Errors occured during startup!" << '\n';
// iterate over all exceptions and notify user
for ( const auto& ex_ptr : exceptions ) {
try {
std::rethrow_exception(ex_ptr);
} catch ( std::exception const& ex ) {
Catch::cerr() << Column( ex.what() ).indent(2) << '\n';
}
}
}
alreadyInstantiated = true;
m_cli = makeCommandLineParser( m_configData );
}
Session::~Session() {
Catch::cleanUp();
}
void Session::showHelp() const {
Catch::cout()
<< "\nCatch v" << libraryVersion() << "\n"
<< m_cli << std::endl
<< "For more detailed usage please see the project docs\n" << std::endl;
}
void Session::libIdentify() {
Catch::cout()
<< std::left << std::setw(16) << "description: " << "A Catch test executable\n"
<< std::left << std::setw(16) << "category: " << "testframework\n"
<< std::left << std::setw(16) << "framework: " << "Catch Test\n"
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
}
int Session::applyCommandLine( int argc, char* argv[] ) {
if( m_startupExceptions )
return 1;
auto result = m_cli.parse( clara::Args( argc, argv ) );
if( !result ) {
Catch::cerr()
<< Colour( Colour::Red )
<< "\nError(s) in input:\n"
<< Column( result.errorMessage() ).indent( 2 )
<< "\n\n";
Catch::cerr() << "Run with -? for usage\n" << std::endl;
return MaxExitCode;
}
if( m_configData.showHelp )
showHelp();
if( m_configData.libIdentify )
libIdentify();
m_config.reset();
return 0;
}
void Session::useConfigData( ConfigData const& configData ) {
m_configData = configData;
m_config.reset();
}
int Session::run( int argc, char* argv[] ) {
if( m_startupExceptions )
return 1;
int returnCode = applyCommandLine( argc, argv );
if( returnCode == 0 )
returnCode = run();
return returnCode;
}
#if defined(WIN32) && defined(UNICODE)
int Session::run( int argc, wchar_t* const argv[] ) {
char **utf8Argv = new char *[ argc ];
for ( int i = 0; i < argc; ++i ) {
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
utf8Argv[ i ] = new char[ bufSize ];
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
}
int returnCode = run( argc, utf8Argv );
for ( int i = 0; i < argc; ++i )
delete [] utf8Argv[ i ];
delete [] utf8Argv;
return returnCode;
}
#endif
int Session::run() {
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
static_cast<void>(std::getchar());
}
int exitCode = runInternal();
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
static_cast<void>(std::getchar());
}
return exitCode;
}
clara::Parser const& Session::cli() const {
return m_cli;
}
void Session::cli( clara::Parser const& newParser ) {
m_cli = newParser;
}
ConfigData& Session::configData() {
return m_configData;
}
Config& Session::config() {
if( !m_config )
m_config = std::make_shared<Config>( m_configData );
return *m_config;
}
int Session::runInternal() {
if( m_startupExceptions )
return 1;
if( m_configData.showHelp || m_configData.libIdentify )
return 0;
try
{
config(); // Force config to be constructed
seedRng( *m_config );
if( m_configData.filenamesAsTags )
applyFilenamesAsTags( *m_config );
// Handle list request
if( Option<std::size_t> listed = list( config() ) )
return static_cast<int>( *listed );
return (std::min)( MaxExitCode, static_cast<int>( runTests( m_config ).assertions.failed ) );
}
catch( std::exception& ex ) {
Catch::cerr() << ex.what() << std::endl;
return MaxExitCode;
}
}
} // end namespace Catch

Some files were not shown because too many files have changed in this diff Show More