Redo generator interface

This commit is contained in:
Martin Hořeňovský 2019-01-27 19:46:28 +01:00
parent 64a9c02315
commit e46a70f829
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
13 changed files with 1284 additions and 2014 deletions

View File

@ -18,33 +18,11 @@ IGeneratorTracker::~IGeneratorTracker() {}
namespace Generators {
GeneratorBase::~GeneratorBase() {}
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) {
assert( selectionSize <= sourceSize );
std::vector<size_t> indices;
indices.reserve( selectionSize );
std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 );
std::set<size_t> seen;
// !TBD: improve this algorithm
while( indices.size() < selectionSize ) {
auto index = uid( rng() );
if( seen.insert( index ).second )
indices.push_back( index );
}
return indices;
}
GeneratorUntypedBase::~GeneratorUntypedBase() {}
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
return getResultCapture().acquireGeneratorTracker( lineInfo );
}
template<>
auto all<int>() -> Generator<int> {
return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() );
}
} // namespace Generators
} // namespace Catch

View File

@ -29,199 +29,140 @@ 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&& 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];
}
bool next() override {
++m_idx;
return m_idx < m_values.size();
}
};
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 {
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();
}
};
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]];
bool next() {
return m_generator->next();
}
};
template <typename T>
struct RequiresASpecialisationFor;
GeneratorWrapper<T> value(T&& value) {
return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
}
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 ) );
GeneratorWrapper<T> values(std::initializer_list<T> values) {
return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
}
template<typename T>
auto random( T const& first, T const& last ) -> Generator<T> {
auto gen = range( first, last );
auto size = gen.size();
class Generators : public IGenerator<T> {
std::vector<GeneratorWrapper<T>> m_generators;
size_t m_current = 0;
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
void populate(GeneratorWrapper<T>&& generator) {
m_generators.emplace_back(std::move(generator));
}
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];
public:
template <typename... Gs>
Generators(Gs... moreGenerators) {
m_generators.reserve(sizeof...(Gs));
populate(std::forward<Gs>(moreGenerators)...);
}
CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
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( 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;
auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
}
template<typename T>
auto makeGenerators( Generator<T>&& generator ) -> Generators<T> {
Generators<T> generators;
generators.populate( std::move( generator ) );
return generators;
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( U&& val, Gs... moreGenerators ) -> Generators<T> {
auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
}
@ -232,15 +173,16 @@ namespace Generators {
// 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())>()[0]) {
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() )
if (!tracker.hasGenerator()) {
tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
}
auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() );
return generator[tracker.getIndex()];
auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
return generator.get();
}
} // namespace Generators

View File

@ -13,16 +13,17 @@
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
@ -31,7 +32,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

View File

