mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-04 05:59:32 +01:00 
			
		
		
		
	Introduce random number (Integral and Float) generators
This commit is contained in:
		@@ -43,6 +43,9 @@ a test case,
 | 
				
			|||||||
  * `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
 | 
				
			||||||
 | 
					* 2 specific purpose generators
 | 
				
			||||||
 | 
					  * `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
 | 
				
			||||||
 | 
					  * `RandomFloatGenerator<Float>` -- generates random Floats from range
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The generators also have associated helper functions that infer their
 | 
					The generators also have associated helper functions that infer their
 | 
				
			||||||
type, making their usage much nicer. These are
 | 
					type, making their usage much nicer. These are
 | 
				
			||||||
@@ -54,6 +57,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`)
 | 
				
			||||||
 | 
					* `range(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
And can be used as shown in the example below to create a generator
 | 
					And can be used as shown in the example below to create a generator
 | 
				
			||||||
that returns 100 odd random number:
 | 
					that returns 100 odd random number:
 | 
				
			||||||
@@ -69,8 +73,6 @@ TEST_CASE("Generating random ints", "[example][generator]") {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_Note that `random` is currently not a part of the first-party generators_.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Apart from registering generators with Catch2, the `GENERATE` macro has
 | 
					Apart from registering generators with Catch2, the `GENERATE` macro has
 | 
				
			||||||
one more purpose, and that is to provide simple way of generating trivial
 | 
					one more purpose, and that is to provide simple way of generating trivial
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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_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
 | 
				
			||||||
// in the conditionally compiled sections
 | 
					// in the conditionally compiled sections
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										88
									
								
								include/internal/catch_generators_specific.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								include/internal/catch_generators_specific.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Created by Martin on 15/6/2018.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Distributed under the Boost Software License, Version 1.0. (See accompanying
 | 
				
			||||||
 | 
					 *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
 | 
				
			||||||
 | 
					#define TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "catch_context.h"
 | 
				
			||||||
 | 
					#include "catch_generators.hpp"
 | 
				
			||||||
 | 
					#include "catch_interfaces_config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <random>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Catch {
 | 
				
			||||||
 | 
					namespace Generators {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Float>
 | 
				
			||||||
 | 
					class RandomFloatingGenerator final : public IGenerator<Float> {
 | 
				
			||||||
 | 
					    // FIXME: What is the right seed?
 | 
				
			||||||
 | 
					    std::minstd_rand m_rand;
 | 
				
			||||||
 | 
					    std::uniform_real_distribution<Float> m_dist;
 | 
				
			||||||
 | 
					    Float m_current_number;
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RandomFloatingGenerator(Float a, Float b):
 | 
				
			||||||
 | 
					        m_rand(getCurrentContext().getConfig()->rngSeed()),
 | 
				
			||||||
 | 
					        m_dist(a, b) {
 | 
				
			||||||
 | 
					        static_cast<void>(next());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Float const& get() const override {
 | 
				
			||||||
 | 
					        return m_current_number;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    bool next() override {
 | 
				
			||||||
 | 
					        m_current_number = m_dist(m_rand);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Integer>
 | 
				
			||||||
 | 
					class RandomIntegerGenerator final : public IGenerator<Integer> {
 | 
				
			||||||
 | 
					    std::minstd_rand m_rand;
 | 
				
			||||||
 | 
					    std::uniform_int_distribution<Integer> m_dist;
 | 
				
			||||||
 | 
					    Integer m_current_number;
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RandomIntegerGenerator(Integer a, Integer b):
 | 
				
			||||||
 | 
					        m_rand(getCurrentContext().getConfig()->rngSeed()),
 | 
				
			||||||
 | 
					        m_dist(a, b) {
 | 
				
			||||||
 | 
					        static_cast<void>(next());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Integer const& get() const override {
 | 
				
			||||||
 | 
					        return m_current_number;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    bool next() override {
 | 
				
			||||||
 | 
					        m_current_number = m_dist(m_rand);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Ideally this would be also constrained against the various char types,
 | 
				
			||||||
 | 
					//       but I don't expect users to run into that in practice.
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
 | 
				
			||||||
 | 
					GeneratorWrapper<T>>::type
 | 
				
			||||||
 | 
					random(T a, T b) {
 | 
				
			||||||
 | 
					    return GeneratorWrapper<T>(
 | 
				
			||||||
 | 
					        pf::make_unique<RandomIntegerGenerator<T>>(a, b)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					typename std::enable_if<std::is_floating_point<T>::value,
 | 
				
			||||||
 | 
					GeneratorWrapper<T>>::type
 | 
				
			||||||
 | 
					random(T a, T b) {
 | 
				
			||||||
 | 
					    return GeneratorWrapper<T>(
 | 
				
			||||||
 | 
					        pf::make_unique<RandomFloatingGenerator<T>>(a, b)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Generators
 | 
				
			||||||
 | 
					} // namespace Catch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_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_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
 | 
				
			||||||
        ${HEADER_DIR}/internal/catch_interfaces_config.h
 | 
					        ${HEADER_DIR}/internal/catch_interfaces_config.h
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -145,3 +145,16 @@ TEST_CASE("Generators -- adapters", "[generators]") {
 | 
				
			|||||||
        REQUIRE(j > 0);
 | 
					        REQUIRE(j > 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Note that because of the non-reproducibility of distributions,
 | 
				
			||||||
 | 
					// anything involving the random generators cannot be part of approvals
 | 
				
			||||||
 | 
					TEST_CASE("Random generator", "[generators][.][approvals]") {
 | 
				
			||||||
 | 
					    SECTION("Infer int from integral arguments") {
 | 
				
			||||||
 | 
					        auto val = GENERATE(take(4, random(0, 1)));
 | 
				
			||||||
 | 
					        STATIC_REQUIRE(std::is_same<decltype(val), int>::value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    SECTION("Infer double from double arguments") {
 | 
				
			||||||
 | 
					        auto val = GENERATE(take(4, random(0., 1.)));
 | 
				
			||||||
 | 
					        STATIC_REQUIRE(std::is_same<decltype(val), double>::value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user