diff options
| author | Phil Nash | 2017-02-28 14:19:09 +0000 |
|---|---|---|
| committer | Phil Nash | 2017-02-28 14:19:09 +0000 |
| commit | 0952b76e16f91922d5353073b5a3ac7341aac006 (patch) | |
| tree | f29d82725c8417282f9716ca39e82362cc740327 | |
| parent | bbeb192ec952e3317971a9aa7eaa8640dd782624 (diff) | |
| download | catch3-1.8.0.tar.gz | |
v1.8.0 releasev1.8.0
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | docs/release-notes.md | 43 | ||||
| -rw-r--r-- | include/internal/catch_version.hpp | 2 | ||||
| -rw-r--r-- | single_include/catch.hpp | 794 |
4 files changed, 547 insertions, 296 deletions
@@ -1,10 +1,10 @@  -*v1.7.2* +*v1.8.0* Build status (on Travis CI) [](https://travis-ci.org/philsquared/Catch) -<a href="https://github.com/philsquared/Catch/releases/download/v1.7.2/catch.hpp">The latest, single header, version can be downloaded directly using this link</a> +<a href="https://github.com/philsquared/Catch/releases/download/v1.8.0/catch.hpp">The latest, single header, version can be downloaded directly using this link</a> ## What's the Catch? diff --git a/docs/release-notes.md b/docs/release-notes.md index e1bd19d2..6922468f 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,3 +1,40 @@ +# 1.8.0 + +### New features/ minor changes + +* Matchers have new, simpler (and documented) interface. + * Catch provides string and vector matchers. + * For details see [Matchers documentation](docs/matchers.md). +* Changed console reporter test duration reporting format (#322) + * Old format: `Some simple comparisons between doubles completed in 0.000123s` + * New format: `xxx.123s: Some simple comparisons between doubles` _(There will always be exactly 3 decimal places)_ +* Added opt-in leak detection under MSVC + Windows (#439) + * Enable it by compiling Catch's main with `CATCH_CONFIG_WINDOWS_CRTDBG` +* Introduced new compile-time flag, `CATCH_CONFIG_FAST_COMPILE`, trading features for compilation speed. + * Moves debug breaks out of tests and into implementation, speeding up compilation time by ~XX% + * _More changes are coming_ +* Added [TAP (Test Anything Protocol)](https://testanything.org/) and [Automake](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html#Log-files-generation-and-test-results-recording) reporters. + * These are not present in the default single-include header and need to be downloaded from GitHub separately. + * For details see [documentation about integrating with build systems](docs/build-systems.md). +* XML reporter now reports filename as part of the `Section` and `TestCase` tags. +* `Approx` now supports an optional margin of absolute error + * It has also received [new documentation](). + +### Fixes +* Silenced C4312 ("conversion from int to 'ClassName *") warnings in the evaluate layer. +* Fixed C4512 ("assignment operator could not be generated") warnings under VS2013. +* Cygwin compatibility fixes + * Signal handling is no longer compiled by default. + * Usage of `gettimeofday` inside Catch should no longer cause compilation errors. +* Improved `-Wparentheses` supression for gcc (#674) + * When compiled with gcc 4.8 or newer, the supression is localized to assertions only + * Otherwise it is supressed for the whole TU +* Fixed test spec parser issue (with escapes in multiple names) + +### Other +* Various documentation fixes and improvements + + # 1.7.2 ### Fixes and minor improvements @@ -31,9 +68,6 @@ Other: * Fixed possible infinite recursion in Windows SEH. * Fixed possible compilation error caused by Catch's operator overloads being ambiguous in regards to user-defined templated operators. -# Older versions -Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history - ## 1.7.0 ### Features/ Changes: @@ -102,6 +136,9 @@ Release notes were not maintained prior to v1.6.0, but you should be able to wor * Tweaks and changes to scripts - particularly for Approval test - to make them more portable +# Older versions +Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history + --- [Home](Readme.md) diff --git a/include/internal/catch_version.hpp b/include/internal/catch_version.hpp index 1041e303..3c3593fa 100644 --- a/include/internal/catch_version.hpp +++ b/include/internal/catch_version.hpp @@ -37,7 +37,7 @@ namespace Catch { return os; } - Version libraryVersion( 1, 7, 2, "", 0 ); + Version libraryVersion( 1, 8, 0, "", 0 ); } diff --git a/single_include/catch.hpp b/single_include/catch.hpp index 2a09fd19..abba8388 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v1.7.2 - * Generated: 2017-02-13 15:57:33.350226 + * Catch v1.8.0 + * Generated: 2017-02-28 14:16:45.289179 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -40,6 +40,12 @@ #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" # pragma GCC diagnostic ignored "-Wunused-variable" + + // For newer version we can use __Pragma to disable the warnings locally +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 4 && __GNUC_MINOR__ <= 7 +# pragma GCC diagnostic ignored "-Wparentheses" +# endif + # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif @@ -82,6 +88,7 @@ // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too @@ -117,12 +124,26 @@ # endif # if defined(CATCH_CPP11_OR_GREATER) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic pop" ) # endif #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +# if !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# endif + +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// // Borland #ifdef __BORLANDC__ @@ -144,12 +165,20 @@ // GCC #ifdef __GNUC__ +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +# define CATCH_GCC_HAS_NEW_PRAGMA +# endif + # if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif -# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_GCC_HAS_NEW_PRAGMA) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "GCC diagnostic push" ) \ + _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "GCC diagnostic pop" ) # endif // - otherwise more recent versions define __cplusplus >= 201103L @@ -290,9 +319,14 @@ #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif // noexcept support: @@ -871,6 +905,9 @@ namespace Catch { template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); + + private: + DecomposedExpression& operator = (DecomposedExpression const&); }; struct AssertionInfo @@ -967,313 +1004,153 @@ namespace Catch { namespace Matchers { namespace Impl { - namespace Generic { - template<typename ExpressionT> class AllOf; - template<typename ExpressionT> class AnyOf; - template<typename ExpressionT> class Not; - } - - template<typename ExpressionT> - struct Matcher : SharedImpl<IShared> - { - typedef ExpressionT ExpressionType; - - virtual ~Matcher() {} - virtual Ptr<Matcher> clone() const = 0; - virtual bool match( ExpressionT const& expr ) const = 0; - virtual std::string toString() const = 0; - - Generic::AllOf<ExpressionT> operator && ( Matcher<ExpressionT> const& other ) const; - Generic::AnyOf<ExpressionT> operator || ( Matcher<ExpressionT> const& other ) const; - Generic::Not<ExpressionT> operator ! () const; - }; - - template<typename DerivedT, typename ExpressionT> - struct MatcherImpl : Matcher<ExpressionT> { + template<typename ArgT> struct MatchAllOf; + template<typename ArgT> struct MatchAnyOf; + template<typename ArgT> struct MatchNotOf; - virtual Ptr<Matcher<ExpressionT> > clone() const { - return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) ); - } - }; - - namespace Generic { - template<typename ExpressionT> - class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT> { + class MatcherUntypedBase { public: - explicit Not( Matcher<ExpressionT> const& matcher ) : m_matcher(matcher.clone()) {} - Not( Not const& other ) : m_matcher( other.m_matcher ) {} - - virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { - return !m_matcher->match( expr ); + std::string toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = describe(); + return m_cachedToString; } - virtual std::string toString() const CATCH_OVERRIDE { - return "not " + m_matcher->toString(); - } + protected: + virtual std::string describe() const = 0; + mutable std::string m_cachedToString; private: - Ptr< Matcher<ExpressionT> > m_matcher; + MatcherUntypedBase& operator = ( MatcherUntypedBase const& ); }; - template<typename ExpressionT> - class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> { - public: + template<typename ObjectT, typename ComparatorT = ObjectT> + struct MatcherBase : MatcherUntypedBase { - AllOf() {} - AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + virtual bool match( ObjectT const& arg ) const = 0; - AllOf& add( Matcher<ExpressionT> const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( !m_matchers[i]->match( expr ) ) + MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const; + MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const; + MatchNotOf<ComparatorT> operator ! () const; + }; + + template<typename ArgT> + struct MatchAllOf : MatcherBase<ArgT> { + virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if (!m_matchers[i]->match(arg)) return false; + } return true; } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; + virtual std::string describe() const CATCH_OVERRIDE { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) - oss << " and "; - oss << m_matchers[i]->toString(); + description += " and "; + description += m_matchers[i]->toString(); } - oss << " )"; - return oss.str(); + description += " )"; + return description; } - AllOf operator && ( Matcher<ExpressionT> const& other ) const { - AllOf allOfExpr( *this ); - allOfExpr.add( other ); - return allOfExpr; + MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) { + m_matchers.push_back( &other ); + return *this; } - private: - std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; + std::vector<MatcherBase<ArgT> const*> m_matchers; }; + template<typename ArgT> + struct MatchAnyOf : MatcherBase<ArgT> { - template<typename ExpressionT> - class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> { - public: - - AnyOf() {} - AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} - - AnyOf& add( Matcher<ExpressionT> const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( m_matchers[i]->match( expr ) ) + virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if (m_matchers[i]->match(arg)) return true; + } return false; } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; + virtual std::string describe() const CATCH_OVERRIDE { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) - oss << " or "; - oss << m_matchers[i]->toString(); + description += " or "; + description += m_matchers[i]->toString(); } - oss << " )"; - return oss.str(); + description += " )"; + return description; } - AnyOf operator || ( Matcher<ExpressionT> const& other ) const { - AnyOf anyOfExpr( *this ); - anyOfExpr.add( other ); - return anyOfExpr; - } - - private: - std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; - }; - - } // namespace Generic - - template<typename ExpressionT> - Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator && ( Matcher<ExpressionT> const& other ) const { - Generic::AllOf<ExpressionT> allOfExpr; - allOfExpr.add( *this ); - allOfExpr.add( other ); - return allOfExpr; - } - - template<typename ExpressionT> - Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator || ( Matcher<ExpressionT> const& other ) const { - Generic::AnyOf<ExpressionT> anyOfExpr; - anyOfExpr.add( *this ); - anyOfExpr.add( other ); - return anyOfExpr; - } - - template<typename ExpressionT> - Generic::Not<ExpressionT> Matcher<ExpressionT>::operator ! () const { - return Generic::Not<ExpressionT>( *this ); - } - - namespace StdString { - - inline std::string makeString( std::string const& str ) { return str; } - inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } - - struct CasedString - { - CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_str( adjustString( str ) ) - {} - std::string adjustString( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No - ? toLower( str ) - : str; - - } - std::string toStringSuffix() const - { - return m_caseSensitivity == CaseSensitive::No - ? " (case insensitive)" - : std::string(); - } - CaseSensitive::Choice m_caseSensitivity; - std::string m_str; - }; - - struct Equals : MatcherImpl<Equals, std::string> { - Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) - : m_data( str, caseSensitivity ) - {} - Equals( Equals const& other ) : m_data( other.m_data ){} - - virtual ~Equals(); - - virtual bool match( std::string const& expr ) const { - return m_data.m_str == m_data.adjustString( expr );; - } - virtual std::string toString() const { - return "equals: \"" + m_data.m_str + '"' + m_data.toStringSuffix(); + MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) { + m_matchers.push_back( &other ); + return *this; } - CasedString m_data; + std::vector<MatcherBase<ArgT> const*> m_matchers; }; - struct Contains : MatcherImpl<Contains, std::string> { - Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) - : m_data( substr, caseSensitivity ){} - Contains( Contains const& other ) : m_data( other.m_data ){} + template<typename ArgT> + struct MatchNotOf : MatcherBase<ArgT> { - virtual ~Contains(); + MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} - virtual bool match( std::string const& expr ) const { - return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { + return !m_underlyingMatcher.match( arg ); } - virtual std::string toString() const { - return "contains: \"" + m_data.m_str + '"' + m_data.toStringSuffix(); - } - - CasedString m_data; - }; - - struct StartsWith : MatcherImpl<StartsWith, std::string> { - StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) - : m_data( substr, caseSensitivity ){} - - StartsWith( StartsWith const& other ) : m_data( other.m_data ){} - virtual ~StartsWith(); - - virtual bool match( std::string const& expr ) const { - 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(); + virtual std::string describe() const CATCH_OVERRIDE { + return "not " + m_underlyingMatcher.toString(); } - - CasedString m_data; + MatcherBase<ArgT> const& m_underlyingMatcher; }; - struct EndsWith : MatcherImpl<EndsWith, std::string> { - EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) - : m_data( substr, caseSensitivity ){} - EndsWith( EndsWith const& other ) : m_data( other.m_data ){} - - virtual ~EndsWith(); - - virtual bool match( std::string const& expr ) const { - 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(); - } + template<typename ObjectT, typename ComparatorT> + MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const { + return MatchAllOf<ComparatorT>() && *this && other; + } + template<typename ObjectT, typename ComparatorT> + MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const { + return MatchAnyOf<ComparatorT>() || *this || other; + } + template<typename ObjectT, typename ComparatorT> + MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const { + return MatchNotOf<ComparatorT>( *this ); + } - CasedString m_data; - }; - } // namespace StdString } // namespace Impl // The following functions create the actual matcher objects. // This allows the types to be inferred - template<typename ExpressionT> - inline Impl::Generic::Not<ExpressionT> Not( Impl::Matcher<ExpressionT> const& m ) { - return Impl::Generic::Not<ExpressionT>( m ); - } - - template<typename ExpressionT> - inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1, - Impl::Matcher<ExpressionT> const& m2 ) { - return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ); - } - template<typename ExpressionT> - inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1, - Impl::Matcher<ExpressionT> const& m2, - Impl::Matcher<ExpressionT> const& m3 ) { - return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 ); - } - template<typename ExpressionT> - inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1, - Impl::Matcher<ExpressionT> const& m2 ) { - return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ); - } - template<typename ExpressionT> - inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1, - Impl::Matcher<ExpressionT> const& m2, - Impl::Matcher<ExpressionT> const& m3 ) { - return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 ); - } - - inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { - return Impl::StdString::Equals( str, caseSensitivity ); - } - inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); - } - inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { - return Impl::StdString::Contains( substr, caseSensitivity ); - } - inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + // - deprecated: prefer ||, && and ! + template<typename T> + inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) { + return Impl::MatchNotOf<T>( underlyingMatcher ); } - inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { - return Impl::StdString::StartsWith( substr ); + template<typename T> + inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) { + return Impl::MatchAllOf<T>() && m1 && m2; } - inline Impl::StdString::StartsWith StartsWith( const char* substr ) { - return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + template<typename T> + inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) { + return Impl::MatchAllOf<T>() && m1 && m2 && m3; } - inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { - return Impl::StdString::EndsWith( substr ); + template<typename T> + inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) { + return Impl::MatchAnyOf<T>() || m1 || m2; } - inline Impl::StdString::EndsWith EndsWith( const char* substr ) { - return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + template<typename T> + inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) { + return Impl::MatchAnyOf<T>() || m1 || m2 || m3; } } // namespace Matchers using namespace Matchers; +using Matchers::Impl::MatcherBase; } // namespace Catch @@ -1328,7 +1205,7 @@ namespace Catch { void captureResult( ResultWas::OfType resultType ); void captureExpression(); void captureExpectedException( std::string const& expectedMessage ); - void captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ); + void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ); void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; @@ -1358,6 +1235,7 @@ namespace Catch { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) #endif #include <cstddef> @@ -1874,6 +1752,8 @@ class ExpressionLhs : public DecomposedExpression { public: ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} + ExpressionLhs& operator = ( const ExpressionLhs& ); + template<typename RhsT> BinaryExpression<T, Internal::IsEqualTo, RhsT const&> operator == ( RhsT const& rhs ) { @@ -1952,6 +1832,8 @@ public: BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} + BinaryExpression& operator = ( BinaryExpression& ); + void endExpression() const { m_rb .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) ) @@ -2246,6 +2128,14 @@ namespace Catch { } +#if defined(CATCH_CONFIG_FAST_COMPILE) +/////////////////////////////////////////////////////////////////////////////// +// We can speedup compilation significantly by breaking into debugger lower in +// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER +// macro in each assertion +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + resultBuilder.react(); +#else /////////////////////////////////////////////////////////////////////////////// // In the event of a failure works out if the debugger needs to be invoked // and/or an exception thrown and takes appropriate action. @@ -2254,6 +2144,7 @@ namespace Catch { #define INTERNAL_CATCH_REACT( resultBuilder ) \ if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ resultBuilder.react(); +#endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ @@ -2262,6 +2153,7 @@ namespace Catch { try { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ ( __catchResult <= expr ).endExpression(); \ + CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ @@ -2825,12 +2717,14 @@ namespace Detail { public: explicit Approx ( double value ) : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), + m_margin( 0.0 ), m_scale( 1.0 ), m_value( value ) {} Approx( Approx const& other ) : m_epsilon( other.m_epsilon ), + m_margin( other.m_margin ), m_scale( other.m_scale ), m_value( other.m_value ) {} @@ -2842,6 +2736,7 @@ namespace Detail { Approx operator()( double value ) { Approx approx( value ); approx.epsilon( m_epsilon ); + approx.margin( m_margin ); approx.scale( m_scale ); return approx; } @@ -2851,7 +2746,11 @@ namespace Detail { 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) ) ); + bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value))); + if (relativeOK) { + return true; + } + return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin; } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> @@ -2895,7 +2794,11 @@ namespace Detail { #else friend bool operator == ( double lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula - return std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); + bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); + if (relativeOK) { + return true; + } + return std::fabs(lhs - rhs.m_value) < rhs.m_margin; } friend bool operator == ( Approx const& lhs, double rhs ) { @@ -2936,6 +2839,11 @@ namespace Detail { return *this; } + Approx& margin( double newMargin ) { + m_margin = newMargin; + return *this; + } + Approx& scale( double newScale ) { m_scale = newScale; return *this; @@ -2949,6 +2857,7 @@ namespace Detail { private: double m_epsilon; + double m_margin; double m_scale; double m_value; }; @@ -2961,6 +2870,153 @@ inline std::string toString<Detail::Approx>( Detail::Approx const& value ) { } // end namespace Catch +// #included from: internal/catch_matchers_string.h +#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED + +namespace Catch { +namespace Matchers { + + namespace StdString { + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); + std::string adjustString( std::string const& str ) const; + std::string caseSensitivitySuffix() const; + + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct StringMatcherBase : MatcherBase<std::string> { + StringMatcherBase( std::string operation, CasedString const& comparator ); + virtual std::string describe() const CATCH_OVERRIDE; + + CasedString m_comparator; + std::string m_operation; + }; + + struct EqualsMatcher : StringMatcherBase { + EqualsMatcher( CasedString const& comparator ); + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + }; + struct ContainsMatcher : StringMatcherBase { + ContainsMatcher( CasedString const& comparator ); + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + }; + struct StartsWithMatcher : StringMatcherBase { + StartsWithMatcher( CasedString const& comparator ); + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + }; + struct EndsWithMatcher : StringMatcherBase { + EndsWithMatcher( CasedString const& comparator ); + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + }; + + } // namespace StdString + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + +} // namespace Matchers +} // namespace Catch + +// #included from: internal/catch_matchers_vector.h +#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED + +namespace Catch { +namespace Matchers { + + namespace Vector { + + template<typename T> + struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> { + + ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} + + bool match(std::vector<T> const &v) const CATCH_OVERRIDE { + return std::find(v.begin(), v.end(), m_comparator) != v.end(); + } + + virtual std::string describe() const CATCH_OVERRID |