@ -14,7 +14,6 @@ namespace Catch {
namespace Generators {
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
size_t m_index = static_cast<size_t>( -1 );
GeneratorBasePtr m_generator;
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
@ -28,7 +27,7 @@ namespace Catch {
ITracker& currentTracker = ctx.currentTracker();
if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
assert( childTracker->isIndexTracker() );
assert( childTracker->isGeneratorTracker() );
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
}
else {
@ -37,29 +36,25 @@ namespace Catch {
}
if( !ctx.completedCycle() && !tracker->isComplete() ) {
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
tracker->moveNext();
tracker->open();
}
return *tracker;
}
void moveNext() {
m_index++;
m_children.clear();
}
// TrackerBase interface
bool isIndexTracker() const override { return true; }
bool isGeneratorTracker() const override { return true; }
auto hasGenerator() const -> bool override {
return !!m_generator;
}
void close() override {
TrackerBase::close();
if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 )
// Generator interface only finds out if it has another item on atual move
if (m_runState == CompletedSuccessfully && m_generator->next()) {
m_children.clear();
m_runState = Executing;
}
}
// IGeneratorTracker interface
auto getGenerator() const -> GeneratorBasePtr const& override {
@ -68,9 +63,6 @@ namespace Catch {
void setGenerator( GeneratorBasePtr&& generator ) override {
m_generator = std::move( generator );
}
auto getIndex() const -> size_t override {
return m_index;
}
};
GeneratorTracker::~GeneratorTracker() {}
}

View File

@ -121,7 +121,7 @@ namespace TestCaseTracking {
}
bool TrackerBase::isSectionTracker() const { return false; }
bool TrackerBase::isIndexTracker() const { return false; }
bool TrackerBase::isGeneratorTracker() const { return false; }
void TrackerBase::open() {
m_runState = Executing;

View File

@ -54,7 +54,7 @@ namespace TestCaseTracking {
// Debug/ checking
virtual bool isSectionTracker() const = 0;
virtual bool isIndexTracker() const = 0;
virtual bool isGeneratorTracker() const = 0;
};
class TrackerContext {
@ -120,7 +120,7 @@ namespace TestCaseTracking {
void openChild() override;
bool isSectionTracker() const override;
bool isIndexTracker() const override;
bool isGeneratorTracker() const override;
void open();

View File

@ -57,106 +57,87 @@ Tricky.tests.cpp:<line number>: passed: !is_true<false>::value for: true
Tricky.tests.cpp:<line number>: passed: !!is_true<true>::value for: true
Tricky.tests.cpp:<line number>: passed: is_true<true>::value for: true
Tricky.tests.cpp:<line number>: passed: !(is_true<false>::value) for: !false
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 4
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 7
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 7
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 4
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 8
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 8
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 4
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 9
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 9
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 5
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 7
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 7
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 5
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 8
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 8
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 5
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 9
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 9
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 6
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 7
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 7
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 6
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 8
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 8
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 6
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 9
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 9
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 4
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 7
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 7
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 4
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 8
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 8
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 4
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 9
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 9
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 5
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 7
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 7
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 5
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 8
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 8
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 5
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 9
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 9
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 6
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 7
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 7
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 6
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 8
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 8
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 6
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 9
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 9
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 4
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 7
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 7
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 4
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 8
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 8
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 4
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 9
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 9
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 5
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 7
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 7
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 5
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 8
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 8
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 5
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 9
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 9
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 6
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 7
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 7
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 6
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 8
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 8
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 6
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 9
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 9
Class.tests.cpp:<line number>: failed: s == "world" for: "hello" == "world"
Class.tests.cpp:<line number>: passed: s == "hello" for: "hello" == "hello"
Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>::m_a.size() == 1 for: 0 == 1
@ -418,48 +399,49 @@ Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, 0.f)
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, -1.f), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, 0)
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, -1), std::domain_error
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 8'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 9'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 10'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 2'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 3.141'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 1.379'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 8'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 9'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 10'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 2'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 3.141'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 1.379'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 8'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 9'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 10'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 2'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 3.141'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 1.379'
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen[2] == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: gen[3] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen[2] == 9 for: 9 == 9
GeneratorsImpl.tests.cpp:<line number>: passed: gen[3] == 7 for: 7 == 7
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: base->size() == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: typed for: 0x<hex digits>
GeneratorsImpl.tests.cpp:<line number>: passed: typed->size() == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: (*typed)[0] == 7 for: 7 == 7
GeneratorsImpl.tests.cpp:<line number>: passed: (*typed)[3] == 11 for: 11 == 11
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 1
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 1
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 1
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 4 > 1
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 4 > 2
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 4 > 3
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 2
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 2
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 2
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 8 > 1
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 8 > 2
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 8 > 3
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 3
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 3
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 3
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 1
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 2
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 3
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 123 for: 123 == 123
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 0 for: 0 == 0
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get().size() == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == "aa" for: "aa" == "aa"
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == "bb" for: "bb" == "bb"
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == "cc" for: "cc" == "cc"
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
Approx.tests.cpp:<line number>: passed: d >= Approx( 1.22 ) for: 1.23 >= Approx( 1.22 )
Approx.tests.cpp:<line number>: passed: d >= Approx( 1.23 ) for: 1.23 >= Approx( 1.23 )
Approx.tests.cpp:<line number>: passed: !(d >= Approx( 1.24 )) for: !(1.23 >= Approx( 1.24 ))
@ -1274,6 +1256,10 @@ Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 =
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 == 3
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 5 == 5
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 4 == 4
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 6 == 6
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 6 == 6
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'Why would you throw a std::string?'
Misc.tests.cpp:<line number>: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""

