Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
catch_generators.hpp
Go to the documentation of this file.
1/*
2 * Created by Phil Nash on 15/6/2018.
3 *
4 * Distributed under the Boost Software License, Version 1.0. (See accompanying
5 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 */
7#ifndef TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
8#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
9
11#include "catch_common.h"
12#include "catch_enforce.h"
13
14#include <memory>
15#include <vector>
16#include <cassert>
17
18#include <utility>
19#include <exception>
20
21namespace Catch {
22
23class GeneratorException : public std::exception {
24 const char* const m_msg = "";
25
26public:
27 GeneratorException(const char* msg):
28 m_msg(msg)
29 {}
30
31 const char* what() const noexcept override final;
32};
33
34namespace Generators {
35
36 // !TBD move this into its own location?
37 namespace pf{
38 template<typename T, typename... Args>
39 std::unique_ptr<T> make_unique( Args&&... args ) {
40 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
41 }
42 }
43
44 template<typename T>
45 struct IGenerator : GeneratorUntypedBase {
46 virtual ~IGenerator() = default;
47
48 // Returns the current element of the generator
49 //
50 // \Precondition The generator is either freshly constructed,
51 // or the last call to `next()` returned true
52 virtual T const& get() const = 0;
53 using type = T;
54 };
55
56 template<typename T>
57 class SingleValueGenerator final : public IGenerator<T> {
58 T m_value;
59 public:
60 SingleValueGenerator(T const& value) : m_value( value ) {}
61 SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
62
63 T const& get() const override {
64 return m_value;
65 }
66 bool next() override {
67 return false;
68 }
69 };
70
71 template<typename T>
72 class FixedValuesGenerator final : public IGenerator<T> {
73 std::vector<T> m_values;
74 size_t m_idx = 0;
75 public:
76 FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
77
78 T const& get() const override {
79 return m_values[m_idx];
80 }
81 bool next() override {
82 ++m_idx;
83 return m_idx < m_values.size();
84 }
85 };
86
87 template <typename T>
88 class GeneratorWrapper final {
89 std::unique_ptr<IGenerator<T>> m_generator;
90 public:
91 GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):
92 m_generator(std::move(generator))
93 {}
94 T const& get() const {
95 return m_generator->get();
96 }
97 bool next() {
98 return m_generator->next();
99 }
100 };
101
102 template <typename T>
104 return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
105 }
106 template <typename T>
107 GeneratorWrapper<T> values(std::initializer_list<T> values) {
108 return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
109 }
110
111 template<typename T>
112 class Generators : public IGenerator<T> {
113 std::vector<GeneratorWrapper<T>> m_generators;
114 size_t m_current = 0;
115
116 void populate(GeneratorWrapper<T>&& generator) {
117 m_generators.emplace_back(std::move(generator));
118 }
119 void populate(T&& val) {
120 m_generators.emplace_back(value(std::move(val)));
121 }
122 template<typename U>
123 void populate(U&& val) {
124 populate(T(std::move(val)));
125 }
126 template<typename U, typename... Gs>
127 void populate(U&& valueOrGenerator, Gs... moreGenerators) {
128 populate(std::forward<U>(valueOrGenerator));
129 populate(std::forward<Gs>(moreGenerators)...);
130 }
131
132 public:
133 template <typename... Gs>
134 Generators(Gs... moreGenerators) {
135 m_generators.reserve(sizeof...(Gs));
136 populate(std::forward<Gs>(moreGenerators)...);
137 }
138
139 T const& get() const override {
140 return m_generators[m_current].get();
141 }
142
143 bool next() override {
144 if (m_current >= m_generators.size()) {
145 return false;
146 }
147 const bool current_status = m_generators[m_current].next();
148 if (!current_status) {
149 ++m_current;
150 }
151 return m_current < m_generators.size();
152 }
153 };
154
155
156 template<typename... Ts>
157 GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {
158 return values<std::tuple<Ts...>>( tuples );
159 }
160
161 // Tag type to signal that a generator sequence should convert arguments to a specific type
162 template <typename T>
163 struct as {};
164
165 template<typename T, typename... Gs>
166 auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
167 return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
168 }
169 template<typename T>
171 return Generators<T>(std::move(generator));
172 }
173 template<typename T, typename... Gs>
174 auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
175 return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
176 }
177 template<typename T, typename U, typename... Gs>
178 auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
179 return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
180 }
181
182 auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
183
184 template<typename L>
185 // Note: The type after -> is weird, because VS2015 cannot parse
186 // the expression used in the typedef inside, when it is in
187 // return type. Yeah.
188 auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
189 using UnderlyingType = typename decltype(generatorExpression())::type;
190
191 IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
192 if (!tracker.hasGenerator()) {
193 tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
194 }
195
196 auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
197 return generator.get();
198 }
199
200} // namespace Generators
201} // namespace Catch
202
203#define GENERATE( ... ) \
204 Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
205#define GENERATE_COPY( ... ) \
206 Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
207#define GENERATE_REF( ... ) \
208 Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
209
210#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
GeneratorException(const char *msg)
const char * what() const noexcept override final
FixedValuesGenerator(std::initializer_list< T > values)
GeneratorWrapper(std::unique_ptr< IGenerator< T > > generator)
T const & get() const override
std::unique_ptr< T > make_unique(Args &&... args)
auto acquireGeneratorTracker(SourceLineInfo const &lineInfo) -> IGeneratorTracker &
auto makeGenerators(GeneratorWrapper< T > &&generator, Gs... moreGenerators) -> Generators< T >
auto generate(SourceLineInfo const &lineInfo, L const &generatorExpression) -> decltype(std::declval< decltype(generatorExpression())>().get())
GeneratorWrapper< T > values(std::initializer_list< T > values)
Definition name.hpp:106
#define value
Definition pkcs11.h:157
#define T(meth, val, expected)
virtual T const & get() const =0
virtual ~IGenerator()=default
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const &=0
virtual void setGenerator(Generators::GeneratorBasePtr &&generator)=0
virtual auto hasGenerator() const -> bool=0
Definition dtoa.c:306