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