mirror of
https://github.com/catchorg/Catch2.git
synced 2025-04-29 04:03:51 +00:00
This is both a really big and a really small commit. It is small in that it only contains renaming, moving and modification of include directives caused by this. It is really big in the obvious way of touching something like 200 files. The new rules for naming files is simple: headers use the `.hpp` extension. The rules for physical file layout is still kinda in progress, but the basics are also simple: * Significant parts of functionality get their own subfolder * Benchmarking is in `catch2/benchmark` * Matchers are in `catch2/matchers` * Generators are in `catch2/generators` * Reporters are in `catch2/reporters` * Baseline testing facilities are in `catch2/` * Various top level folders also contain `internal` subfolder, with files that users probably do not want to include directly, at least not until they have to write something like their own reporter. * The exact files in these subfolders is likely to change later on Note that while some includes were cleaned up in this commit, it is only the low hanging fruit and further cleanup using automatic tooling will happen later. Also note that various include guards, copyright notices and file headers will also be standardized later, rather than in this commit.
200 lines
7.0 KiB
C++
200 lines
7.0 KiB
C++
/*
|
|
* 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 <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
|
#include <catch2/internal/catch_common.hpp>
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <cassert>
|
|
#include <tuple>
|
|
#include <utility>
|
|
|
|
namespace Catch {
|
|
|
|
namespace Generators {
|
|
|
|
namespace Detail {
|
|
|
|
//! Throws GeneratorException with the provided message
|
|
[[noreturn]]
|
|
void throw_generator_exception(char const * msg);
|
|
|
|
} // end namespace detail
|
|
|
|
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>(std::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
|
|
}
|
|
template <typename T>
|
|
GeneratorWrapper<T> values(std::initializer_list<T> values) {
|
|
return GeneratorWrapper<T>(std::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<std::decay_t<Ts>...>> 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( 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( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
|
|
using UnderlyingType = typename decltype(generatorExpression())::type;
|
|
|
|
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
|
|
if (!tracker.hasGenerator()) {
|
|
tracker.setGenerator(std::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( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
|
#define GENERATE_COPY( ... ) \
|
|
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
|
#define GENERATE_REF( ... ) \
|
|
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
|
|
|
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|