From a5a22cdadb0e0573de7dc2547165736349439298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Mon, 7 Oct 2019 20:24:37 +0200 Subject: [PATCH] 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 --- .../internal/catch_generators_specific.hpp | 14 +++++----- .../GeneratorsImpl.tests.cpp | 27 ++++++++++++++++++- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/include/internal/catch_generators_specific.hpp b/include/internal/catch_generators_specific.hpp index 7985ac70..0734ee78 100644 --- a/include/internal/catch_generators_specific.hpp +++ b/include/internal/catch_generators_specific.hpp @@ -10,6 +10,7 @@ #include "catch_context.h" #include "catch_generators.hpp" #include "catch_interfaces_config.h" +#include "catch_random_number_generator.h" #include @@ -18,14 +19,13 @@ namespace Generators { template class RandomFloatingGenerator final : public IGenerator { - // FIXME: What is the right seed? - std::minstd_rand m_rand; + Catch::SimplePcg32& m_rng; std::uniform_real_distribution m_dist; Float m_current_number; public: RandomFloatingGenerator(Float a, Float b): - m_rand(getCurrentContext().getConfig()->rngSeed()), + m_rng(rng()), m_dist(a, b) { static_cast(next()); } @@ -34,20 +34,20 @@ public: return m_current_number; } bool next() override { - m_current_number = m_dist(m_rand); + m_current_number = m_dist(m_rng); return true; } }; template class RandomIntegerGenerator final : public IGenerator { - std::minstd_rand m_rand; + Catch::SimplePcg32& m_rng; std::uniform_int_distribution m_dist; Integer m_current_number; public: RandomIntegerGenerator(Integer a, Integer b): - m_rand(getCurrentContext().getConfig()->rngSeed()), + m_rng(rng()), m_dist(a, b) { static_cast(next()); } @@ -56,7 +56,7 @@ public: return m_current_number; } bool next() override { - m_current_number = m_dist(m_rand); + m_current_number = m_dist(m_rng); return true; } }; diff --git a/projects/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp b/projects/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp index dbc1d957..076c91a9 100644 --- a/projects/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp +++ b/projects/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp @@ -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))); 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(std::unique_ptr>(new TestGen(nc)))); 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); + } +}