diff --git a/CMakeLists.txt b/CMakeLists.txt
index 97a11485..0fa91501 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,7 +13,7 @@ set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
set(HEADER_DIR ${CATCH_DIR}/include)
-set(CATCH_VERSION_NUMBER 2.0.1)
+set(CATCH_VERSION_NUMBER 2.1.0)
if(USE_WMAIN)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
diff --git a/README.md b/README.md
index 6d50ed5c..207ba30e 100644
--- a/README.md
+++ b/README.md
@@ -5,13 +5,13 @@
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
[![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
-[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/tB8z0G3kMAIZkIca)
+[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/nerce2MiN6sVmfCi)
The latest version of the single header can be downloaded directly using this link
## Catch2 is released!
-If you've been using an earlier version of Catch, please see the
+If you've been using an earlier version of Catch, please see the
Breaking Changes section of [the release notes](https://github.com/catchorg/Catch2/releases/tag/v2.0.1)
before moving to Catch2. You might also like to read [this blog post](http://www.levelofindirection.com/journal/2017/11/3/catch2-released.html) for more details.
diff --git a/conanfile.py b/conanfile.py
index b4993b71..354f68a4 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -4,7 +4,7 @@ from conans import ConanFile
class CatchConan(ConanFile):
name = "Catch"
- version = "2.0.1"
+ version = "2.1.0"
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
author = "philsquared"
generators = "cmake"
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 1a762dbd..5c02f6bf 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -1,4 +1,45 @@
+
+# 2.1.0
+
+## Improvements
+* Various performance improvements
+ * On top of the performance regression fixes
+* Experimental support for PCH was added (#1061)
+* `CATCH_CONFIG_EXTERNAL_INTERFACES` now brings in declarations of Console, Compact, XML and JUnit reporters
+* `MatcherBase` no longer has a pointless second template argument
+* Reduced the number of warning suppressions that leak into user's code
+ * Bugs in g++ 4.x and 5.x mean that some of them have to be left in
+
+
+## Fixes
+* Fixed performance regression from Catch classic
+ * One of the performance improvement patches for Catch classic was not applied to Catch2
+* Fixed platform detection for iOS (#1084)
+* Fixed compilation when `g++` is used together with `libc++` (#1110)
+* Fixed TeamCity reporter compilation with the single header version
+ * To fix the underlying issue we will be versioning reporters in single_include folder per release
+* The XML reporter will now report `WARN` messages even when not used with `-s`
+* Fixed compilation when `VectorContains` matcher was combined using `&&` (#1092)
+* Fixed test duration overflowing after 10 seconds (#1125, #1129)
+* Fixed `std::uncaught_exception` deprecation warning (#1124)
+
+
+## New features
+* New Matchers
+ * Regex matcher for strings, `Matches`.
+ * Set-equal matcher for vectors, `UnorderedEquals`
+ * Floating point matchers, `WithinAbs` and `WithinULP`.
+* Stringification now attempts to decompose all containers (#606)
+ * Containers are objects that respond to ADL `begin(T)` and `end(T)`.
+
+
+## Other changes
+* Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version
+
+
+
+
# 2.0.1
## Breaking changes
diff --git a/include/internal/catch_version.cpp b/include/internal/catch_version.cpp
index a9dc64e6..8b50ace0 100644
--- a/include/internal/catch_version.cpp
+++ b/include/internal/catch_version.cpp
@@ -37,7 +37,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 2, 0, 1, "", 0 );
+ static Version version( 2, 1, 0, "", 0 );
return version;
}
diff --git a/single_include/catch.hpp b/single_include/catch.hpp
index 362f8693..ef720908 100644
--- a/single_include/catch.hpp
+++ b/single_include/catch.hpp
@@ -1,9 +1,9 @@
/*
- * Catch v2.0.1
- * Generated: 2017-11-03 11:53:39.642003
+ * Catch v2.1.0
+ * Generated: 2018-01-10 13:51:15.378034
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
- * Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved.
+ * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -26,9 +26,6 @@
# pragma warning(push)
# pragma warning(disable: 161 1682)
# else // __ICC
-# pragma clang diagnostic ignored "-Wglobal-constructors"
-# pragma clang diagnostic ignored "-Wvariadic-macros"
-# pragma clang diagnostic ignored "-Wc99-extensions"
# pragma clang diagnostic ignored "-Wunused-variable"
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wpadded"
@@ -36,27 +33,33 @@
# pragma clang diagnostic ignored "-Wcovered-switch-default"
# endif
#elif defined __GNUC__
-# pragma GCC diagnostic ignored "-Wvariadic-macros"
# pragma GCC diagnostic ignored "-Wunused-variable"
# pragma GCC diagnostic ignored "-Wparentheses"
-
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wpadded"
#endif
// end catch_suppress_warnings.h
#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
# define CATCH_IMPL
+# define CATCH_CONFIG_ALL_PARTS
+#endif
+
+// In the impl file, we want to have access to all parts of the headers
+// Can also be used to sanely support PCHs
+#if defined(CATCH_CONFIG_ALL_PARTS)
# define CATCH_CONFIG_EXTERNAL_INTERFACES
# if defined(CATCH_CONFIG_DISABLE_MATCHERS)
# undef CATCH_CONFIG_DISABLE_MATCHERS
# endif
+# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
#endif
+#if !defined(CATCH_CONFIG_IMPL_ONLY)
// start catch_platform.h
#ifdef __APPLE__
# include
-# if TARGET_OS_MAC == 1
+# if TARGET_OS_OSX == 1
# define CATCH_PLATFORM_MAC
# elif TARGET_OS_IPHONE == 1
# define CATCH_PLATFORM_IPHONE
@@ -70,6 +73,7 @@
#endif
// end catch_platform.h
+
#ifdef CATCH_IMPL
# ifndef CLARA_CONFIG_MAIN
# define CLARA_CONFIG_MAIN_NOT_DEFINED
@@ -77,6 +81,13 @@
# endif
#endif
+// start catch_user_interfaces.h
+
+namespace Catch {
+ unsigned int rngSeed();
+}
+
+// end catch_user_interfaces.h
// start catch_tag_alias_autoregistrar.h
// start catch_common.h
@@ -228,7 +239,10 @@ namespace Catch {
struct SourceLineInfo {
SourceLineInfo() = delete;
- SourceLineInfo( char const* _file, std::size_t _line ) noexcept;
+ SourceLineInfo( char const* _file, std::size_t _line ) noexcept
+ : file( _file ),
+ line( _line )
+ {}
SourceLineInfo( SourceLineInfo const& other ) = default;
SourceLineInfo( SourceLineInfo && ) = default;
@@ -245,11 +259,6 @@ namespace Catch {
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
- // This is just here to avoid compiler warnings with macro constants and boolean literals
- bool isTrue( bool value );
- bool alwaysTrue();
- bool alwaysFalse();
-
// Use this in variadic streaming macros to allow
// >> +StreamEndStop
// as well as
@@ -275,7 +284,10 @@ namespace Catch {
} // end namespace Catch
-#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
// end catch_tag_alias_autoregistrar.h
// start catch_test_registry.h
@@ -330,10 +342,12 @@ namespace Catch {
/// visible - but it does mean (substring) StringRefs should not be shared between
/// threads.
class StringRef {
- friend struct StringRefTestAccess;
-
+ public:
using size_type = std::size_t;
+ private:
+ friend struct StringRefTestAccess;
+
char const* m_start;
size_type m_size;
@@ -341,16 +355,50 @@ namespace Catch {
void takeOwnership();
- public: // construction/ assignment
- StringRef() noexcept;
- StringRef( StringRef const& other ) noexcept;
- StringRef( StringRef&& other ) noexcept;
- StringRef( char const* rawChars ) noexcept;
- StringRef( char const* rawChars, size_type size ) noexcept;
- StringRef( std::string const& stdString ) noexcept;
- ~StringRef() noexcept;
+ static constexpr char const* const s_empty = "";
+
+ public: // construction/ assignment
+ StringRef() noexcept
+ : StringRef( s_empty, 0 )
+ {}
+
+ StringRef( StringRef const& other ) noexcept
+ : m_start( other.m_start ),
+ m_size( other.m_size )
+ {}
+
+ StringRef( StringRef&& other ) noexcept
+ : m_start( other.m_start ),
+ m_size( other.m_size ),
+ m_data( other.m_data )
+ {
+ other.m_data = nullptr;
+ }
+
+ StringRef( char const* rawChars ) noexcept;
+
+ StringRef( char const* rawChars, size_type size ) noexcept
+ : m_start( rawChars ),
+ m_size( size )
+ {}
+
+ StringRef( std::string const& stdString ) noexcept
+ : m_start( stdString.c_str() ),
+ m_size( stdString.size() )
+ {}
+
+ ~StringRef() noexcept {
+ delete[] m_data;
+ }
+
+ auto operator = ( StringRef const &other ) noexcept -> StringRef& {
+ delete[] m_data;
+ m_data = nullptr;
+ m_start = other.m_start;
+ m_size = other.m_size;
+ return *this;
+ }
- auto operator = ( StringRef other ) noexcept -> StringRef&;
operator std::string() const;
void swap( StringRef& other ) noexcept;
@@ -362,8 +410,13 @@ namespace Catch {
auto operator[] ( size_type index ) const noexcept -> char;
public: // named queries
- auto empty() const noexcept -> bool;
- auto size() const noexcept -> size_type;
+ auto empty() const noexcept -> bool {
+ return m_size == 0;
+ }
+ auto size() const noexcept -> size_type {
+ return m_size;
+ }
+
auto numberOfCharacters() const noexcept -> size_type;
auto c_str() const -> char const*;
@@ -382,6 +435,10 @@ namespace Catch {
auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
+ inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
+ return StringRef( rawChars, size );
+ }
+
} // namespace Catch
// end catch_stringref.h
@@ -407,7 +464,7 @@ auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {
}
struct NameAndTags {
- NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept;
+ NameAndTags( StringRef name_ = StringRef(), StringRef tags_ = StringRef() ) noexcept;
StringRef name;
StringRef tags;
};
@@ -473,15 +530,121 @@ struct AutoReg : NonCopyable {
// start catch_assertionhandler.h
+// start catch_assertioninfo.h
+
+// start catch_result_type.h
+
+namespace Catch {
+
+ // ResultWas::OfType enum
+ struct ResultWas { enum OfType {
+ Unknown = -1,
+ Ok = 0,
+ Info = 1,
+ Warning = 2,
+
+ FailureBit = 0x10,
+
+ ExpressionFailed = FailureBit | 1,
+ ExplicitFailure = FailureBit | 2,
+
+ Exception = 0x100 | FailureBit,
+
+ ThrewException = Exception | 1,
+ DidntThrowException = Exception | 2,
+
+ FatalErrorCondition = 0x200 | FailureBit
+
+ }; };
+
+ bool isOk( ResultWas::OfType resultType );
+ bool isJustInfo( int flags );
+
+ // ResultDisposition::Flags enum
+ struct ResultDisposition { enum Flags {
+ Normal = 0x01,
+
+ ContinueOnFailure = 0x02, // Failures fail test, but execution continues
+ FalseTest = 0x04, // Prefix expression with !
+ SuppressFail = 0x08 // Failures are reported but do not fail the test
+ }; };
+
+ ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );
+
+ bool shouldContinueOnFailure( int flags );
+ inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
+ bool shouldSuppressFailure( int flags );
+
+} // end namespace Catch
+
+// end catch_result_type.h
+namespace Catch {
+
+ struct AssertionInfo
+ {
+ StringRef macroName;
+ SourceLineInfo lineInfo;
+ StringRef capturedExpression;
+ ResultDisposition::Flags resultDisposition;
+
+ // We want to delete this constructor but a compiler bug in 4.8 means
+ // the struct is then treated as non-aggregate
+ //AssertionInfo() = delete;
+ };
+
+} // end namespace Catch
+
+// end catch_assertioninfo.h
// start catch_decomposer.h
// start catch_tostring.h
-#include
#include
#include
#include
#include
+// start catch_stream.h
+
+#include
+#include
+#include
+
+namespace Catch {
+
+ std::ostream& cout();
+ std::ostream& cerr();
+ std::ostream& clog();
+
+ class StringRef;
+
+ struct IStream {
+ virtual ~IStream();
+ virtual std::ostream& stream() const = 0;
+ };
+
+ auto makeStream( StringRef const &filename ) -> IStream const*;
+
+ class ReusableStringStream {
+ std::size_t m_index;
+ std::ostream* m_oss;
+ public:
+ ReusableStringStream();
+ ~ReusableStringStream();
+
+ auto str() const -> std::string;
+
+ template
+ auto operator << ( T const& value ) -> ReusableStringStream& {
+ *m_oss << value;
+ return *this;
+ }
+ auto get() -> std::ostream& { return *m_oss; }
+
+ static void cleanup();
+ };
+}
+
+// end catch_stream.h
#ifdef __OBJC__
// start catch_objc_arc.hpp
@@ -535,7 +698,7 @@ inline id performOptionalSelector( id obj, SEL sel ) {
#endif
// We need a dummy global operator<< so we can bring it into Catch namespace later
-struct Catch_global_namespace_dummy;
+struct Catch_global_namespace_dummy {};
std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
namespace Catch {
@@ -566,25 +729,37 @@ namespace Catch {
static const bool value = decltype(test(0))::value;
};
+ template
+ std::string convertUnknownEnumToString( E e );
+
+ template
+ typename std::enable_if::value, std::string>::type convertUnstreamable( T const& ) {
+ return Detail::unprintableString;
+ };
+ template
+ typename std::enable_if::value, std::string>::type convertUnstreamable( T const& value ) {
+ return convertUnknownEnumToString( value );
+ };
+
} // namespace Detail
// If we decide for C++14, change these to enable_if_ts
- template
+ template
struct StringMaker {
template
static
typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type
- convert(const Fake& t) {
- std::ostringstream sstr;
- sstr << t;
- return sstr.str();
+ convert(const Fake& value) {
+ ReusableStringStream rss;
+ rss << value;
+ return rss.str();
}
template
static
typename std::enable_if::value, std::string>::type
- convert(const Fake&) {
- return Detail::unprintableString;
+ convert( const Fake& value ) {
+ return Detail::convertUnstreamable( value );
}
};
@@ -597,6 +772,11 @@ namespace Catch {
return ::Catch::StringMaker::type>::type>::convert(e);
}
+ template
+ std::string convertUnknownEnumToString( E e ) {
+ return ::Catch::Detail::stringify(static_cast::type>(e));
+ }
+
} // namespace Detail
// Some predefined specializations
@@ -627,6 +807,18 @@ namespace Catch {
static std::string convert(wchar_t * str);
};
+ template
+ struct is_string_array : std::false_type {};
+
+ template
+ struct is_string_array : std::true_type {};
+
+ template
+ struct is_string_array : std::true_type {};
+
+ template
+ struct is_string_array : std::true_type {};
+
template
struct StringMaker {
static std::string convert(const char* str) {
@@ -729,32 +921,18 @@ namespace Catch {
namespace Detail {
template
std::string rangeToString(InputIterator first, InputIterator last) {
- std::ostringstream oss;
- oss << "{ ";
+ ReusableStringStream rss;
+ rss << "{ ";
if (first != last) {
- oss << ::Catch::Detail::stringify(*first);
+ rss << ::Catch::Detail::stringify(*first);
for (++first; first != last; ++first)
- oss << ", " << ::Catch::Detail::stringify(*first);
+ rss << ", " << ::Catch::Detail::stringify(*first);
}
- oss << " }";
- return oss.str();
+ rss << " }";
+ return rss.str();
}
}
- template
- struct StringMaker > {
- static std::string convert( std::vector const& v ) {
- return ::Catch::Detail::rangeToString( v.begin(), v.end() );
- }
- };
-
- template
- struct EnumStringMaker {
- static std::string convert(const T& t) {
- return ::Catch::Detail::stringify(static_cast::type>(t));
- }
- };
-
#ifdef __OBJC__
template<>
struct StringMaker {
@@ -798,13 +976,13 @@ namespace Catch {
template
struct StringMaker > {
static std::string convert(const std::pair& pair) {
- std::ostringstream oss;
- oss << "{ "
+ ReusableStringStream rss;
+ rss << "{ "
<< ::Catch::Detail::stringify(pair.first)
<< ", "
<< ::Catch::Detail::stringify(pair.second)
<< " }";
- return oss.str();
+ return rss.str();
}
};
}
@@ -841,22 +1019,72 @@ namespace Catch {
template
struct StringMaker> {
static std::string convert(const std::tuple& tuple) {
- std::ostringstream os;
- os << '{';
- Detail::TupleElementPrinter>::print(tuple, os);
- os << " }";
- return os.str();
+ ReusableStringStream rss;
+ rss << '{';
+ Detail::TupleElementPrinter>::print(tuple, rss.get());
+ rss << " }";
+ return rss.str();
}
};
}
#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
+namespace Catch {
+ struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
+
+ // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
+ using std::begin;
+ using std::end;
+
+ not_this_one begin( ... );
+ not_this_one end( ... );
+
+ template
+ struct is_range {
+ static const bool value =
+ !std::is_same())), not_this_one>::value &&
+ !std::is_same())), not_this_one>::value;
+ };
+
+ template
+ std::string rangeToString( Range const& range ) {
+ return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
+ }
+
+ // Handle vector specially
+ template
+ std::string rangeToString( std::vector const& v ) {
+ ReusableStringStream rss;
+ rss << "{ ";
+ bool first = true;
+ for( bool b : v ) {
+ if( first )
+ first = false;
+ else
+ rss << ", ";
+ rss << ::Catch::Detail::stringify( b );
+ }
+ rss << " }";
+ return rss.str();
+ }
+
+ template
+ struct StringMaker::value && !is_string_array::value>::type> {
+ static std::string convert( R const& range ) {
+ return rangeToString( range );
+ }
+ };
+
+} // namespace Catch
+
// Separate std::chrono::duration specialization
#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
#include
#include
#include
+namespace Catch {
+
template
struct ratio_string {
static std::string symbol();
@@ -864,69 +1092,68 @@ struct ratio_string {
template
std::string ratio_string::symbol() {
- std::ostringstream oss;
- oss << '[' << Ratio::num << '/'
+ Catch::ReusableStringStream rss;
+ rss << '[' << Ratio::num << '/'
<< Ratio::den << ']';
- return oss.str();
+ return rss.str();
}
template <>
struct ratio_string {
- static std::string symbol() { return "a"; }
+ static std::string symbol();
};
template <>
struct ratio_string {
- static std::string symbol() { return "f"; }
+ static std::string symbol();
};
template <>
struct ratio_string {
- static std::string symbol() { return "p"; }
+ static std::string symbol();
};
template <>
struct ratio_string {
- static std::string symbol() { return "n"; }
+ static std::string symbol();
};
template <>
struct ratio_string {
- static std::string symbol() { return "u"; }
+ static std::string symbol();
};
template <>
struct ratio_string {
- static std::string symbol() { return "m"; }
+ static std::string symbol();
};
-namespace Catch {
////////////
// std::chrono::duration specializations
template
struct StringMaker> {
static std::string convert(std::chrono::duration const& duration) {
- std::ostringstream oss;
- oss << duration.count() << ' ' << ratio_string::symbol() << 's';
- return oss.str();
+ ReusableStringStream rss;
+ rss << duration.count() << ' ' << ratio_string::symbol() << 's';
+ return rss.str();
}
};
template
struct StringMaker>> {
static std::string convert(std::chrono::duration> const& duration) {
- std::ostringstream oss;
- oss << duration.count() << " s";
- return oss.str();
+ ReusableStringStream rss;
+ rss << duration.count() << " s";
+ return rss.str();
}
};
template
struct StringMaker>> {
static std::string convert(std::chrono::duration> const& duration) {
- std::ostringstream oss;
- oss << duration.count() << " m";
- return oss.str();
+ ReusableStringStream rss;
+ rss << duration.count() << " m";
+ return rss.str();
}
};
template
struct StringMaker>> {
static std::string convert(std::chrono::duration> const& duration) {
- std::ostringstream oss;
- oss << duration.count() << " h";
- return oss.str();
+ ReusableStringStream rss;
+ rss << duration.count() << " h";
+ return rss.str();
}
};
@@ -972,7 +1199,7 @@ namespace Catch {
#endif
// end catch_tostring.h
-#include
+#include
#ifdef _MSC_VER
#pragma warning(push)
@@ -985,27 +1212,32 @@ namespace Catch {
namespace Catch {
struct ITransientExpression {
- virtual auto isBinaryExpression() const -> bool = 0;
- virtual auto getResult() const -> bool = 0;
+ auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
+ auto getResult() const -> bool { return m_result; }
virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
- // We don't actually need a virtual destructore, but many static analysers
+ ITransientExpression( bool isBinaryExpression, bool result )
+ : m_isBinaryExpression( isBinaryExpression ),
+ m_result( result )
+ {}
+
+ // We don't actually need a virtual destructor, but many static analysers
// complain if it's not here :-(
virtual ~ITransientExpression();
+
+ bool m_isBinaryExpression;
+ bool m_result;
+
};
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
template
class BinaryExpr : public ITransientExpression {
- bool m_result;
LhsT m_lhs;
StringRef m_op;
RhsT m_rhs;
- auto isBinaryExpression() const -> bool override { return true; }
- auto getResult() const -> bool override { return m_result; }
-
void streamReconstructedExpression( std::ostream &os ) const override {
formatReconstructedExpression
( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
@@ -1013,7 +1245,7 @@ namespace Catch {
public:
BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
- : m_result( comparisonResult ),
+ : ITransientExpression{ true, comparisonResult },
m_lhs( lhs ),
m_op( op ),
m_rhs( rhs )
@@ -1024,15 +1256,15 @@ namespace Catch {
class UnaryExpr : public ITransientExpression {
LhsT m_lhs;
- auto isBinaryExpression() const -> bool override { return false; }
- auto getResult() const -> bool override { return m_lhs ? true : false; }
-
void streamReconstructedExpression( std::ostream &os ) const override {
os << Catch::Detail::stringify( m_lhs );
}
public:
- UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {}
+ explicit UnaryExpr( LhsT lhs )
+ : ITransientExpression{ false, lhs ? true : false },
+ m_lhs( lhs )
+ {}
};
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
@@ -1062,43 +1294,43 @@ namespace Catch {
class ExprLhs {
LhsT m_lhs;
public:
- ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
+ explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
template
auto operator == ( RhsT const& rhs ) -> BinaryExpr const {
- return BinaryExpr( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs );
+ return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs };
}
auto operator == ( bool rhs ) -> BinaryExpr const {
- return BinaryExpr( m_lhs == rhs, m_lhs, "==", rhs );
+ return { m_lhs == rhs, m_lhs, "==", rhs };
}
template
auto operator != ( RhsT const& rhs ) -> BinaryExpr const {
- return BinaryExpr( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs );
+ return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs };
}
auto operator != ( bool rhs ) -> BinaryExpr const {
- return BinaryExpr( m_lhs != rhs, m_lhs, "!=", rhs );
+ return { m_lhs != rhs, m_lhs, "!=", rhs };
}
template
auto operator > ( RhsT const& rhs ) -> BinaryExpr const {
- return BinaryExpr( m_lhs > rhs, m_lhs, ">", rhs );
+ return { m_lhs > rhs, m_lhs, ">", rhs };
}
template
auto operator < ( RhsT const& rhs ) -> BinaryExpr const {
- return BinaryExpr( m_lhs < rhs, m_lhs, "<", rhs );
+ return { m_lhs < rhs, m_lhs, "<", rhs };
}
template
auto operator >= ( RhsT const& rhs ) -> BinaryExpr const {
- return BinaryExpr( m_lhs >= rhs, m_lhs, ">=", rhs );
+ return { m_lhs >= rhs, m_lhs, ">=", rhs };
}
template
auto operator <= ( RhsT const& rhs ) -> BinaryExpr const {
- return BinaryExpr( m_lhs <= rhs, m_lhs, "<=", rhs );
+ return { m_lhs <= rhs, m_lhs, "<=", rhs };
}
auto makeUnaryExpr() const -> UnaryExpr {
- return UnaryExpr( m_lhs );
+ return UnaryExpr{ m_lhs };
}
};
@@ -1112,10 +1344,11 @@ namespace Catch {
struct Decomposer {
template
auto operator <= ( T const& lhs ) -> ExprLhs {
- return ExprLhs( lhs );
+ return ExprLhs{ lhs };
}
+
auto operator <=( bool value ) -> ExprLhs {
- return ExprLhs( value );
+ return ExprLhs{ value };
}
};
@@ -1126,79 +1359,88 @@ namespace Catch {
#endif
// end catch_decomposer.h
-// start catch_assertioninfo.h
+// start catch_interfaces_capture.h
-// start catch_result_type.h
+#include
namespace Catch {
- // ResultWas::OfType enum
- struct ResultWas { enum OfType {
- Unknown = -1,
- Ok = 0,
- Info = 1,
- Warning = 2,
+ class AssertionResult;
+ struct AssertionInfo;
+ struct SectionInfo;
+ struct SectionEndInfo;
+ struct MessageInfo;
+ struct Counts;
+ struct BenchmarkInfo;
+ struct BenchmarkStats;
+ struct AssertionReaction;
- FailureBit = 0x10,
+ struct ITransientExpression;
- ExpressionFailed = FailureBit | 1,
- ExplicitFailure = FailureBit | 2,
+ struct IResultCapture {
- Exception = 0x100 | FailureBit,
+ virtual ~IResultCapture();
- ThrewException = Exception | 1,
- DidntThrowException = Exception | 2,
+ virtual bool sectionStarted( SectionInfo const& sectionInfo,
+ Counts& assertions ) = 0;
+ virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
+ virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
- FatalErrorCondition = 0x200 | FailureBit
+ virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
+ virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
- }; };
+ virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+ virtual void popScopedMessage( MessageInfo const& message ) = 0;
- bool isOk( ResultWas::OfType resultType );
- bool isJustInfo( int flags );
+ virtual void handleFatalErrorCondition( StringRef message ) = 0;
- // ResultDisposition::Flags enum
- struct ResultDisposition { enum Flags {
- Normal = 0x01,
+ virtual void handleExpr
+ ( AssertionInfo const& info,
+ ITransientExpression const& expr,
+ AssertionReaction& reaction ) = 0;
+ virtual void handleMessage
+ ( AssertionInfo const& info,
+ ResultWas::OfType resultType,
+ StringRef const& message,
+ AssertionReaction& reaction ) = 0;
+ virtual void handleUnexpectedExceptionNotThrown
+ ( AssertionInfo const& info,
+ AssertionReaction& reaction ) = 0;
+ virtual void handleUnexpectedInflightException
+ ( AssertionInfo const& info,
+ std::string const& message,
+ AssertionReaction& reaction ) = 0;
+ virtual void handleIncomplete
+ ( AssertionInfo const& info ) = 0;
+ virtual void handleNonExpr
+ ( AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ AssertionReaction &reaction ) = 0;
- ContinueOnFailure = 0x02, // Failures fail test, but execution continues
- FalseTest = 0x04, // Prefix expression with !
- SuppressFail = 0x08 // Failures are reported but do not fail the test
- }; };
+ virtual bool lastAssertionPassed() = 0;
+ virtual void assertionPassed() = 0;
- ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );
-
- bool shouldContinueOnFailure( int flags );
- bool isFalseTest( int flags );
- bool shouldSuppressFailure( int flags );
-
-} // end namespace Catch
-
-// end catch_result_type.h
-namespace Catch {
-
- struct AssertionInfo
- {
- StringRef macroName;
- SourceLineInfo lineInfo;
- StringRef capturedExpression;
- ResultDisposition::Flags resultDisposition;
-
- // We want to delete this constructor but a compiler bug in 4.8 means
- // the struct is then treated as non-aggregate
- //AssertionInfo() = delete;
+ // Deprecated, do not use:
+ virtual std::string getCurrentTestName() const = 0;
+ virtual const AssertionResult* getLastResult() const = 0;
+ virtual void exceptionEarlyReported() = 0;
};
-} // end namespace Catch
+ IResultCapture& getResultCapture();
+}
-// end catch_assertioninfo.h
+// end catch_interfaces_capture.h
namespace Catch {
struct TestFailureException{};
struct AssertionResultData;
+ struct IResultCapture;
+ class RunContext;
class LazyExpression {
friend class AssertionHandler;
friend struct AssertionStats;
+ friend class RunContext;
ITransientExpression const* m_transientExpression = nullptr;
bool m_isNegated;
@@ -1212,11 +1454,16 @@ namespace Catch {
friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
};
+ struct AssertionReaction {
+ bool shouldDebugBreak = false;
+ bool shouldThrow = false;
+ };
+
class AssertionHandler {
AssertionInfo m_assertionInfo;
- bool m_shouldDebugBreak = false;
- bool m_shouldThrow = false;
- bool m_inExceptionGuard = false;
+ AssertionReaction m_reaction;
+ bool m_completed = false;
+ IResultCapture& m_resultCapture;
public:
AssertionHandler
@@ -1224,26 +1471,31 @@ namespace Catch {
SourceLineInfo const& lineInfo,
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition );
- ~AssertionHandler();
-
- void handle( ITransientExpression const& expr );
+ ~AssertionHandler() {
+ if ( !m_completed ) {
+ m_resultCapture.handleIncomplete( m_assertionInfo );
+ }
+ }
template
- void handle( ExprLhs const& expr ) {
- handle( expr.makeUnaryExpr() );
+ void handleExpr( ExprLhs const& expr ) {
+ handleExpr( expr.makeUnaryExpr() );
}
- void handle( ResultWas::OfType resultType );
- void handle( ResultWas::OfType resultType, StringRef const& message );
- void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated );
- void handle( AssertionResultData const& resultData, ITransientExpression const* expr );
+ void handleExpr( ITransientExpression const& expr );
- auto shouldDebugBreak() const -> bool;
+ void handleMessage(ResultWas::OfType resultType, StringRef const& message);
+
+ void handleExceptionThrownAsExpected();
+ void handleUnexpectedExceptionNotThrown();
+ void handleExceptionNotThrownAsExpected();
+ void handleThrowingCallSkipped();
+ void handleUnexpectedInflightException();
+
+ void complete();
+ void setCompleted();
+
+ // query
auto allowThrows() const -> bool;
- void reactWithDebugBreak() const;
- void reactWithoutDebugBreak() const;
- void useActiveException();
- void setExceptionGuard();
- void unsetExceptionGuard();
};
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
@@ -1254,7 +1506,6 @@ namespace Catch {
// start catch_message.h
#include
-#include
namespace Catch {
@@ -1283,8 +1534,7 @@ namespace Catch {
return *this;
}
- // !TBD reuse a global/ thread-local stream
- std::ostringstream m_stream;
+ ReusableStringStream m_stream;
};
struct MessageBuilder : MessageStream {
@@ -1303,7 +1553,7 @@ namespace Catch {
class ScopedMessage {
public:
- ScopedMessage( MessageBuilder const& builder );
+ explicit ScopedMessage( MessageBuilder const& builder );
~ScopedMessage();
MessageInfo m_info;
@@ -1312,89 +1562,6 @@ namespace Catch {
} // end namespace Catch
// end catch_message.h
-// start catch_interfaces_capture.h
-
-#include
-
-namespace Catch {
-
- class AssertionResult;
- struct AssertionInfo;
- struct SectionInfo;
- struct SectionEndInfo;
- struct MessageInfo;
- struct Counts;
- struct BenchmarkInfo;
- struct BenchmarkStats;
-
- struct IResultCapture {
-
- virtual ~IResultCapture();
-
- virtual void assertionStarting( AssertionInfo const& info ) = 0;
- virtual void assertionEnded( AssertionResult const& result ) = 0;
- virtual bool sectionStarted( SectionInfo const& sectionInfo,
- Counts& assertions ) = 0;
- virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
- virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
-
- virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
- virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
-
- virtual void pushScopedMessage( MessageInfo const& message ) = 0;
- virtual void popScopedMessage( MessageInfo const& message ) = 0;
-
- virtual std::string getCurrentTestName() const = 0;
- virtual const AssertionResult* getLastResult() const = 0;
-
- virtual void exceptionEarlyReported() = 0;
-
- virtual void handleFatalErrorCondition( StringRef message ) = 0;
-
- virtual bool lastAssertionPassed() = 0;
- virtual void assertionPassed() = 0;
- virtual void assertionRun() = 0;
- };
-
- IResultCapture& getResultCapture();
-}
-
-// end catch_interfaces_capture.h
-// start catch_debugger.h
-
-namespace Catch {
- bool isDebuggerActive();
-}
-
-#ifdef CATCH_PLATFORM_MAC
-
- #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
-
-#elif defined(CATCH_PLATFORM_LINUX)
- // If we can use inline assembler, do it because this allows us to break
- // 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") /* NOLINT */
- #else // Fall back to the generic way.
- #include
-
- #define CATCH_TRAP() raise(SIGTRAP)
- #endif
-#elif defined(_MSC_VER)
- #define CATCH_TRAP() __debugbreak()
-#elif defined(__MINGW32__)
- extern "C" __declspec(dllimport) void __stdcall DebugBreak();
- #define CATCH_TRAP() DebugBreak()
-#endif
-
-#ifdef CATCH_TRAP
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
-#else
- #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
-#endif
-
-// end catch_debugger.h
#if !defined(CATCH_CONFIG_DISABLE)
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
@@ -1404,48 +1571,33 @@ namespace Catch {
#endif
#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( handler ) \
- handler.reactWithDebugBreak();
///////////////////////////////////////////////////////////////////////////////
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
// macros.
-// This can potentially cause false negative, if the test code catches
-// the exception before it propagates back up to the runner.
-#define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard();
-#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard();
+#define INTERNAL_CATCH_TRY
+#define INTERNAL_CATCH_CATCH( capturer )
#else // CATCH_CONFIG_FAST_COMPILE
-///////////////////////////////////////////////////////////////////////////////
-// In the event of a failure works out if the debugger needs to be invoked
-// and/or an exception thrown and takes appropriate action.
-// This needs to be done as a macro so the debugger will stop in the user
-// source code rather than in Catch library code
-#define INTERNAL_CATCH_REACT( handler ) \
- if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
- handler.reactWithoutDebugBreak();
-
-#define INTERNAL_CATCH_TRY( capturer ) try
-#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); }
+#define INTERNAL_CATCH_TRY try
+#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); }
#endif
+#define INTERNAL_CATCH_REACT( handler ) handler.complete();
+
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
- INTERNAL_CATCH_TRY( catchAssertionHandler ) { \
+ INTERNAL_CATCH_TRY { \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
- catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \
+ catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
+ } while( (void)0, false && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
///////////////////////////////////////////////////////////////////////////////
@@ -1464,13 +1616,13 @@ namespace Catch {
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
try { \
static_cast(__VA_ARGS__); \
- catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
+ catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
} \
catch( ... ) { \
- catchAssertionHandler.useActiveException(); \
+ catchAssertionHandler.handleUnexpectedInflightException(); \
} \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( Catch::alwaysFalse() )
+ } while( false )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
@@ -1479,15 +1631,15 @@ namespace Catch {
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast(__VA_ARGS__); \
- catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
} \
catch( ... ) { \
- catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
+ catchAssertionHandler.handleExceptionThrownAsExpected(); \
} \
else \
- catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( Catch::alwaysFalse() )
+ } while( false )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
@@ -1496,30 +1648,30 @@ namespace Catch {
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast(expr); \
- catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
} \
catch( exceptionType const& ) { \
- catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
+ catchAssertionHandler.handleExceptionThrownAsExpected(); \
} \
catch( ... ) { \
- catchAssertionHandler.useActiveException(); \
+ catchAssertionHandler.handleUnexpectedInflightException(); \
} \
else \
- catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( Catch::alwaysFalse() )
+ } while( false )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
- catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
+ catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( Catch::alwaysFalse() )
+ } while( false )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_INFO( macroName, log ) \
- Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
+ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
///////////////////////////////////////////////////////////////////////////////
// Although this is matcher-based, it can be used with just a string
@@ -1529,15 +1681,15 @@ namespace Catch {
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast(__VA_ARGS__); \
- catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
} \
catch( ... ) { \
- handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
+ Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
} \
else \
- catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( Catch::alwaysFalse() )
+ } while( false )
#endif // CATCH_CONFIG_DISABLE
@@ -1617,8 +1769,8 @@ namespace Catch {
uint64_t m_nanoseconds = 0;
public:
void start();
- auto getElapsedNanoseconds() const -> unsigned int;
- auto getElapsedMicroseconds() const -> unsigned int;
+ auto getElapsedNanoseconds() const -> uint64_t;
+ auto getElapsedMicroseconds() const -> uint64_t;
auto getElapsedMilliseconds() const -> unsigned int;
auto getElapsedSeconds() const -> double;
};
@@ -1812,7 +1964,9 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
static std::string translatorName( signature ); \
- namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
static std::string translatorName( signature )
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
@@ -1820,22 +1974,8 @@ namespace Catch {
// end catch_interfaces_exception.h
// start catch_approx.h
-// start catch_enforce.h
-
-#include
-#include
-
-#define CATCH_PREPARE_EXCEPTION( type, msg ) \
- type( static_cast( std::ostringstream() << msg ).str() )
-#define CATCH_INTERNAL_ERROR( msg ) \
- throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
-#define CATCH_ERROR( msg ) \
- throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg )
-#define CATCH_ENFORCE( condition, msg ) \
- do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
-
-// end catch_enforce.h
#include
+#include
namespace Catch {
namespace Detail {
@@ -1906,9 +2046,12 @@ namespace Detail {
template ::value>::type>
Approx& epsilon( T const& newEpsilon ) {
double epsilonAsDouble = static_cast(newEpsilon);
- CATCH_ENFORCE(epsilonAsDouble >= 0 && epsilonAsDouble <= 1.0,
- "Invalid Approx::epsilon: " << epsilonAsDouble
- << ", Approx::epsilon has to be between 0 and 1");
+ if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) {
+ throw std::domain_error
+ ( "Invalid Approx::epsilon: " +
+ Catch::Detail::stringify( epsilonAsDouble ) +
+ ", Approx::epsilon has to be between 0 and 1" );
+ }
m_epsilon = epsilonAsDouble;
return *this;
}
@@ -1916,9 +2059,13 @@ namespace Detail {
template ::value>::type>
Approx& margin( T const& newMargin ) {
double marginAsDouble = static_cast(newMargin);
- CATCH_ENFORCE(marginAsDouble >= 0,
- "Invalid Approx::margin: " << marginAsDouble
- << ", Approx::Margin has to be non-negative.");
+ if( marginAsDouble < 0 ) {
+ throw std::domain_error
+ ( "Invalid Approx::margin: " +
+ Catch::Detail::stringify( marginAsDouble ) +
+ ", Approx::Margin has to be non-negative." );
+
+ }
m_margin = marginAsDouble;
return *this;
}
@@ -2013,12 +2160,12 @@ namespace Matchers {
virtual bool match( PtrT* arg ) const = 0;
};
- template
- struct MatcherBase : MatcherUntypedBase, MatcherMethod {
+ template
+ struct MatcherBase : MatcherUntypedBase, MatcherMethod {
- MatchAllOf operator && ( MatcherBase const& other ) const;
- MatchAnyOf operator || ( MatcherBase const& other ) const;
- MatchNotOf operator ! () const;
+ MatchAllOf operator && ( MatcherBase const& other ) const;
+ MatchAnyOf operator || ( MatcherBase const& other ) const;
+ MatchNotOf operator ! () const;
};
template
@@ -2102,17 +2249,17 @@ namespace Matchers {
MatcherBase const& m_underlyingMatcher;
};
- template
- MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const {
- return MatchAllOf() && *this && other;
+ template
+ MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const {
+ return MatchAllOf() && *this && other;
}
- template
- MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const {
- return MatchAnyOf() || *this || other;
+ template
+ MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const {
+ return MatchAnyOf() || *this || other;
}
- template
- MatchNotOf MatcherBase::operator ! () const {
- return MatchNotOf( *this );
+ template
+ MatchNotOf MatcherBase::operator ! () const {
+ return MatchNotOf( *this );
}
} // namespace Impl
@@ -2125,6 +2272,49 @@ using Matchers::Impl::MatcherBase;
} // namespace Catch
// end catch_matchers.h
+// start catch_matchers_floating.h
+
+#include
+#include
+
+namespace Catch {
+namespace Matchers {
+
+ namespace Floating {
+
+ enum class FloatingPointKind : uint8_t;
+
+ struct WithinAbsMatcher : MatcherBase {
+ WithinAbsMatcher(double target, double margin);
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ double m_margin;
+ };
+
+ struct WithinUlpsMatcher : MatcherBase {
+ WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ int m_ulps;
+ FloatingPointKind m_type;
+ };
+
+ } // namespace Floating
+
+ // The following functions create the actual matcher objects.
+ // This allows the types to be inferred
+ Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff);
+ Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff);
+ Floating::WithinAbsMatcher WithinAbs(double target, double margin);
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_floating.h
// start catch_matchers_string.h
#include
@@ -2169,6 +2359,16 @@ namespace Matchers {
bool match( std::string const& source ) const override;
};
+ struct RegexMatcher : MatcherBase {
+ RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity );
+ bool match( std::string const& matchee ) const override;
+ std::string describe() const override;
+
+ private:
+ std::string m_regex;
+ CaseSensitive::Choice m_caseSensitivity;
+ };
+
} // namespace StdString
// The following functions create the actual matcher objects.
@@ -2178,6 +2378,7 @@ namespace Matchers {
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 );
+ StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
} // namespace Matchers
} // namespace Catch
@@ -2185,13 +2386,36 @@ namespace Matchers {
// end catch_matchers_string.h
// start catch_matchers_vector.h
+#include
+
namespace Catch {
namespace Matchers {
namespace Vector {
+ namespace Detail {
+ template
+ size_t count(InputIterator first, InputIterator last, T const& item) {
+ size_t cnt = 0;
+ for (; first != last; ++first) {
+ if (*first == item) {
+ ++cnt;
+ }
+ }
+ return cnt;
+ }
+ template
+ bool contains(InputIterator first, InputIterator last, T const& item) {
+ for (; first != last; ++first) {
+ if (*first == item) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
template
- struct ContainsElementMatcher : MatcherBase, T> {
+ struct ContainsElementMatcher : MatcherBase> {
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
@@ -2212,7 +2436,7 @@ namespace Matchers {
};
template
- struct ContainsMatcher : MatcherBase, std::vector > {
+ struct ContainsMatcher : MatcherBase> {
ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {}
@@ -2242,7 +2466,7 @@ namespace Matchers {
};
template
- struct EqualsMatcher : MatcherBase, std::vector > {
+ struct EqualsMatcher : MatcherBase> {
EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {}
@@ -2264,6 +2488,46 @@ namespace Matchers {
std::vector const& m_comparator;
};
+ template
+ struct UnorderedEqualsMatcher : MatcherBase> {
+ UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {}
+ bool match(std::vector const& vec) const override {
+ // Note: This is a reimplementation of std::is_permutation,
+ // because I don't want to include inside the common path
+ if (m_target.size() != vec.size()) {
+ return false;
+ }
+ auto lfirst = m_target.begin(), llast = m_target.end();
+ auto rfirst = vec.begin(), rlast = vec.end();
+ // Cut common prefix to optimize checking of permuted parts
+ while (lfirst != llast && *lfirst != *rfirst) {
+ ++lfirst; ++rfirst;
+ }
+ if (lfirst == llast) {
+ return true;
+ }
+
+ for (auto mid = lfirst; mid != llast; ++mid) {
+ // Skip already counted items
+ if (Detail::contains(lfirst, mid, *mid)) {
+ continue;
+ }
+ size_t num_vec = Detail::count(rfirst, rlast, *mid);
+ if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ std::string describe() const override {
+ return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
+ }
+ private:
+ std::vector const& m_target;
+ };
+
} // namespace Vector
// The following functions create the actual matcher objects.
@@ -2284,6 +2548,11 @@ namespace Matchers {
return Vector::EqualsMatcher( comparator );
}
+ template
+ Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) {
+ return Vector::UnorderedEqualsMatcher(target);
+ }
+
} // namespace Matchers
} // namespace Catch
@@ -2295,18 +2564,14 @@ namespace Catch {
ArgT const& m_arg;
MatcherT m_matcher;
StringRef m_matcherString;
- bool m_result;
public:
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString )
- : m_arg( arg ),
+ : ITransientExpression{ true, matcher.match( arg ) },
+ m_arg( arg ),
m_matcher( matcher ),
- m_matcherString( matcherString ),
- m_result( matcher.match( arg ) )
+ m_matcherString( matcherString )
{}
- auto isBinaryExpression() const -> bool override { return true; }
- auto getResult() const -> bool override { return m_result; }
-
void streamReconstructedExpression( std::ostream &os ) const override {
auto matcherAsString = m_matcher.toString();
os << Catch::Detail::stringify( m_arg ) << ' ';
@@ -2332,11 +2597,11 @@ namespace Catch {
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
- INTERNAL_CATCH_TRY( catchAssertionHandler ) { \
- catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
+ INTERNAL_CATCH_TRY { \
+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( Catch::alwaysFalse() )
+ } while( false )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
@@ -2345,18 +2610,18 @@ namespace Catch {
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast(__VA_ARGS__ ); \
- catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
} \
catch( exceptionType const& ex ) { \
- catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
} \
catch( ... ) { \
- catchAssertionHandler.useActiveException(); \
+ catchAssertionHandler.handleUnexpectedInflightException(); \
} \
else \
- catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
+ catchAssertionHandler.handleThrowingCallSkipped(); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( Catch::alwaysFalse() )
+ } while( false )
// end catch_capture_matchers.h
#endif
@@ -2918,69 +3183,6 @@ namespace Catch {
// end catch_interfaces_config.h
// Libstdc++ doesn't like incomplete classes for unique_ptr
-// start catch_stream.h
-
-// start catch_streambuf.h
-
-#include
-
-namespace Catch {
-
- class StreamBufBase : public std::streambuf {
- public:
- virtual ~StreamBufBase();
- };
-}
-
-// end catch_streambuf.h
-#include
-#include
-#include
-#include
-
-namespace Catch {
-
- std::ostream& cout();
- std::ostream& cerr();
- std::ostream& clog();
-
- struct IStream {
- virtual ~IStream();
- virtual std::ostream& stream() const = 0;
- };
-
- class FileStream : public IStream {
- mutable std::ofstream m_ofs;
- public:
- FileStream( std::string const& filename );
- ~FileStream() override = default;
- public: // IStream
- std::ostream& stream() const override;
- };
-
- class CoutStream : public IStream {
- mutable std::ostream m_os;
- public:
- CoutStream();
- ~CoutStream() override = default;
-
- public: // IStream
- std::ostream& stream() const override;
- };
-
- class DebugOutStream : public IStream {
- std::unique_ptr m_streamBuf;
- mutable std::ostream m_os;
- public:
- DebugOutStream();
- ~DebugOutStream() override = default;
-
- public: // IStream
- std::ostream& stream() const override;
- };
-}
-
-// end catch_stream.h
#include
#include
@@ -3115,7 +3317,7 @@ namespace Catch {
std::string getExpandedExpression() const;
std::string getMessage() const;
SourceLineInfo getSourceInfo() const;
- std::string getTestMacroName() const;
+ StringRef getTestMacroName() const;
//protected:
AssertionInfo m_info;
@@ -3408,6 +3610,7 @@ namespace Catch {
#include
#include
#include
+#include
namespace Catch {
void prepareExpandedExpression(AssertionResult& result);
@@ -3423,7 +3626,8 @@ namespace Catch {
stream( _config.stream() )
{
m_reporterPrefs.shouldRedirectStdOut = false;
- CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" );
+ if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
+ throw std::domain_error( "Verbosity level not supported by this reporter" );
}
ReporterPreferences getPreferences() const override {
@@ -3536,7 +3740,8 @@ namespace Catch {
stream( _config.stream() )
{
m_reporterPrefs.shouldRedirectStdOut = false;
- CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" );
+ if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
+ throw std::domain_error( "Verbosity level not supported by this reporter" );
}
~CumulativeReporterBase() override = default;
@@ -3738,7 +3943,7 @@ namespace Catch {
public:
- ReporterRegistrar( std::string const& name ) {
+ explicit ReporterRegistrar( std::string const& name ) {
getMutableRegistryHub().registerReporter( name, std::make_shared() );
}
};
@@ -3783,9 +3988,303 @@ namespace Catch {
#endif // CATCH_CONFIG_DISABLE
// end catch_reporter_registrars.hpp
+// Allow users to base their work off existing reporters
+// start catch_reporter_compact.h
+
+namespace Catch {
+
+ struct CompactReporter : StreamingReporterBase {
+
+ using StreamingReporterBase::StreamingReporterBase;
+
+ ~CompactReporter() override;
+
+ static std::string getDescription();
+
+ ReporterPreferences getPreferences() const override;
+
+ void noMatchingTestCases(std::string const& spec) override;
+
+ void assertionStarting(AssertionInfo const&) override;
+
+ bool assertionEnded(AssertionStats const& _assertionStats) override;
+
+ void sectionEnded(SectionStats const& _sectionStats) override;
+
+ void testRunEnded(TestRunStats const& _testRunStats) override;
+
+ };
+
+} // end namespace Catch
+
+// end catch_reporter_compact.h
+// start catch_reporter_console.h
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
+ // Note that 4062 (not all labels are handled
+ // and default is missing) is enabled
+#endif
+
+namespace Catch {
+ // Fwd decls
+ struct SummaryColumn;
+ class TablePrinter;
+
+ struct ConsoleReporter : StreamingReporterBase {
+ std::unique_ptr m_tablePrinter;
+
+ ConsoleReporter(ReporterConfig const& config);
+ ~ConsoleReporter() override;
+ static std::string getDescription();
+
+ void noMatchingTestCases(std::string const& spec) override;
+
+ void assertionStarting(AssertionInfo const&) override;
+
+ bool assertionEnded(AssertionStats const& _assertionStats) override;
+
+ void sectionStarting(SectionInfo const& _sectionInfo) override;
+ void sectionEnded(SectionStats const& _sectionStats) override;
+
+ void benchmarkStarting(BenchmarkInfo const& info) override;
+ void benchmarkEnded(BenchmarkStats const& stats) override;
+
+ void testCaseEnded(TestCaseStats const& _testCaseStats) override;
+ void testGroupEnded(TestGroupStats const& _testGroupStats) override;
+ void testRunEnded(TestRunStats const& _testRunStats) override;
+
+ private:
+
+ void lazyPrint();
+
+ void lazyPrintWithoutClosingBenchmarkTable();
+ void lazyPrintRunInfo();
+ void lazyPrintGroupInfo();
+ void printTestCaseAndSectionHeader();
+
+ void printClosedHeader(std::string const& _name);
+ void printOpenHeader(std::string const& _name);
+
+ // if string has a : in first line will set indent to follow it on
+ // subsequent lines
+ void printHeaderString(std::string const& _string, std::size_t indent = 0);
+
+ void printTotals(Totals const& totals);
+ void printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row);
+
+ void printTotalsDivider(Totals const& totals);
+ void printSummaryDivider();
+
+ private:
+ bool m_headerPrinted = false;
+ };
+
+} // end namespace Catch
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+// end catch_reporter_console.h
+// start catch_reporter_junit.h
+
+// start catch_xmlwriter.h
+
+#include
+
+namespace Catch {
+
+ class XmlEncode {
+ public:
+ enum ForWhat { ForTextNodes, ForAttributes };
+
+ XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );
+
+ void encodeTo( std::ostream& os ) const;
+
+ friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
+
+ private:
+ std::string m_str;
+ ForWhat m_forWhat;
+ };
+
+ class XmlWriter {
+ public:
+
+ class ScopedElement {
+ public:
+ ScopedElement( XmlWriter* writer );
+
+ ScopedElement( ScopedElement&& other ) noexcept;
+ ScopedElement& operator=( ScopedElement&& other ) noexcept;
+
+ ~ScopedElement();
+
+ ScopedElement& writeText( std::string const& text, bool indent = true );
+
+ template
+ ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+ m_writer->writeAttribute( name, attribute );
+ return *this;
+ }
+
+ private:
+ mutable XmlWriter* m_writer = nullptr;
+ };
+
+ XmlWriter( std::ostream& os = Catch::cout() );
+ ~XmlWriter();
+
+ XmlWriter( XmlWriter const& ) = delete;
+ XmlWriter& operator=( XmlWriter const& ) = delete;
+
+ XmlWriter& startElement( std::string const& name );
+
+ ScopedElement scopedElement( std::string const& name );
+
+ XmlWriter& endElement();
+
+ XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
+
+ XmlWriter& writeAttribute( std::string const& name, bool attribute );
+
+ template
+ XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
+ ReusableStringStream rss;
+ rss << attribute;
+ return writeAttribute( name, rss.str() );
+ }
+
+ XmlWriter& writeText( std::string const& text, bool indent = true );
+
+ XmlWriter& writeComment( std::string const& text );
+
+ void writeStylesheetRef( std::string const& url );
+
+ XmlWriter& writeBlankLine();
+
+ void ensureTagClosed();
+
+ private:
+
+ void writeDeclaration();
+
+ void newlineIfNecessary();
+
+ bool m_tagIsOpen = false;
+ bool m_needsNewline = false;
+ std::vector m_tags;
+ std::string m_indent;
+ std::ostream& m_os;
+ };
+
+}
+
+// end catch_xmlwriter.h
+namespace Catch {
+
+ class JunitReporter : public CumulativeReporterBase {
+ public:
+ JunitReporter(ReporterConfig const& _config);
+
+ ~JunitReporter() override;
+
+ static std::string getDescription();
+
+ void noMatchingTestCases(std::string const& /*spec*/) override;
+
+ void testRunStarting(TestRunInfo const& runInfo) override;
+
+ void testGroupStarting(GroupInfo const& groupInfo) override;
+
+ void testCaseStarting(TestCaseInfo const& testCaseInfo) override;
+ bool assertionEnded(AssertionStats const& assertionStats) override;
+
+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
+
+ void testGroupEnded(TestGroupStats const& testGroupStats) override;
+
+ void testRunEndedCumulative() override;
+
+ void writeGroup(TestGroupNode const& groupNode, double suiteTime);
+
+ void writeTestCase(TestCaseNode const& testCaseNode);
+
+ void writeSection(std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode);
+
+ void writeAssertions(SectionNode const& sectionNode);
+ void writeAssertion(AssertionStats const& stats);
+
+ XmlWriter xml;
+ Timer suiteTimer;
+ std::string stdOutForSuite;
+ std::string stdErrForSuite;
+ unsigned int unexpectedExceptions = 0;
+ bool m_okToFail = false;
+ };
+
+} // end namespace Catch
+
+// end catch_reporter_junit.h
+// start catch_reporter_xml.h
+
+namespace Catch {
+ class XmlReporter : public StreamingReporterBase {
+ public:
+ XmlReporter(ReporterConfig const& _config);
+
+ ~XmlReporter() override;
+
+ static std::string getDescription();
+
+ virtual std::string getStylesheetRef() const;
+
+ void writeSourceInfo(SourceLineInfo const& sourceInfo);
+
+ public: // StreamingReporterBase
+
+ void noMatchingTestCases(std::string const& s) override;
+
+ void testRunStarting(TestRunInfo const& testInfo) override;
+
+ void testGroupStarting(GroupInfo const& groupInfo) override;
+
+ void testCaseStarting(TestCaseInfo const& testInfo) override;
+
+ void sectionStarting(SectionInfo const& sectionInfo) override;
+
+ void assertionStarting(AssertionInfo const&) override;
+
+ bool assertionEnded(AssertionStats const& assertionStats) override;
+
+ void sectionEnded(SectionStats const& sectionStats) override;
+
+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
+
+ void testGroupEnded(TestGroupStats const& testGroupStats) override;
+
+ void testRunEnded(TestRunStats const& testRunStats) override;
+
+ private:
+ Timer m_testCaseTimer;
+ XmlWriter m_xml;
+ int m_sectionDepth = 0;
+ };
+
+} // end namespace Catch
+
+// end catch_reporter_xml.h
+
// end catch_external_interfaces.h
#endif
+#endif // ! CATCH_CONFIG_IMPL_ONLY
+
#ifdef CATCH_IMPL
// start catch_impl.hpp
@@ -4008,9 +4507,9 @@ namespace Detail {
}
std::string Approx::toString() const {
- std::ostringstream oss;
- oss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
- return oss.str();
+ ReusableStringStream rss;
+ rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
+ return rss.str();
}
bool Approx::equalityComparisonImpl(const double other) const {
@@ -4038,6 +4537,7 @@ namespace Catch {
struct IResultCapture;
struct IRunner;
struct IConfig;
+ struct IMutableContext;
using IConfigPtr = std::shared_ptr;
@@ -4047,7 +4547,7 @@ namespace Catch {
virtual IResultCapture* getResultCapture() = 0;
virtual IRunner* getRunner() = 0;
- virtual IConfigPtr getConfig() const = 0;
+ virtual IConfigPtr const& getConfig() const = 0;
};
struct IMutableContext : IContext
@@ -4056,16 +4556,291 @@ namespace Catch {
virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
virtual void setRunner( IRunner* runner ) = 0;
virtual void setConfig( IConfigPtr const& config ) = 0;
+
+ private:
+ static IMutableContext *currentContext;
+ friend IMutableContext& getCurrentMutableContext();
+ friend void cleanUpContext();
+ static void createContext();
};
- IContext& getCurrentContext();
- IMutableContext& getCurrentMutableContext();
+ inline IMutableContext& getCurrentMutableContext()
+ {
+ if( !IMutableContext::currentContext )
+ IMutableContext::createContext();
+ return *IMutableContext::currentContext;
+ }
+
+ inline IContext& getCurrentContext()
+ {
+ return getCurrentMutableContext();
+ }
+
void cleanUpContext();
}
// end catch_context.h
-#include
+// start catch_debugger.h
+namespace Catch {
+ bool isDebuggerActive();
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+ #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+
+#elif defined(CATCH_PLATFORM_LINUX)
+ // If we can use inline assembler, do it because this allows us to break
+ // 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") /* NOLINT */
+ #else // Fall back to the generic way.
+ #include
+
+ #define CATCH_TRAP() raise(SIGTRAP)
+ #endif
+#elif defined(_MSC_VER)
+ #define CATCH_TRAP() __debugbreak()
+#elif defined(__MINGW32__)
+ extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+ #define CATCH_TRAP() DebugBreak()
+#endif
+
+#ifdef CATCH_TRAP
+ #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
+#else
+ #define CATCH_BREAK_INTO_DEBUGGER() (void)0, 0
+#endif
+
+// end catch_debugger.h
+// start catch_run_context.h
+
+// start catch_fatal_condition.h
+
+#include
+
+#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+// start catch_windows_h_proxy.h
+
+
+#if defined(CATCH_PLATFORM_WINDOWS)
+
+#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
+# define CATCH_DEFINED_NOMINMAX
+# define NOMINMAX
+#endif
+#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
+# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include
+#else
+#include
+#endif
+
+#ifdef CATCH_DEFINED_NOMINMAX
+# undef NOMINMAX
+#endif
+#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
+# undef WIN32_LEAN_AND_MEAN
+#endif
+
+#endif // defined(CATCH_PLATFORM_WINDOWS)
+
+// end catch_windows_h_proxy.h
+
+# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
+
+namespace Catch {
+ struct FatalConditionHandler {
+ void reset();
+ };
+}
+
+# else // CATCH_CONFIG_WINDOWS_SEH is defined
+
+namespace Catch {
+
+ struct FatalConditionHandler {
+
+ static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
+ FatalConditionHandler();
+ static void reset();
+ ~FatalConditionHandler();
+
+ private:
+ static bool isSet;
+ static ULONG guaranteeSize;
+ static PVOID exceptionHandlerHandle;
+ };
+
+} // namespace Catch
+
+# endif // CATCH_CONFIG_WINDOWS_SEH
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
+
+namespace Catch {
+ struct FatalConditionHandler {
+ void reset();
+ };
+}
+
+# else // CATCH_CONFIG_POSIX_SIGNALS is defined
+
+#include
+
+namespace Catch {
+
+ struct FatalConditionHandler {
+
+ static bool isSet;
+ static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)];
+ static stack_t oldSigStack;
+ static char altStackMem[];
+
+ static void handleSignal( int sig );
+
+ FatalConditionHandler();
+ ~FatalConditionHandler();
+ static void reset();
+ };
+
+} // namespace Catch
+
+# endif // CATCH_CONFIG_POSIX_SIGNALS
+
+#endif // not Windows
+
+// end catch_fatal_condition.h
+#include
+
+namespace Catch {
+
+ struct IMutableContext;
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class RunContext : public IResultCapture, public IRunner {
+
+ public:
+ RunContext( RunContext const& ) = delete;
+ RunContext& operator =( RunContext const& ) = delete;
+
+ explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter );
+
+ ~RunContext() override;
+
+ void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount );
+ void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount );
+
+ Totals runTest(TestCase const& testCase);
+
+ IConfigPtr config() const;
+ IStreamingReporter& reporter() const;
+
+ public: // IResultCapture
+
+ // Assertion handlers
+ void handleExpr
+ ( AssertionInfo const& info,
+ ITransientExpression const& expr,
+ AssertionReaction& reaction ) override;
+ void handleMessage
+ ( AssertionInfo const& info,
+ ResultWas::OfType resultType,
+ StringRef const& message,
+ AssertionReaction& reaction ) override;
+ void handleUnexpectedExceptionNotThrown
+ ( AssertionInfo const& info,
+ AssertionReaction& reaction ) override;
+ void handleUnexpectedInflightException
+ ( AssertionInfo const& info,
+ std::string const& message,
+ AssertionReaction& reaction ) override;
+ void handleIncomplete
+ ( AssertionInfo const& info ) override;
+ void handleNonExpr
+ ( AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ AssertionReaction &reaction ) override;
+
+ bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
+
+ void sectionEnded( SectionEndInfo const& endInfo ) override;
+ void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
+
+ void benchmarkStarting( BenchmarkInfo const& info ) override;
+ void benchmarkEnded( BenchmarkStats const& stats ) override;
+
+ void pushScopedMessage( MessageInfo const& message ) override;
+ void popScopedMessage( MessageInfo const& message ) override;
+
+ std::string getCurrentTestName() const override;
+
+ const AssertionResult* getLastResult() const override;
+
+ void exceptionEarlyReported() override;
+
+ void handleFatalErrorCondition( StringRef message ) override;
+
+ bool lastAssertionPassed() override;
+
+ void assertionPassed() override;
+
+ public:
+ // !TBD We need to do this another way!
+ bool aborting() const override;
+
+ private:
+
+ void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr );
+ void invokeActiveTestCase();
+
+ void resetAssertionInfo();
+ bool testForMissingAssertions( Counts& assertions );
+
+ void assertionEnded( AssertionResult const& result );
+ void reportExpr
+ ( AssertionInfo const &info,
+ ResultWas::OfType resultType,
+ ITransientExpression const *expr,
+ bool negated );
+
+ void populateReaction( AssertionReaction& reaction );
+
+ private:
+
+ void handleUnfinishedSections();
+
+ TestRunInfo m_runInfo;
+ IMutableContext& m_context;
+ TestCase const* m_activeTestCase = nullptr;
+ ITracker* m_testCaseTracker;
+ Option m_lastResult;
+
+ IConfigPtr m_config;
+ Totals m_totals;
+ IStreamingReporterPtr m_reporter;
+ std::vector m_messages;
+ AssertionInfo m_lastAssertionInfo;
+ std::vector m_unfinishedSections;
+ std::vector m_activeSections;
+ TrackerContext m_trackerContext;
+ bool m_lastAssertionPassed = false;
+ bool m_shouldReportUnexpected = true;
+ bool m_includeSuccessfulResults;
+ };
+
+} // end namespace Catch
+
+// end catch_run_context.h
namespace Catch {
auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
@@ -4104,86 +4879,55 @@ namespace Catch {
SourceLineInfo const& lineInfo,
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition )
- : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }
- {
- getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo );
+ : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
+ m_resultCapture( getResultCapture() )
+ {}
+
+ void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
+ m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
}
- AssertionHandler::~AssertionHandler() {
- if ( m_inExceptionGuard ) {
- handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" );
- getCurrentContext().getResultCapture()->exceptionEarlyReported();
- }
- }
-
- void AssertionHandler::handle( ITransientExpression const& expr ) {
-
- bool negated = isFalseTest( m_assertionInfo.resultDisposition );
- bool result = expr.getResult() != negated;
-
- handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated );
- }
- void AssertionHandler::handle( ResultWas::OfType resultType ) {
- handle( resultType, nullptr, false );
- }
- void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) {
- AssertionResultData data( resultType, LazyExpression( false ) );
- data.message = message;
- handle( data, nullptr );
- }
- void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) {
- AssertionResultData data( resultType, LazyExpression( negated ) );
- handle( data, expr );
- }
- void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) {
-
- getResultCapture().assertionRun();
-
- AssertionResult assertionResult{ m_assertionInfo, resultData };
- assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
-
- getResultCapture().assertionEnded( assertionResult );
-
- if( !assertionResult.isOk() ) {
- m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak();
- m_shouldThrow =
- getCurrentContext().getRunner()->aborting() ||
- (m_assertionInfo.resultDisposition & ResultDisposition::Normal);
- }
+ void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) {
+ m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
}
auto AssertionHandler::allowThrows() const -> bool {
return getCurrentContext().getConfig()->allowThrows();
}
- auto AssertionHandler::shouldDebugBreak() const -> bool {
- return m_shouldDebugBreak;
- }
- void AssertionHandler::reactWithDebugBreak() const {
- if (m_shouldDebugBreak) {
- ///////////////////////////////////////////////////////////////////
- // To inspect the state during test, you need to go one level up the callstack
- // To go back to the test and change execution, jump over the reactWithoutDebugBreak() call
- ///////////////////////////////////////////////////////////////////
+ void AssertionHandler::complete() {
+ setCompleted();
+ if( m_reaction.shouldDebugBreak ) {
+
+ // If you find your debugger stopping you here then go one level up on the
+ // call-stack for the code that caused it (typically a failed assertion)
+
+ // (To go back to the test and change execution, jump over the throw, next)
CATCH_BREAK_INTO_DEBUGGER();
}
- reactWithoutDebugBreak();
- }
- void AssertionHandler::reactWithoutDebugBreak() const {
- if( m_shouldThrow )
+ if( m_reaction.shouldThrow )
throw Catch::TestFailureException();
}
-
- void AssertionHandler::useActiveException() {
- handle( ResultWas::ThrewException, Catch::translateActiveException() );
+ void AssertionHandler::setCompleted() {
+ m_completed = true;
}
- void AssertionHandler::setExceptionGuard() {
- assert( m_inExceptionGuard == false );
- m_inExceptionGuard = true;
+ void AssertionHandler::handleUnexpectedInflightException() {
+ m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
}
- void AssertionHandler::unsetExceptionGuard() {
- assert( m_inExceptionGuard == true );
- m_inExceptionGuard = false;
+
+ void AssertionHandler::handleExceptionThrownAsExpected() {
+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+ }
+ void AssertionHandler::handleExceptionNotThrownAsExpected() {
+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
+ }
+
+ void AssertionHandler::handleUnexpectedExceptionNotThrown() {
+ m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
+ }
+
+ void AssertionHandler::handleThrowingCallSkipped() {
+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
}
// This is the overload that takes a string and infers the Equals matcher from it
@@ -4205,10 +4949,9 @@ namespace Catch {
if( reconstructedExpression.empty() ) {
if( lazyExpression ) {
- // !TBD Use stringstream for now, but rework above to pass stream in
- std::ostringstream oss;
- oss << lazyExpression;
- reconstructedExpression = oss.str();
+ ReusableStringStream rss;
+ rss << lazyExpression;
+ reconstructedExpression = rss.str();
}
}
return reconstructedExpression;
@@ -4243,7 +4986,7 @@ namespace Catch {
std::string AssertionResult::getExpression() const {
if( isFalseTest( m_info.resultDisposition ) )
- return "!(" + std::string(m_info.capturedExpression) + ")";
+ return "!(" + m_info.capturedExpression + ")";
else
return m_info.capturedExpression;
}
@@ -4254,9 +4997,9 @@ namespace Catch {
expr = m_info.capturedExpression;
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
- expr += m_info.macroName;
+ expr += m_info.macroName.c_str();
expr += "( ";
- expr += m_info.capturedExpression;
+ expr += m_info.capturedExpression.c_str();
expr += " )";
}
return expr;
@@ -4280,7 +5023,7 @@ namespace Catch {
return m_info.lineInfo;
}
- std::string AssertionResult::getTestMacroName() const {
+ StringRef AssertionResult::getTestMacroName() const {
return m_info.macroName;
}
@@ -4324,7 +5067,7 @@ namespace Catch {
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
std::string exceptionMessage = Catch::translateActiveException();
MatchExpr expr( exceptionMessage, matcher, matcherString );
- handler.handle( expr );
+ handler.handleExpr( expr );
}
} // namespace Catch
@@ -5766,10 +6509,6 @@ namespace Catch {
namespace Catch {
- SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept
- : file( _file ),
- line( _line )
- {}
bool SourceLineInfo::empty() const noexcept {
return file[0] == '\0';
}
@@ -5789,10 +6528,6 @@ namespace Catch {
return os;
}
- bool isTrue( bool value ){ return value; }
- bool alwaysTrue() { return true; }
- bool alwaysFalse() { return false; }
-
std::string StreamEndStop::operator+() const {
return std::string();
}
@@ -5804,6 +6539,21 @@ namespace Catch {
// end catch_common.cpp
// start catch_config.cpp
+// start catch_enforce.h
+
+#include
+#include
+
+#define CATCH_PREPARE_EXCEPTION( type, msg ) \
+ type( static_cast( Catch::ReusableStringStream().get() << msg ).str() )
+#define CATCH_INTERNAL_ERROR( msg ) \
+ throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
+#define CATCH_ERROR( msg ) \
+ throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg )
+#define CATCH_ENFORCE( condition, msg ) \
+ do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
+
+// end catch_enforce.h
namespace Catch {
Config::Config( ConfigData const& data )
@@ -5853,16 +6603,7 @@ namespace Catch {
Verbosity Config::verbosity() const { return m_data.verbosity; }
IStream const* Config::openStream() {
- if( m_data.outputFilename.empty() )
- return new CoutStream();
- else if( m_data.outputFilename[0] == '%' ) {
- if( m_data.outputFilename == "%debug" )
- return new DebugOutStream();
- else
- CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" );
- }
- else
- return new FileStream( m_data.outputFilename );
+ return Catch::makeStream(m_data.outputFilename);
}
} // end namespace Catch
@@ -5889,36 +6630,8 @@ namespace Catch {
}
// end catch_errno_guard.h
-// start catch_windows_h_proxy.h
+#include
-
-#if defined(CATCH_PLATFORM_WINDOWS)
-
-#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
-# define CATCH_DEFINED_NOMINMAX
-# define NOMINMAX
-#endif
-#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
-# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-#endif
-
-#ifdef __AFXDLL
-#include
-#else
-#include
-#endif
-
-#ifdef CATCH_DEFINED_NOMINMAX
-# undef NOMINMAX
-#endif
-#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
-# undef WIN32_LEAN_AND_MEAN
-#endif
-
-#endif // defined(CATCH_PLATFORM_WINDOWS)
-
-// end catch_windows_h_proxy.h
namespace Catch {
namespace {
@@ -6131,7 +6844,7 @@ namespace Catch {
return m_runner;
}
- virtual IConfigPtr getConfig() const override {
+ virtual IConfigPtr const& getConfig() const override {
return m_config;
}
@@ -6156,21 +6869,16 @@ namespace Catch {
IResultCapture* m_resultCapture = nullptr;
};
- namespace {
- Context* currentContext = nullptr;
- }
- IMutableContext& getCurrentMutableContext() {
- if( !currentContext )
- currentContext = new Context();
- return *currentContext;
- }
- IContext& getCurrentContext() {
- return getCurrentMutableContext();
+ IMutableContext *IMutableContext::currentContext = nullptr;
+
+ void IMutableContext::createContext()
+ {
+ currentContext = new Context();
}
void cleanUpContext() {
- delete currentContext;
- currentContext = nullptr;
+ delete IMutableContext::currentContext;
+ IMutableContext::currentContext = nullptr;
}
IContext::~IContext() = default;
IMutableContext::~IMutableContext() = default;
@@ -6208,13 +6916,15 @@ namespace Catch {
#ifdef CATCH_PLATFORM_MAC
- #include