View File

@ -1170,6 +1170,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
test cases: 243 | 183 passed | 56 failed | 4 failed as expected
assertions: 1262 | 1126 passed | 115 failed | 21 failed as expected
test cases: 244 | 184 passed | 56 failed | 4 failed as expected
assertions: 1248 | 1112 passed | 115 failed | 21 failed as expected

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="17" failures="113" tests="1277" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="113" tests="1263" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
@ -70,7 +70,7 @@ Condition.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/negation" time="{duration}"/>
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/double negation" time="{duration}"/>
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/direct" time="{duration}"/>
<testcase classname="<exe-name>.global" name="10x10 ints" time="{duration}"/>
<testcase classname="<exe-name>.global" name="3x3x3 ints" time="{duration}"/>
<testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that fails" time="{duration}">
<failure message="&quot;hello&quot; == &quot;world&quot;" type="REQUIRE">
Class.tests.cpp:<line number>
@ -339,14 +339,12 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators/one" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators/two" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/range" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/fixed values" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/combined" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/values" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/values2" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/type erasure" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- simple/one" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- simple/two" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators internals/Single value" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators internals/Preset values" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators internals/Generator combinator" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators internals/Explicitly typed generator sequence" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Greater-than inequalities with different epsilons" time="{duration}"/>
<testcase classname="<exe-name>.global" name="INFO and WARN do not abort tests" time="{duration}"/>
<testcase classname="<exe-name>.global" name="INFO gets logged on failure" time="{duration}">
@ -938,6 +936,7 @@ Tricky.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker_and_operator> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_operator> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="strlen3" time="{duration}"/>
<testcase classname="<exe-name>.global" name="tables" time="{duration}"/>
<testcase classname="<exe-name>.global" name="thrown std::strings are translated" time="{duration}">
<error type="TEST_CASE">
Why would you throw a std::string?

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +1,46 @@
#include "catch.hpp"
// Tests of generartor implementation details
TEST_CASE("Generators impl", "[impl]") {
// Tests of generator implementation details
TEST_CASE("Generators internals", "[generators][internals]") {
using namespace Catch::Generators;
SECTION( "range" ) {
auto gen = range(1,3);
CHECK( gen.size() == 2 );
CHECK( gen[0] == 1 );
CHECK( gen[1] == 2 );
SECTION("Single value") {
auto gen = value(123);
REQUIRE(gen.get() == 123);
REQUIRE_FALSE(gen.next());
}
SECTION( "fixed values" ) {
auto gen = values( { 3, 1, 4, 1 } );
CHECK( gen.size() == 4 );
CHECK( gen[0] == 3 );
CHECK( gen[1] == 1 );
CHECK( gen[2] == 4 );
CHECK( gen[3] == 1 );
SECTION("Preset values") {
auto gen = values({ 1, 3, 5 });
REQUIRE(gen.get() == 1);
REQUIRE(gen.next());
REQUIRE(gen.get() == 3);
REQUIRE(gen.next());
REQUIRE(gen.get() == 5);
REQUIRE_FALSE(gen.next());
}
SECTION( "combined" ) {
auto gen = makeGenerators( range( 1, 3 ), values( { 9, 7 } ) );
CHECK( gen.size() == 4 );
CHECK( gen[0] == 1 );
CHECK( gen[1] == 2 );
CHECK( gen[2] == 9 );
CHECK( gen[3] == 7 );
}
SECTION( "values" ) {
auto gen = makeGenerators( 3, 1 );
CHECK( gen.size() == 2 );
CHECK( gen[0] == 3 );
CHECK( gen[1] == 1 );
}
SECTION( "values2" ) {
auto gen = makeGenerators( 3, 1 );
CHECK( gen.size() == 2 );
CHECK( gen[0] == 3 );
CHECK( gen[1] == 1 );
}
SECTION( "type erasure" ) {
auto gen = makeGenerators( range( 7, 10 ), 11 );
// Make type erased version
auto dynCopy = pf::make_unique<Generators<int>>( std::move( gen ) );
std::unique_ptr<GeneratorBase const> base = std::move( dynCopy );
// Only thing we can do is ask for the size
CHECK( base->size() == 4 );
// Restore typed version
auto typed = dynamic_cast<Generators<int> const*>( base.get() );
REQUIRE( typed );
CHECK( typed->size() == 4 );
CHECK( (*typed)[0] == 7 );
CHECK( (*typed)[3] == 11 );
}
}
TEST_CASE("Generators impl - random", "[approvals]") {
using namespace Catch::Generators;
SECTION( "random range" ) {
auto gen = random( 3, 9 );
CHECK( gen.size() == 6 );
for( size_t i = 0; i < 6; ++i ) {
CHECK( gen[i] >= 3 );
CHECK( gen[i] <= 8 );
if( i > 0 )
CHECK( gen[i] != gen[i-1] );
}
}
SECTION( "random selection" ) {
auto gen = random<int>( 10 );
CHECK( gen.size() == 10 );
for( size_t i = 0; i < 10; ++i ) {
if( i > 0 )
CHECK( gen[i] != gen[i-1] );
SECTION("Generator combinator") {
auto gen = makeGenerators(1, 5, values({ 2, 4 }), 0);
REQUIRE(gen.get() == 1);
REQUIRE(gen.next());
REQUIRE(gen.get() == 5);
REQUIRE(gen.next());
REQUIRE(gen.get() == 2);
REQUIRE(gen.next());
REQUIRE(gen.get() == 4);
REQUIRE(gen.next());
REQUIRE(gen.get() == 0);
REQUIRE_FALSE(gen.next());
}
SECTION("Explicitly typed generator sequence") {
auto gen = makeGenerators(as<std::string>{}, "aa", "bb", "cc");
// This just checks that the type is std::string:
REQUIRE(gen.get().size() == 2);
// Iterate over the generator
REQUIRE(gen.get() == "aa");
REQUIRE(gen.next());
REQUIRE(gen.get() == "bb");
REQUIRE(gen.next());
REQUIRE(gen.get() == "cc");
REQUIRE_FALSE(gen.next());
}
}

View File

@ -1,53 +1,58 @@
#include "catch.hpp"
// Examples of usage of Generators
#include <cstring>
// This test doesn't do much - it just shows how you can have several generators, of different
// types (ie `i` and `j` are different types), can be sequenced using `,` and
// can be expressed as named generators (like range) or as individual values.
// Generators can be mixed with SECTIONs.
// At time of writing the generated values are not automatically reported as part of the test
// name or associated values - so we explicitly CAPTURE then (run this with `-s` to see them).
// We could also incorporate them into the section names using DYNAMIC_SECTION. See the BDD
// example later for more information.
TEST_CASE("Generators") {
auto i = GENERATE( as<std::string>(), "a", "b", "c" );
// Generators and sections can be nested freely
TEST_CASE("Generators -- simple", "[generators]") {
auto i = GENERATE(1, 2, 3);
SECTION("one") {
auto j = GENERATE( range( 8, 11 ), 2 );
CAPTURE( i, j );
SUCCEED();
auto j = GENERATE(values({ -3, -2, -1 }));
REQUIRE(j < i);
}
SECTION("two") {
auto j = GENERATE( 3.141, 1.379 );
CAPTURE( i, j );
SUCCEED();
// You can also explicitly set type for generators via Catch::Generators::as
auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");
REQUIRE(4u * i > str.size());
}
}
// This one generates the cross-product of two ranges.
// It's mostly here to demonstrate the performance which, at time of writing,
// leaves a lot to be desired.
TEST_CASE( "100x100 ints", "[.][approvals]" ) {
auto x = GENERATE( range( 0,100 ) );
auto y = GENERATE( range( 200,300 ) );
// You can create a cartesian-product of generators by creating multiple ones
TEST_CASE("3x3x3 ints", "[generators]") {
auto x = GENERATE(1, 2, 3);
auto y = GENERATE(4, 5, 6);
auto z = GENERATE(7, 8, 9);
// These assertions will be run 27 times (3x3x3)
CHECK(x < y);
CHECK(y < z);
REQUIRE(x < z);
}
// smaller version
TEST_CASE( "10x10 ints" ) {
auto x = GENERATE( range( 1,11 ) );
auto y = GENERATE( range( 101, 111 ) );
// You can also create data tuples
TEST_CASE("tables", "[generators]") {
// Note that this will not compile with libstdc++ older than libstdc++6
// See https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list
// for possible workarounds
// auto data = GENERATE(table<char const*, int>({
// {"first", 5},
// {"second", 6},
// {"third", 5},
// {"etc...", 6}
// }));
CHECK( x < y );
// Workaround for the libstdc++ bug mentioned above
using tuple_type = std::tuple<char const*, int>;
auto data = GENERATE(table<char const*, int>({
tuple_type{"first", 5},
tuple_type{"second", 6},
tuple_type{"third", 5},
tuple_type{"etc...", 6}
}));
REQUIRE(strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)));
}
// Some of the following tests use structured bindings for convenience and so are
// conditionally compiled using the de-facto (and soon to be formally) standard
// feature macros
#ifdef __cpp_structured_bindings
@ -56,7 +61,7 @@ TEST_CASE( "10x10 ints" ) {
// but it demonstrates a possible usage.
// Spelling out the pair like this is a bit verbose, so read on for better examples
// - the use of structured bindings here is an optional convenience
TEST_CASE( "strlen", "[approvals]" ) {
TEST_CASE( "strlen", "[approvals][generators]" ) {
auto [test_input, expected] = GENERATE( values<std::pair<std::string_view, size_t>>({
{"one", 3},
{"two", 3},
@ -69,7 +74,7 @@ TEST_CASE( "strlen", "[approvals]" ) {
// A nicer way to do pairs (or more) of values - using the table generator.
// Note, you must specify the types up-front.
TEST_CASE( "strlen2", "[approvals]" ) {
TEST_CASE( "strlen2", "[approvals][generators]" ) {
auto [test_input, expected] = GENERATE( table<std::string, size_t>({
{"one", 3},
{"two", 3},
@ -81,11 +86,11 @@ TEST_CASE( "strlen2", "[approvals]" ) {
}
#endif
// An alternate way of doing data tables without structure bindings
// - I'd prefer to have the Data class within the test case but gcc 4.x doesn't seem to like it
// An alternate way of doing data tables without structured bindings
struct Data { std::string str; size_t len; };
TEST_CASE( "strlen3" ) {
TEST_CASE( "strlen3", "[generators]" ) {
auto data = GENERATE( values<Data>({
{"one", 3},
{"two", 3},
@ -96,15 +101,7 @@ TEST_CASE( "strlen3" ) {
REQUIRE( data.str.size() == data.len );
}
// A nod towards property-based testing - generate a random selection of numbers
// in a range and assert on global properties those numbers.
static auto square( int i ) -> int { return i*i; }
TEST_CASE( "Random numbers in a range", "[.][approvals]" ) {
auto x = GENERATE( random( -10000, 10000 ) );
CAPTURE( x );
REQUIRE( square(x) >= 0 );
}
#ifdef __cpp_structured_bindings
@ -118,7 +115,7 @@ TEST_CASE( "Random numbers in a range", "[.][approvals]" ) {
static auto eatCucumbers( int start, int eat ) -> int { return start-eat; }
SCENARIO("Eating cucumbers", "[approvals]") {
SCENARIO("Eating cucumbers", "[generators][approvals]") {
auto [start, eat, left] = GENERATE( table<int,int,int> ({
{ 12, 5, 7 },