summaryrefslogtreecommitdiff
path: root/test/ruby/test_rand.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_rand.rb')
-rw-r--r--test/ruby/test_rand.rb473
1 files changed, 392 insertions, 81 deletions
diff --git a/test/ruby/test_rand.rb b/test/ruby/test_rand.rb
index e2fd127f9c..f177664943 100644
--- a/test/ruby/test_rand.rb
+++ b/test/ruby/test_rand.rb
@@ -1,131 +1,442 @@
+# frozen_string_literal: false
require 'test/unit'
class TestRand < Test::Unit::TestCase
+ def assert_random_int(m, init = 0, iterate: 5)
+ srand(init)
+ rnds = [Random.new(init)]
+ rnds2 = [rnds[0].dup]
+ rnds3 = [rnds[0].dup]
+ iterate.times do |i|
+ w = rand(m)
+ rnds.each do |rnd|
+ assert_equal(w, rnd.rand(m))
+ end
+ rnds2.each do |rnd|
+ r=rnd.rand(i...(m+i))
+ assert_equal(w+i, r)
+ end
+ rnds3.each do |rnd|
+ r=rnd.rand(i..(m+i-1))
+ assert_equal(w+i, r)
+ end
+ rnds << Marshal.load(Marshal.dump(rnds[-1]))
+ rnds2 << Marshal.load(Marshal.dump(rnds2[-1]))
+ end
+ end
+
def test_mt
- srand(0x00000456_00000345_00000234_00000123)
- %w(1067595299 955945823 477289528 4107218783 4228976476).each {|w|
- assert_equal(w.to_i, rand(0x100000000))
- }
+ assert_random_int(0x100000000, 0x00000456_00000345_00000234_00000123)
end
def test_0x3fffffff
- srand(0)
- %w(209652396 398764591 924231285 404868288 441365315).each {|w|
- assert_equal(w.to_i, rand(0x3fffffff))
- }
+ assert_random_int(0x3fffffff)
end
def test_0x40000000
- srand(0)
- %w(209652396 398764591 924231285 404868288 441365315).each {|w|
- assert_equal(w.to_i, rand(0x40000000))
- }
+ assert_random_int(0x40000000)
end
def test_0x40000001
- srand(0)
- %w(209652396 398764591 924231285 441365315 192771779).each {|w|
- assert_equal(w.to_i, rand(0x40000001))
- }
+ assert_random_int(0x40000001)
end
def test_0xffffffff
- srand(0)
- %w(2357136044 2546248239 3071714933 3626093760 2588848963).each {|w|
- assert_equal(w.to_i, rand(0xffffffff))
- }
+ assert_random_int(0xffffffff)
end
def test_0x100000000
- srand(0)
- %w(2357136044 2546248239 3071714933 3626093760 2588848963).each {|w|
- assert_equal(w.to_i, rand(0x100000000))
- }
+ assert_random_int(0x100000000)
end
def test_0x100000001
- srand(0)
- %w(2546248239 1277901399 243580376 1171049868 2051556033).each {|w|
- assert_equal(w.to_i, rand(0x100000001))
- }
+ assert_random_int(0x100000001)
end
def test_rand_0x100000000
- srand(311702798)
- %w(4119812344 3870378946 80324654 4294967296 410016213).each {|w|
- assert_equal(w.to_i, rand(0x100000001))
- }
+ assert_random_int(0x100000001, 311702798)
end
def test_0x1000000000000
- srand(0)
- %w(11736396900911
- 183025067478208
- 197104029029115
- 130583529618791
- 180361239846611).each {|w|
- assert_equal(w.to_i, rand(0x1000000000000))
- }
+ assert_random_int(0x1000000000000)
end
def test_0x1000000000001
- srand(0)
- %w(187121911899765
- 197104029029115
- 180361239846611
- 236336749852452
- 208739549485656).each {|w|
- assert_equal(w.to_i, rand(0x1000000000001))
- }
+ assert_random_int(0x1000000000001)
end
def test_0x3fffffffffffffff
- srand(0)
- %w(900450186894289455
- 3969543146641149120
- 1895649597198586619
- 827948490035658087
- 3203365596207111891).each {|w|
- assert_equal(w.to_i, rand(0x3fffffffffffffff))
- }
+ assert_random_int(0x3fffffffffffffff)
end
def test_0x4000000000000000
- srand(0)
- %w(900450186894289455
- 3969543146641149120
- 1895649597198586619
- 827948490035658087
- 3203365596207111891).each {|w|
- assert_equal(w.to_i, rand(0x4000000000000000))
- }
+ assert_random_int(0x4000000000000000)
end
def test_0x4000000000000001
+ assert_random_int(0x4000000000000001)
+ end
+
+ def test_0x10000000000
+ assert_random_int(0x10000000000, 3)
+ end
+
+ def test_0x10000
+ assert_random_int(0x10000)
+ end
+
+ def assert_same_numbers(type, *nums)
+ nums.each do |n|
+ assert_instance_of(type, n)
+ end
+ x = nums.shift
+ nums.each do |n|
+ assert_equal(x, n)
+ end
+ x
+ end
+
+ def test_types
+ o = Object.new
+ class << o
+ def to_int; 100; end
+ def class; Integer; end
+ end
+
srand(0)
- %w(900450186894289455
- 3969543146641149120
- 1895649597198586619
- 827948490035658087
- 2279347887019741461).each {|w|
- assert_equal(w.to_i, rand(0x4000000000000001))
- }
+ nums = [100.0, (2**100).to_f, (2**100), o, o, o].map do |m|
+ k = Integer
+ assert_kind_of(k, x = rand(m), m.inspect)
+ [m, k, x]
+ end
+ assert_kind_of(Integer, rand(-(2**100).to_f))
+
+ srand(0)
+ rnd = Random.new(0)
+ rnd2 = Random.new(0)
+ nums.each do |m, k, x|
+ assert_same_numbers(m.class, Random.rand(m), rnd.rand(m), rnd2.rand(m))
+ end
+ end
+
+ def test_srand
+ srand
+ assert_kind_of(Integer, rand(2))
+ assert_kind_of(Integer, Random.new.rand(2))
+
+ srand(2**100)
+ rnd = Random.new(2**100)
+ r = 3.times.map do
+ assert_same_numbers(Integer, rand(0x100000000), rnd.rand(0x100000000))
+ end
+ srand(2**100)
+ r.each do |n|
+ assert_same_numbers(Integer, n, rand(0x100000000))
+ end
+ end
+
+ def test_shuffle
+ srand(0)
+ result = [*1..5].shuffle
+ assert_equal([*1..5], result.sort)
+ assert_equal(result, [*1..5].shuffle(random: Random.new(0)))
+ end
+
+ def test_big_seed
+ assert_random_int(0x100000000, 2**1000000-1)
+ end
+
+ def test_random_gc
+ r = Random.new(0)
+ 3.times do
+ assert_kind_of(Integer, r.rand(0x100000000))
+ end
+ GC.start
+ 3.times do
+ assert_kind_of(Integer, r.rand(0x100000000))
+ end
+ end
+
+ def test_random_type_error
+ assert_raise(TypeError) { Random.new(Object.new) }
+ assert_raise(TypeError) { Random.new(0).rand(Object.new) }
+ end
+
+ def test_random_argument_error
+ r = Random.new(0)
+ assert_raise(ArgumentError) { r.rand(0, 0) }
+ assert_raise(ArgumentError, '[ruby-core:24677]') { r.rand(-1) }
+ assert_raise(ArgumentError, '[ruby-core:24677]') { r.rand(-1.0) }
+ assert_raise(ArgumentError, '[ruby-core:24677]') { r.rand(0) }
+ assert_equal(0, r.rand(1), '[ruby-dev:39166]')
+ assert_equal(0, r.rand(0...1), '[ruby-dev:39166]')
+ assert_equal(0, r.rand(0..0), '[ruby-dev:39166]')
+ assert_equal(0.0, r.rand(0.0..0.0), '[ruby-dev:39166]')
+ assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0...0) }
+ assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0..-1) }
+ assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0.0...0.0) }
+ assert_raise(ArgumentError, '[ruby-dev:39166]') { r.rand(0.0...-0.1) }
+ bug3027 = '[ruby-core:29075]'
+ assert_raise(ArgumentError, bug3027) { r.rand(nil) }
+ end
+
+ def test_random_seed
+ assert_equal(0, Random.new(0).seed)
+ assert_equal(0x100000000, Random.new(0x100000000).seed)
+ assert_equal(2**100, Random.new(2**100).seed)
end
- def test_neg_0x10000000000
- ws = %w(455570294424 1073054410371 790795084744 2445173525 1088503892627)
- srand(3)
- ws.each {|w| assert_equal(w.to_i, rand(0x10000000000)) }
- srand(3)
- ws.each {|w| assert_equal(w.to_i, rand(-0x10000000000)) }
+ def test_random_dup
+ r1 = Random.new(0)
+ r2 = r1.dup
+ 3.times do
+ assert_same_numbers(Integer, r1.rand(0x100000000), r2.rand(0x100000000))
+ end
+ r2 = r1.dup
+ 3.times do
+ assert_same_numbers(Integer, r1.rand(0x100000000), r2.rand(0x100000000))
+ end
end
- def test_neg_0x10000
- ws = %w(2732 43567 42613 52416 45891)
+ def test_random_bytes
srand(0)
- ws.each {|w| assert_equal(w.to_i, rand(0x10000)) }
+ r = Random.new(0)
+
+ assert_equal("", r.bytes(0))
+ assert_equal("", Random.bytes(0))
+
+ x = r.bytes(1)
+ assert_equal(1, x.bytesize)
+ assert_equal(x, Random.bytes(1))
+
+ x = r.bytes(10)
+ assert_equal(10, x.bytesize)
+ assert_equal(x, Random.bytes(10))
+ end
+
+ def test_random_range
srand(0)
- ws.each {|w| assert_equal(w.to_i, rand(-0x10000)) }
+ r = Random.new(0)
+ now = Time.now
+ [5..9, -1000..1000, 2**100+5..2**100+9, 3.1..4, now..(now+2)].each do |range|
+ 3.times do
+ x = rand(range)
+ assert_instance_of(range.first.class, x)
+ assert_equal(x, r.rand(range))
+ assert_include(range, x)
+ end
+ end
+ end
+
+ def test_random_float
+ r = Random.new(0)
+ 3.times do
+ assert_include(0...1.0, r.rand)
+ end
+ [2.0, (2**100).to_f].each do |x|
+ range = 0...x
+ 3.times do
+ assert_include(range, r.rand(x), "rand(#{x})")
+ end
+ end
+
+ assert_raise(Errno::EDOM, Errno::ERANGE) { r.rand(1.0 / 0.0) }
+ assert_raise(Errno::EDOM, Errno::ERANGE) { r.rand(0.0 / 0.0) }
+ assert_raise(Errno::EDOM) {r.rand(1..)}
+ assert_raise(Errno::EDOM) {r.rand(..1)}
+
+ r = Random.new(0)
+ [1.0...2.0, 1.0...11.0, 2.0...4.0].each do |range|
+ 3.times do
+ assert_include(range, r.rand(range), "[ruby-core:24655] rand(#{range})")
+ end
+ end
+
+ assert_nothing_raised {r.rand(-Float::MAX..Float::MAX)}
+ end
+
+ def test_random_equal
+ r = Random.new(0)
+ assert_equal(r, r)
+ assert_equal(r, r.dup)
+ r1 = r.dup
+ r2 = r.dup
+ r1.rand(0x100)
+ assert_not_equal(r1, r2)
+ r2.rand(0x100)
+ assert_equal(r1, r2)
end
+ def test_fork_shuffle
+ pid = fork do
+ (1..10).to_a.shuffle
+ raise 'default seed is not set' if srand == 0
+ end
+ _, st = Process.waitpid2(pid)
+ assert_predicate(st, :success?, "#{st.inspect}")
+ rescue NotImplementedError, ArgumentError
+ end
+
+ def assert_fork_status(n, mesg, &block)
+ IO.pipe do |r, w|
+ (1..n).map do
+ st = desc = nil
+ IO.pipe do |re, we|
+ p1 = fork {
+ re.close
+ STDERR.reopen(we)
+ w.puts(block.call.to_s)
+ }
+ we.close
+ err = Thread.start {re.read}
+ _, st = Process.waitpid2(p1)
+ desc = FailDesc[st, mesg, err.value]
+ end
+ assert(!st.signaled?, desc)
+ assert(st.success?, mesg)
+ r.gets.strip
+ end
+ end
+ end
+
+ def test_rand_reseed_on_fork
+ GC.start
+ bug5661 = '[ruby-core:41209]'
+
+ assert_fork_status(1, bug5661) {Random.rand(4)}
+ r1, r2 = *assert_fork_status(2, bug5661) {Random.rand}
+ assert_not_equal(r1, r2, bug5661)
+
+ assert_fork_status(1, bug5661) {rand(4)}
+ r1, r2 = *assert_fork_status(2, bug5661) {rand}
+ assert_not_equal(r1, r2, bug5661)
+
+ stable = Random.new
+ assert_fork_status(1, bug5661) {stable.rand(4)}
+ r1, r2 = *assert_fork_status(2, bug5661) {stable.rand}
+ assert_equal(r1, r2, bug5661)
+
+ assert_fork_status(1, '[ruby-core:82100] [Bug #13753]') do
+ Random.rand(4)
+ end
+ rescue NotImplementedError
+ end
+
+ def test_seed
+ bug3104 = '[ruby-core:29292]'
+ rand_1 = Random.new(-1).rand
+ assert_not_equal(rand_1, Random.new((1 << 31) -1).rand, "#{bug3104} (2)")
+ assert_not_equal(rand_1, Random.new((1 << 63) -1).rand, "#{bug3104} (2)")
+
+ [-1, -2**10, -2**40].each {|n|
+ b = (2**64).coerce(n)[0]
+ r1 = Random.new(n).rand
+ r2 = Random.new(b).rand
+ assert_equal(r1, r2)
+ }
+ end
+
+ def test_seed_leading_zero_guard
+ guard = 1<<32
+ range = 0...(1<<32)
+ all_assertions_foreach(nil, 0, 1, 2) do |i|
+ assert_not_equal(Random.new(i).rand(range), Random.new(i+guard).rand(range))
+ end
+ end
+
+ def test_marshal
+ bug3656 = '[ruby-core:31622]'
+ assert_raise(TypeError, bug3656) {
+ Random.new.__send__(:marshal_load, 0)
+ }
+ end
+
+ def test_initialize_frozen
+ r = Random.new(0)
+ r.freeze
+ assert_raise(FrozenError, '[Bug #6540]') do
+ r.__send__(:initialize, r)
+ end
+ end
+
+ def test_marshal_load_frozen
+ r = Random.new(0)
+ d = r.__send__(:marshal_dump)
+ r.freeze
+ assert_raise(FrozenError, '[Bug #6540]') do
+ r.__send__(:marshal_load, d)
+ end
+ end
+
+ def test_random_ulong_limited
+ def (gen = Object.new).rand(*) 1 end
+ assert_equal([2], (1..100).map {[1,2,3].sample(random: gen)}.uniq)
+
+ def (gen = Object.new).rand(*) 100 end
+ assert_raise_with_message(RangeError, /big 100\z/) {[1,2,3].sample(random: gen)}
+
+ bug7903 = '[ruby-dev:47061] [Bug #7903]'
+ def (gen = Object.new).rand(*) -1 end
+ assert_raise_with_message(RangeError, /small -1\z/, bug7903) {[1,2,3].sample(random: gen)}
+
+ bug7935 = '[ruby-core:52779] [Bug #7935]'
+ class << (gen = Object.new)
+ def rand(limit) @limit = limit; 0 end
+ attr_reader :limit
+ end
+ [1, 2].sample(1, random: gen)
+ assert_equal(2, gen.limit, bug7935)
+ end
+
+ def test_random_ulong_limited_no_rand
+ c = Class.new do
+ undef rand
+ def bytes(n)
+ "\0"*n
+ end
+ end
+ gen = c.new.extend(Random::Formatter)
+ assert_equal(1, [1, 2].sample(random: gen))
+ end
+
+ def test_default_seed
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ verbose, $VERBOSE = $VERBOSE, nil
+ seed = Random.seed
+ rand1 = Random.rand
+ $VERBOSE = verbose
+ rand2 = Random.new(seed).rand
+ assert_equal(rand1, rand2)
+
+ srand seed
+ rand3 = rand
+ assert_equal(rand1, rand3)
+ end;
+ end
+
+ def test_urandom
+ [0, 1, 100].each do |size|
+ v = Random.urandom(size)
+ assert_kind_of(String, v)
+ assert_equal(size, v.bytesize)
+ end
+ end
+
+ def test_new_seed
+ size = 0
+ n = 8
+ n.times do
+ v = Random.new_seed
+ assert_kind_of(Integer, v)
+ size += v.size
+ end
+ # probability of failure <= 1/256**8
+ assert_operator(size.fdiv(n), :>, 15)
+ end
+
+ def test_broken_marshal
+ assert_raise(ArgumentError) { Marshal.load("\x04\bU:\vRandom" + Marshal.dump([1,0,1])[2..]) }
+ assert_raise(ArgumentError) { Marshal.load("\x04\bU:\vRandom" + Marshal.dump([1,-1,1])[2..]) }
+ end
end