summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bx/3rdparty/catch/catch.hpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/bx/3rdparty/catch/catch.hpp')
-rw-r--r--3rdparty/bx/3rdparty/catch/catch.hpp1558
1 files changed, 1071 insertions, 487 deletions
diff --git a/3rdparty/bx/3rdparty/catch/catch.hpp b/3rdparty/bx/3rdparty/catch/catch.hpp
index 7df2fd09c00..2a09fd193a0 100644
--- a/3rdparty/bx/3rdparty/catch/catch.hpp
+++ b/3rdparty/bx/3rdparty/catch/catch.hpp
@@ -1,6 +1,6 @@
/*
- * Catch v1.5.4
- * Generated: 2016-05-12 19:16:01.957320
+ * Catch v1.7.2
+ * Generated: 2017-02-13 15:57:33.350226
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@@ -60,21 +60,6 @@
// #included from: catch_common.h
#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
-#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
-#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
-#ifdef CATCH_CONFIG_COUNTER
-# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
-#else
-# 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 <stdexcept>
-#include <algorithm>
-
// #included from: catch_compiler_capabilities.h
#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
@@ -89,11 +74,14 @@
// 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?
// ****************
// Note to maintainers: if new toggles are added please document them
// in configuration.md, too
@@ -106,8 +94,16 @@
// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
-#if defined(__cplusplus) && __cplusplus >= 201103L
-# define CATCH_CPP11_OR_GREATER
+#ifdef __cplusplus
+
+# if __cplusplus >= 201103L
+# define CATCH_CPP11_OR_GREATER
+# endif
+
+# if __cplusplus >= 201402L
+# define CATCH_CPP14_OR_GREATER
+# endif
+
#endif
#ifdef __clang__
@@ -165,6 +161,8 @@
// 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
@@ -173,6 +171,8 @@
#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
#endif // _MSC_VER
@@ -238,6 +238,12 @@
# 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
@@ -260,18 +266,30 @@
#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_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
+#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_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
+#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_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#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)
+// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for
+// analytics) because, at time of writing, __COUNTER__ is not properly handled by it.
+// This does not affect compilation
+#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__)
# 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
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
@@ -307,6 +325,20 @@
# define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
#endif
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
+#ifdef CATCH_CONFIG_COUNTER
+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
+#else
+# 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>
+
namespace Catch {
struct IConfig;
@@ -359,7 +391,9 @@ namespace Catch {
}
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 );
@@ -379,8 +413,8 @@ namespace Catch {
SourceLineInfo();
SourceLineInfo( char const* _file, std::size_t _line );
- SourceLineInfo( SourceLineInfo const& other );
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ SourceLineInfo(SourceLineInfo const& other) = default;
SourceLineInfo( SourceLineInfo && ) = default;
SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
SourceLineInfo& operator = ( SourceLineInfo && ) = default;
@@ -389,7 +423,7 @@ namespace Catch {
bool operator == ( SourceLineInfo const& other ) const;
bool operator < ( SourceLineInfo const& other ) const;
- std::string file;
+ char const* file;
std::size_t line;
};
@@ -423,8 +457,6 @@ 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 );
-#include <ostream>
-
namespace Catch {
class NotImplementedException : public std::exception
@@ -557,10 +589,6 @@ namespace Catch {
#pragma clang diagnostic pop
#endif
-#include <memory>
-#include <vector>
-#include <stdlib.h>
-
namespace Catch {
class TestCase;
@@ -824,6 +852,27 @@ namespace Catch {
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& );
+ };
+
struct AssertionInfo
{
AssertionInfo() {}
@@ -840,11 +889,41 @@ namespace Catch {
struct AssertionResultData
{
- AssertionResultData() : resultType( ResultWas::Unknown ) {}
+ AssertionResultData() : decomposedExpression( CATCH_NULL )
+ , resultType( ResultWas::Unknown )
+ , negated( false )
+ , parenthesized( false ) {}
+
+ void negate( bool parenthesize ) {
+ negated = !negated;
+ parenthesized = parenthesize;
+ if( resultType == ResultWas::Ok )
+ resultType = ResultWas::ExpressionFailed;
+ else if( resultType == ResultWas::ExpressionFailed )
+ resultType = ResultWas::Ok;
+ }
+
+ std::string const& 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;
+ }
- std::string reconstructedExpression;
+ mutable DecomposedExpression const* decomposedExpression;
+ mutable std::string reconstructedExpression;
std::string message;
ResultWas::OfType resultType;
+ bool negated;
+ bool parenthesized;
};
class AssertionResult {
@@ -871,6 +950,8 @@ namespace Catch {
std::string getMessage() const;
SourceLineInfo getSourceInfo() const;
std::string getTestMacroName() const;
+ void discardDecomposedExpression() const;
+ void expandDecomposedExpression() const;
protected:
AssertionInfo m_info;
@@ -1057,7 +1138,7 @@ namespace Matchers {
{
return m_caseSensitivity == CaseSensitive::No
? " (case insensitive)"
- : "";
+ : std::string();
}
CaseSensitive::Choice m_caseSensitivity;
std::string m_str;
@@ -1075,7 +1156,7 @@ namespace Matchers {
return m_data.m_str == m_data.adjustString( expr );;
}
virtual std::string toString() const {
- return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ return "equals: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
}
CasedString m_data;
@@ -1092,7 +1173,7 @@ namespace Matchers {
return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos;
}
virtual std::string toString() const {
- return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ return "contains: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
}
CasedString m_data;
@@ -1110,7 +1191,7 @@ namespace Matchers {
return startsWith( m_data.adjustString( expr ), m_data.m_str );
}
virtual std::string toString() const {
- return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ return "starts with: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
}
CasedString m_data;
@@ -1127,7 +1208,7 @@ namespace Matchers {
return endsWith( m_data.adjustString( expr ), m_data.m_str );
}
virtual std::string toString() const {
- return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ return "ends with: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
}
CasedString m_data;
@@ -1202,22 +1283,20 @@ namespace Catch {
template<typename T> class ExpressionLhs;
- struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
-
struct CopyableStream {
CopyableStream() {}
CopyableStream( CopyableStream const& other ) {
oss << other.oss.str();
}
CopyableStream& operator=( CopyableStream const& other ) {
- oss.str("");
+ oss.str(std::string());
oss << other.oss.str();
return *this;
}
std::ostringstream oss;
};
- class ResultBuilder {
+ class ResultBuilder : public DecomposedExpression {
public:
ResultBuilder( char const* macroName,
SourceLineInfo const& lineInfo,
@@ -1235,19 +1314,15 @@ namespace Catch {
return *this;
}
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
-
ResultBuilder& setResultType( ResultWas::OfType result );
ResultBuilder& setResultType( bool result );
- ResultBuilder& setLhs( std::string const& lhs );
- ResultBuilder& setRhs( std::string const& rhs );
- ResultBuilder& setOp( std::string const& op );
- void endExpression();
+ void endExpression( DecomposedExpression const& expr );
+
+ virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
- std::string reconstructExpression() const;
AssertionResult build() const;
+ AssertionResult build( DecomposedExpression const& expr ) const;
void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
void captureResult( ResultWas::OfType resultType );
@@ -1259,14 +1334,12 @@ namespace Catch {
bool shouldDebugBreak() const;
bool allowThrows() const;
+ template<typename ArgT, typename MatcherT>
+ void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
+
private:
AssertionInfo m_assertionInfo;
AssertionResultData m_data;
- struct ExprComponents {
- ExprComponents() : testFalse( false ) {}
- bool testFalse;
- std::string lhs, rhs, op;
- } m_exprComponents;
CopyableStream m_stream;
bool m_shouldDebugBreak;
@@ -1788,90 +1861,155 @@ std::string toString( T const& value ) {
namespace Catch {
-// Wraps the LHS of an expression and captures the operator and RHS (if any) -
-// wrapping them all in a ResultBuilder object
-template<typename T>
-class ExpressionLhs {
- ExpressionLhs& operator = ( ExpressionLhs const& );
-# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
-# endif
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression;
+template<typename ArgT, typename MatcherT>
+class MatchExpression;
+
+// Wraps the LHS of an expression and overloads comparison operators
+// for also capturing those and RHS (if any)
+template<typename T>
+class ExpressionLhs : public DecomposedExpression {
public:
- ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
-# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- ExpressionLhs( ExpressionLhs const& ) = default;
- ExpressionLhs( ExpressionLhs && ) = default;
-# endif
+ ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
template<typename RhsT>
- ResultBuilder& operator == ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
+ operator == ( RhsT const& rhs ) {
return captureExpression<Internal::IsEqualTo>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator != ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
+ operator != ( RhsT const& rhs ) {
return captureExpression<Internal::IsNotEqualTo>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator < ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsLessThan, RhsT const&>
+ operator < ( RhsT const& rhs ) {
return captureExpression<Internal::IsLessThan>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator > ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
+ operator > ( RhsT const& rhs ) {
return captureExpression<Internal::IsGreaterThan>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator <= ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
+ operator <= ( RhsT const& rhs ) {
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator >= ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
+ operator >= ( RhsT const& rhs ) {
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
}
- ResultBuilder& operator == ( bool rhs ) {
+ BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
return captureExpression<Internal::IsEqualTo>( rhs );
}
- ResultBuilder& operator != ( bool rhs ) {
+ BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
return captureExpression<Internal::IsNotEqualTo>( rhs );
}
void endExpression() {
- bool value = m_lhs ? true : false;
+ m_truthy = m_lhs ? true : false;
m_rb
- .setLhs( Catch::toString( value ) )
- .setResultType( value )
- .endExpression();
+ .setResultType( m_truthy )
+ .endExpression( *this );
}
- // Only simple binary expressions are allowed on the LHS.
- // If more complex compositions are required then place the sub expression in parentheses
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
+ virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+ dest = Catch::toString( m_truthy );
+ }
private:
template<Internal::Operator Op, typename RhsT>
- ResultBuilder& captureExpression( RhsT const& rhs ) {
- return m_rb
- .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
- .setLhs( Catch::toString( m_lhs ) )
- .setRhs( Catch::toString( rhs ) )
- .setOp( Internal::OperatorTraits<Op>::getName() );
+ BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
+ return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
+ }
+
+ template<Internal::Operator Op>
+ BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
+ return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
}
private:
ResultBuilder& m_rb;
T m_lhs;
+ bool m_truthy;
+};
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression : public DecomposedExpression {
+public:
+ BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
+ : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
+
+ void endExpression() const {
+ m_rb
+ .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
+ .endExpression( *this );
+ }
+
+ virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+ return true;
+ }
+
+ virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+ std::string lhs = Catch::toString( m_lhs );
+ std::string rhs = Catch::toString( m_rhs );
+ char delim = lhs.size() + rhs.size() < 40 &&
+ lhs.find('\n') == std::string::npos &&
+ rhs.find('\n') == std::string::npos ? ' ' : '\n';
+ dest.reserve( 7 + lhs.size() + rhs.size() );
+ // 2 for spaces around operator
+ // 2 for operator
+ // 2 for parentheses (conditionally added later)
+ // 1 for negation (conditionally added later)
+ dest = lhs;
+ dest += delim;
+ dest += Internal::OperatorTraits<Op>::getName();
+ dest += delim;
+ dest += rhs;
+ }
+
+private:
+ ResultBuilder& m_rb;
+ LhsT m_lhs;
+ RhsT m_rhs;
+};
+
+template<typename ArgT, typename MatcherT>
+class MatchExpression : public DecomposedExpression {
+public:
+ MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
+ : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
+
+ virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+ return true;
+ }
+
+ virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+ std::string matcherAsString = m_matcher.toString();
+ dest = Catch::toString( m_arg );
+ dest += ' ';
+ if( matcherAsString == Detail::unprintableString )
+ dest += m_matcherString;
+ else
+ dest += matcherAsString;
+ }
+
+private:
+ ArgT m_arg;
+ MatcherT m_matcher;
+ char const* m_matcherString;
};
} // end namespace Catch
@@ -1888,6 +2026,14 @@ namespace Catch {
return ExpressionLhs<bool>( *this, value );
}
+ template<typename ArgT, typename MatcherT>
+ inline 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
// #included from: catch_message.h
@@ -1990,11 +2136,19 @@ namespace Catch {
#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
-#define CATCH_PLATFORM_MAC
+# define CATCH_PLATFORM_MAC
#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
-#define CATCH_PLATFORM_IPHONE
+# define CATCH_PLATFORM_IPHONE
+#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
+# 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
#include <string>
@@ -2009,27 +2163,36 @@ namespace Catch{
// The following code snippet based on:
// http://cocoawithlove.com/2008/03/break-into-debugger.html
- #ifdef DEBUG
- #if defined(__ppc64__) || defined(__ppc__)
- #define CATCH_BREAK_INTO_DEBUGGER() \
- if( Catch::isDebuggerActive() ) { \
- __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
- : : : "memory","r0","r3","r4" ); \
- }
- #else
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
- #endif
+ #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" )
+ #else
+ #define CATCH_TRAP() __asm__("int $3\n" : : )
#endif
+#elif defined(CATCH_PLATFORM_LINUX)
+ // If we can use inline assembler, do it because this allows us to break
+ // directly at the location of the failing check instead of breaking inside
+ // raise() called from it, i.e. one stack frame below.
+ #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
+ #define CATCH_TRAP() asm volatile ("int $3")
+ #else // Fall back to the generic way.
+ #include <signal.h>
+
+ #define CATCH_TRAP() raise(SIGTRAP)
+ #endif
#elif defined(_MSC_VER)
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
+ #define CATCH_TRAP() __debugbreak()
#elif defined(__MINGW32__)
extern "C" __declspec(dllimport) void __stdcall DebugBreak();
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
+ #define CATCH_TRAP() DebugBreak()
#endif
-#ifndef CATCH_BREAK_INTO_DEBUGGER
-#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#ifdef CATCH_TRAP
+ #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
+#else
+ #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
#endif
// #included from: catch_interfaces_runner.h
@@ -2044,6 +2207,45 @@ namespace Catch {
};
}
+// #included from: catch_type_traits.hpp
+#define TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+
+ template <typename T>
+ using add_lvalue_reference = std::add_lvalue_reference<T>;
+
+ template <typename T>
+ using add_const = std::add_const<T>;
+
+#else
+
+ template <typename T>
+ struct add_const {
+ typedef const T type;
+ };
+
+ template <typename T>
+ struct add_lvalue_reference {
+ typedef T& type;
+ };
+ template <typename T>
+ struct add_lvalue_reference<T&> {
+ typedef T& type;
+ };
+ // No && overload, because that is C++11, in which case we have
+ // proper type_traits implementation from the standard library
+
+#endif
+
+}
+
///////////////////////////////////////////////////////////////////////////////
// In the event of a failure works out if the debugger needs to be invoked
// and/or an exception thrown and takes appropriate action.
@@ -2062,10 +2264,11 @@ namespace Catch {
( __catchResult <= expr ).endExpression(); \
} \
catch( ... ) { \
- __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
+ __catchResult.useActiveException( resultDisposition ); \
} \
INTERNAL_CATCH_REACT( __catchResult ) \
- } while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+ } 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_IF( expr, resultDisposition, macroName ) \
@@ -2082,7 +2285,7 @@ namespace Catch {
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
try { \
- expr; \
+ static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
} \
catch( ... ) { \
@@ -2097,7 +2300,7 @@ namespace Catch {
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
if( __catchResult.allowThrows() ) \
try { \
- expr; \
+ static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
} \
catch( ... ) { \
@@ -2111,13 +2314,13 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
do { \
- Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
if( __catchResult.allowThrows() ) \
try { \
- expr; \
+ static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
} \
- catch( exceptionType ) { \
+ catch( Catch::add_const<Catch::add_lvalue_reference<exceptionType>::type>::type ) { \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
} \
catch( ... ) { \
@@ -2156,13 +2359,7 @@ namespace Catch {
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
try { \
- std::string matcherAsString = (matcher).toString(); \
- __catchResult \
- .setLhs( Catch::toString( arg ) ) \
- .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
- .setOp( "matches" ) \
- .setResultType( (matcher).match( arg ) ); \
- __catchResult.captureExpression(); \
+ __catchResult.captureMatch( arg, matcher, #matcher ); \
} catch( ... ) { \
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
} \
@@ -2245,6 +2442,8 @@ namespace Catch {
};
}
+#include <string>
+
namespace Catch {
struct SectionInfo {
@@ -2615,6 +2814,10 @@ namespace Catch {
#include <cmath>
#include <limits>
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+#include <type_traits>
+#endif
+
namespace Catch {
namespace Detail {
@@ -2643,9 +2846,56 @@ namespace Detail {
return approx;
}
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator == ( const T& lhs, Approx const& rhs ) {
+ // Thanks to Richard Harris for his help refining this formula
+ auto lhs_v = double(lhs);
+ return std::fabs( lhs_v - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs_v), std::fabs(rhs.m_value) ) );
+ }
+
+ 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 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 rhs ) {
+ return !operator==( rhs, lhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator <= ( T lhs, Approx const& rhs )
+ {
+ return 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 rhs )
+ {
+ return lhs.m_value < double(rhs) || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator >= ( T lhs, Approx const& rhs )
+ {
+ return 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 rhs )
+ {
+ return lhs.m_value > double(rhs) || lhs == rhs;
+ }
+#else
friend bool operator == ( double lhs, Approx const& rhs ) {
// Thanks to Richard Harris for his help refining this formula
- return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
+ return std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
}
friend bool operator == ( Approx const& lhs, double rhs ) {
@@ -2660,6 +2910,27 @@ namespace Detail {
return !operator==( rhs, lhs );
}
+ friend bool operator <= ( double lhs, Approx const& rhs )
+ {
+ return lhs < rhs.m_value || lhs == rhs;
+ }
+
+ friend bool operator <= ( Approx const& lhs, double rhs )
+ {
+ return lhs.m_value < rhs || lhs == rhs;
+ }
+
+ friend bool operator >= ( double lhs, Approx const& rhs )
+ {
+ return lhs > rhs.m_value || lhs == rhs;
+ }
+
+ friend bool operator >= ( Approx const& lhs, double rhs )
+ {
+ return lhs.m_value > rhs || lhs == rhs;
+ }
+#endif
+
Approx& epsilon( double newEpsilon ) {
m_epsilon = newEpsilon;
return *this;
@@ -2814,7 +3085,8 @@ namespace Catch {
IsHidden = 1 << 1,
ShouldFail = 1 << 2,
MayFail = 1 << 3,
- Throws = 1 << 4
+ Throws = 1 << 4,
+ NonPortable = 1 << 5
};
TestCaseInfo( std::string const& _name,
@@ -3109,6 +3381,8 @@ return @ desc; \
// #included from: catch_wildcard_pattern.hpp
#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+#include <stdexcept>
+
namespace Catch
{
class WildcardPattern {
@@ -3126,11 +3400,11 @@ namespace Catch
m_wildcard( NoWildcard ),
m_pattern( adjustCase( pattern ) )
{
- if( startsWith( m_pattern, "*" ) ) {
+ if( startsWith( m_pattern, '*' ) ) {
m_pattern = m_pattern.substr( 1 );
m_wildcard = WildcardAtStart;
}
- if( endsWith( m_pattern, "*" ) ) {
+ if( endsWith( m_pattern, '*' ) ) {
m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
}
@@ -3215,10 +3489,11 @@ namespace Catch {
bool matches( TestCaseInfo const& testCase ) const {
// All patterns in a filter must match for the filter to be a match
- for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
+ for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
if( !(*it)->matches( testCase ) )
return false;
- return true;
+ }
+ return true;
}
};
@@ -3248,11 +3523,12 @@ namespace Catch {
namespace Catch {
class TestSpecParser {
- enum Mode{ None, Name, QuotedName, Tag };
+ enum Mode{ None, Name, QuotedName, Tag, EscapedName };
Mode m_mode;
bool m_exclusion;
std::size_t m_start, m_pos;
std::string m_arg;
+ std::vector<std::size_t> m_escapeChars;
TestSpec::Filter m_currentFilter;
TestSpec m_testSpec;
ITagAliasRegistry const* m_tagAliases;
@@ -3265,6 +3541,7 @@ namespace Catch {
m_exclusion = false;
m_start = std::string::npos;
m_arg = m_tagAliases->expandAliases( arg );
+ m_escapeChars.clear();
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
visitChar( m_arg[m_pos] );
if( m_mode == Name )
@@ -3283,6 +3560,7 @@ namespace Catch {
case '~': m_exclusion = true; return;
case '[': return startNewMode( Tag, ++m_pos );
case '"': return startNewMode( QuotedName, ++m_pos );
+ case '\\': return escape();
default: startNewMode( Name, m_pos ); break;
}
}
@@ -3298,7 +3576,11 @@ namespace Catch {
addPattern<TestSpec::NamePattern>();
startNewMode( Tag, ++m_pos );
}
+ else if( c == '\\' )
+ escape();
}
+ else if( m_mode == EscapedName )
+ m_mode = Name;
else if( m_mode == QuotedName && c == '"' )
addPattern<TestSpec::NamePattern>();
else if( m_mode == Tag && c == ']' )
@@ -3308,10 +3590,19 @@ namespace Catch {
m_mode = mode;
m_start = start;
}
+ void escape() {
+ if( m_mode == None )
+ m_start = m_pos;
+ m_mode = EscapedName;
+ m_escapeChars.push_back( m_pos );
+ }
std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
template<typename T>
void addPattern() {
std::string token = subString();
+ for( size_t i = 0; i < m_escapeChars.size(); ++i )
+ token = token.substr( 0, m_escapeChars[i]-i ) + token.substr( m_escapeChars[i]+1-i );
+ m_escapeChars.clear();
if( startsWith( token, "exclude:" ) ) {
m_exclusion = true;
token = token.substr( 8 );
@@ -3345,7 +3636,7 @@ namespace Catch {
// #included from: catch_interfaces_config.h
#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
-#include <iostream>
+#include <iosfwd>
#include <string>
#include <vector>
@@ -3397,6 +3688,8 @@ namespace Catch {
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
virtual UseColour::YesOrNo useColour() const = 0;
+ virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+
};
}
@@ -3419,6 +3712,7 @@ namespace Catch {
#include <streambuf>
#include <ostream>
#include <fstream>
+#include <memory>
namespace Catch {
@@ -3450,7 +3744,7 @@ namespace Catch {
};
class DebugOutStream : public IStream {
- std::auto_ptr<StreamBufBase> m_streamBuf;
+ CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
mutable std::ostream m_os;
public:
DebugOutStream();
@@ -3464,8 +3758,7 @@ namespace Catch {
#include <memory>
#include <vector>
#include <string>
-#include <iostream>
-#include <ctime>
+#include <stdexcept>
#ifndef CATCH_CONFIG_CONSOLE_WIDTH
#define CATCH_CONFIG_CONSOLE_WIDTH 80
@@ -3522,6 +3815,7 @@ namespace Catch {
std::vector<std::string> reporterNames;
std::vector<std::string> testsOrTags;
+ std::vector<std::string> sectionsToRun;
};
class Config : public SharedImpl<IConfig> {
@@ -3546,8 +3840,7 @@ namespace Catch {
}
}
- virtual ~Config() {
- }
+ virtual ~Config() {}
std::string const& getFilename() const {
return m_data.outputFilename ;
@@ -3560,27 +3853,26 @@ namespace Catch {
std::string getProcessName() const { return m_data.processName; }
- bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
+ std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
+ std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
- std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
-
- int abortAfter() const { return m_data.abortAfter; }
-
- TestSpec const& testSpec() const { return m_testSpec; }
+ virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; }
bool showHelp() const { return m_data.showHelp; }
- bool showInvisibles() const { return m_data.showInvisibles; }
// IConfig interface
- virtual bool allowThrows() const { return !m_data.noThrow; }
- virtual std::ostream& stream() const { return m_stream->stream(); }
- virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
- virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
- virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
- virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
- virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; }
- virtual unsigned int rngSeed() const { return m_data.rngSeed; }
- virtual UseColour::YesOrNo useColour() const { return m_data.useColour; }
+ 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; }
private:
@@ -3598,7 +3890,7 @@ namespace Catch {
}
ConfigData m_data;
- std::auto_ptr<IStream const> m_stream;
+ CATCH_AUTO_PTR( IStream const ) m_stream;
TestSpec m_testSpec;
};
@@ -3986,9 +4278,12 @@ namespace Clara {
inline void convertInto( std::string const& _source, std::string& _dest ) {
_dest = _source;
}
+ char toLowerCh(char c) {
+ return static_cast<char>( ::tolower( c ) );
+ }
inline void convertInto( std::string const& _source, bool& _dest ) {
std::string sourceLC = _source;
- std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower );
+ std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh );
if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
_dest = true;
else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
@@ -4177,7 +4472,7 @@ namespace Clara {
}
}
Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
- if( std::string( ":=\0", 5 ).find( c ) == std::string::npos )
+ if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
return mode;
std::string optName = arg.substr( from, i-from );
@@ -4191,7 +4486,7 @@ namespace Clara {
return None;
}
Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
- if( inQuotes || std::string( "\0", 3 ).find( c ) == std::string::npos )
+ if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
return mode;
std::string data = arg.substr( from, i-from );
@@ -4639,6 +4934,7 @@ STITCH_CLARA_CLOSE_NAMESPACE
#endif
#include <fstream>
+#include <ctime>
namespace Catch {
@@ -4649,13 +4945,14 @@ namespace Catch {
config.abortAfter = x;
}
inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
+ inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
inline void addWarning( ConfigData& config, std::string const& _warning ) {
if( _warning == "NoAssertions" )
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
else
- throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
+ throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
}
inline void setOrder( ConfigData& config, std::string const& order ) {
if( startsWith( "declared", order ) )
@@ -4665,7 +4962,7 @@ namespace Catch {
else if( startsWith( "random", order ) )
config.runOrder = RunTests::InRandomOrder;
else
- throw std::runtime_error( "Unrecognised ordering: '" + order + "'" );
+ throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
}
inline void setRngSeed( ConfigData& config, std::string const& seed ) {
if( seed == "time" ) {
@@ -4676,7 +4973,7 @@ namespace Catch {
ss << seed;
ss >> config.rngSeed;
if( ss.fail() )
- throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" );
+ throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" );
}
}
inline void setVerbosity( ConfigData& config, int level ) {
@@ -4711,8 +5008,11 @@ namespace Catch {
std::string line;
while( std::getline( f, line ) ) {
line = trim(line);
- if( !line.empty() && !startsWith( line, "#" ) )
- addTestOrTags( config, "\"" + line + "\"," );
+ if( !line.empty() && !startsWith( line, '#' ) ) {
+ if( !startsWith( line, '"' ) )
+ line = '"' + line + '"';
+ addTestOrTags( config, line + ',' );
+ }
}
}
@@ -4799,6 +5099,10 @@ namespace Catch {
.describe( "adds a tag for the filename" )
.bind( &ConfigData::filenamesAsTags );
+ cli["-c"]["--section"]
+ .describe( "specify section to run" )
+ .bind( &addSectionToRun, "section name" );
+
// Less common commands which don't have a short form
cli["--list-test-names-only"]
.describe( "list all/matching test cases names only" )
@@ -4871,19 +5175,16 @@ namespace Tbc {
TextAttributes()
: initialIndent( std::string::npos ),
indent( 0 ),
- width( consoleWidth-1 ),
- tabChar( '\t' )
+ width( consoleWidth-1 )
{}
TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
- TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
std::size_t initialIndent; // indent of first line, or npos
std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
std::size_t width; // maximum width of text, including indent. Longer text will wrap
- char tabChar; // If this char is seen the indent is changed to current pos
};
class Text {
@@ -4891,62 +5192,76 @@ namespace Tbc {
Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
: attr( _attr )
{
- std::string wrappableChars = " [({.,/|\\-";
- std::size_t indent = _attr.initialIndent != std::string::npos
- ? _attr.initialIndent
- : _attr.indent;
- std::string remainder = _str;
+ const std::string wrappableBeforeChars = "[({<\t";
+ const std::string wrappableAfterChars = "])}>-,./|\\";
+ const std::string wrappableInsteadOfChars = " \n\r";
+ std::string indent = _attr.initialIndent != std::string::npos
+ ? std::string( _attr.initialIndent, ' ' )
+ : std::string( _attr.indent, ' ' );
+
+ typedef std::string::const_iterator iterator;
+ iterator it = _str.begin();
+ const iterator strEnd = _str.end();
+
+ while( it != strEnd ) {
- while( !remainder.empty() ) {
if( lines.size() >= 1000 ) {
lines.push_back( "... message truncated due to excessive size" );
return;
}
- std::size_t tabPos = std::string::npos;
- std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
- std::size_t pos = remainder.find_first_of( '\n' );
- if( pos <= width ) {
- width = pos;
- }
- pos = remainder.find_last_of( _attr.tabChar, width );
- if( pos != std::string::npos ) {
- tabPos = pos;
- if( remainder[width] == '\n' )
- width--;
- remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
- }
- if( width == remainder.size() ) {
- spliceLine( indent, remainder, width );
- }
- else if( remainder[width] == '\n' ) {
- spliceLine( indent, remainder, width );
- if( width <= 1 || remainder.size() != 1 )
- remainder = remainder.substr( 1 );
- indent = _attr.indent;
- }
- else {
- pos = remainder.find_last_of( wrappableChars, width );
- if( pos != std::string::npos && pos > 0 ) {
- spliceLine( indent, remainder, pos );
- if( remainder[0] == ' ' )
- remainder = remainder.substr( 1 );
+ std::string suffix;
+ std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) );
+ iterator itEnd = it+width;
+ iterator itNext = _str.end();
+
+ iterator itNewLine = std::find( it, itEnd, '\n' );
+ if( itNewLine != itEnd )
+ itEnd = itNewLine;
+
+ if( itEnd != strEnd ) {
+ bool foundWrapPoint = false;
+ iterator findIt = itEnd;
+ do {
+ if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) {
+ itEnd = findIt+1;
+ itNext = findIt+1;
+ foundWrapPoint = true;
+ }
+ else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) {
+ itEnd = findIt;
+ itNext = findIt;
+ foundWrapPoint = true;
+ }
+ else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) {
+ itNext = findIt+1;
+ itEnd = findIt;
+ foundWrapPoint = true;
+ }
+ if( findIt == it )
+ break;
+ else
+ --findIt;
+ }
+ while( !foundWrapPoint );
+
+ if( !foundWrapPoint ) {
+ // No good wrap char, so we'll break mid word and add a hyphen
+ --itEnd;
+ itNext = itEnd;
+ suffix = "-";
}
else {
- spliceLine( indent, remainder, width-1 );
- lines.back() += "-";
+ while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos )
+ --itEnd;
}
- if( lines.size() == 1 )
- indent = _attr.indent;
- if( tabPos != std::string::npos )
- indent += tabPos;
}
- }
- }
+ lines.push_back( indent + std::string( it, itEnd ) + suffix );
- void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
- lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
- _remainder = _remainder.substr( _pos );
+ if( indent.size() != _attr.indent )
+ indent = std::string( _attr.indent, ' ' );
+ it = itNext;
+ }
}
typedef std::vector<std::string>::const_iterator const_iterator;
@@ -5055,7 +5370,6 @@ namespace Catch {
#include <string>
#include <ostream>
#include <map>
-#include <assert.h>
namespace Catch
{
@@ -5343,9 +5657,9 @@ namespace Catch {
}
if( !config.testSpec().hasFilters() )
- Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
+ Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
else
- Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
+ Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
return matchedTests;
}
@@ -5360,7 +5674,10 @@ namespace Catch {
++it ) {
matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
- Catch::cout() << testCaseInfo.name << std::endl;
+ if( startsWith( testCaseInfo.name, '#' ) )
+ Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl;
+ else
+ Catch::cout() << testCaseInfo.name << std::endl;
}
return matchedTests;
}
@@ -5421,9 +5738,9 @@ namespace Catch {
.setInitialIndent( 0 )
.setIndent( oss.str().size() )
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
- Catch::cout() << oss.str() << wrapper << "\n";
+ Catch::cout() << oss.str() << wrapper << '\n';
}
- Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
+ Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
return tagCounts.size();
}
@@ -5442,9 +5759,9 @@ namespace Catch {
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
Catch::cout() << " "
<< it->first
- << ":"
+ << ':'
<< std::string( maxNameLen - it->first.size() + 2, ' ' )
- << wrapper << "\n";
+ << wrapper << '\n';
}
Catch::cout() << std::endl;
return factories.size();
@@ -5475,15 +5792,27 @@ namespace Catch {
#include <string>
#include <assert.h>
#include <vector>
+#include <iterator>
+#include <stdexcept>
namespace Catch {
namespace TestCaseTracking {
+ struct NameAndLocation {
+ std::string name;
+ SourceLineInfo location;
+
+ NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
+ : name( _name ),
+ location( _location )
+ {}
+ };
+
struct ITracker : SharedImpl<> {
virtual ~ITracker();
// static queries
- virtual std::string name() const = 0;
+ virtual NameAndLocation const& nameAndLocation() const = 0;
// dynamic queries
virtual bool isComplete() const = 0; // Successfully completed or failed
@@ -5499,7 +5828,7 @@ namespace TestCaseTracking {
virtual void markAsNeedingAnotherRun() = 0;
virtual void addChild( Ptr<ITracker> const& child ) = 0;
- virtual ITracker* findChild( std::string const& name ) = 0;
+ virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
virtual void openChild() = 0;
// Debug/ checking
@@ -5507,7 +5836,7 @@ namespace TestCaseTracking {
virtual bool isIndexTracker() const = 0;
};
- class TrackerContext {
+ class TrackerContext {
enum RunState {
NotStarted,
@@ -5569,30 +5898,32 @@ namespace TestCaseTracking {
Failed
};
class TrackerHasName {
- std::string m_name;
+ NameAndLocation m_nameAndLocation;
public:
- TrackerHasName( std::string const& name ) : m_name( name ) {}
+ TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
bool operator ()( Ptr<ITracker> const& tracker ) {
- return tracker->name() == m_name;
+ return
+ tracker->nameAndLocation().name == m_nameAndLocation.name &&
+ tracker->nameAndLocation().location == m_nameAndLocation.location;
}
};
typedef std::vector<Ptr<ITracker> > Children;
- std::string m_name;
+ NameAndLocation m_nameAndLocation;
TrackerContext& m_ctx;
ITracker* m_parent;
Children m_children;
CycleState m_runState;
public:
- TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent )
- : m_name( name ),
+ TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+ : m_nameAndLocation( nameAndLocation ),
m_ctx( ctx ),
m_parent( parent ),
m_runState( NotStarted )
{}
virtual ~TrackerBase();
- virtual std::string name() const CATCH_OVERRIDE {
- return m_name;
+ virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE {
+ return m_nameAndLocation;
}
virtual bool isComplete() const CATCH_OVERRIDE {
return m_runState == CompletedSuccessfully || m_runState == Failed;
@@ -5611,8 +5942,8 @@ namespace TestCaseTracking {
m_children.push_back( child );
}
- virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE {
- Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) );
+ virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE {
+ Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
return( it != m_children.end() )
? it->get()
: CATCH_NULL;
@@ -5690,32 +6021,56 @@ namespace TestCaseTracking {
};
class SectionTracker : public TrackerBase {
+ std::vector<std::string> m_filters;
public:
- SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent )
- : TrackerBase( name, ctx, parent )
- {}
+ SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+ : TrackerBase( nameAndLocation, ctx, parent )
+ {
+ if( parent ) {
+ while( !parent->isSectionTracker() )
+ parent = &parent->parent();
+
+ SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
+ addNextFilters( parentSection.m_filters );
+ }
+ }
virtual ~SectionTracker();
virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
- static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
+ static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
SectionTracker* section = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker();
- if( ITracker* childTracker = currentTracker.findChild( name ) ) {
+ if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
assert( childTracker->isSectionTracker() );
section = static_cast<SectionTracker*>( childTracker );
}
else {
- section = new SectionTracker( name, ctx, &currentTracker );
+ section = new SectionTracker( nameAndLocation, ctx, &currentTracker );
currentTracker.addChild( section );
}
- if( !ctx.completedCycle() && !section->isComplete() ) {
+ if( !ctx.completedCycle() )
+ section->tryOpen();
+ return *section;
+ }
+
+ void tryOpen() {
+ if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
+ open();
+ }
- section->open();
+ void addInitialFilters( std::vector<std::string> const& filters ) {
+ if( !filters.empty() ) {
+ m_filters.push_back(""); // Root - should never be consulted
+ m_filters.push_back(""); // Test Case - not a section filter
+ std::copy( filters.begin(), filters.end(), std::back_inserter( m_filters ) );
}
- return *section;
+ }
+ void addNextFilters( std::vector<std::string> const& filters ) {
+ if( filters.size() > 1 )
+ std::copy( filters.begin()+1, filters.end(), std::back_inserter( m_filters ) );
}
};
@@ -5723,8 +6078,8 @@ namespace TestCaseTracking {
int m_size;
int m_index;
public:
- IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size )
- : TrackerBase( name, ctx, parent ),
+ IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
+ : TrackerBase( nameAndLocation, ctx, parent ),
m_size( size ),
m_index( -1 )
{}
@@ -5732,17 +6087,17 @@ namespace TestCaseTracking {
virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
- static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
+ static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
IndexTracker* tracker = CATCH_NULL;
ITracker& currentTracker = ctx.currentTracker();
- if( ITracker* childTracker = currentTracker.findChild( name ) ) {
+ if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
assert( childTracker->isIndexTracker() );
tracker = static_cast<IndexTracker*>( childTracker );
}
else {
- tracker = new IndexTracker( name, ctx, &currentTracker, size );
+ tracker = new IndexTracker( nameAndLocation, ctx, &currentTracker, size );
currentTracker.addChild( tracker );
}
@@ -5770,7 +6125,7 @@ namespace TestCaseTracking {
};
inline ITracker& TrackerContext::startRun() {
- m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL );
+ m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL );
m_currentTracker = CATCH_NULL;
m_runState = Executing;
return *m_rootTracker;
@@ -5790,35 +6145,128 @@ using TestCaseTracking::IndexTracker;
namespace Catch {
- // Report the error condition then exit the process
- inline void fatal( std::string const& message, int exitCode ) {
+ // Report the error condition
+ inline void reportFatal( std::string const& message ) {
IContext& context = Catch::getCurrentContext();
IResultCapture* resultCapture = context.getResultCapture();
resultCapture->handleFatalErrorCondition( message );
-
- if( Catch::alwaysTrue() ) // avoids "no return" warnings
- exit( exitCode );
}
} // namespace Catch
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+// #included from: catch_windows_h_proxy.h
+
+#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED
+
+#ifdef CATCH_DEFINES_NOMINMAX
+# define NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef CATCH_DEFINES_NOMINMAX
+# undef NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+# undef WIN32_LEAN_AND_MEAN
+#endif
+
+
+# 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 {
- void reset() {}
- };
+
+ static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
+ for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
+ reset();
+ 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 //////////////////////////
#include <signal.h>
namespace Catch {
- struct SignalDefs { int id; const char* name; };
+ struct SignalDefs {
+ int id;
+ const char* name;
+ };
extern SignalDefs signalDefs[];
SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
@@ -5827,35 +6275,66 @@ namespace Catch {
{ 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 ) {
- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
- if( sig == signalDefs[i].id )
- fatal( signalDefs[i].name, -sig );
- fatal( "<unknown signal>", -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() : m_isSet( true ) {
- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
- signal( signalDefs[i].id, handleSignal );
+ 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();
}
- void reset() {
- if( m_isSet ) {
- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
- signal( signalDefs[i].id, SIG_DFL );
- m_isSet = false;
+ 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 m_isSet;
};
+ bool FatalConditionHandler::isSet = false;
+ struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
+ stack_t FatalConditionHandler::oldSigStack = {};
+ char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+
} // namespace Catch
#endif // not Windows
@@ -5934,10 +6413,12 @@ namespace Catch {
m_activeTestCase = &testCase;
do {
- m_trackerContext.startRun();
+ 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, testInfo.name );
+ m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
runCurrentTest( redirectedCout, redirectedCerr );
}
while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
@@ -5982,7 +6463,7 @@ namespace Catch {
m_messages.clear();
// Reset working state
- m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
+ m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
m_lastResult = result;
}
@@ -5991,10 +6472,7 @@ namespace Catch {
Counts& assertions
)
{
- std::ostringstream oss;
- oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
-
- ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() );
+ ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
if( !sectionTracker.isOpen() )
return false;
m_activeSections.push_back( &sectionTracker );
@@ -6053,7 +6531,7 @@ namespace Catch {
virtual std::string getCurrentTestName() const {
return m_activeTestCase
? m_activeTestCase->getTestCaseInfo().name
- : "";
+ : std::string();
}
virtual const AssertionResult* getLastResult() const {
@@ -6083,11 +6561,11 @@ namespace Catch {
deltaTotals.testCases.failed = 1;
m_reporter->testCaseEnded( TestCaseStats( testInfo,
deltaTotals,
- "",
- "",
+ std::string(),
+ std::string(),
false ) );
m_totals.testCases.failed++;
- testGroupEnded( "", m_totals, 1, 1 );
+ testGroupEnded( std::string(), m_totals, 1, 1 );
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
}
@@ -6106,7 +6584,7 @@ namespace Catch {
Counts prevAssertions = m_totals.assertions;
double duration = 0;
try {
- m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
+ m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal );
seedRng( *m_config );
@@ -6436,16 +6914,29 @@ namespace Catch {
#include <vector>
#include <set>
#include <sstream>
-#include <iostream>
#include <algorithm>
namespace Catch {
- struct LexSort {
- bool operator() (TestCase i,TestCase j) const { return (i<j);}
- };
struct RandomNumberGenerator {
- int operator()( int n ) const { return std::rand() % n; }
+ typedef std::ptrdiff_t result_type;
+
+ result_type operator()( result_type n ) const { return std::rand() % n; }
+
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+ static constexpr result_type min() { return 0; }
+ static constexpr result_type max() { return 1000000; }
+ result_type operator()() const { return std::rand() % max(); }
+#endif
+ template<typename V>
+ static void shuffle( V& vector ) {
+ RandomNumberGenerator rng;
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+ std::shuffle( vector.begin(), vector.end(), rng );
+#else
+ std::random_shuffle( vector.begin(), vector.end(), rng );
+#endif
+ }
};
inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
@@ -6454,14 +6945,12 @@ namespace Catch {
switch( config.runOrder() ) {
case RunTests::InLexicographicalOrder:
- std::sort( sorted.begin(), sorted.end(), LexSort() );
+ std::sort( sorted.begin(), sorted.end() );
break;
case RunTests::InRandomOrder:
{
seedRng( config );
-
- RandomNumberGenerator rng;
- std::random_shuffle( sorted.begin(), sorted.end(), rng );
+ RandomNumberGenerator::shuffle( sorted );
}
break;
case RunTests::InDeclarationOrder:
@@ -6485,7 +6974,7 @@ namespace Catch {
ss << Colour( Colour::Red )
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
- << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
+ << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
throw std::runtime_error(ss.str());
@@ -6517,7 +7006,7 @@ namespace Catch {
virtual void registerTest( TestCase const& testCase ) {
std::string name = testCase.getTestCaseInfo().name;
- if( name == "" ) {
+ if( name.empty() ) {
std::ostringstream oss;
oss << "Anonymous test case " << ++m_unnamedCount;
return registerTest( testCase.withName( oss.str() ) );
@@ -6566,7 +7055,7 @@ namespace Catch {
inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
std::string className = classOrQualifiedMethodName;
- if( startsWith( className, "&" ) )
+ if( startsWith( className, '&' ) )
{
std::size_t lastColons = className.rfind( "::" );
std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
@@ -6784,7 +7273,7 @@ namespace Catch {
// #included from: catch_notimplemented_exception.hpp
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
-#include <ostream>
+#include <sstream>
namespace Catch {
@@ -6856,7 +7345,7 @@ namespace Catch {
m_ofs.open( filename.c_str() );
if( m_ofs.fail() ) {
std::ostringstream oss;
- oss << "Unable to open file: '" << filename << "'";
+ oss << "Unable to open file: '" << filename << '\'';
throw std::domain_error( oss.str() );
}
}
@@ -6909,6 +7398,11 @@ namespace Catch {
Context( Context const& );
void operator=( Context const& );
+ public:
+ virtual ~Context() {
+ deleteAllValues( m_generatorsByTestName );
+ }
+
public: // IContext
virtual IResultCapture* getResultCapture() {
return m_resultCapture;
@@ -7022,16 +7516,6 @@ namespace Catch {
#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-
-#ifdef __AFXDLL
-#include <AfxWin.h>
-#else
-#include <windows.h>
-#endif
-
namespace Catch {
namespace {
@@ -7112,7 +7596,7 @@ namespace {
case Colour::White: return setColour( "[0m" );
case Colour::Red: return setColour( "[0;31m" );
case Colour::Green: return setColour( "[0;32m" );
- case Colour::Blue: return setColour( "[0:34m" );
+ case Colour::Blue: return setColour( "[0;34m" );
case Colour::Cyan: return setColour( "[0;36m" );
case Colour::Yellow: return setColour( "[0;33m" );
case Colour::Grey: return setColour( "[1;30m" );
@@ -7298,7 +7782,7 @@ namespace Catch {
std::string AssertionResult::getExpression() const {
if( isFalseTest( m_info.resultDisposition ) )
- return "!" + m_info.capturedExpression;
+ return '!' + m_info.capturedExpression;
else
return m_info.capturedExpression;
}
@@ -7314,7 +7798,7 @@ namespace Catch {
}
std::string AssertionResult::getExpandedExpression() const {
- return m_resultData.reconstructedExpression;
+ return m_resultData.reconstructExpression();
}
std::string AssertionResult::getMessage() const {
@@ -7328,15 +7812,25 @@ namespace Catch {
return m_info.macroName;
}
+ void AssertionResult::discardDecomposedExpression() const {
+ m_resultData.decomposedExpression = CATCH_NULL;
+ }
+
+ void AssertionResult::expandDecomposedExpression() const {
+ m_resultData.reconstructExpression();
+ }
+
} // end namespace Catch
// #included from: catch_test_case_info.hpp
#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+#include <cctype>
+
namespace Catch {
inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
- if( startsWith( tag, "." ) ||
+ if( startsWith( tag, '.' ) ||
tag == "hide" ||
tag == "!hide" )
return TestCaseInfo::IsHidden;
@@ -7346,11 +7840,13 @@ namespace Catch {
return TestCaseInfo::ShouldFail;
else if( tag == "!mayfail" )
return TestCaseInfo::MayFail;
+ else if( tag == "!nonportable" )
+ return TestCaseInfo::NonPortable;
else
return TestCaseInfo::None;
}
inline bool isReservedTag( std::string const& tag ) {
- return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] );
+ return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
}
inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
if( isReservedTag( tag ) ) {
@@ -7420,7 +7916,7 @@ namespace Catch {
std::ostringstream oss;
for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
- oss << "[" << *it << "]";
+ oss << '[' << *it << ']';
std::string lcaseTag = toLower( *it );
testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
testCaseInfo.lcaseTags.insert( lcaseTag );
@@ -7536,18 +8032,18 @@ namespace Catch {
{}
std::ostream& operator << ( std::ostream& os, Version const& version ) {
- os << version.majorVersion << "."
- << version.minorVersion << "."
+ os << version.majorVersion << '.'
+ << version.minorVersion << '.'
<< version.patchNumber;
if( !version.branchName.empty() ) {
- os << "-" << version.branchName
- << "." << version.buildNumber;
+ os << '-' << version.branchName
+ << '.' << version.buildNumber;
}
return os;
}
- Version libraryVersion( 1, 5, 4, "", 0 );
+ Version libraryVersion( 1, 7, 2, "", 0 );
}
@@ -7718,7 +8214,6 @@ namespace Catch
#endif
#ifdef CATCH_PLATFORM_WINDOWS
-#include <windows.h>
#else
#include <sys/time.h>
#endif
@@ -7767,19 +8262,31 @@ namespace Catch {
// #included from: catch_common.hpp
#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+#include <cstring>
+#include <cctype>
+
namespace Catch {
bool startsWith( std::string const& s, std::string const& prefix ) {
- return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
+ return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
+ }
+ bool startsWith( std::string const& s, char prefix ) {
+ return !s.empty() && s[0] == prefix;
}
bool endsWith( std::string const& s, std::string const& suffix ) {
- return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
+ return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
+ }
+ bool endsWith( std::string const& s, char suffix ) {
+ return !s.empty() && s[s.size()-1] == suffix;
}
bool contains( std::string const& s, std::string const& infix ) {
return s.find( infix ) != std::string::npos;
}
+ char toLowerCh(char c) {
+ return static_cast<char>( std::tolower( c ) );
+ }
void toLowerInPlace( std::string& s ) {
- std::transform( s.begin(), s.end(), s.begin(), ::tolower );
+ std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
}
std::string toLower( std::string const& s ) {
std::string lc = s;
@@ -7791,7 +8298,7 @@ namespace Catch {
std::string::size_type start = str.find_first_not_of( whitespaceChars );
std::string::size_type end = str.find_last_not_of( whitespaceChars );
- return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
+ return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
}
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
@@ -7814,29 +8321,25 @@ namespace Catch {
{}
std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
- os << pluraliser.m_count << " " << pluraliser.m_label;
+ os << pluraliser.m_count << ' ' << pluraliser.m_label;
if( pluraliser.m_count != 1 )
- os << "s";
+ os << 's';
return os;
}
- SourceLineInfo::SourceLineInfo() : line( 0 ){}
+ SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){}
SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
: file( _file ),
line( _line )
{}
- SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
- : file( other.file ),
- line( other.line )
- {}
bool SourceLineInfo::empty() const {
- return file.empty();
+ return file[0] == '\0';
}
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
- return line == other.line && file == other.file;
+ return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
}
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
- return line < other.line || ( line == other.line && file < other.file );
+ return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
}
void seedRng( IConfig const& config ) {
@@ -7849,16 +8352,16 @@ namespace Catch {
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
#ifndef __GNUG__
- os << info.file << "(" << info.line << ")";
+ os << info.file << '(' << info.line << ')';
#else
- os << info.file << ":" << info.line;
+ os << info.file << ':' << info.line;
#endif
return os;
}
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
std::ostringstream oss;
- oss << locationInfo << ": Internal Catch error: '" << message << "'";
+ oss << locationInfo << ": Internal Catch error: '" << message << '\'';
if( alwaysTrue() )
throw std::logic_error( oss.str() );
}
@@ -7905,8 +8408,6 @@ namespace Catch {
// #included from: catch_debugger.hpp
#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
-#include <iostream>
-
#ifdef CATCH_PLATFORM_MAC
#include <assert.h>
@@ -7955,6 +8456,33 @@ namespace Catch {
}
} // namespace Catch
+#elif defined(CATCH_PLATFORM_LINUX)
+ #include <fstream>
+ #include <string>
+
+ namespace Catch{
+ // The standard POSIX way of detecting a debugger is to attempt to
+ // ptrace() the process, but this needs to be done from a child and not
+ // this process itself to still allow attaching to this process later
+ // if wanted, so is rather heavy. Under Linux we have the PID of the
+ // "debugger" (which doesn't need to be gdb, of course, it could also
+ // be strace, for example) in /proc/$PID/status, so just get it from
+ // there instead.
+ bool isDebuggerActive(){
+ std::ifstream in("/proc/self/status");
+ for( std::string line; std::getline(in, line); ) {
+ static const int PREFIX_LEN = 11;
+ if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
+ // We're traced if the PID is not 0 and no other PID starts
+ // with 0 digit, so it's enough to check for just a single
+ // character.
+ return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
+ }
+ }
+
+ return false;
+ }
+ } // namespace Catch
#elif defined(_MSC_VER)
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
namespace Catch {
@@ -7976,7 +8504,7 @@ namespace Catch {
#endif // Platform
#ifdef CATCH_PLATFORM_WINDOWS
- extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
+
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
::OutputDebugStringA( text.c_str() );
@@ -8052,7 +8580,7 @@ std::string toString( std::string const& value ) {
}
}
}
- return "\"" + s + "\"";
+ return '"' + s + '"';
}
std::string toString( std::wstring const& value ) {
@@ -8073,19 +8601,19 @@ std::string toString( char* const value ) {
std::string toString( const wchar_t* const value )
{
- return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
+ return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
}
std::string toString( wchar_t* const value )
{
- return Catch::toString( static_cast<const wchar_t*>( value ) );
+ return Catch::toString( static_cast<const wchar_t*>( value ) );
}
std::string toString( int value ) {
std::ostringstream oss;
oss << value;
if( value > Detail::hexThreshold )
- oss << " (0x" << std::hex << value << ")";
+ oss << " (0x" << std::hex << value << ')';
return oss.str();
}
@@ -8093,7 +8621,7 @@ std::string toString( unsigned long value ) {
std::ostringstream oss;
oss << value;
if( value > Detail::hexThreshold )
- oss << " (0x" << std::hex << value << ")";
+ oss << " (0x" << std::hex << value << ')';
return oss.str();
}
@@ -8121,7 +8649,7 @@ std::string toString( const double value ) {
return fpToString( value, 10 );
}
std::string toString( const float value ) {
- return fpToString( value, 5 ) + "f";
+ return fpToString( value, 5 ) + 'f';
}
std::string toString( bool value ) {
@@ -8129,9 +8657,19 @@ std::string toString( bool value ) {
}
std::string toString( char value ) {
- return value < ' '
- ? toString( static_cast<unsigned int>( value ) )
- : Detail::makeString( value );
+ if ( value == '\r' )
+ return "'\\r'";
+ if ( value == '\f' )
+ return "'\\f'";
+ if ( value == '\n' )
+ return "'\\n'";
+ if ( value == '\t' )
+ return "'\\t'";
+ if ( '\0' <= value && value < ' ' )
+ return toString( static_cast<unsigned int>( value ) );
+ char chstr[] = "' '";
+ chstr[1] = value;
+ return chstr;
}
std::string toString( signed char value ) {
@@ -8147,14 +8685,14 @@ std::string toString( long long value ) {
std::ostringstream oss;
oss << value;
if( value > Detail::hexThreshold )
- oss << " (0x" << std::hex << value << ")";
+ oss << " (0x" << std::hex << value << ')';
return oss.str();
}
std::string toString( unsigned long long value ) {
std::ostringstream oss;
oss << value;
if( value > Detail::hexThreshold )
- oss << " (0x" << std::hex << value << ")";
+ oss << " (0x" << std::hex << value << ')';
return oss.str();
}
#endif
@@ -8211,22 +8749,10 @@ namespace Catch {
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
return *this;
}
- ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
- m_exprComponents.lhs = lhs;
- return *this;
- }
- ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
- m_exprComponents.rhs = rhs;
- return *this;
- }
- ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
- m_exprComponents.op = op;
- return *this;
- }
- void ResultBuilder::endExpression() {
- m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition );
- captureExpression();
+ void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
+ AssertionResult result = build( expr );
+ handleResult( result );
}
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
@@ -8239,6 +8765,7 @@ namespace Catch {
setResultType( resultType );
captureExpression();
}
+
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
if( expectedMessage.empty() )
captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() );
@@ -8248,7 +8775,7 @@ namespace Catch {
void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) {
- assert( m_exprComponents.testFalse == false );
+ assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
AssertionResultData data = m_data;
data.resultType = ResultWas::Ok;
data.reconstructedExpression = m_assertionInfo.capturedExpression;
@@ -8266,6 +8793,7 @@ namespace Catch {
AssertionResult result = build();
handleResult( result );
}
+
void ResultBuilder::handleResult( AssertionResult const& result )
{
getResultCapture().assertionEnded( result );
@@ -8277,6 +8805,7 @@ namespace Catch {
m_shouldThrow = true;
}
}
+
void ResultBuilder::react() {
if( m_shouldThrow )
throw Catch::TestFailureException();
@@ -8287,43 +8816,32 @@ namespace Catch {
AssertionResult ResultBuilder::build() const
{
- assert( m_data.resultType != ResultWas::Unknown );
+ 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;
- // Flip bool results if testFalse is set
- if( m_exprComponents.testFalse ) {
- if( data.resultType == ResultWas::Ok )
- data.resultType = ResultWas::ExpressionFailed;
- else if( data.resultType == ResultWas::ExpressionFailed )
- data.resultType = ResultWas::Ok;
+ // Flip bool results if FalseTest flag is set
+ if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
+ data.negate( expr.isBinaryExpression() );
}
data.message = m_stream.oss.str();
- data.reconstructedExpression = reconstructExpression();
- if( m_exprComponents.testFalse ) {
- if( m_exprComponents.op == "" )
- data.reconstructedExpression = "!" + data.reconstructedExpression;
- else
- data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
- }
+ data.decomposedExpression = &expr; // for lazy reconstruction
return AssertionResult( m_assertionInfo, data );
}
- std::string ResultBuilder::reconstructExpression() const {
- if( m_exprComponents.op == "" )
- return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
- else if( m_exprComponents.op == "matches" )
- return m_exprComponents.lhs + " " + m_exprComponents.rhs;
- else if( m_exprComponents.op != "!" ) {
- if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
- m_exprComponents.lhs.find("\n") == std::string::npos &&
- m_exprComponents.rhs.find("\n") == std::string::npos )
- return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
- else
- return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
- }
- else
- return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
+
+ void ResultBuilder::reconstructExpression( std::string& dest ) const {
+ dest = m_assertionInfo.capturedExpression;
}
} // end namespace Catch
@@ -8352,9 +8870,6 @@ namespace Catch {
} // end namespace Catch
-#include <map>
-#include <iostream>
-
namespace Catch {
TagAliasRegistry::~TagAliasRegistry() {}
@@ -8384,7 +8899,7 @@ namespace Catch {
void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
- if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) {
+ if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
std::ostringstream oss;
oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
throw std::domain_error( oss.str().c_str() );
@@ -8392,7 +8907,7 @@ namespace Catch {
if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
std::ostringstream oss;
oss << "error: tag alias, \"" << alias << "\" already registered.\n"
- << "\tFirst seen at " << find(alias)->lineInfo << "\n"
+ << "\tFirst seen at " << find(alias)->lineInfo << '\n'
<< "\tRedefined at " << lineInfo;
throw std::domain_error( oss.str().c_str() );
}
@@ -8660,12 +9175,12 @@ namespace Catch {
struct BySectionInfo {
BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
- BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
+ BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
bool operator() ( Ptr<SectionNode> const& node ) const {
return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
}
private:
- void operator=( BySectionInfo const& );
+ void operator=( BySectionInfo const& );
SectionInfo const& m_other;
};
@@ -8721,6 +9236,12 @@ namespace Catch {
assert( !m_sectionStack.empty() );
SectionNode& sectionNode = *m_sectionStack.back();
sectionNode.assertions.push_back( assertionStats );
+ // AssertionResult holds a pointer to a temporary DecomposedExpression,
+ // which getExpandedExpression() calls to build the expression string.
+ // Our section stack copy of the assertionResult will likely outlive the
+ // temporary, so it must be expanded or discarded now to avoid calling
+ // a destroyed object later.
+ prepareExpandedExpression( sectionNode.assertions.back().assertionResult );
return true;
}
virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
@@ -8755,6 +9276,13 @@ namespace Catch {
virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
+ virtual void prepareExpandedExpression( AssertionResult& result ) const {
+ if( result.isOk() )
+ result.discardDecomposedExpression();
+ else
+ result.expandDecomposedExpression();
+ }
+
Ptr<IConfig const> m_config;
std::ostream& stream;
std::vector<AssertionStats> m_assertions;
@@ -8775,7 +9303,7 @@ namespace Catch {
char const* getLineOfChars() {
static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
if( !*line ) {
- memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
+ std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
}
return line;
@@ -8860,7 +9388,7 @@ namespace Catch {
return new T( config );
}
virtual std::string getDescription() const {
- return "";
+ return std::string();
}
};
@@ -8927,9 +9455,13 @@ namespace Catch {
break;
default:
- // Escape control chars - based on contribution by @espenalb in PR #465
- if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
- os << "&#x" << std::uppercase << std::hex << static_cast<int>( c );
+ // Escape control chars - based on contribution by @espenalb in PR #465 and
+ // by @mrpi PR #588
+ if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
+ // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+ os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
+ << static_cast<int>( c );
+ }
else
os << c;
}
@@ -8983,14 +9515,18 @@ namespace Catch {
XmlWriter()
: m_tagIsOpen( false ),
m_needsNewline( false ),
- m_os( &Catch::cout() )
- {}
+ m_os( Catch::cout() )
+ {
+ writeDeclaration();
+ }
XmlWriter( std::ostream& os )
: m_tagIsOpen( false ),
m_needsNewline( false ),
- m_os( &os )
- {}
+ m_os( os )
+ {
+ writeDeclaration();
+ }
~XmlWriter() {
while( !m_tags.empty() )
@@ -9000,7 +9536,7 @@ namespace Catch {
XmlWriter& startElement( std::string const& name ) {
ensureTagClosed();
newlineIfNecessary();
- stream() << m_indent << "<" << name;
+ m_os << m_indent << '<' << name;
m_tags.push_back( name );
m_indent += " ";
m_tagIsOpen = true;
@@ -9017,24 +9553,25 @@ namespace Catch {
newlineIfNecessary();
m_indent = m_indent.substr( 0, m_indent.size()-2 );
if( m_tagIsOpen ) {
- stream() << "/>\n";
+ m_os << "/>";
m_tagIsOpen = false;
}
else {
- stream() << m_indent << "</" << m_tags.back() << ">\n";
+ m_os << m_indent << "</" << m_tags.back() << ">";
}
+ m_os << std::endl;
m_tags.pop_back();
return *this;
}
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
if( !name.empty() && !attribute.empty() )
- stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\"";
+ m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
return *this;
}
XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
- stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
+ m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
return *this;
}
@@ -9050,8 +9587,8 @@ namespace Catch {
bool tagWasOpen = m_tagIsOpen;
ensureTagClosed();
if( tagWasOpen && indent )
- stream() << m_indent;
- stream() << XmlEncode( text );
+ m_os << m_indent;
+ m_os << XmlEncode( text );
m_needsNewline = true;
}
return *this;
@@ -9059,39 +9596,39 @@ namespace Catch {
XmlWriter& writeComment( std::string const& text ) {
ensureTagClosed();
- stream() << m_indent << "<!--" << text << "-->";
+ m_os << m_indent << "<!--" << text << "-->";
m_needsNewline = true;
return *this;
}
+ void writeStylesheetRef( std::string const& url ) {
+ m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
+ }
+
XmlWriter& writeBlankLine() {
ensureTagClosed();
- stream() << "\n";
+ m_os << '\n';
return *this;
}
- void setStream( std::ostream& os ) {
- m_os = &os;
+ void ensureTagClosed() {
+ if( m_tagIsOpen ) {
+ m_os << ">" << std::endl;
+ m_tagIsOpen = false;
+ }
}
private:
XmlWriter( XmlWriter const& );
void operator=( XmlWriter const& );
- std::ostream& stream() {
- return *m_os;
- }
-
- void ensureTagClosed() {
- if( m_tagIsOpen ) {
- stream() << ">\n";
- m_tagIsOpen = false;
- }
+ void writeDeclaration() {
+ m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
}
void newlineIfNecessary() {
if( m_needsNewline ) {
- stream() << "\n";
+ m_os << std::endl;
m_needsNewline = false;
}
}
@@ -9100,7 +9637,7 @@ namespace Catch {
bool m_needsNewline;
std::vector<std::string> m_tags;
std::string m_indent;
- std::ostream* m_os;
+ std::ostream& m_os;
};
}
@@ -9124,6 +9661,7 @@ namespace Catch {
public:
XmlReporter( ReporterConfig const& _config )
: StreamingReporterBase( _config ),
+ m_xml(_config.stream()),
m_sectionDepth( 0 )
{
m_reporterPrefs.shouldRedirectStdOut = true;
@@ -9135,6 +9673,10 @@ namespace Catch {
return "Reports test results as an XML document";
}
+ virtual std::string getStylesheetRef() const {
+ return std::string();
+ }
+
public: // StreamingReporterBase
virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE {
@@ -9143,7 +9685,9 @@ namespace Catch {
virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testRunStarting( testInfo );
- m_xml.setStream( stream );
+ std::string stylesheetRef = getStylesheetRef();
+ if( !stylesheetRef.empty() )
+ m_xml.writeStylesheetRef( stylesheetRef );
m_xml.startElement( "Catch" );
if( !m_config->name().empty() )
m_xml.writeAttribute( "name", m_config->name() );
@@ -9157,10 +9701,14 @@ namespace Catch {
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseStarting(testInfo);
- m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
+ m_xml.startElement( "TestCase" )
+ .writeAttribute( "name", trim( testInfo.name ) )
+ .writeAttribute( "description", testInfo.description )
+ .writeAttribute( "tags", testInfo.tagsAsString );
if ( m_config->showDurations() == ShowDurations::Always )
m_testCaseTimer.start();
+ m_xml.ensureTagClosed();
}
virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
@@ -9169,6 +9717,7 @@ namespace Catch {
m_xml.startElement( "Section" )
.writeAttribute( "name", trim( sectionInfo.name ) )
.writeAttribute( "description", sectionInfo.description );
+ m_xml.ensureTagClosed();
}
}
@@ -9200,7 +9749,7 @@ namespace Catch {
if( assertionResult.hasExpression() ) {
m_xml.startElement( "Expression" )
.writeAttribute( "success", assertionResult.succeeded() )
- .writeAttribute( "type", assertionResult.getTestMacroName() )
+ .writeAttribute( "type", assertionResult.getTestMacroName() )
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line );
@@ -9219,7 +9768,7 @@ namespace Catch {
.writeText( assertionResult.getMessage() );
break;
case ResultWas::FatalErrorCondition:
- m_xml.scopedElement( "Fatal Error Condition" )
+ m_xml.scopedElement( "FatalErrorCondition" )
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line )
.writeText( assertionResult.getMessage() );
@@ -9268,6 +9817,11 @@ namespace Catch {
if ( m_config->showDurations() == ShowDurations::Always )
e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
+ if( !testCaseStats.stdOut.empty() )
+ m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
+ if( !testCaseStats.stdErr.empty() )
+ m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
+
m_xml.endElement();
}
@@ -9307,6 +9861,35 @@ namespace Catch {
namespace Catch {
+ namespace {
+ std::string getCurrentTimestamp() {
+ // Beware, this is not reentrant because of backward compatibility issues
+ // Also, UTC only, again because of backward compatibility (%z is C++11)
+ time_t rawtime;
+ std::time(&rawtime);
+ const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z");
+
+#ifdef _MSC_VER
+ std::tm timeInfo = {};
+ gmtime_s(&timeInfo, &rawtime);
+#else
+ std::tm* timeInfo;
+ timeInfo = std::gmtime(&rawtime);
+#endif
+
+ char timeStamp[timeStampSize];
+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+ std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+ return std::string(timeStamp);
+ }
+
+ }
+
class JunitReporter : public CumulativeReporterBase {
public:
JunitReporter( ReporterConfig const& _config )
@@ -9371,7 +9954,7 @@ namespace Catch {
xml.writeAttribute( "time", "" );
else
xml.writeAttribute( "time", suiteTime );
- xml.writeAttribute( "timestamp", "tbd" ); // !TBD
+ xml.writeAttribute( "timestamp", getCurrentTimestamp() );
// Write test cases
for( TestGroupNode::ChildNodes::const_iterator
@@ -9406,7 +9989,7 @@ namespace Catch {
SectionNode const& sectionNode ) {
std::string name = trim( sectionNode.stats.sectionInfo.name );
if( !rootName.empty() )
- name = rootName + "/" + name;
+ name = rootName + '/' + name;
if( !sectionNode.assertions.empty() ||
!sectionNode.stdOut.empty() ||
@@ -9484,14 +10067,14 @@ namespace Catch {
std::ostringstream oss;
if( !result.getMessage().empty() )
- oss << result.getMessage() << "\n";
+ oss << result.getMessage() << '\n';
for( std::vector<MessageInfo>::const_iterator
it = stats.infoMessages.begin(),
itEnd = stats.infoMessages.end();
it != itEnd;
++it )
if( it->type == ResultWas::Info )
- oss << it->message << "\n";
+ oss << it->message << '\n';
oss << "at " << result.getSourceInfo();
xml.writeText( oss.str(), false );
@@ -9526,7 +10109,7 @@ namespace Catch {
}
virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
- stream << "No test cases matched '" << spec << "'" << std::endl;
+ stream << "No test cases matched '" << spec << '\'' << std::endl;
}
virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {
@@ -9568,12 +10151,12 @@ namespace Catch {
}
if( m_headerPrinted ) {
if( m_config->showDurations() == ShowDurations::Always )
- stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+ stream << "Completed in " << _sectionStats.durationInSeconds << 's' << std::endl;
m_headerPrinted = false;
}
else {
if( m_config->showDurations() == ShowDurations::Always )
- stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+ stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << 's' << std::endl;
}
StreamingReporterBase::sectionEnded( _sectionStats );
}
@@ -9587,7 +10170,7 @@ namespace Catch {
printSummaryDivider();
stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
printTotals( _testGroupStats.totals );
- stream << "\n" << std::endl;
+ stream << '\n' << std::endl;
}
StreamingReporterBase::testGroupEnded( _testGroupStats );
}
@@ -9679,13 +10262,13 @@ namespace Catch {
printSourceInfo();
if( stats.totals.assertions.total() > 0 ) {
if( result.isOk() )
- stream << "\n";
+ stream << '\n';
printResultType();
printOriginalExpression();
printReconstructedExpression();
}
else {
- stream << "\n";
+ stream << '\n';
}
printMessage();
}
@@ -9702,25 +10285,25 @@ namespace Catch {
Colour colourGuard( Colour::OriginalExpression );
stream << " ";
stream << result.getExpressionInMacro();
- stream << "\n";
+ stream << '\n';
}
}
void printReconstructedExpression() const {
if( result.hasExpandedExpression() ) {
stream << "with expansion:\n";
Colour colourGuard( Colour::ReconstructedExpression );
- stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n";
+ stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n';
}
}
void printMessage() const {
if( !messageLabel.empty() )
- stream << messageLabel << ":" << "\n";
+ stream << messageLabel << ':' << '\n';
for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
it != itEnd;
++it ) {
// If this assertion is a warning ignore any INFO messages
if( printInfoMessages || it->type != ResultWas::Info )
- stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n";
+ stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n';
}
}
void printSourceInfo() const {
@@ -9752,7 +10335,7 @@ namespace Catch {
}
}
void lazyPrintRunInfo() {
- stream << "\n" << getLineOfChars<'~'>() << "\n";
+ stream << '\n' << getLineOfChars<'~'>() << '\n';
Colour colour( Colour::SecondaryText );
stream << currentTestRunInfo->name
<< " is a Catch v" << libraryVersion << " host application.\n"
@@ -9783,22 +10366,22 @@ namespace Catch {
printHeaderString( it->name, 2 );
}
- SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
+ SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
if( !lineInfo.empty() ){
- stream << getLineOfChars<'-'>() << "\n";
+ stream << getLineOfChars<'-'>() << '\n';
Colour colourGuard( Colour::FileName );
- stream << lineInfo << "\n";
+ stream << lineInfo << '\n';
}
- stream << getLineOfChars<'.'>() << "\n" << std::endl;
+ stream << getLineOfChars<'.'>() << '\n' << std::endl;
}
void printClosedHeader( std::string const& _name ) {
printOpenHeader( _name );
- stream << getLineOfChars<'.'>() << "\n";
+ stream << getLineOfChars<'.'>() << '\n';
}
void printOpenHeader( std::string const& _name ) {
- stream << getLineOfChars<'-'>() << "\n";
+ stream << getLineOfChars<'-'>() << '\n';
{
Colour colourGuard( Colour::Headers );
printHeaderString( _name );
@@ -9815,7 +10398,7 @@ namespace Catch {
i = 0;
stream << Text( _string, TextAttributes()
.setIndent( indent+i)
- .setInitialIndent( indent ) ) << "\n";
+ .setInitialIndent( indent ) ) << '\n';
}
struct SummaryColumn {
@@ -9830,9 +10413,9 @@ namespace Catch {
std::string row = oss.str();
for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
while( it->size() < row.size() )
- *it = " " + *it;
+ *it = ' ' + *it;
while( it->size() > row.size() )
- row = " " + row;
+ row = ' ' + row;
}
rows.push_back( row );
return *this;
@@ -9852,8 +10435,8 @@ namespace Catch {
stream << Colour( Colour::ResultSuccess ) << "All tests passed";
stream << " ("
<< pluralise( totals.assertions.passed, "assertion" ) << " in "
- << pluralise( totals.testCases.passed, "test case" ) << ")"
- << "\n";
+ << pluralise( totals.testCases.passed, "test case" ) << ')'
+ << '\n';
}
else {
@@ -9888,10 +10471,10 @@ namespace Catch {
else if( value != "0" ) {
stream << Colour( Colour::LightGrey ) << " | ";
stream << Colour( it->colour )
- << value << " " << it->label;
+ << value << ' ' << it->label;
}
}
- stream << "\n";
+ stream << '\n';
}
static std::size_t makeRatio( std::size_t number, std::size_t total ) {
@@ -9927,10 +10510,10 @@ namespace Catch {
else {
stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
}
- stream << "\n";
+ stream << '\n';
}
void printSummaryDivider() {
- stream << getLineOfChars<'-'>() << "\n";
+ stream << getLineOfChars<'-'>() << '\n';
}
private:
@@ -9965,7 +10548,7 @@ namespace Catch {
}
virtual void noMatchingTestCases( std::string const& spec ) {
- stream << "No test cases matched '" << spec << "'" << std::endl;
+ stream << "No test cases matched '" << spec << '\'' << std::endl;
}
virtual void assertionStarting( AssertionInfo const& ) {
@@ -9992,7 +10575,7 @@ namespace Catch {
virtual void testRunEnded( TestRunStats const& _testRunStats ) {
printTotals( _testRunStats.totals );
- stream << "\n" << std::endl;
+ stream << '\n' << std::endl;
StreamingReporterBase::testRunEnded( _testRunStats );
}
@@ -10092,26 +10675,26 @@ namespace Catch {
void printSourceInfo() const {
Colour colourGuard( Colour::FileName );
- stream << result.getSourceInfo() << ":";
+ stream << result.getSourceInfo() << ':';
}
void printResultType( Colour::Code colour, std::string passOrFail ) const {
if( !passOrFail.empty() ) {
{
Colour colourGuard( colour );
- stream << " " << passOrFail;
+ stream << ' ' << passOrFail;
}
- stream << ":";
+ stream << ':';
}
}
void printIssue( std::string issue ) const {
- stream << " " << issue;
+ stream << ' ' << issue;
}
void printExpressionWas() {
if( result.hasExpression() ) {
- stream << ";";
+ stream << ';';
{
Colour colour( dimColour() );
stream << " expression was:";
@@ -10122,7 +10705,7 @@ namespace Catch {
void printOriginalExpression() const {
if( result.hasExpression() ) {
- stream << " " << result.getExpression();
+ stream << ' ' << result.getExpression();
}
}
@@ -10138,7 +10721,7 @@ namespace Catch {
void printMessage() {
if ( itMessage != messages.end() ) {
- stream << " '" << itMessage->message << "'";
+ stream << " '" << itMessage->message << '\'';
++itMessage;
}
}
@@ -10153,13 +10736,13 @@ namespace Catch {
{
Colour colourGuard( colour );
- stream << " with " << pluralise( N, "message" ) << ":";
+ stream << " with " << pluralise( N, "message" ) << ':';
}
for(; itMessage != itEnd; ) {
// If this assertion is a warning ignore any INFO messages
if( printInfoMessages || itMessage->type != ResultWas::Info ) {
- stream << " '" << itMessage->message << "'";
+ stream << " '" << itMessage->message << '\'';
if ( ++itMessage != itEnd ) {
Colour colourGuard( dimColour() );
stream << " and";
@@ -10185,7 +10768,7 @@ namespace Catch {
// - green: Passed [both/all] N tests cases with M assertions.
std::string bothOrAll( std::size_t count ) const {
- return count == 1 ? "" : count == 2 ? "both " : "all " ;
+ return count == 1 ? std::string() : count == 2 ? "both " : "all " ;
}
void printTotals( const Totals& totals ) const {
@@ -10196,12 +10779,12 @@ namespace Catch {
Colour colour( Colour::ResultError );
const std::string qualify_assertions_failed =
totals.assertions.failed == totals.assertions.total() ?
- bothOrAll( totals.assertions.failed ) : "";
+ bothOrAll( totals.assertions.failed ) : std::string();
stream <<
"Failed " << bothOrAll( totals.testCases.failed )
<< pluralise( totals.testCases.failed, "test case" ) << ", "
"failed " << qualify_assertions_failed <<
- pluralise( totals.assertions.failed, "assertion" ) << ".";
+ pluralise( totals.assertions.failed, "assertion" ) << '.';
}
else if( totals.assertions.total() == 0 ) {
stream <<
@@ -10213,14 +10796,14 @@ namespace Catch {
Colour colour( Colour::ResultError );
stream <<
"Failed " << pluralise( totals.testCases.failed, "test case" ) << ", "
- "failed " << pluralise( totals.assertions.failed, "assertion" ) << ".";
+ "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.';
}
else {
Colour colour( Colour::ResultSuccess );
stream <<
"Passed " << bothOrAll( totals.testCases.passed )
<< pluralise( totals.testCases.passed, "test case" ) <<
- " with " << pluralise( totals.assertions.passed, "assertion" ) << ".";
+ " with " << pluralise( totals.assertions.passed, "assertion" ) << '.';
}
}
};
@@ -10306,7 +10889,8 @@ namespace Catch {
// Standard C/C++ main entry point
int main (int argc, char * argv[]) {
- return Catch::Session().run( argc, argv );
+ int result = Catch::Session().run( argc, argv );
+ return ( result < 0xff ? result : 0xff );
}
#else // __OBJC__
@@ -10324,7 +10908,7 @@ int main (int argc, char * const argv[]) {
[pool drain];
#endif
- return result;
+ return ( result < 0xff ? result : 0xff );
}
#endif // __OBJC__
@@ -10354,12 +10938,12 @@ int main (int argc, char * const argv[]) {
#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
-#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
+#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CATCH_CHECK_THROWS" )
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" )
#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
-#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )