| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 | 
							- /*
 
-  *  Created by Phil Nash on 15/6/2018.
 
-  *
 
-  *  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)
 
-  */
 
- #ifndef TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
 
- #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
 
- #include "catch_interfaces_generatortracker.h"
 
- #include "catch_common.h"
 
- #include "catch_enforce.h"
 
- #include "catch_stringref.h"
 
- #include <memory>
 
- #include <vector>
 
- #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?
 
-     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 : 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 final : public IGenerator<T> {
 
-         T m_value;
 
-     public:
 
-         SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
 
-         T const& get() const override {
 
-             return m_value;
 
-         }
 
-         bool next() override {
 
-             return false;
 
-         }
 
-     };
 
-     template<typename T>
 
-     class FixedValuesGenerator final : public IGenerator<T> {
 
-         static_assert(!std::is_same<T, bool>::value,
 
-             "FixedValuesGenerator does not support bools because of std::vector<bool>"
 
-             "specialization, use SingleValue Generator instead.");
 
-         std::vector<T> m_values;
 
-         size_t m_idx = 0;
 
-     public:
 
-         FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
 
-         T const& get() const override {
 
-             return m_values[m_idx];
 
-         }
 
-         bool next() override {
 
-             ++m_idx;
 
-             return m_idx < m_values.size();
 
-         }
 
-     };
 
-     template <typename T>
 
-     class GeneratorWrapper final {
 
-         std::unique_ptr<IGenerator<T>> m_generator;
 
-     public:
 
-         GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):
 
-             m_generator(std::move(generator))
 
-         {}
 
-         T const& get() const {
 
-             return m_generator->get();
 
-         }
 
-         bool next() {
 
-             return m_generator->next();
 
-         }
 
-     };
 
-     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 Generators : public IGenerator<T> {
 
-         std::vector<GeneratorWrapper<T>> m_generators;
 
-         size_t m_current = 0;
 
-         void populate(GeneratorWrapper<T>&& generator) {
 
-             m_generators.emplace_back(std::move(generator));
 
-         }
 
-         void populate(T&& val) {
 
-             m_generators.emplace_back(value(std::forward<T>(val)));
 
-         }
 
-         template<typename U>
 
-         void populate(U&& val) {
 
-             populate(T(std::forward<U>(val)));
 
-         }
 
-         template<typename U, typename... Gs>
 
-         void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {
 
-             populate(std::forward<U>(valueOrGenerator));
 
-             populate(std::forward<Gs>(moreGenerators)...);
 
-         }
 
-     public:
 
-         template <typename... Gs>
 
-         Generators(Gs &&... moreGenerators) {
 
-             m_generators.reserve(sizeof...(Gs));
 
-             populate(std::forward<Gs>(moreGenerators)...);
 
-         }
 
-         T const& get() const override {
 
-             return m_generators[m_current].get();
 
-         }
 
-         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... Ts>
 
-     GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {
 
-         return values<std::tuple<Ts...>>( tuples );
 
-     }
 
-     // Tag type to signal that a generator sequence should convert arguments to a specific type
 
-     template <typename T>
 
-     struct as {};
 
-     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 makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
 
-         return Generators<T>(std::move(generator));
 
-     }
 
-     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( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
 
-         return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
 
-     }
 
-     auto acquireGeneratorTracker( StringRef generatorName, 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 generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
 
-         using UnderlyingType = typename decltype(generatorExpression())::type;
 
-         IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );
 
-         if (!tracker.hasGenerator()) {
 
-             tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
 
-         }
 
-         auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
 
-         return generator.get();
 
-     }
 
- } // namespace Generators
 
- } // namespace Catch
 
- #define GENERATE( ... ) \
 
-     Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
 
-                                  CATCH_INTERNAL_LINEINFO, \
 
-                                  [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
 
- #define GENERATE_COPY( ... ) \
 
-     Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
 
-                                  CATCH_INTERNAL_LINEINFO, \
 
-                                  [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
 
- #define GENERATE_REF( ... ) \
 
-     Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
 
-                                  CATCH_INTERNAL_LINEINFO, \
 
-                                  [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
 
- #endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
 
 
  |