Have the random generators use the global rng instance

This means that if you nest multiple random generators inside one
test case, they will not return the same sequence of numbers.

Idea taken from #1736 by Amit Herman.

Closes #1736
Closes #1734
This commit is contained in:
Martin Hořeňovský 2019-10-07 20:24:37 +02:00
parent 535da5c513
commit a5a22cdadb
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
2 changed files with 33 additions and 8 deletions

View File

@ -10,6 +10,7 @@
#include "catch_context.h" #include "catch_context.h"
#include "catch_generators.hpp" #include "catch_generators.hpp"
#include "catch_interfaces_config.h" #include "catch_interfaces_config.h"
#include "catch_random_number_generator.h"
#include <random> #include <random>
@ -18,14 +19,13 @@ namespace Generators {
template <typename Float> template <typename Float>
class RandomFloatingGenerator final : public IGenerator<Float> { class RandomFloatingGenerator final : public IGenerator<Float> {
// FIXME: What is the right seed? Catch::SimplePcg32& m_rng;
std::minstd_rand m_rand;
std::uniform_real_distribution<Float> m_dist; std::uniform_real_distribution<Float> m_dist;
Float m_current_number; Float m_current_number;
public: public:
RandomFloatingGenerator(Float a, Float b): RandomFloatingGenerator(Float a, Float b):
m_rand(getCurrentContext().getConfig()->rngSeed()), m_rng(rng()),
m_dist(a, b) { m_dist(a, b) {
static_cast<void>(next()); static_cast<void>(next());
} }
@ -34,20 +34,20 @@ public:
return m_current_number; return m_current_number;
} }
bool next() override { bool next() override {
m_current_number = m_dist(m_rand); m_current_number = m_dist(m_rng);
return true; return true;
} }
}; };
template <typename Integer> template <typename Integer>
class RandomIntegerGenerator final : public IGenerator<Integer> { class RandomIntegerGenerator final : public IGenerator<Integer> {
std::minstd_rand m_rand; Catch::SimplePcg32& m_rng;
std::uniform_int_distribution<Integer> m_dist; std::uniform_int_distribution<Integer> m_dist;
Integer m_current_number; Integer m_current_number;
public: public:
RandomIntegerGenerator(Integer a, Integer b): RandomIntegerGenerator(Integer a, Integer b):
m_rand(getCurrentContext().getConfig()->rngSeed()), m_rng(rng()),
m_dist(a, b) { m_dist(a, b) {
static_cast<void>(next()); static_cast<void>(next());
} }
@ -56,7 +56,7 @@ public:
return m_current_number; return m_current_number;
} }
bool next() override { bool next() override {
m_current_number = m_dist(m_rand); m_current_number = m_dist(m_rng);
return true; return true;
} }
}; };

View File

@ -250,7 +250,7 @@ int const& TestGen::get() const {
} }
TEST_CASE("GENERATE capture macros", "[generators][internals][.approvals]") { TEST_CASE("GENERATE capture macros", "[generators][internals][approvals]") {
auto value = GENERATE(take(10, random(0, 10))); auto value = GENERATE(take(10, random(0, 10)));
non_copyable nc; nc.value = value; non_copyable nc; nc.value = value;
@ -258,3 +258,28 @@ TEST_CASE("GENERATE capture macros", "[generators][internals][.approvals]") {
auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new TestGen(nc)))); auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new TestGen(nc))));
REQUIRE(value == value2); REQUIRE(value == value2);
} }
TEST_CASE("Multiple random generators in one test case output different values", "[generators][internals][approvals]") {
SECTION("Integer") {
auto random1 = Catch::Generators::random(0, 1000);
auto random2 = Catch::Generators::random(0, 1000);
size_t same = 0;
for (size_t i = 0; i < 1000; ++i) {
same += random1.get() == random2.get();
random1.next(); random2.next();
}
// 0.5% seems like a sane bound for random identical elements within 1000 runs
REQUIRE(same < 5);
}
SECTION("Float") {
auto random1 = Catch::Generators::random(0., 1000.);
auto random2 = Catch::Generators::random(0., 1000.);
size_t same = 0;
for (size_t i = 0; i < 1000; ++i) {
same += random1.get() == random2.get();
random1.next(); random2.next();
}
// 0.5% seems like a sane bound for random identical elements within 1000 runs
REQUIRE(same < 5);
}
}