mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-03 21:49:32 +01:00 
			
		
		
		
	Add ChunkGenerator
This generator collects values from the underlying generator until it has a specified amount of them, and then returns them in one "chunk". In case the underlying generator does not have enough elements for a specific chunk, the left-over elements are discarded. Closes #1538
This commit is contained in:
		@@ -36,13 +36,14 @@ a test case,
 | 
				
			|||||||
* 2 fundamental generators
 | 
					* 2 fundamental generators
 | 
				
			||||||
  * `ValueGenerator<T>` -- contains only single element
 | 
					  * `ValueGenerator<T>` -- contains only single element
 | 
				
			||||||
  * `ValuesGenerator<T>` -- contains multiple elements
 | 
					  * `ValuesGenerator<T>` -- contains multiple elements
 | 
				
			||||||
* 4 generic generators that modify other generators
 | 
					* 5 generic generators that modify other generators
 | 
				
			||||||
  * `FilterGenerator<T, Predicate>` -- filters out elements from a generator
 | 
					  * `FilterGenerator<T, Predicate>` -- filters out elements from a generator
 | 
				
			||||||
  for which the predicate returns "false"
 | 
					  for which the predicate returns "false"
 | 
				
			||||||
  * `TakeGenerator<T>` -- takes first `n` elements from a generator
 | 
					  * `TakeGenerator<T>` -- takes first `n` elements from a generator
 | 
				
			||||||
  * `RepeatGenerator<T>` -- repeats output from a generator `n` times
 | 
					  * `RepeatGenerator<T>` -- repeats output from a generator `n` times
 | 
				
			||||||
  * `MapGenerator<T, U, Func>` -- returns the result of applying `Func`
 | 
					  * `MapGenerator<T, U, Func>` -- returns the result of applying `Func`
 | 
				
			||||||
  on elements from a different generator
 | 
					  on elements from a different generator
 | 
				
			||||||
 | 
					  * `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator
 | 
				
			||||||
* 3 specific purpose generators
 | 
					* 3 specific purpose generators
 | 
				
			||||||
  * `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
 | 
					  * `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
 | 
				
			||||||
  * `RandomFloatGenerator<Float>` -- generates random Floats from range
 | 
					  * `RandomFloatGenerator<Float>` -- generates random Floats from range
 | 
				
			||||||
@@ -58,6 +59,7 @@ type, making their usage much nicer. These are
 | 
				
			|||||||
* `repeat(repeats, GeneratorWrapper<T>&&)` for `RepeatGenerator<T>`
 | 
					* `repeat(repeats, GeneratorWrapper<T>&&)` for `RepeatGenerator<T>`
 | 
				
			||||||
* `map(func, GeneratorWrapper<T>&&)` for `MapGenerator<T, T, Func>` (map `T` to `T`)
 | 
					* `map(func, GeneratorWrapper<T>&&)` for `MapGenerator<T, T, Func>` (map `T` to `T`)
 | 
				
			||||||
* `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`)
 | 
					* `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`)
 | 
				
			||||||
 | 
					* `chunk(chunk-size, GeneratorWrapper<T>&&)` for `ChunkGenerator<T>`
 | 
				
			||||||
* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
 | 
					* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
 | 
				
			||||||
* `range(start, end)` for `RangeGenerator<T>` with a step size of `1` 
 | 
					* `range(start, end)` for `RangeGenerator<T>` with a step size of `1` 
 | 
				
			||||||
* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
 | 
					* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,6 +63,7 @@
 | 
				
			|||||||
#include "internal/catch_capture_matchers.h"
 | 
					#include "internal/catch_capture_matchers.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include "internal/catch_generators.hpp"
 | 
					#include "internal/catch_generators.hpp"
 | 
				
			||||||
 | 
					#include "internal/catch_generators_generic.hpp"
 | 
				
			||||||
#include "internal/catch_generators_specific.hpp"
 | 
					#include "internal/catch_generators_specific.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// These files are included here so the single_include script doesn't put them
 | 
					// These files are included here so the single_include script doesn't put them
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -179,176 +179,6 @@ namespace Generators {
 | 
				
			|||||||
        return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
 | 
					        return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    template <typename T>
 | 
					 | 
				
			||||||
    GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
 | 
					 | 
				
			||||||
        return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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"));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        T const& get() const override {
 | 
					 | 
				
			||||||
            return m_generator.get();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return m_current_repeat < m_target_repeats;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    template <typename T>
 | 
					 | 
				
			||||||
    GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
 | 
					 | 
				
			||||||
        return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    template <typename T, typename U, typename Func>
 | 
					 | 
				
			||||||
    class MapGenerator : public IGenerator<T> {
 | 
					 | 
				
			||||||
        // TBD: provide static assert for mapping function, for friendly error message
 | 
					 | 
				
			||||||
        GeneratorWrapper<U> m_generator;
 | 
					 | 
				
			||||||
        Func m_function;
 | 
					 | 
				
			||||||
        // To avoid returning dangling reference, we have to save the values
 | 
					 | 
				
			||||||
        T m_cache;
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        template <typename F2 = Func>
 | 
					 | 
				
			||||||
        MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
 | 
					 | 
				
			||||||
            m_generator(std::move(generator)),
 | 
					 | 
				
			||||||
            m_function(std::forward<F2>(function)),
 | 
					 | 
				
			||||||
            m_cache(m_function(m_generator.get()))
 | 
					 | 
				
			||||||
        {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        T const& get() const override {
 | 
					 | 
				
			||||||
            return m_cache;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        bool next() override {
 | 
					 | 
				
			||||||
            const auto success = m_generator.next();
 | 
					 | 
				
			||||||
            if (success) {
 | 
					 | 
				
			||||||
                m_cache = m_function(m_generator.get());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return success;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    template <typename T, typename U, typename Func>
 | 
					 | 
				
			||||||
    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
 | 
					 | 
				
			||||||
        return GeneratorWrapper<T>(
 | 
					 | 
				
			||||||
            pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    template <typename T, typename Func>
 | 
					 | 
				
			||||||
    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<T>&& generator) {
 | 
					 | 
				
			||||||
        return GeneratorWrapper<T>(
 | 
					 | 
				
			||||||
            pf::make_unique<MapGenerator<T, T, Func>>(std::forward<Func>(function), std::move(generator))
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
 | 
					    auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template<typename L>
 | 
					    template<typename L>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										230
									
								
								include/internal/catch_generators_generic.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								include/internal/catch_generators_generic.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,230 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Created by Martin on 23/2/2019.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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_GENERIC_HPP_INCLUDED
 | 
				
			||||||
 | 
					#define TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "catch_generators.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Catch {
 | 
				
			||||||
 | 
					namespace Generators {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T>
 | 
				
			||||||
 | 
					    GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
 | 
				
			||||||
 | 
					        return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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"));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        T const& get() const override {
 | 
				
			||||||
 | 
					            return m_generator.get();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return m_current_repeat < m_target_repeats;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T>
 | 
				
			||||||
 | 
					    GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
 | 
				
			||||||
 | 
					        return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T, typename U, typename Func>
 | 
				
			||||||
 | 
					    class MapGenerator : public IGenerator<T> {
 | 
				
			||||||
 | 
					        // TBD: provide static assert for mapping function, for friendly error message
 | 
				
			||||||
 | 
					        GeneratorWrapper<U> m_generator;
 | 
				
			||||||
 | 
					        Func m_function;
 | 
				
			||||||
 | 
					        // To avoid returning dangling reference, we have to save the values
 | 
				
			||||||
 | 
					        T m_cache;
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        template <typename F2 = Func>
 | 
				
			||||||
 | 
					        MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
 | 
				
			||||||
 | 
					            m_generator(std::move(generator)),
 | 
				
			||||||
 | 
					            m_function(std::forward<F2>(function)),
 | 
				
			||||||
 | 
					            m_cache(m_function(m_generator.get()))
 | 
				
			||||||
 | 
					        {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        T const& get() const override {
 | 
				
			||||||
 | 
					            return m_cache;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        bool next() override {
 | 
				
			||||||
 | 
					            const auto success = m_generator.next();
 | 
				
			||||||
 | 
					            if (success) {
 | 
				
			||||||
 | 
					                m_cache = m_function(m_generator.get());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return success;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T, typename U, typename Func>
 | 
				
			||||||
 | 
					    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
 | 
				
			||||||
 | 
					        return GeneratorWrapper<T>(
 | 
				
			||||||
 | 
					            pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    template <typename T, typename Func>
 | 
				
			||||||
 | 
					    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<T>&& generator) {
 | 
				
			||||||
 | 
					        return GeneratorWrapper<T>(
 | 
				
			||||||
 | 
					            pf::make_unique<MapGenerator<T, T, Func>>(std::forward<Func>(function), std::move(generator))
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T>
 | 
				
			||||||
 | 
					    class ChunkGenerator final : public IGenerator<std::vector<T>> {
 | 
				
			||||||
 | 
					        std::vector<T> m_chunk;
 | 
				
			||||||
 | 
					        size_t m_chunk_size;
 | 
				
			||||||
 | 
					        GeneratorWrapper<T> m_generator;
 | 
				
			||||||
 | 
					        bool m_used_up = false;
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
 | 
				
			||||||
 | 
					            m_chunk_size(size), m_generator(std::move(generator))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            m_chunk.reserve(m_chunk_size);
 | 
				
			||||||
 | 
					            m_chunk.push_back(m_generator.get());
 | 
				
			||||||
 | 
					            for (size_t i = 1; i < m_chunk_size; ++i) {
 | 
				
			||||||
 | 
					                if (!m_generator.next()) {
 | 
				
			||||||
 | 
					                    Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                m_chunk.push_back(m_generator.get());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std::vector<T> const& get() const override {
 | 
				
			||||||
 | 
					            return m_chunk;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        bool next() override {
 | 
				
			||||||
 | 
					            m_chunk.clear();
 | 
				
			||||||
 | 
					            for (size_t idx = 0; idx < m_chunk_size; ++idx) {
 | 
				
			||||||
 | 
					                if (!m_generator.next()) {
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                m_chunk.push_back(m_generator.get());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T>
 | 
				
			||||||
 | 
					    GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
 | 
				
			||||||
 | 
					        return GeneratorWrapper<std::vector<T>>(
 | 
				
			||||||
 | 
					            pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Generators
 | 
				
			||||||
 | 
					} // namespace Catch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
 | 
				
			||||||
@@ -102,6 +102,7 @@ set(INTERNAL_HEADERS
 | 
				
			|||||||
        ${HEADER_DIR}/internal/catch_external_interfaces.h
 | 
					        ${HEADER_DIR}/internal/catch_external_interfaces.h
 | 
				
			||||||
        ${HEADER_DIR}/internal/catch_fatal_condition.h
 | 
					        ${HEADER_DIR}/internal/catch_fatal_condition.h
 | 
				
			||||||
        ${HEADER_DIR}/internal/catch_generators.hpp
 | 
					        ${HEADER_DIR}/internal/catch_generators.hpp
 | 
				
			||||||
 | 
					        ${HEADER_DIR}/internal/catch_generators_generic.hpp
 | 
				
			||||||
        ${HEADER_DIR}/internal/catch_generators_specific.hpp
 | 
					        ${HEADER_DIR}/internal/catch_generators_specific.hpp
 | 
				
			||||||
        ${HEADER_DIR}/internal/catch_impl.hpp
 | 
					        ${HEADER_DIR}/internal/catch_impl.hpp
 | 
				
			||||||
        ${HEADER_DIR}/internal/catch_interfaces_capture.h
 | 
					        ${HEADER_DIR}/internal/catch_interfaces_capture.h
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -417,6 +417,19 @@ Generators.tests.cpp:<line number>: passed: j > 0 for: 3 > 0
 | 
				
			|||||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 1 > 0
 | 
					Generators.tests.cpp:<line number>: passed: j > 0 for: 1 > 0
 | 
				
			||||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 2 > 0
 | 
					Generators.tests.cpp:<line number>: passed: j > 0 for: 2 > 0
 | 
				
			||||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 3 > 0
 | 
					Generators.tests.cpp:<line number>: passed: j > 0 for: 3 > 0
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 1 == 1
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 2 == 2
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 3 == 3
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 1 == 1
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.front() < 3 for: 1 < 3
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 2 == 2
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk2.front() < 3 for: 2 < 3
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: passed: chunk(2, value(1)), Catch::GeneratorException
 | 
				
			||||||
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 1
 | 
					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: -2 < 1
 | 
				
			||||||
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 1
 | 
					Generators.tests.cpp:<line number>: passed: j < i for: -1 < 1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1175,5 +1175,5 @@ due to unexpected exception with message:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
===============================================================================
 | 
					===============================================================================
 | 
				
			||||||
test cases:  245 |  185 passed |  56 failed |  4 failed as expected
 | 
					test cases:  245 |  185 passed |  56 failed |  4 failed as expected
 | 
				
			||||||
assertions: 1365 | 1229 passed | 115 failed | 21 failed as expected
 | 
					assertions: 1378 | 1242 passed | 115 failed | 21 failed as expected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3080,6 +3080,117 @@ Generators.tests.cpp:<line number>: PASSED:
 | 
				
			|||||||
with expansion:
 | 
					with expansion:
 | 
				
			||||||
  3 > 0
 | 
					  3 > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators -- adapters
 | 
				
			||||||
 | 
					  Chunking a generator into sized pieces
 | 
				
			||||||
 | 
					  Number of elements in source is divisible by chunk size
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>
 | 
				
			||||||
 | 
					...............................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.size() == 2 )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  2 == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.front() == chunk2.back() )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  1 == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators -- adapters
 | 
				
			||||||
 | 
					  Chunking a generator into sized pieces
 | 
				
			||||||
 | 
					  Number of elements in source is divisible by chunk size
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>
 | 
				
			||||||
 | 
					...............................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.size() == 2 )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  2 == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.front() == chunk2.back() )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  2 == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators -- adapters
 | 
				
			||||||
 | 
					  Chunking a generator into sized pieces
 | 
				
			||||||
 | 
					  Number of elements in source is divisible by chunk size
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>
 | 
				
			||||||
 | 
					...............................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.size() == 2 )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  2 == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.front() == chunk2.back() )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  3 == 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators -- adapters
 | 
				
			||||||
 | 
					  Chunking a generator into sized pieces
 | 
				
			||||||
 | 
					  Number of elements in source is not divisible by chunk size
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>
 | 
				
			||||||
 | 
					...............................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.size() == 2 )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  2 == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.front() == chunk2.back() )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  1 == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.front() < 3 )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  1 < 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators -- adapters
 | 
				
			||||||
 | 
					  Chunking a generator into sized pieces
 | 
				
			||||||
 | 
					  Number of elements in source is not divisible by chunk size
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>
 | 
				
			||||||
 | 
					...............................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.size() == 2 )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  2 == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.front() == chunk2.back() )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  2 == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE( chunk2.front() < 3 )
 | 
				
			||||||
 | 
					with expansion:
 | 
				
			||||||
 | 
					  2 < 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators -- adapters
 | 
				
			||||||
 | 
					  Chunking a generator into sized pieces
 | 
				
			||||||
 | 
					  Throws on too small generators
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>
 | 
				
			||||||
 | 
					...............................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generators.tests.cpp:<line number>: PASSED:
 | 
				
			||||||
 | 
					  REQUIRE_THROWS_AS( chunk(2, value(1)), Catch::GeneratorException )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-------------------------------------------------------------------------------
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
Generators -- simple
 | 
					Generators -- simple
 | 
				
			||||||
  one
 | 
					  one
 | 
				
			||||||
@@ -10574,5 +10685,5 @@ Misc.tests.cpp:<line number>: PASSED:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
===============================================================================
 | 
					===============================================================================
 | 
				
			||||||
test cases:  245 |  172 passed |  69 failed |  4 failed as expected
 | 
					test cases:  245 |  172 passed |  69 failed |  4 failed as expected
 | 
				
			||||||
assertions: 1379 | 1229 passed | 129 failed | 21 failed as expected
 | 
					assertions: 1392 | 1242 passed | 129 failed | 21 failed as expected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
    <property name="random-seed" value="1"/>
 | 
					    <property name="random-seed" value="1"/>
 | 
				
			||||||
  </properties>
 | 
					  </properties>
 | 
				
			||||||
loose text artifact
 | 
					loose text artifact
 | 
				
			||||||
  <testsuite name="<exe-name>" errors="17" failures="113" tests="1380" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
 | 
					  <testsuite name="<exe-name>" errors="17" failures="113" tests="1393" 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="# 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="#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}"/>
 | 
					    <testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
 | 
				
			||||||
@@ -347,6 +347,9 @@ Message.tests.cpp:<line number>
 | 
				
			|||||||
    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Same type" time="{duration}"/>
 | 
					    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Same type" time="{duration}"/>
 | 
				
			||||||
    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different type" time="{duration}"/>
 | 
					    <testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different type" time="{duration}"/>
 | 
				
			||||||
    <testcase classname="<exe-name>.global" name="Generators -- adapters/Repeating a generator" time="{duration}"/>
 | 
					    <testcase classname="<exe-name>.global" name="Generators -- adapters/Repeating a generator" time="{duration}"/>
 | 
				
			||||||
 | 
					    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is divisible by chunk size" time="{duration}"/>
 | 
				
			||||||
 | 
					    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is not divisible by chunk size" time="{duration}"/>
 | 
				
			||||||
 | 
					    <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Throws on too small generators" time="{duration}"/>
 | 
				
			||||||
    <testcase classname="<exe-name>.global" name="Generators -- simple/one" 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 -- simple/two" time="{duration}"/>
 | 
				
			||||||
    <testcase classname="<exe-name>.global" name="Generators internals/Single value" time="{duration}"/>
 | 
					    <testcase classname="<exe-name>.global" name="Generators internals/Single value" time="{duration}"/>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3538,7 +3538,7 @@
 | 
				
			|||||||
      </Section>
 | 
					      </Section>
 | 
				
			||||||
      <OverallResult success="true"/>
 | 
					      <OverallResult success="true"/>
 | 
				
			||||||
    </TestCase>
 | 
					    </TestCase>
 | 
				
			||||||
    <TestCase name="Generators -- adapters" tags="[generators]" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
					    <TestCase name="Generators -- adapters" tags="[generators][generic]" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
      <Section name="Filtering by predicate" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
					      <Section name="Filtering by predicate" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
					        <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
          <Original>
 | 
					          <Original>
 | 
				
			||||||
@@ -3755,6 +3755,146 @@
 | 
				
			|||||||
        </Expression>
 | 
					        </Expression>
 | 
				
			||||||
        <OverallResults successes="1" failures="0" expectedFailures="0"/>
 | 
					        <OverallResults successes="1" failures="0" expectedFailures="0"/>
 | 
				
			||||||
      </Section>
 | 
					      </Section>
 | 
				
			||||||
 | 
					      <Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					        <Section name="Number of elements in source is divisible by chunk size" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.size() == 2
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              2 == 2
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.front() == chunk2.back()
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              1 == 1
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <OverallResults successes="2" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					        </Section>
 | 
				
			||||||
 | 
					        <OverallResults successes="2" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					      </Section>
 | 
				
			||||||
 | 
					      <Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					        <Section name="Number of elements in source is divisible by chunk size" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.size() == 2
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              2 == 2
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.front() == chunk2.back()
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              2 == 2
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <OverallResults successes="2" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					        </Section>
 | 
				
			||||||
 | 
					        <OverallResults successes="2" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					      </Section>
 | 
				
			||||||
 | 
					      <Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					        <Section name="Number of elements in source is divisible by chunk size" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.size() == 2
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              2 == 2
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.front() == chunk2.back()
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              3 == 3
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <OverallResults successes="2" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					        </Section>
 | 
				
			||||||
 | 
					        <OverallResults successes="2" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					      </Section>
 | 
				
			||||||
 | 
					      <Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					        <Section name="Number of elements in source is not divisible by chunk size" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.size() == 2
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              2 == 2
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.front() == chunk2.back()
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              1 == 1
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.front() < 3
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              1 < 3
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <OverallResults successes="3" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					        </Section>
 | 
				
			||||||
 | 
					        <OverallResults successes="3" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					      </Section>
 | 
				
			||||||
 | 
					      <Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					        <Section name="Number of elements in source is not divisible by chunk size" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.size() == 2
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              2 == 2
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.front() == chunk2.back()
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              2 == 2
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk2.front() < 3
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              2 < 3
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <OverallResults successes="3" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					        </Section>
 | 
				
			||||||
 | 
					        <OverallResults successes="3" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					      </Section>
 | 
				
			||||||
 | 
					      <Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					        <Section name="Throws on too small generators" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					          <Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
 | 
					            <Original>
 | 
				
			||||||
 | 
					              chunk(2, value(1)), Catch::GeneratorException
 | 
				
			||||||
 | 
					            </Original>
 | 
				
			||||||
 | 
					            <Expanded>
 | 
				
			||||||
 | 
					              chunk(2, value(1)), Catch::GeneratorException
 | 
				
			||||||
 | 
					            </Expanded>
 | 
				
			||||||
 | 
					          </Expression>
 | 
				
			||||||
 | 
					          <OverallResults successes="1" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					        </Section>
 | 
				
			||||||
 | 
					        <OverallResults successes="1" failures="0" expectedFailures="0"/>
 | 
				
			||||||
 | 
					      </Section>
 | 
				
			||||||
      <OverallResult success="true"/>
 | 
					      <OverallResult success="true"/>
 | 
				
			||||||
    </TestCase>
 | 
					    </TestCase>
 | 
				
			||||||
    <TestCase name="Generators -- simple" tags="[generators]" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
					    <TestCase name="Generators -- simple" tags="[generators]" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
 | 
				
			||||||
@@ -12785,7 +12925,7 @@ loose text artifact
 | 
				
			|||||||
      </Section>
 | 
					      </Section>
 | 
				
			||||||
      <OverallResult success="true"/>
 | 
					      <OverallResult success="true"/>
 | 
				
			||||||
    </TestCase>
 | 
					    </TestCase>
 | 
				
			||||||
    <OverallResults successes="1229" failures="130" expectedFailures="21"/>
 | 
					    <OverallResults successes="1242" failures="130" expectedFailures="21"/>
 | 
				
			||||||
  </Group>
 | 
					  </Group>
 | 
				
			||||||
  <OverallResults successes="1229" failures="129" expectedFailures="21"/>
 | 
					  <OverallResults successes="1242" failures="129" expectedFailures="21"/>
 | 
				
			||||||
</Catch>
 | 
					</Catch>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,7 +114,7 @@ SCENARIO("Eating cucumbers", "[generators][approvals]") {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// There are also some generic generator manipulators
 | 
					// There are also some generic generator manipulators
 | 
				
			||||||
TEST_CASE("Generators -- adapters", "[generators]") {
 | 
					TEST_CASE("Generators -- adapters", "[generators][generic]") {
 | 
				
			||||||
    // TODO: This won't work yet, introduce GENERATE_VAR?
 | 
					    // TODO: This won't work yet, introduce GENERATE_VAR?
 | 
				
			||||||
    //auto numbers = Catch::Generators::values({ 1, 2, 3, 4, 5, 6 });
 | 
					    //auto numbers = Catch::Generators::values({ 1, 2, 3, 4, 5, 6 });
 | 
				
			||||||
    SECTION("Filtering by predicate") {
 | 
					    SECTION("Filtering by predicate") {
 | 
				
			||||||
@@ -144,6 +144,23 @@ TEST_CASE("Generators -- adapters", "[generators]") {
 | 
				
			|||||||
        auto j = GENERATE(repeat(2, values({ 1, 2, 3 })));
 | 
					        auto j = GENERATE(repeat(2, values({ 1, 2, 3 })));
 | 
				
			||||||
        REQUIRE(j > 0);
 | 
					        REQUIRE(j > 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    SECTION("Chunking a generator into sized pieces") {
 | 
				
			||||||
 | 
					        SECTION("Number of elements in source is divisible by chunk size") {
 | 
				
			||||||
 | 
					            auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3, 3 })));
 | 
				
			||||||
 | 
					            REQUIRE(chunk2.size() == 2);
 | 
				
			||||||
 | 
					            REQUIRE(chunk2.front() == chunk2.back());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        SECTION("Number of elements in source is not divisible by chunk size") {
 | 
				
			||||||
 | 
					            auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3 })));
 | 
				
			||||||
 | 
					            REQUIRE(chunk2.size() == 2);
 | 
				
			||||||
 | 
					            REQUIRE(chunk2.front() == chunk2.back());
 | 
				
			||||||
 | 
					            REQUIRE(chunk2.front() < 3);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        SECTION("Throws on too small generators") {
 | 
				
			||||||
 | 
					            using namespace Catch::Generators;
 | 
				
			||||||
 | 
					            REQUIRE_THROWS_AS(chunk(2, value(1)), Catch::GeneratorException);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Note that because of the non-reproducibility of distributions,
 | 
					// Note that because of the non-reproducibility of distributions,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user