/ externals / catch / examples / 300-Gen-OwnGenerator.cpp
300-Gen-OwnGenerator.cpp
 1  
 2  //              Copyright Catch2 Authors
 3  // Distributed under the Boost Software License, Version 1.0.
 4  //   (See accompanying file LICENSE.txt or copy at
 5  //        https://www.boost.org/LICENSE_1_0.txt)
 6  
 7  // SPDX-License-Identifier: BSL-1.0
 8  
 9  // 300-Gen-OwnGenerator.cpp
10  // Shows how to define a custom generator.
11  
12  // Specifically we will implement a random number generator for integers
13  // It will have infinite capacity and settable lower/upper bound
14  
15  #include <catch2/catch_test_macros.hpp>
16  #include <catch2/generators/catch_generators.hpp>
17  #include <catch2/generators/catch_generators_adapters.hpp>
18  
19  #include <random>
20  
21  namespace {
22  
23  // This class shows how to implement a simple generator for Catch tests
24  class RandomIntGenerator : public Catch::Generators::IGenerator<int> {
25      std::minstd_rand m_rand;
26      std::uniform_int_distribution<> m_dist;
27      int current_number;
28  public:
29  
30      RandomIntGenerator(int low, int high):
31          m_rand(std::random_device{}()),
32          m_dist(low, high)
33      {
34          static_cast<void>(next());
35      }
36  
37      int const& get() const override;
38      bool next() override {
39          current_number = m_dist(m_rand);
40          return true;
41      }
42  };
43  
44  // Avoids -Wweak-vtables
45  int const& RandomIntGenerator::get() const {
46      return current_number;
47  }
48  
49  // This helper function provides a nicer UX when instantiating the generator
50  // Notice that it returns an instance of GeneratorWrapper<int>, which
51  // is a value-wrapper around std::unique_ptr<IGenerator<int>>.
52  Catch::Generators::GeneratorWrapper<int> random(int low, int high) {
53      return Catch::Generators::GeneratorWrapper<int>(
54          new RandomIntGenerator(low, high)
55          // Another possibility:
56          // Catch::Detail::make_unique<RandomIntGenerator>(low, high)
57      );
58  }
59  
60  } // end anonymous namespaces
61  
62  // The two sections in this test case are equivalent, but the first one
63  // is much more readable/nicer to use
64  TEST_CASE("Generating random ints", "[example][generator]") {
65      SECTION("Nice UX") {
66          auto i = GENERATE(take(100, random(-100, 100)));
67          REQUIRE(i >= -100);
68          REQUIRE(i <= 100);
69      }
70      SECTION("Creating the random generator directly") {
71          auto i = GENERATE(take(100, GeneratorWrapper<int>(Catch::Detail::make_unique<RandomIntGenerator>(-100, 100))));
72          REQUIRE(i >= -100);
73          REQUIRE(i <= 100);
74      }
75  }
76  
77  // Compiling and running this file will result in 400 successful assertions