1<a id="top"></a> 2# Data Generators 3 4> Introduced in Catch 2.6.0. 5 6Data generators (also known as _data driven/parametrized test cases_) 7let you reuse the same set of assertions across different input values. 8In Catch2, this means that they respect the ordering and nesting 9of the `TEST_CASE` and `SECTION` macros, and their nested sections 10are run once per each value in a generator. 11 12This is best explained with an example: 13```cpp 14TEST_CASE("Generators") { 15 auto i = GENERATE(1, 2, 3); 16 SECTION("one") { 17 auto j = GENERATE( -3, -2, -1 ); 18 REQUIRE(j < i); 19 } 20} 21``` 22 23The assertion in this test case will be run 9 times, because there 24are 3 possible values for `i` (1, 2, and 3) and there are 3 possible 25values for `j` (-3, -2, and -1). 26 27 28There are 2 parts to generators in Catch2, the `GENERATE` macro together 29with the already provided generators, and the `IGenerator<T>` interface 30that allows users to implement their own generators. 31 32## Provided generators 33 34Catch2's provided generator functionality consists of three parts, 35 36* `GENERATE` macro, that serves to integrate generator expression with 37a test case, 38* 2 fundamental generators 39 * `SingleValueGenerator<T>` -- contains only single element 40 * `FixedValuesGenerator<T>` -- contains multiple elements 41* 5 generic generators that modify other generators 42 * `FilterGenerator<T, Predicate>` -- filters out elements from a generator 43 for which the predicate returns "false" 44 * `TakeGenerator<T>` -- takes first `n` elements from a generator 45 * `RepeatGenerator<T>` -- repeats output from a generator `n` times 46 * `MapGenerator<T, U, Func>` -- returns the result of applying `Func` 47 on elements from a different generator 48 * `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator 49* 4 specific purpose generators 50 * `RandomIntegerGenerator<Integral>` -- generates random Integrals from range 51 * `RandomFloatGenerator<Float>` -- generates random Floats from range 52 * `RangeGenerator<T>` -- generates all values inside an arithmetic range 53 * `IteratorGenerator<T>` -- copies and returns values from an iterator range 54 55> `ChunkGenerator<T>`, `RandomIntegerGenerator<Integral>`, `RandomFloatGenerator<Float>` and `RangeGenerator<T>` were introduced in Catch 2.7.0. 56 57> `IteratorGenerator<T>` was introduced in Catch 2.10.0. 58 59The generators also have associated helper functions that infer their 60type, making their usage much nicer. These are 61 62* `value(T&&)` for `SingleValueGenerator<T>` 63* `values(std::initializer_list<T>)` for `FixedValuesGenerator<T>` 64* `table<Ts...>(std::initializer_list<std::tuple<Ts...>>)` for `FixedValuesGenerator<std::tuple<Ts...>>` 65* `filter(predicate, GeneratorWrapper<T>&&)` for `FilterGenerator<T, Predicate>` 66* `take(count, GeneratorWrapper<T>&&)` for `TakeGenerator<T>` 67* `repeat(repeats, GeneratorWrapper<T>&&)` for `RepeatGenerator<T>` 68* `map(func, GeneratorWrapper<T>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`, deduced from `Func`) 69* `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`) 70* `chunk(chunk-size, GeneratorWrapper<T>&&)` for `ChunkGenerator<T>` 71* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator` 72* `range(Arithemtic start, Arithmetic end)` for `RangeGenerator<Arithmetic>` with a step size of `1` 73* `range(Arithmetic start, Arithmetic end, Arithmetic step)` for `RangeGenerator<Arithmetic>` with a custom step size 74* `from_range(InputIterator from, InputIterator to)` for `IteratorGenerator<T>` 75* `from_range(Container const&)` for `IteratorGenerator<T>` 76 77> `chunk()`, `random()` and both `range()` functions were introduced in Catch 2.7.0. 78 79> `from_range` has been introduced in Catch 2.10.0 80 81> `range()` for floating point numbers has been introduced in Catch 2.11.0 82 83And can be used as shown in the example below to create a generator 84that returns 100 odd random number: 85 86```cpp 87TEST_CASE("Generating random ints", "[example][generator]") { 88 SECTION("Deducing functions") { 89 auto i = GENERATE(take(100, filter([](int i) { return i % 2 == 1; }, random(-100, 100)))); 90 REQUIRE(i > -100); 91 REQUIRE(i < 100); 92 REQUIRE(i % 2 == 1); 93 } 94} 95``` 96 97 98Apart from registering generators with Catch2, the `GENERATE` macro has 99one more purpose, and that is to provide simple way of generating trivial 100generators, as seen in the first example on this page, where we used it 101as `auto i = GENERATE(1, 2, 3);`. This usage converted each of the three 102literals into a single `SingleValueGenerator<int>` and then placed them all in 103a special generator that concatenates other generators. It can also be 104used with other generators as arguments, such as `auto i = GENERATE(0, 2, 105take(100, random(300, 3000)));`. This is useful e.g. if you know that 106specific inputs are problematic and want to test them separately/first. 107 108**For safety reasons, you cannot use variables inside the `GENERATE` macro. 109This is done because the generator expression _will_ outlive the outside 110scope and thus capturing references is dangerous. If you need to use 111variables inside the generator expression, make sure you thought through 112the lifetime implications and use `GENERATE_COPY` or `GENERATE_REF`.** 113 114> `GENERATE_COPY` and `GENERATE_REF` were introduced in Catch 2.7.1. 115 116You can also override the inferred type by using `as<type>` as the first 117argument to the macro. This can be useful when dealing with string literals, 118if you want them to come out as `std::string`: 119 120```cpp 121TEST_CASE("type conversion", "[generators]") { 122 auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc"); 123 REQUIRE(str.size() > 0); 124} 125``` 126 127## Generator interface 128 129You can also implement your own generators, by deriving from the 130`IGenerator<T>` interface: 131 132```cpp 133template<typename T> 134struct IGenerator : GeneratorUntypedBase { 135 // via GeneratorUntypedBase: 136 // Attempts to move the generator to the next element. 137 // Returns true if successful (and thus has another element that can be read) 138 virtual bool next() = 0; 139 140 // Precondition: 141 // The generator is either freshly constructed or the last call to next() returned true 142 virtual T const& get() const = 0; 143}; 144``` 145 146However, to be able to use your custom generator inside `GENERATE`, it 147will need to be wrapped inside a `GeneratorWrapper<T>`. 148`GeneratorWrapper<T>` is a value wrapper around a 149`std::unique_ptr<IGenerator<T>>`. 150 151For full example of implementing your own generator, look into Catch2's 152examples, specifically 153[Generators: Create your own generator](../examples/300-Gen-OwnGenerator.cpp). 154 155