Make Random*Generators be seedable

This is a necessary step to fix issue with combining multiple
random generators in one test case, with different section nesting.
This commit is contained in:
Martin Hořeňovský 2022-05-17 17:57:15 +02:00
parent 359cd6187d
commit 7a2a6c632f
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
4 changed files with 51 additions and 10 deletions

View File

@ -222,6 +222,7 @@ set(IMPL_SOURCES
${SOURCES_DIR}/internal/catch_wildcard_pattern.cpp ${SOURCES_DIR}/internal/catch_wildcard_pattern.cpp
${SOURCES_DIR}/internal/catch_xmlwriter.cpp ${SOURCES_DIR}/internal/catch_xmlwriter.cpp
${SOURCES_DIR}/internal/catch_test_case_info_hasher.cpp ${SOURCES_DIR}/internal/catch_test_case_info_hasher.cpp
${SOURCES_DIR}/generators/catch_generators_random.cpp
) )
set(INTERNAL_FILES ${IMPL_SOURCES} ${INTERNAL_HEADERS}) set(INTERNAL_FILES ${IMPL_SOURCES} ${INTERNAL_HEADERS})

View File

@ -0,0 +1,13 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/generators/catch_generators_random.hpp>
#include <catch2/internal/catch_context.hpp>
std::uint32_t Catch::Generators::Detail::getSeed() { return sharedRng()(); }

View File

@ -16,16 +16,21 @@
namespace Catch { namespace Catch {
namespace Generators { namespace Generators {
namespace Detail {
// Returns a suitable seed for a random floating generator based off
// the primary internal rng. It does so by taking current value from
// the rng and returning it as the seed.
std::uint32_t getSeed();
}
template <typename Float> template <typename Float>
class RandomFloatingGenerator final : public IGenerator<Float> { class RandomFloatingGenerator final : public IGenerator<Float> {
Catch::SimplePcg32& m_rng; Catch::SimplePcg32 m_rng;
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, std::uint32_t seed ):
RandomFloatingGenerator(Float a, Float b): m_rng(seed),
m_rng(sharedRng()),
m_dist(a, b) { m_dist(a, b) {
static_cast<void>(next()); static_cast<void>(next());
} }
@ -41,13 +46,12 @@ public:
template <typename Integer> template <typename Integer>
class RandomIntegerGenerator final : public IGenerator<Integer> { class RandomIntegerGenerator final : public IGenerator<Integer> {
Catch::SimplePcg32& m_rng; 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, std::uint32_t seed ):
RandomIntegerGenerator(Integer a, Integer b): m_rng(seed),
m_rng(sharedRng()),
m_dist(a, b) { m_dist(a, b) {
static_cast<void>(next()); static_cast<void>(next());
} }
@ -68,7 +72,7 @@ std::enable_if_t<std::is_integral<T>::value && !std::is_same<T, bool>::value,
GeneratorWrapper<T>> GeneratorWrapper<T>>
random(T a, T b) { random(T a, T b) {
return GeneratorWrapper<T>( return GeneratorWrapper<T>(
Catch::Detail::make_unique<RandomIntegerGenerator<T>>(a, b) Catch::Detail::make_unique<RandomIntegerGenerator<T>>(a, b, Detail::getSeed())
); );
} }
@ -77,7 +81,7 @@ std::enable_if_t<std::is_floating_point<T>::value,
GeneratorWrapper<T>> GeneratorWrapper<T>>
random(T a, T b) { random(T a, T b) {
return GeneratorWrapper<T>( return GeneratorWrapper<T>(
Catch::Detail::make_unique<RandomFloatingGenerator<T>>(a, b) Catch::Detail::make_unique<RandomFloatingGenerator<T>>(a, b, Detail::getSeed())
); );
} }

View File

@ -511,3 +511,26 @@ TEST_CASE( "Generator element stringification is cached",
REQUIRE( generator.stringificationCalls() == 1 ); REQUIRE( generator.stringificationCalls() == 1 );
} }
TEST_CASE( "Random generators can be seeded", "[generators][approvals]" ) {
SECTION( "Integer generator" ) {
using Catch::Generators::RandomIntegerGenerator;
RandomIntegerGenerator<int> rng1( 0, 100, 0x1234 ),
rng2( 0, 100, 0x1234 );
for ( size_t i = 0; i < 10; ++i ) {
REQUIRE( rng1.get() == rng2.get() );
rng1.next(); rng2.next();
}
}
SECTION("Float generator") {
using Catch::Generators::RandomFloatingGenerator;
RandomFloatingGenerator<double> rng1( 0., 100., 0x1234 ),
rng2( 0., 100., 0x1234 );
for ( size_t i = 0; i < 10; ++i ) {
REQUIRE( rng1.get() == rng2.get() );
rng1.next();
rng2.next();
}
}
}