diff --git a/stdlib/Random/src/RNGs.jl b/stdlib/Random/src/RNGs.jl index 5c36b085cd505..bbef56f449a43 100644 --- a/stdlib/Random/src/RNGs.jl +++ b/stdlib/Random/src/RNGs.jl @@ -386,6 +386,7 @@ copy!(::_GLOBAL_RNG, src::Xoshiro) = copy!(default_rng(), src) copy(::_GLOBAL_RNG) = copy(default_rng()) GLOBAL_SEED = 0 +set_global_seed!(seed) = global GLOBAL_SEED = seed function seed!(::_GLOBAL_RNG, seed=rand(RandomDevice(), UInt64, 4)) global GLOBAL_SEED = seed diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index f803d8bf01721..1e18dcb3f8279 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1275,6 +1275,7 @@ function testset_beginend(args, tests, source) # by wrapping the body in a function local RNG = default_rng() local oldrng = copy(RNG) + local oldseed = Random.GLOBAL_SEED try # RNG is re-seeded with its own seed to ease reproduce a failed test Random.seed!(Random.GLOBAL_SEED) @@ -1288,6 +1289,7 @@ function testset_beginend(args, tests, source) record(ts, Error(:nontest_error, Expr(:tuple), err, Base.current_exceptions(), $(QuoteNode(source)))) finally copy!(RNG, oldrng) + Random.set_global_seed!(oldseed) pop_testset() ret = finish(ts) end @@ -1368,6 +1370,7 @@ function testset_forloop(args, testloop, source) local ts local RNG = default_rng() local oldrng = copy(RNG) + local oldseed = Random.GLOBAL_SEED Random.seed!(Random.GLOBAL_SEED) local tmprng = copy(RNG) try @@ -1381,6 +1384,7 @@ function testset_forloop(args, testloop, source) push!(arr, finish(ts)) end copy!(RNG, oldrng) + Random.set_global_seed!(oldseed) end arr end diff --git a/stdlib/Test/test/runtests.jl b/stdlib/Test/test/runtests.jl index 3c56ad8feba51..ab1995c335e89 100644 --- a/stdlib/Test/test/runtests.jl +++ b/stdlib/Test/test/runtests.jl @@ -869,6 +869,29 @@ end Random.seed!(seed) @test a == rand() @test b == rand() + + # Even when seed!() is called within a testset A, subsequent testsets + # should start with the same "global RNG state" as what A started with, + # such that the test `refvalue == rand(Int)` below succeeds. + # Currently, this means that Random.GLOBAL_SEED has to be restored, + # in addition to the state of Random.default_rng(). + GLOBAL_SEED_orig = Random.GLOBAL_SEED + local refvalue + @testset "GLOBAL_SEED is also preserved (setup)" begin + @test GLOBAL_SEED_orig == Random.GLOBAL_SEED + refvalue = rand(Int) + Random.seed!() + @test GLOBAL_SEED_orig != Random.GLOBAL_SEED + end + @test GLOBAL_SEED_orig == Random.GLOBAL_SEED + @testset "GLOBAL_SEED is also preserved (forloop)" for _=1:3 + @test refvalue == rand(Int) + Random.seed!() + end + @test GLOBAL_SEED_orig == Random.GLOBAL_SEED + @testset "GLOBAL_SEED is also preserved (beginend)" begin + @test refvalue == rand(Int) + end end @testset "InterruptExceptions #21043" begin @@ -1202,4 +1225,4 @@ Test.finish(ts::PassInformationTestSet) = ts @test ts.results[2].data == ErrorException @test ts.results[2].value == ErrorException("Msg") @test ts.results[2].source == LineNumberNode(test_throws_line_number, @__FILE__) -end \ No newline at end of file +end