diff options
Diffstat (limited to 'spec/ruby/core/random')
| -rw-r--r-- | spec/ruby/core/random/bytes_spec.rb | 29 | ||||
| -rw-r--r-- | spec/ruby/core/random/default_spec.rb | 7 | ||||
| -rw-r--r-- | spec/ruby/core/random/equal_value_spec.rb | 37 | ||||
| -rw-r--r-- | spec/ruby/core/random/fixtures/classes.rb | 15 | ||||
| -rw-r--r-- | spec/ruby/core/random/new_seed_spec.rb | 24 | ||||
| -rw-r--r-- | spec/ruby/core/random/new_spec.rb | 38 | ||||
| -rw-r--r-- | spec/ruby/core/random/rand_spec.rb | 224 | ||||
| -rw-r--r-- | spec/ruby/core/random/random_number_spec.rb | 8 | ||||
| -rw-r--r-- | spec/ruby/core/random/seed_spec.rb | 29 | ||||
| -rw-r--r-- | spec/ruby/core/random/shared/bytes.rb | 17 | ||||
| -rw-r--r-- | spec/ruby/core/random/shared/rand.rb | 9 | ||||
| -rw-r--r-- | spec/ruby/core/random/srand_spec.rb | 39 | ||||
| -rw-r--r-- | spec/ruby/core/random/urandom_spec.rb | 25 |
13 files changed, 501 insertions, 0 deletions
diff --git a/spec/ruby/core/random/bytes_spec.rb b/spec/ruby/core/random/bytes_spec.rb new file mode 100644 index 0000000000..c9be07cd3f --- /dev/null +++ b/spec/ruby/core/random/bytes_spec.rb @@ -0,0 +1,29 @@ +# encoding: binary +require_relative '../../spec_helper' +require_relative 'shared/bytes' + +describe "Random#bytes" do + it_behaves_like :random_bytes, :bytes, Random.new + + it "returns the same output for a given seed" do + Random.new(33).bytes(2).should == Random.new(33).bytes(2) + end + + it "returns the same numeric output for a given seed across all implementations and platforms" do + rnd = Random.new(33) + rnd.bytes(2).should == "\x14\\" + rnd.bytes(1000) # skip some + rnd.bytes(2).should == "\xA1p" + end + + it "returns the same numeric output for a given huge seed across all implementations and platforms" do + rnd = Random.new(2 ** (63 * 4)) + rnd.bytes(2).should == "_\x91" + rnd.bytes(1000) # skip some + rnd.bytes(2).should == "\x17\x12" + end +end + +describe "Random.bytes" do + it_behaves_like :random_bytes, :bytes, Random +end diff --git a/spec/ruby/core/random/default_spec.rb b/spec/ruby/core/random/default_spec.rb new file mode 100644 index 0000000000..9e4845986d --- /dev/null +++ b/spec/ruby/core/random/default_spec.rb @@ -0,0 +1,7 @@ +require_relative '../../spec_helper' + +describe "Random::DEFAULT" do + it "is no longer defined" do + Random.should_not.const_defined?(:DEFAULT) + end +end diff --git a/spec/ruby/core/random/equal_value_spec.rb b/spec/ruby/core/random/equal_value_spec.rb new file mode 100644 index 0000000000..5f470d6a4c --- /dev/null +++ b/spec/ruby/core/random/equal_value_spec.rb @@ -0,0 +1,37 @@ +require_relative '../../spec_helper' + +describe "Random#==" do + it "returns true if the two objects have the same state" do + a = Random.new(42) + b = Random.new(42) + a.send(:state).should == b.send(:state) + a.should == b + end + + it "returns false if the two objects have different state" do + a = Random.new + b = Random.new + a.send(:state).should_not == b.send(:state) + a.should_not == b + end + + it "returns true if the two objects have the same seed" do + a = Random.new(42) + b = Random.new(42.5) + a.seed.should == b.seed + a.should == b + end + + it "returns false if the two objects have a different seed" do + a = Random.new(42) + b = Random.new(41) + a.seed.should_not == b.seed + a.should_not == b + end + + it "returns false if the other object is not a Random" do + a = Random.new(42) + a.should_not == 42 + a.should_not == [a] + end +end diff --git a/spec/ruby/core/random/fixtures/classes.rb b/spec/ruby/core/random/fixtures/classes.rb new file mode 100644 index 0000000000..9c8d113e24 --- /dev/null +++ b/spec/ruby/core/random/fixtures/classes.rb @@ -0,0 +1,15 @@ +module RandomSpecs + CustomRangeInteger = Struct.new(:value) do + def to_int; value; end + def <=>(other); to_int <=> other.to_int; end + def -(other); self.class.new(to_int - other.to_int); end + def +(other); self.class.new(to_int + other.to_int); end + end + + CustomRangeFloat = Struct.new(:value) do + def to_f; value; end + def <=>(other); to_f <=> other.to_f; end + def -(other); to_f - other.to_f; end + def +(other); self.class.new(to_f + other.to_f); end + end +end diff --git a/spec/ruby/core/random/new_seed_spec.rb b/spec/ruby/core/random/new_seed_spec.rb new file mode 100644 index 0000000000..7a93da99aa --- /dev/null +++ b/spec/ruby/core/random/new_seed_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../spec_helper' + +describe "Random.new_seed" do + it "returns an Integer" do + Random.new_seed.should be_an_instance_of(Integer) + end + + it "returns an arbitrary seed value each time" do + bigs = 200.times.map { Random.new_seed } + bigs.uniq.size.should == 200 + end + + it "is not affected by Kernel#srand" do + begin + srand 25 + a = Random.new_seed + srand 25 + b = Random.new_seed + a.should_not == b + ensure + srand Random.new_seed + end + end +end diff --git a/spec/ruby/core/random/new_spec.rb b/spec/ruby/core/random/new_spec.rb new file mode 100644 index 0000000000..69210cef03 --- /dev/null +++ b/spec/ruby/core/random/new_spec.rb @@ -0,0 +1,38 @@ +require_relative "../../spec_helper" +describe "Random.new" do + it "returns a new instance of Random" do + Random.new.should be_an_instance_of(Random) + end + + it "uses a random seed value if none is supplied" do + Random.new.seed.should be_an_instance_of(Integer) + end + + it "returns Random instances initialized with different seeds" do + first = Random.new + second = Random.new + (0..20).map { first.rand }.should_not == (0..20).map { second.rand } + end + + it "accepts an Integer seed value as an argument" do + Random.new(2).seed.should == 2 + end + + it "accepts (and truncates) a Float seed value as an argument" do + Random.new(3.4).seed.should == 3 + end + + it "accepts (and converts to Integer) a Rational seed value as an argument" do + Random.new(Rational(20,2)).seed.should == 10 + end + + it "accepts (and converts to Integer) a Complex (without imaginary part) seed value as an argument" do + Random.new(Complex(20)).seed.should == 20 + end + + it "raises a RangeError if passed a Complex (with imaginary part) seed value as an argument" do + -> do + Random.new(Complex(20,2)) + end.should raise_error(RangeError) + end +end diff --git a/spec/ruby/core/random/rand_spec.rb b/spec/ruby/core/random/rand_spec.rb new file mode 100644 index 0000000000..9244177ab5 --- /dev/null +++ b/spec/ruby/core/random/rand_spec.rb @@ -0,0 +1,224 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require_relative 'shared/rand' + +describe "Random.rand" do + it_behaves_like :random_number, :rand, Random.new + it_behaves_like :random_number, :rand, Random + + it "returns a Float >= 0 if no max argument is passed" do + floats = 200.times.map { Random.rand } + floats.min.should >= 0 + end + + it "returns a Float < 1 if no max argument is passed" do + floats = 200.times.map { Random.rand } + floats.max.should < 1 + end + + it "returns the same sequence for a given seed if no max argument is passed" do + Random.srand 33 + floats_a = 20.times.map { Random.rand } + Random.srand 33 + floats_b = 20.times.map { Random.rand } + floats_a.should == floats_b + end + + it "returns an Integer >= 0 if an Integer argument is passed" do + ints = 200.times.map { Random.rand(34) } + ints.min.should >= 0 + end + + it "returns an Integer < the max argument if an Integer argument is passed" do + ints = 200.times.map { Random.rand(55) } + ints.max.should < 55 + end + + it "returns the same sequence for a given seed if an Integer argument is passed" do + Random.srand 33 + floats_a = 20.times.map { Random.rand(90) } + Random.srand 33 + floats_b = 20.times.map { Random.rand(90) } + floats_a.should == floats_b + end + + it "coerces arguments to Integers with #to_int" do + obj = mock_numeric('int') + obj.should_receive(:to_int).and_return(99) + Random.rand(obj).should be_kind_of(Integer) + end +end + +describe "Random#rand with Fixnum" do + it "returns an Integer" do + Random.new.rand(20).should be_an_instance_of(Integer) + end + + it "returns a Fixnum greater than or equal to 0" do + prng = Random.new + ints = 20.times.map { prng.rand(5) } + ints.min.should >= 0 + end + + it "returns a Fixnum less than the argument" do + prng = Random.new + ints = 20.times.map { prng.rand(5) } + ints.max.should <= 4 + end + + it "returns the same sequence for a given seed" do + prng = Random.new 33 + a = 20.times.map { prng.rand(90) } + prng = Random.new 33 + b = 20.times.map { prng.rand(90) } + a.should == b + end + + it "eventually returns all possible values" do + prng = Random.new 33 + 100.times.map{ prng.rand(10) }.uniq.sort.should == (0...10).to_a + end + + it "raises an ArgumentError when the argument is 0" do + -> do + Random.new.rand(0) + end.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when the argument is negative" do + -> do + Random.new.rand(-12) + end.should raise_error(ArgumentError) + end +end + +describe "Random#rand with Bignum" do + it "typically returns a Bignum" do + rnd = Random.new(1) + 10.times.map{ rnd.rand(bignum_value*2) }.max.should be_an_instance_of(Integer) + end + + it "returns a Bignum greater than or equal to 0" do + prng = Random.new + bigs = 20.times.map { prng.rand(bignum_value) } + bigs.min.should >= 0 + end + + it "returns a Bignum less than the argument" do + prng = Random.new + bigs = 20.times.map { prng.rand(bignum_value) } + bigs.max.should < bignum_value + end + + it "returns the same sequence for a given seed" do + prng = Random.new 33 + a = 20.times.map { prng.rand(bignum_value) } + prng = Random.new 33 + b = 20.times.map { prng.rand(bignum_value) } + a.should == b + end + + it "raises an ArgumentError when the argument is negative" do + -> do + Random.new.rand(-bignum_value) + end.should raise_error(ArgumentError) + end +end + +describe "Random#rand with Float" do + it "returns a Float" do + Random.new.rand(20.43).should be_an_instance_of(Float) + end + + it "returns a Float greater than or equal to 0.0" do + prng = Random.new + floats = 20.times.map { prng.rand(5.2) } + floats.min.should >= 0.0 + end + + it "returns a Float less than the argument" do + prng = Random.new + floats = 20.times.map { prng.rand(4.30) } + floats.max.should < 4.30 + end + + it "returns the same sequence for a given seed" do + prng = Random.new 33 + a = 20.times.map { prng.rand(89.2928) } + prng = Random.new 33 + b = 20.times.map { prng.rand(89.2928) } + a.should == b + end + + it "raises an ArgumentError when the argument is negative" do + -> do + Random.new.rand(-1.234567) + end.should raise_error(ArgumentError) + end +end + +describe "Random#rand with Range" do + it "returns an element from the Range" do + Random.new.rand(20..43).should be_an_instance_of(Integer) + end + + it "supports custom object types" do + rand(RandomSpecs::CustomRangeInteger.new(1)..RandomSpecs::CustomRangeInteger.new(42)).should be_an_instance_of(RandomSpecs::CustomRangeInteger) + rand(RandomSpecs::CustomRangeFloat.new(1.0)..RandomSpecs::CustomRangeFloat.new(42.0)).should be_an_instance_of(RandomSpecs::CustomRangeFloat) + rand(Time.now..Time.now).should be_an_instance_of(Time) + end + + it "returns an object that is a member of the Range" do + prng = Random.new + r = 20..30 + 20.times { r.member?(prng.rand(r)).should be_true } + end + + it "works with inclusive ranges" do + prng = Random.new 33 + r = 3..5 + 40.times.map { prng.rand(r) }.uniq.sort.should == [3,4,5] + end + + it "works with exclusive ranges" do + prng = Random.new 33 + r = 3...5 + 20.times.map { prng.rand(r) }.uniq.sort.should == [3,4] + end + + it "returns the same sequence for a given seed" do + prng = Random.new 33 + a = 20.times.map { prng.rand(76890.028..800000.00) } + prng = Random.new 33 + b = 20.times.map { prng.rand(76890.028..800000.00) } + a.should == b + end + + it "eventually returns all possible values" do + prng = Random.new 33 + 100.times.map{ prng.rand(10..20) }.uniq.sort.should == (10..20).to_a + 100.times.map{ prng.rand(10...20) }.uniq.sort.should == (10...20).to_a + end + + it "considers Integers as Floats if one end point is a float" do + Random.new(42).rand(0.0..1).should be_kind_of(Float) + Random.new(42).rand(0..1.0).should be_kind_of(Float) + end + + it "returns a float within a given float range" do + Random.new(42).rand(0.0...100.0).should == 37.454011884736246 + Random.new(42).rand(-100.0...0.0).should == -62.545988115263754 + end + + it "raises an ArgumentError when the startpoint lacks #+ and #- methods" do + -> do + Random.new.rand(Object.new..67) + end.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when the endpoint lacks #+ and #- methods" do + -> do + Random.new.rand(68..Object.new) + end.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/core/random/random_number_spec.rb b/spec/ruby/core/random/random_number_spec.rb new file mode 100644 index 0000000000..bad81aeff6 --- /dev/null +++ b/spec/ruby/core/random/random_number_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require_relative 'shared/rand' + +describe "Random.random_number" do + it_behaves_like :random_number, :random_number, Random.new + + it_behaves_like :random_number, :random_number, Random +end diff --git a/spec/ruby/core/random/seed_spec.rb b/spec/ruby/core/random/seed_spec.rb new file mode 100644 index 0000000000..bf4524fdd9 --- /dev/null +++ b/spec/ruby/core/random/seed_spec.rb @@ -0,0 +1,29 @@ +require_relative '../../spec_helper' + +describe "Random#seed" do + it "returns an Integer" do + Random.new.seed.should be_kind_of(Integer) + end + + it "returns an arbitrary seed if the constructor was called without arguments" do + Random.new.seed.should_not == Random.new.seed + end + + it "returns the same generated seed when repeatedly called on the same object" do + prng = Random.new + prng.seed.should == prng.seed + end + + it "returns the seed given in the constructor" do + prng = Random.new(36788) + prng.seed.should == prng.seed + prng.seed.should == 36788 + end + + it "returns the given seed coerced with #to_int" do + obj = mock_numeric('int') + obj.should_receive(:to_int).and_return(34) + prng = Random.new(obj) + prng.seed.should == 34 + end +end diff --git a/spec/ruby/core/random/shared/bytes.rb b/spec/ruby/core/random/shared/bytes.rb new file mode 100644 index 0000000000..9afad3b7f8 --- /dev/null +++ b/spec/ruby/core/random/shared/bytes.rb @@ -0,0 +1,17 @@ +describe :random_bytes, shared: true do + it "returns a String" do + @object.send(@method, 1).should be_an_instance_of(String) + end + + it "returns a String of the length given as argument" do + @object.send(@method, 15).length.should == 15 + end + + it "returns a binary String" do + @object.send(@method, 15).encoding.should == Encoding::BINARY + end + + it "returns a random binary String" do + @object.send(@method, 12).should_not == @object.send(@method, 12) + end +end diff --git a/spec/ruby/core/random/shared/rand.rb b/spec/ruby/core/random/shared/rand.rb new file mode 100644 index 0000000000..d3b24b8851 --- /dev/null +++ b/spec/ruby/core/random/shared/rand.rb @@ -0,0 +1,9 @@ +describe :random_number, shared: true do + it "returns a Float if no max argument is passed" do + @object.send(@method).should be_kind_of(Float) + end + + it "returns an Integer if an Integer argument is passed" do + @object.send(@method, 20).should be_kind_of(Integer) + end +end diff --git a/spec/ruby/core/random/srand_spec.rb b/spec/ruby/core/random/srand_spec.rb new file mode 100644 index 0000000000..1ef8e32cfb --- /dev/null +++ b/spec/ruby/core/random/srand_spec.rb @@ -0,0 +1,39 @@ +require_relative '../../spec_helper' + +describe "Random.srand" do + it "returns an arbitrary seed if .srand wasn't called previously with an argument and no argument is supplied this time" do + Random.srand # Reset to random seed in case .srand was called previously + Random.srand.should_not == Random.srand + end + + it "returns the previous argument to .srand if one was given and no argument is supplied" do + Random.srand 34 + Random.srand.should == 34 + end + + it "returns an arbitrary seed if .srand wasn't called previously with an argument and 0 is supplied this time" do + Random.srand # Reset to random seed in case .srand was called previously + Random.srand(0).should_not == Random.srand(0) + end + + it "returns the previous argument to .srand if one was given and 0 is supplied" do + Random.srand 34 + Random.srand(0).should == 34 + end + + it "seeds Random.rand such that its return value is deterministic" do + Random.srand 176542 + a = 20.times.map { Random.rand } + Random.srand 176542 + b = 20.times.map { Random.rand } + a.should == b + end + + it "seeds Kernel.rand such that its return value is deterministic" do + Random.srand 176542 + a = 20.times.map { Kernel.rand } + Random.srand 176542 + b = 20.times.map { Kernel.rand } + a.should == b + end +end diff --git a/spec/ruby/core/random/urandom_spec.rb b/spec/ruby/core/random/urandom_spec.rb new file mode 100644 index 0000000000..6f180e54ac --- /dev/null +++ b/spec/ruby/core/random/urandom_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../spec_helper' + +describe "Random.urandom" do + it "returns a String" do + Random.urandom(1).should be_an_instance_of(String) + end + + it "returns a String of the length given as argument" do + Random.urandom(15).length.should == 15 + end + + it "raises an ArgumentError on a negative size" do + -> { + Random.urandom(-1) + }.should raise_error(ArgumentError) + end + + it "returns a binary String" do + Random.urandom(15).encoding.should == Encoding::BINARY + end + + it "returns a random binary String" do + Random.urandom(12).should_not == Random.urandom(12) + end +end |
