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

summaryrefslogtreecommitdiffhomepage
path: root/single_include
diff options
context:
space:
mode:
authorMartin Hořeňovský2019-01-31 22:32:55 +0100
committerMartin Hořeňovský2019-01-31 22:32:55 +0100
commitd75e9b3c0f24fe42553131873459611ed155e297 (patch)
tree1634224aa17770e6962a7860e16ece29038895db /single_include
parent67308bb606e2640d3622861a0e45d83169bdebb5 (diff)
downloadcatch3-2.6.0.tar.gz
v2.6.0v2.6.0
Diffstat (limited to 'single_include')
-rw-r--r--single_include/catch2/catch.hpp897
1 files changed, 611 insertions, 286 deletions
diff --git a/single_include/catch2/catch.hpp b/single_include/catch2/catch.hpp
index b1b2411d..cc3f97cb 100644
--- a/single_include/catch2/catch.hpp
+++ b/single_include/catch2/catch.hpp
@@ -1,9 +1,9 @@
/*
- * Catch v2.5.0
- * Generated: 2018-11-26 20:46:12.165372
+ * Catch v2.6.0
+ * Generated: 2019-01-31 22:25:55.560884
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
- * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved.
+ * Copyright (c) 2019 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)
@@ -14,7 +14,7 @@
#define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 5
+#define CATCH_VERSION_MINOR 6
#define CATCH_VERSION_PATCH 0
#ifdef __clang__
@@ -36,10 +36,11 @@
# pragma clang diagnostic ignored "-Wcovered-switch-default"
# endif
#elif defined __GNUC__
- // GCC likes to warn on REQUIREs, and we cannot suppress them
- // locally because g++'s support for _Pragma is lacking in older,
- // still supported, versions
-# pragma GCC diagnostic ignored "-Wparentheses"
+ // Because REQUIREs trigger GCC's -Wparentheses, and because still
+ // supported version of g++ have only buggy support for _Pragmas,
+ // Wparentheses have to be suppressed globally.
+# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details
+
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-variable"
# pragma GCC diagnostic ignored "-Wpadded"
@@ -274,6 +275,14 @@ namespace Catch {
#endif
////////////////////////////////////////////////////////////////////////////////
+// Check if optional is available and usable
+#if defined(__has_include)
+# if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
+# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+#endif // __has_include
+
+////////////////////////////////////////////////////////////////////////////////
// Check if variant is available and usable
#if defined(__has_include)
# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
@@ -283,9 +292,11 @@ namespace Catch {
# include <ciso646>
# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
# define CATCH_CONFIG_NO_CPP17_VARIANT
-# else
+# else
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+# else
+# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
# endif // defined(__clang__) && (__clang_major__ < 8)
# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
#endif // __has_include
@@ -309,6 +320,10 @@ namespace Catch {
# define CATCH_CONFIG_CPP11_TO_STRING
#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
+# define CATCH_CONFIG_CPP17_OPTIONAL
+#endif
+
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
@@ -407,10 +422,10 @@ namespace Catch {
line( _line )
{}
- SourceLineInfo( SourceLineInfo const& other ) = default;
- SourceLineInfo( SourceLineInfo && ) = default;
- SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
- SourceLineInfo& operator = ( SourceLineInfo && ) = default;
+ SourceLineInfo( SourceLineInfo const& other ) = default;
+ SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+ SourceLineInfo( SourceLineInfo&& ) noexcept = default;
+ SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
bool empty() const noexcept;
bool operator == ( SourceLineInfo const& other ) const noexcept;
@@ -463,7 +478,6 @@ namespace Catch {
// start catch_interfaces_testcase.h
#include <vector>
-#include <memory>
namespace Catch {
@@ -474,8 +488,6 @@ namespace Catch {
virtual ~ITestInvoker();
};
- using ITestCasePtr = std::shared_ptr<ITestInvoker>;
-
class TestCase;
struct IConfig;
@@ -500,8 +512,6 @@ namespace Catch {
namespace Catch {
- class StringData;
-
/// A non-owning string class (similar to the forthcoming std::string_view)
/// Note that, because a StringRef may be a substring of another string,
/// it may not be null terminated. c_str() must return a null terminated
@@ -621,6 +631,8 @@ inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noex
// start catch_type_traits.hpp
+#include <type_traits>
+
namespace Catch{
#ifdef CATCH_CPP17_OR_GREATER
@@ -713,7 +725,85 @@ struct is_unique<T0, T1, Rest...> : std::integral_constant
#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
#endif
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)>
+
+#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\
+ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types))
+
// end catch_preprocessor.hpp
+// start catch_meta.hpp
+
+
+#include <type_traits>
+
+template< typename... >
+struct TypeList{};
+
+template< typename... >
+struct append;
+
+template< template<typename...> class L1
+ , typename...E1
+ , template<typename...> class L2
+ , typename...E2
+ >
+struct append< L1<E1...>, L2<E2...> >
+{
+ using type = L1<E1..., E2...>;
+};
+
+template< template<typename...> class L1
+ , typename...E1
+ , template<typename...> class L2
+ , typename...E2
+ , typename...Rest
+ >
+struct append< L1<E1...>, L2<E2...>, Rest...>
+{
+ using type = typename append< L1<E1..., E2...>, Rest... >::type;
+};
+
+template< template<typename...> class
+ , typename...
+ >
+struct rewrap;
+
+template< template<typename...> class Container
+ , template<typename...> class List
+ , typename...elems
+ >
+struct rewrap<Container, List<elems...>>
+{
+ using type = TypeList< Container< elems... > >;
+};
+
+template< template<typename...> class Container
+ , template<typename...> class List
+ , class...Elems
+ , typename...Elements>
+struct rewrap<Container, List<Elems...>, Elements...>
+{
+ using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type;
+};
+
+template< template<typename...> class...Containers >
+struct combine
+{
+ template< typename...Types >
+ struct with_types
+ {
+ template< template <typename...> class Final >
+ struct into
+ {
+ using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type;
+ };
+ };
+};
+
+template<typename T>
+struct always_false : std::false_type {};
+
+// end catch_meta.hpp
namespace Catch {
template<typename C>
@@ -849,6 +939,38 @@ struct AutoReg : NonCopyable {
return 0;\
}();
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> static void TestFuncName(); \
+ namespace { \
+ template<typename... Types> \
+ struct TestName { \
+ TestName() { \
+ CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \
+ int index = 0; \
+ using expander = int[]; \
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \
+ } \
+ }; \
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ using TestInit = combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
+ ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \
+ TestInit(); \
+ return 0; \
+ }(); \
+ } \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> \
+ static void TestFuncName()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ),Name,Tags,__VA_ARGS__)
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+#endif
+
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ \
@@ -879,6 +1001,41 @@ struct AutoReg : NonCopyable {
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) )
#endif
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+ void test();\
+ };\
+ namespace {\
+ template<typename...Types>\
+ struct TestNameClass{\
+ TestNameClass(){\
+ CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\
+ int index = 0;\
+ using expander = int[];\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ using TestInit = combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
+ ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\
+ TestInit();\
+ return 0;\
+ }(); \
+ }\
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ template<typename TestType> \
+ void TestName<TestType>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) )
+#endif
+
// end catch_test_registry.h
// start catch_capture.hpp
@@ -1370,6 +1527,7 @@ namespace Catch {
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
#endif
// Separate std::pair specialization
@@ -1391,6 +1549,24 @@ namespace Catch {
}
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
+#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
+#include <optional>
+namespace Catch {
+ template<typename T>
+ struct StringMaker<std::optional<T> > {
+ static std::string convert(const std::optional<T>& optional) {
+ ReusableStringStream rss;
+ if (optional.has_value()) {
+ rss << ::Catch::Detail::stringify(*optional);
+ } else {
+ rss << "{ }";
+ }
+ return rss.str();
+ }
+ };
+}
+#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
+
// Separate std::tuple specialization
#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
#include <tuple>
@@ -1652,6 +1828,7 @@ struct ratio_string<std::milli> {
#pragma warning(disable:4018) // more "signed/unsigned mismatch"
#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
#pragma warning(disable:4180) // qualifier applied to function type has no meaning
+#pragma warning(disable:4800) // Forcing result to true or false
#endif
namespace Catch {
@@ -1695,6 +1872,62 @@ namespace Catch {
m_op( op ),
m_rhs( rhs )
{}
+
+ template<typename T>
+ auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename T>
+ auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<T>::value,
+ "chained comparisons are not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
};
template<typename LhsT>
@@ -1707,7 +1940,7 @@ namespace Catch {
public:
explicit UnaryExpr( LhsT lhs )
- : ITransientExpression{ false, lhs ? true : false },
+ : ITransientExpression{ false, static_cast<bool>(lhs) },
m_lhs( lhs )
{}
};
@@ -1774,6 +2007,20 @@ namespace Catch {
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
}
+ template<typename RhsT>
+ auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<RhsT>::value,
+ "operator&& is not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
+ template<typename RhsT>
+ auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+ static_assert(always_false<RhsT>::value,
+ "operator|| is not supported inside assertions, "
+ "wrap the expression inside parentheses, or decompose it");
+ }
+
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
return UnaryExpr<LhsT>{ m_lhs };
}
@@ -3175,16 +3422,17 @@ namespace Catch {
namespace Catch {
namespace Generators {
- class GeneratorBase {
- protected:
- size_t m_size = 0;
-
+ class GeneratorUntypedBase {
public:
- GeneratorBase( size_t size ) : m_size( size ) {}
- virtual ~GeneratorBase();
- auto size() const -> size_t { return m_size; }
+ GeneratorUntypedBase() = default;
+ virtual ~GeneratorUntypedBase();
+ // Attempts to move the generator to the next element
+ //
+ // Returns true iff the move succeeded (and a valid element
+ // can be retrieved).
+ virtual bool next() = 0;
};
- using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
+ using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;
} // namespace Generators
@@ -3193,7 +3441,6 @@ namespace Catch {
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
@@ -3233,8 +3480,21 @@ namespace Catch {
#include <cassert>
#include <utility>
+#include <exception>
namespace Catch {
+
+class GeneratorException : public std::exception {
+ const char* const m_msg = "";
+
+public:
+ GeneratorException(const char* msg):
+ m_msg(msg)
+ {}
+
+ const char* what() const noexcept override final;
+};
+
namespace Generators {
// !TBD move this into its own location?
@@ -3246,197 +3506,308 @@ namespace Generators {
}
template<typename T>
- struct IGenerator {
- virtual ~IGenerator() {}
- virtual auto get( size_t index ) const -> T = 0;
+ struct IGenerator : GeneratorUntypedBase {
+ virtual ~IGenerator() = default;
+
+ // Returns the current element of the generator
+ //
+ // \Precondition The generator is either freshly constructed,
+ // or the last call to `next()` returned true
+ virtual T const& get() const = 0;
+ using type = T;
};
template<typename T>
- class SingleValueGenerator : public IGenerator<T> {
+ class SingleValueGenerator final : public IGenerator<T> {
T m_value;
public:
- SingleValueGenerator( T const& value ) : m_value( value ) {}
+ SingleValueGenerator(T const& value) : m_value( value ) {}
+ SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
- auto get( size_t ) const -> T override {
+ T const& get() const override {
return m_value;
}
+ bool next() override {
+ return false;
+ }
};
template<typename T>
- class FixedValuesGenerator : public IGenerator<T> {
+ class FixedValuesGenerator final : public IGenerator<T> {
std::vector<T> m_values;
-
+ size_t m_idx = 0;
public:
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
- auto get( size_t index ) const -> T override {
- return m_values[index];
+ T const& get() const override {
+ return m_values[m_idx];
}
- };
-
- 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);
+ bool next() override {
+ ++m_idx;
+ return m_idx < m_values.size();
}
};
- 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 {
+ template <typename T>
+ class GeneratorWrapper final {
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 )
+ GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):
+ m_generator(std::move(generator))
{}
-
- auto size() const -> size_t { return m_size; }
- auto operator[]( size_t index ) const -> T {
- assert( index < m_size );
- return m_generator->get( index );
+ T const& get() const {
+ return m_generator->get();
+ }
+ bool next() {
+ return m_generator->next();
}
};
- std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
+ template <typename T>
+ GeneratorWrapper<T> value(T&& value) {
+ return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
+ }
+ template <typename T>
+ GeneratorWrapper<T> values(std::initializer_list<T> values) {
+ return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
+ }
template<typename T>
- class GeneratorRandomiser : public IGenerator<T> {
- Generator<T> m_baseGenerator;
+ class Generators : public IGenerator<T> {
+ std::vector<GeneratorWrapper<T>> m_generators;
+ size_t m_current = 0;
- 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]];
+ void populate(GeneratorWrapper<T>&& generator) {
+ m_generators.emplace_back(std::move(generator));
+ }
+ void populate(T&& val) {
+ m_generators.emplace_back(value(std::move(val)));
+ }
+ template<typename U>
+ void populate(U&& val) {
+ populate(T(std::move(val)));
+ }
+ template<typename U, typename... Gs>
+ void populate(U&& valueOrGenerator, Gs... moreGenerators) {
+ populate(std::forward<U>(valueOrGenerator));
+ populate(std::forward<Gs>(moreGenerators)...);
}
- };
- template<typename T>
- struct RequiresASpecialisationFor;
+ public:
+ template <typename... Gs>
+ Generators(Gs... moreGenerators) {
+ m_generators.reserve(sizeof...(Gs));
+ populate(std::forward<Gs>(moreGenerators)...);
+ }
- template<typename T>
- auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); }
+ T const& get() const override {
+ return m_generators[m_current].get();
+ }
- template<>
- auto all<int>() -> Generator<int>;
+ bool next() override {
+ if (m_current >= m_generators.size()) {
+ return false;
+ }
+ const bool current_status = m_generators[m_current].next();
+ if (!current_status) {
+ ++m_current;
+ }
+ return m_current < m_generators.size();
+ }
+ };
- 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... Ts>
+ GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {
+ return values<std::tuple<Ts...>>( tuples );
}
- template<typename T>
- auto random( T const& first, T const& last ) -> Generator<T> {
- auto gen = range( first, last );
- auto size = gen.size();
+ // Tag type to signal that a generator sequence should convert arguments to a specific type
+ template <typename T>
+ struct as {};
- return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
+ template<typename T, typename... Gs>
+ auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
+ return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
}
template<typename T>
- auto random( size_t size ) -> Generator<T> {
- return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) );
+ auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
+ return Generators<T>(std::move(generator));
}
-
- 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, typename... Gs>
+ auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
}
-
- template<typename T>
- auto as() -> Generator<T> {
- return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() );
+ template<typename T, typename U, typename... Gs>
+ auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
+ return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
}
- 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>
+ class TakeGenerator : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ size_t m_returned = 0;
+ size_t m_target;
+ public:
+ TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
+ m_generator(std::move(generator)),
+ m_target(target)
+ {
+ assert(target != 0 && "Empty generators are not allowed");
+ }
+ T const& get() const override {
+ return m_generator.get();
+ }
+ bool next() override {
+ ++m_returned;
+ if (m_returned >= m_target) {
+ return false;
+ }
- template<typename T>
- struct Generators : GeneratorBase {
- std::vector<Generator<T>> m_generators;
+ const auto success = m_generator.next();
+ // If the underlying generator does not contain enough values
+ // then we cut short as well
+ if (!success) {
+ m_returned = m_target;
+ }
+ return success;
+ }
+ };
- using type = T;
+ template <typename T>
+ GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
+ }
- Generators() : GeneratorBase( 0 ) {}
+ template <typename T, typename Predicate>
+ class FilterGenerator : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ Predicate m_predicate;
+ public:
+ template <typename P = Predicate>
+ FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
+ m_generator(std::move(generator)),
+ m_predicate(std::forward<P>(pred))
+ {
+ if (!m_predicate(m_generator.get())) {
+ // It might happen that there are no values that pass the
+ // filter. In that case we throw an exception.
+ auto has_initial_value = next();
+ if (!has_initial_value) {
+ Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
+ }
+ }
+ }
- void populate( T&& val ) {
- m_size += 1;
- m_generators.emplace_back( value( std::move( val ) ) );
+ T const& get() const override {
+ return m_generator.get();
}
- template<typename U>
- void populate( U&& val ) {
- populate( T( std::move( val ) ) );
+
+ bool next() override {
+ bool success = m_generator.next();
+ if (!success) {
+ return false;
+ }
+ while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
+ return success;
}
- void populate( Generator<T>&& generator ) {
- m_size += generator.size();
- m_generators.emplace_back( std::move( generator ) );
+ };
+
+ template <typename T, typename Predicate>
+ GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
+ return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
+ }
+
+ template <typename T>
+ class RepeatGenerator : public IGenerator<T> {
+ GeneratorWrapper<T> m_generator;
+ mutable std::vector<T> m_returned;
+ size_t m_target_repeats;
+ size_t m_current_repeat = 0;
+ size_t m_repeat_index = 0;
+ public:
+ RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
+ m_generator(std::move(generator)),
+ m_target_repeats(repeats)
+ {
+ assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
}
- template<typename U, typename... Gs>
- void populate( U&& valueOrGenerator, Gs... moreGenerators ) {
- populate( std::forward<U>( valueOrGenerator ) );
- populate( std::forward<Gs>( moreGenerators )... );
+ T const& get() const override {
+ if (m_current_repeat == 0) {
+ m_returned.push_back(m_generator.get());
+ return m_returned.back();
+ }
+ return m_returned[m_repeat_index];
}
- 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];
+ bool next() override {
+ // There are 2 basic cases:
+ // 1) We are still reading the generator
+ // 2) We are reading our own cache
+
+ // In the first case, we need to poke the underlying generator.
+ // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
+ if (m_current_repeat == 0) {
+ const auto success = m_generator.next();
+ if (!success) {
+ ++m_current_repeat;
+ }
+ return m_current_repeat < m_target_repeats;
+ }
+
+ // In the second case, we need to move indices forward and check that we haven't run up against the end
+ ++m_repeat_index;
+ if (m_repeat_index == m_returned.size()) {
+ m_repeat_index = 0;
+ ++m_current_repeat;
}
- CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
+ return m_current_repeat < m_target_repeats;
}
};
- 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>(