Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMartin Hořeňovský2018-09-04 11:59:15 +0200
committerMartin Hořeňovský2018-09-04 11:59:15 +0200
commit60b05b20413afe4ad9980e627862474a9b8ba4cd (patch)
tree89612c7d982d903a68bf7a85458ebe5f0c9a7496
parent232ea3c456ee6fe70a9a8971c4e0e45bb27d1293 (diff)
downloadcatch3-2.4.0.tar.gz
v2.4.0v2.4.0
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md4
-rw-r--r--conanfile.py2
-rw-r--r--docs/release-notes.md29
-rw-r--r--include/catch.hpp2
-rw-r--r--include/internal/catch_version.cpp2
-rw-r--r--single_include/catch2/catch.hpp957
-rw-r--r--single_include/catch2/catch_reporter_teamcity.hpp4
-rw-r--r--test_package/conanfile.py2
9 files changed, 798 insertions, 206 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7c87eece..1b9ffd55 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,7 +6,7 @@ if(NOT DEFINED PROJECT_NAME)
set(NOT_SUBPROJECT ON)
endif()
-project(Catch2 LANGUAGES CXX VERSION 2.3.0)
+project(Catch2 LANGUAGES CXX VERSION 2.4.0)
# Provide path for scripts
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
diff --git a/README.md b/README.md
index 386f8534..10893c11 100644
--- a/README.md
+++ b/README.md
@@ -5,11 +5,11 @@
[![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/Gcuv2Xx3wmWIPNzy)
+[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/4wRGoJ1WzLjRM7HZ)
[![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
-<a href="https://github.com/catchorg/Catch2/releases/download/v2.3.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
+<a href="https://github.com/catchorg/Catch2/releases/download/v2.4.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!
diff --git a/conanfile.py b/conanfile.py
index 76053959..fe47763c 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -4,7 +4,7 @@ from conans import ConanFile, CMake
class CatchConan(ConanFile):
name = "Catch"
- version = "2.3.0"
+ version = "2.4.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 e40be99c..607ea073 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -1,5 +1,34 @@
<a id="top"></a>
+# 2.4.0
+
+**This release brings two new experimental features, generator support
+and a `-fno-exceptions` support. Being experimental means that they
+will not be subject to the usual stability guarantees provided by semver.**
+
+## Improvements
+* Various small runtime performance improvements
+* `CAPTURE` macro is now variadic
+* Added `AND_GIVEN` macro (#1360)
+* Added experimental support for data generators
+ * See [their documentation](generators.md) for details
+* Added support for compiling and running Catch without exceptions
+ * Doing so limits the functionality somewhat
+ * Look [into the documentation](configuration.md#disablingexceptions) for details
+
+## Fixes
+* Suppressed `-Wnon-virtual-dtor` warnings in Matchers (#1357)
+* Suppressed `-Wunreachable-code` warnings in floating point matchers (#1350)
+
+## CMake
+* It is now possible to override which Python is used to run Catch's tests (#1365)
+* Catch now provides infrastructure for adding tests that check compile-time configuration
+* Catch no longer tries to install itself when used as a subproject (#1373)
+* Catch2ConfigVersion.cmake is now generated as arch-independent (#1368)
+ * This means that installing Catch from 32-bit machine and copying it to 64-bit one works
+ * This fixes conan installation of Catch
+
+
# 2.3.0
**This release changes the include paths provided by our CMake and
diff --git a/include/catch.hpp b/include/catch.hpp
index 10ce0610..a2a6f59a 100644
--- a/include/catch.hpp
+++ b/include/catch.hpp
@@ -10,7 +10,7 @@
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 3
+#define CATCH_VERSION_MINOR 4
#define CATCH_VERSION_PATCH 0
#ifdef __clang__
diff --git a/include/internal/catch_version.cpp b/include/internal/catch_version.cpp
index 1585ff7a..57938e16 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, 3, 0, "", 0 );
+ static Version version( 2, 4, 0, "", 0 );
return version;
}
diff --git a/single_include/catch2/catch.hpp b/single_include/catch2/catch.hpp
index bdc2f74a..b0fa6416 100644
--- a/single_include/catch2/catch.hpp
+++ b/single_include/catch2/catch.hpp
@@ -1,6 +1,6 @@
/*
- * Catch v2.3.0
- * Generated: 2018-07-23 10:09:14.936841
+ * Catch v2.4.0
+ * Generated: 2018-09-04 11:55:01.682061
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved.
@@ -14,7 +14,7 @@
#define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 3
+#define CATCH_VERSION_MINOR 4
#define CATCH_VERSION_PATCH 0
#ifdef __clang__
@@ -108,6 +108,7 @@ namespace Catch {
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
+// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
// ****************
// Note to maintainers: if new toggles are added please document them
// in configuration.md, too
@@ -221,7 +222,12 @@ namespace Catch {
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
+// Check if we are compiled with -fno-exceptions or equivalent
+#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
+# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
+#endif
+////////////////////////////////////////////////////////////////////////////////
// DJGPP
#ifdef __DJGPP__
# define CATCH_INTERNAL_CONFIG_NO_WCHAR
@@ -269,6 +275,10 @@ namespace Catch {
# define CATCH_CONFIG_NEW_CAPTURE
#endif
+#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+# define CATCH_CONFIG_DISABLE_EXCEPTIONS
+#endif
+
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
@@ -282,6 +292,16 @@ namespace Catch {
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
#endif
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+#define CATCH_TRY if ((true))
+#define CATCH_CATCH_ALL if ((false))
+#define CATCH_CATCH_ANON(type) if ((false))
+#else
+#define CATCH_TRY try
+#define CATCH_CATCH_ALL catch (...)
+#define CATCH_CATCH_ANON(type) catch (type)
+#endif
+
// end catch_compiler_capabilities.h
#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
@@ -522,6 +542,10 @@ namespace Catch {
} // namespace Catch
+inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
+ return Catch::StringRef( rawChars, size );
+}
+
// end catch_stringref.h
namespace Catch {
@@ -725,8 +749,6 @@ namespace Catch {
return *this;
}
auto get() -> std::ostream& { return *m_oss; }
-
- static void cleanup();
};
}
@@ -1514,8 +1536,10 @@ namespace Catch {
struct BenchmarkInfo;
struct BenchmarkStats;
struct AssertionReaction;
+ struct SourceLineInfo;
struct ITransientExpression;
+ struct IGeneratorTracker;
struct IResultCapture {
@@ -1526,6 +1550,8 @@ namespace Catch {
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
+ virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
@@ -1607,7 +1633,7 @@ namespace Catch {
public:
AssertionHandler
- ( StringRef macroName,
+ ( StringRef const& macroName,
SourceLineInfo const& lineInfo,
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition );
@@ -1638,7 +1664,7 @@ namespace Catch {
auto allowThrows() const -> bool;
};
- void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
+ void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );
} // namespace Catch
@@ -1646,15 +1672,16 @@ namespace Catch {
// start catch_message.h
#include <string>
+#include <vector>
namespace Catch {
struct MessageInfo {
- MessageInfo( std::string const& _macroName,
+ MessageInfo( StringRef const& _macroName,
SourceLineInfo const& _lineInfo,
ResultWas::OfType _type );
- std::string macroName;
+ StringRef macroName;
std::string message;
SourceLineInfo lineInfo;
ResultWas::OfType type;
@@ -1678,7 +1705,7 @@ namespace Catch {
};
struct MessageBuilder : MessageStream {
- MessageBuilder( std::string const& macroName,
+ MessageBuilder( StringRef const& macroName,
SourceLineInfo const& lineInfo,
ResultWas::OfType type );
@@ -1699,6 +1726,28 @@ namespace Catch {
MessageInfo m_info;
};
+ class Capturer {
+ std::vector<MessageInfo> m_messages;
+ IResultCapture& m_resultCapture = getResultCapture();
+ size_t m_captured = 0;
+ public:
+ Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
+ ~Capturer();
+
+ void captureValue( size_t index, StringRef value );
+
+ template<typename T>
+ void captureValues( size_t index, T&& value ) {
+ captureValue( index, Catch::Detail::stringify( value ) );
+ }
+
+ template<typename T, typename... Ts>
+ void captureValues( size_t index, T&& value, Ts&&... values ) {
+ captureValues( index, value );
+ captureValues( index+1, values... );
+ }
+ };
+
} // end namespace Catch
// end catch_message.h
@@ -1710,7 +1759,7 @@ namespace Catch {
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
#endif
-#if defined(CATCH_CONFIG_FAST_COMPILE)
+#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
///////////////////////////////////////////////////////////////////////////////
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
@@ -1730,7 +1779,7 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
do { \
- Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
INTERNAL_CATCH_TRY { \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
@@ -1753,7 +1802,7 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
do { \
- Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
try { \
static_cast<void>(__VA_ARGS__); \
catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
@@ -1767,7 +1816,7 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
do { \
- Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(__VA_ARGS__); \
@@ -1784,7 +1833,7 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
do { \
- Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(expr); \
@@ -1804,27 +1853,32 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
do { \
- Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( false )
///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
+ auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
+ varName.captureValues( 0, __VA_ARGS__ )
+
+///////////////////////////////////////////////////////////////////////////////
#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_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
///////////////////////////////////////////////////////////////////////////////
// Although this is matcher-based, it can be used with just a string
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
do { \
- Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(__VA_ARGS__); \
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
} \
catch( ... ) { \
- Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
+ Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \
} \
else \
catchAssertionHandler.handleThrowingCallSkipped(); \
@@ -2029,7 +2083,7 @@ namespace Catch {
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
- virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+ virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
};
@@ -2044,7 +2098,7 @@ namespace Catch {
virtual void registerStartupException() noexcept = 0;
};
- IRegistryHub& getRegistryHub();
+ IRegistryHub const& getRegistryHub();
IMutableRegistryHub& getMutableRegistryHub();
void cleanUp();
std::string translateActiveException();
@@ -2126,7 +2180,6 @@ namespace Catch {
// start catch_approx.h
#include <type_traits>
-#include <stdexcept>
namespace Catch {
namespace Detail {
@@ -2134,6 +2187,12 @@ namespace Detail {
class Approx {
private:
bool equalityComparisonImpl(double other) const;
+ // Validates the new margin (margin >= 0)
+ // out-of-line to avoid including stdexcept in the header
+ void setMargin(double margin);
+ // Validates the new epsilon (0 < epsilon < 1)
+ // out-of-line to avoid including stdexcept in the header
+ void setEpsilon(double epsilon);
public:
explicit Approx ( double value );
@@ -2145,9 +2204,9 @@ namespace Detail {
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx operator()( T const& value ) {
Approx approx( static_cast<double>(value) );
- approx.epsilon( m_epsilon );
- approx.margin( m_margin );
- approx.scale( m_scale );
+ approx.m_epsilon = m_epsilon;
+ approx.m_margin = m_margin;
+ approx.m_scale = m_scale;
return approx;
}
@@ -2199,27 +2258,14 @@ namespace Detail {
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& epsilon( T const& newEpsilon ) {
double epsilonAsDouble = static_cast<double>(newEpsilon);
- 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;
+ setEpsilon(epsilonAsDouble);
return *this;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& margin( T const& newMargin ) {
double marginAsDouble = static_cast<double>(newMargin);
- if( marginAsDouble < 0 ) {
- throw std::domain_error
- ( "Invalid Approx::margin: " +
- Catch::Detail::stringify( marginAsDouble ) +
- ", Approx::Margin has to be non-negative." );
-
- }
- m_margin = marginAsDouble;
+ setMargin(marginAsDouble);
return *this;
}
@@ -2309,6 +2355,11 @@ namespace Matchers {
mutable std::string m_cachedToString;
};
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
template<typename ObjectT>
struct MatcherMethod {
virtual bool match( ObjectT const& arg ) const = 0;
@@ -2318,6 +2369,10 @@ namespace Matchers {
virtual bool match( PtrT* arg ) const = 0;
};
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
template<typename T>
struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
@@ -2771,7 +2826,7 @@ namespace Catch {
MatcherT m_matcher;
StringRef m_matcherString;
public:
- MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString )
+ MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
: ITransientExpression{ true, matcher.match( arg ) },
m_arg( arg ),
m_matcher( matcher ),
@@ -2790,10 +2845,10 @@ namespace Catch {
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
- void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString );
+ void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString );
template<typename ArgT, typename MatcherT>
- auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr<ArgT, MatcherT> {
+ auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
}
@@ -2802,9 +2857,9 @@ 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 ); \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
INTERNAL_CATCH_TRY { \
- catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( false )
@@ -2812,14 +2867,14 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
do { \
- Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(__VA_ARGS__ ); \
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
} \
catch( exceptionType const& ex ) { \
- catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \
} \
catch( ... ) { \
catchAssertionHandler.handleUnexpectedInflightException(); \
@@ -2831,6 +2886,304 @@ namespace Catch {
// end catch_capture_matchers.h
#endif
+// start catch_generators.hpp
+
+// start catch_interfaces_generatortracker.h
+
+
+#include <memory>
+
+namespace Catch {
+
+ namespace Generators {
+ class GeneratorBase {
+ protected:
+ size_t m_size = 0;
+
+ public:
+ GeneratorBase( size_t size ) : m_size( size ) {}
+ virtual ~GeneratorBase();
+ auto size() const -> size_t { return m_size; }
+ };
+ using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
+
+ } // namespace Generators
+
+ struct IGeneratorTracker {
+ virtual ~IGeneratorTracker();
+ virtual auto hasGenerator() const -> bool = 0;
+ virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
+ virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
+ virtual auto getIndex() const -> std::size_t = 0;
+ };
+
+} // namespace Catch
+
+// end catch_interfaces_generatortracker.h
+// start catch_enforce.h
+
+#include <stdexcept>
+
+namespace Catch {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ template <typename Ex>
+ [[noreturn]]
+ void throw_exception(Ex const& e) {
+ throw e;
+ }
+#else // ^^ Exceptions are enabled // Exceptions are disabled vv
+ [[noreturn]]
+ void throw_exception(std::exception const& e);
+#endif
+} // namespace Catch;
+
+#define CATCH_PREPARE_EXCEPTION( type, msg ) \
+ type( ( Catch::ReusableStringStream() << msg ).str() )
+#define CATCH_INTERNAL_ERROR( msg ) \
+ Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
+#define CATCH_ERROR( msg ) \
+ Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
+#define CATCH_RUNTIME_ERROR( msg ) \
+ Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
+#define CATCH_ENFORCE( condition, msg ) \
+ do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
+
+// end catch_enforce.h
+#include <memory>
+#include <vector>
+#include <cassert>
+
+#include <utility>
+
+namespace Catch {
+namespace Generators {
+
+ // !TBD move this into its own location?
+ namespace pf{
+ template<typename T, typename... Args>
+ std::unique_ptr<T> make_unique( Args&&... args ) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+ }
+ }
+
+ template<typename T>
+ struct IGenerator {
+ virtual ~IGenerator() {}
+ virtual auto get( size_t index ) const -> T = 0;
+ };
+
+ template<typename T>
+ class SingleValueGenerator : public IGenerator<T> {
+ T m_value;
+ public:
+ SingleValueGenerator( T const& value ) : m_value( value ) {}
+
+ auto get( size_t ) const -> T override {
+ return m_value;
+ }
+ };
+
+ template<typename T>
+ class FixedValuesGenerator : public IGenerator<T> {
+ std::vector<T> m_values;
+
+ public:
+ FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
+
+ auto get( size_t index ) const -> T override {
+ return m_values[index];
+ }
+ };
+
+ template<typename T>
+ class RangeGenerator : public IGenerator<T> {
+ T const m_first;
+ T const m_last;
+
+ public:
+ RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) {
+ assert( m_last > m_first );
+ }
+
+ auto get( size_t index ) const -> T override {
+ // ToDo:: introduce a safe cast to catch potential overflows
+ return static_cast<T>(m_first+index);
+ }
+ };
+
+ template<typename T>
+ struct NullGenerator : IGenerator<T> {
+ auto get( size_t ) const -> T override {
+ CATCH_INTERNAL_ERROR("A Null Generator is always empty");
+ }
+ };
+
+ template<typename T>
+ class Generator {
+ std::unique_ptr<IGenerator<T>> m_generator;
+ size_t m_size;
+
+ public:
+ Generator( size_t size, std::unique_ptr<IGenerator<T>> generator )
+ : m_generator( std::move( generator ) ),
+ m_size( size )
+ {}
+
+ auto size() const -> size_t { return m_size; }
+ auto operator[]( size_t index ) const -> T {
+ assert( index < m_size );
+ return m_generator->get( index );
+ }
+ };
+
+ std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
+
+ template<typename T>
+ class GeneratorRandomiser : public IGenerator<T> {
+ Generator<T> m_baseGenerator;
+
+ std::vector<size_t> m_indices;
+ public:
+ GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems )
+ : m_baseGenerator( std::move( baseGenerator ) ),
+ m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) )
+ {}
+
+ auto get( size_t index ) const -> T override {
+ return m_baseGenerator[m_indices[index]];
+ }
+ };
+
+ template<typename T>
+ struct RequiresASpecialisationFor;
+
+ template<typename T>
+ auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); }
+
+ template<>
+ auto all<int>() -> Generator<int>;
+
+ template<typename T>
+ auto range( T const& first, T const& last ) -> Generator<T> {
+ return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) );
+ }
+
+ template<typename T>
+ auto random( T const& first, T const& last ) -> Generator<T> {
+ auto gen = range( first, last );
+ auto size = gen.size();
+
+ return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
+ }
+ template<typename T>
+ auto random( size_t size ) -> Generator<T> {
+ return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) );
+ }
+
+ template<typename T>
+ auto values( std::initializer_list<T> values ) -> Generator<T> {
+ return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) );
+ }
+ template<typename T>
+ auto value( T const& val ) -> Generator<T> {
+ return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) );
+ }
+
+ template<typename T>
+ auto as() -> Generator<T> {
+ return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() );
+ }
+
+ template<typename... Ts>
+ auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> {
+ return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) );
+ }
+
+ template<typename T>
+ struct Generators : GeneratorBase {
+ std::vector<Generator<T>> m_generators;
+
+ using type = T;
+
+ Generators() : GeneratorBase( 0 ) {}
+
+ void populate( T&& val ) {
+ m_size += 1;
+ m_generators.emplace_back( value( std::move( val ) ) );
+ }
+ template<typename U>
+ void populate( U&& val ) {
+ populate( T( std::move( val ) ) );
+ }
+ void populate( Generator<T>&& generator ) {
+ m_size += generator.size();
+ m_generators.emplace_back( std::move( generator ) );
+ }
+
+ template<typename U, typename... Gs>
+ void populate( U&& valueOrGenerator, Gs... moreGenerators ) {
+ populate( std::forward<U>( valueOrGenerator ) );
+ populate( std::forward<Gs>( moreGenerators )... );
+ }
+
+ auto operator[]( size_t index ) const -> T {
+ size_t sizes = 0;
+ for( auto const& gen : m_generators ) {
+ auto localIndex = index-sizes;
+ sizes += gen.size();
+ if( index < sizes )
+ return gen[localIndex];
+ }
+ CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
+ }
+ };
+
+ template<typename T, typename... Gs>
+ auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
+ Generators<T> generators;
+ generators.m_generators.reserve( 1+sizeof...(Gs) );
+ generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... );
+ return generators;
+ }
+ template<typename T>
+ auto makeGenerators( Generator<T>&& generator ) -> Generators<T> {
+ Generators<T> generators;
+ generators.populate( std::move( generator ) );
+ return generators;
+ }
+ template<typename T, typename... Gs>
+ auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
+ }
+ template<typename T, typename U, typename... Gs>
+ auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
+ }
+
+ auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+
+ template<typename L>
+ // Note: The type after -> is weird, because VS2015 cannot parse
+ // the expression used in the typedef inside, when it is in
+ // return type. Yeah, ¯\_(ツ)_/¯
+ auto