Home | History | Annotate | Download | only in docs
      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