# Data Generators Data generators (also known as _data driven/parametrized test cases_) let you reuse the same set of assertions across different input values. In Catch2, this means that they respect the ordering and nesting of the `TEST_CASE` and `SECTION` macros, and their nested sections are run once per each value in a generator. This is best explained with an example: ```cpp TEST_CASE("Generators") { auto i = GENERATE(1, 2, 3); SECTION("one") { auto j = GENERATE( -3, -2, -1 ); REQUIRE(j < i); } } ``` The assertion in this test case will be run 9 times, because there are 3 possible values for `i` (1, 2, and 3) and there are 3 possible values for `j` (-3, -2, and -1). There are 2 parts to generators in Catch2, the `GENERATE` macro together with the already provided generators, and the `IGenerator` interface that allows users to implement their own generators. ## Provided generators Catch2's provided generator functionality consists of three parts, * `GENERATE` macro, that serves to integrate generator expression with a test case, * 2 fundamental generators * `ValueGenerator` -- contains only single element * `ValuesGenerator` -- contains multiple elements * 5 generic generators that modify other generators * `FilterGenerator` -- filters out elements from a generator for which the predicate returns "false" * `TakeGenerator` -- takes first `n` elements from a generator * `RepeatGenerator` -- repeats output from a generator `n` times * `MapGenerator` -- returns the result of applying `Func` on elements from a different generator * `ChunkGenerator` -- returns chunks (inside `std::vector`) of n elements from a generator * 3 specific purpose generators * `RandomIntegerGenerator` -- generates random Integrals from range * `RandomFloatGenerator` -- generates random Floats from range * `RangeGenerator` -- generates all values inside a specific range The generators also have associated helper functions that infer their type, making their usage much nicer. These are * `value(T&&)` for `ValueGenerator` * `values(std::initializer_list)` for `ValuesGenerator` * `filter(predicate, GeneratorWrapper&&)` for `FilterGenerator` * `take(count, GeneratorWrapper&&)` for `TakeGenerator` * `repeat(repeats, GeneratorWrapper&&)` for `RepeatGenerator` * `map(func, GeneratorWrapper&&)` for `MapGenerator` (map `U` to `T`, deduced from `Func`) * `map(func, GeneratorWrapper&&)` for `MapGenerator` (map `U` to `T`) * `chunk(chunk-size, GeneratorWrapper&&)` for `ChunkGenerator` * `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator` * `range(start, end)` for `RangeGenerator` with a step size of `1` * `range(start, end, step)` for `RangeGenerator` with a custom step size And can be used as shown in the example below to create a generator that returns 100 odd random number: ```cpp TEST_CASE("Generating random ints", "[example][generator]") { SECTION("Deducing functions") { auto i = GENERATE(take(100, filter([](int i) { return i % 2 == 1; }, random(-100, 100)))); REQUIRE(i > -100); REQUIRE(i < 100); REQUIRE(i % 2 == 1); } } ``` Apart from registering generators with Catch2, the `GENERATE` macro has one more purpose, and that is to provide simple way of generating trivial generators, as seen in the first example on this page, where we used it as `auto i = GENERATE(1, 2, 3);`. This usage converted each of the three literals into a single `ValueGenerator` and then placed them all in a special generator that concatenates other generators. It can also be used with other generators as arguments, such as `auto i = GENERATE(0, 2, take(100, random(300, 3000)));`. This is useful e.g. if you know that specific inputs are problematic and want to test them separately/first. **For safety reasons, you cannot use variables inside the `GENERATE` macro.** You can also override the inferred type by using `as` as the first argument to the macro. This can be useful when dealing with string literals, if you want them to come out as `std::string`: ```cpp TEST_CASE("type conversion", "[generators]") { auto str = GENERATE(as{}, "a", "bb", "ccc"); REQUIRE(str.size() > 0); } ``` ## Generator interface You can also implement your own generators, by deriving from the `IGenerator` interface: ```cpp template struct IGenerator : GeneratorUntypedBase { // via GeneratorUntypedBase: // Attempts to move the generator to the next element. // Returns true if successful (and thus has another element that can be read) virtual bool next() = 0; // Precondition: // The generator is either freshly constructed or the last call to next() returned true virtual T const& get() const = 0; }; ``` However, to be able to use your custom generator inside `GENERATE`, it will need to be wrapped inside a `GeneratorWrapper`. `GeneratorWrapper` is a value wrapper around a `std::unique_ptr>`. For full example of implementing your own generator, look into Catch2's examples, specifically [Generators: Create your own generator](../examples/300-Gen-OwnGenerator.cpp).