aboutsummaryrefslogtreecommitdiffstats
path: root/examples/300-Gen-OwnGenerator.cpp
blob: 9cb02e396a718b51c651155486016987bd968e7d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//              Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
//   (See accompanying file LICENSE.txt or copy at
//        https://www.boost.org/LICENSE_1_0.txt)

// SPDX-License-Identifier: BSL-1.0

// 300-Gen-OwnGenerator.cpp
// Shows how to define a custom generator.

// Specifically we will implement a random number generator for integers
// It will have infinite capacity and settable lower/upper bound

#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include <catch2/generators/catch_generators_adapters.hpp>

#include <random>

namespace {

// This class shows how to implement a simple generator for Catch tests
class RandomIntGenerator final : public Catch::Generators::IGenerator<int> {
    std::minstd_rand m_rand;
    std::uniform_int_distribution<> m_dist;
    int current_number;
public:

    RandomIntGenerator(int low, int high):
        m_rand(std::random_device{}()),
        m_dist(low, high)
    {
        static_cast<void>(next());
    }

    int const& get() const override;
    bool next() override {
        current_number = m_dist(m_rand);
        return true;
    }
};

// Avoids -Wweak-vtables
int const& RandomIntGenerator::get() const {
    return current_number;
}

// This helper function provides a nicer UX when instantiating the generator
// Notice that it returns an instance of GeneratorWrapper<int>, which
// is a value-wrapper around std::unique_ptr<IGenerator<int>>.
Catch::Generators::GeneratorWrapper<int> random(int low, int high) {
    return Catch::Generators::GeneratorWrapper<int>(
        new RandomIntGenerator(low, high)
        // Another possibility:
        // Catch::Detail::make_unique<RandomIntGenerator>(low, high)
    );
}

} // end anonymous namespaces

// The two sections in this test case are equivalent, but the first one
// is much more readable/nicer to use
TEST_CASE("Generating random ints", "[example][generator]") {
    SECTION("Nice UX") {
        auto i = GENERATE(take(100, random(-100, 100)));
        REQUIRE(i >= -100);
        REQUIRE(i <= 100);
    }
    SECTION("Creating the random generator directly") {
        auto i = GENERATE(take(100, GeneratorWrapper<int>(Catch::Detail::make_unique<RandomIntGenerator>(-100, 100))));
        REQUIRE(i >= -100);
        REQUIRE(i <= 100);
    }
}

// Compiling and running this file will result in 400 successful assertions