diff options
Diffstat (limited to 'spec/ruby/core/range')
24 files changed, 435 insertions, 405 deletions
diff --git a/spec/ruby/core/range/bsearch_spec.rb b/spec/ruby/core/range/bsearch_spec.rb index 438c7ce314..5254ab756c 100644 --- a/spec/ruby/core/range/bsearch_spec.rb +++ b/spec/ruby/core/range/bsearch_spec.rb @@ -9,22 +9,30 @@ describe "Range#bsearch" do it_behaves_like :enumeratorized_with_unknown_size, :bsearch, (1..3) it "raises a TypeError if the block returns an Object" do - -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError) + -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError, "wrong argument type Object (must be numeric, true, false or nil)") end - it "raises a TypeError if the block returns a String" do - -> { (0..1).bsearch { "1" } }.should raise_error(TypeError) + it "raises a TypeError if the block returns a String and boundaries are Integer values" do + -> { (0..1).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)") + end + + it "raises a TypeError if the block returns a String and boundaries are Float values" do + -> { (0.0..1.0).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)") end it "raises a TypeError if the Range has Object values" do value = mock("range bsearch") r = Range.new value, value - -> { r.bsearch { true } }.should raise_error(TypeError) + -> { r.bsearch { true } }.should raise_error(TypeError, "can't do binary search for MockObject") end it "raises a TypeError if the Range has String values" do - -> { ("a".."e").bsearch { true } }.should raise_error(TypeError) + -> { ("a".."e").bsearch { true } }.should raise_error(TypeError, "can't do binary search for String") + end + + it "raises TypeError when non-Numeric begin/end and block not passed" do + -> { ("a".."e").bsearch }.should raise_error(TypeError, "can't do binary search for String") end context "with Integer values" do @@ -94,6 +102,10 @@ describe "Range#bsearch" do (4..2).bsearch { 0 }.should == nil (4..2).bsearch { -1 }.should == nil end + + it "returns enumerator when block not passed" do + (0...3).bsearch.kind_of?(Enumerator).should == true + end end context "with Float values" do @@ -156,7 +168,6 @@ describe "Range#bsearch" do it "returns nil if the block returns greater than zero for every element" do (0.3..3.0).bsearch { |x| x <=> -1 }.should be_nil - end it "returns nil if the block never returns zero" do @@ -213,6 +224,10 @@ describe "Range#bsearch" do (0...inf).bsearch { |x| x >= Float::MAX ? 0 : 1 }.should == Float::MAX end end + + it "returns enumerator when block not passed" do + (0.1...2.3).bsearch.kind_of?(Enumerator).should == true + end end context "with endless ranges and Integer values" do @@ -250,6 +265,10 @@ describe "Range#bsearch" do [1, 2, 3].should include(result) end end + + it "returns enumerator when block not passed" do + eval("(-2..)").bsearch.kind_of?(Enumerator).should == true + end end context "with endless ranges and Float values" do @@ -327,112 +346,121 @@ describe "Range#bsearch" do eval("(0.0...)").bsearch { 0 }.should != inf end end + + it "returns enumerator when block not passed" do + eval("(0.1..)").bsearch.kind_of?(Enumerator).should == true + end end + context "with beginless ranges and Integer values" do + context "with a block returning true or false" do + it "returns the smallest element for which block returns true" do + (..10).bsearch { |x| x >= 2 }.should == 2 + (...-1).bsearch { |x| x >= -10 }.should == -10 + end + end - ruby_version_is "2.7" do - context "with beginless ranges and Integer values" do - context "with a block returning true or false" do - it "returns the smallest element for which block returns true" do - eval("(..10)").bsearch { |x| x >= 2 }.should == 2 - eval("(...-1)").bsearch { |x| x >= -10 }.should == -10 - end + context "with a block returning negative, zero, positive numbers" do + it "returns nil if the block returns greater than zero for every element" do + (..0).bsearch { |x| 1 }.should be_nil end - context "with a block returning negative, zero, positive numbers" do - it "returns nil if the block returns greater than zero for every element" do - eval("(..0)").bsearch { |x| 1 }.should be_nil - end + it "returns nil if the block never returns zero" do + (..0).bsearch { |x| x > 5 ? -1 : 1 }.should be_nil + end - it "returns nil if the block never returns zero" do - eval("(..0)").bsearch { |x| x > 5 ? -1 : 1 }.should be_nil - end + it "accepts Float::INFINITY from the block" do + (..0).bsearch { |x| Float::INFINITY }.should be_nil + end - it "accepts Float::INFINITY from the block" do - eval("(..0)").bsearch { |x| Float::INFINITY }.should be_nil - end + it "returns an element at an index for which block returns 0.0" do + result = (..10).bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 } + result.should == 2 + end - it "returns an element at an index for which block returns 0.0" do - result = eval("(..10)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 } - result.should == 2 - end + it "returns an element at an index for which block returns 0" do + result = (...10).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 } + [1, 2, 3].should include(result) + end + end + + it "returns enumerator when block not passed" do + (..10).bsearch.kind_of?(Enumerator).should == true + end + end - it "returns an element at an index for which block returns 0" do - result = eval("(...10)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 } - [1, 2, 3].should include(result) - end + context "with beginless ranges and Float values" do + context "with a block returning true or false" do + it "returns nil if the block returns true for every element" do + (..-0.1).bsearch { |x| x > 0.0 }.should be_nil + (...-0.1).bsearch { |x| x > 0.0 }.should be_nil + end + + it "returns nil if the block returns nil for every element" do + (..-0.1).bsearch { |x| nil }.should be_nil + (...-0.1).bsearch { |x| nil }.should be_nil + end + + it "returns the smallest element for which block returns true" do + (..10).bsearch { |x| x >= 2 }.should == 2 + (..10).bsearch { |x| x >= 1 }.should == 1 + end + + it "works with infinity bounds" do + inf = Float::INFINITY + (..inf).bsearch { |x| true }.should == -inf + (...inf).bsearch { |x| true }.should == -inf + (..-inf).bsearch { |x| true }.should == -inf + (...-inf).bsearch { |x| true }.should == nil end end - context "with beginless ranges and Float values" do - context "with a block returning true or false" do - it "returns nil if the block returns true for every element" do - eval("(..-0.1)").bsearch { |x| x > 0.0 }.should be_nil - eval("(...-0.1)").bsearch { |x| x > 0.0 }.should be_nil - end - - it "returns nil if the block returns nil for every element" do - eval("(..-0.1)").bsearch { |x| nil }.should be_nil - eval("(...-0.1)").bsearch { |x| nil }.should be_nil - end - - it "returns the smallest element for which block returns true" do - eval("(..10)").bsearch { |x| x >= 2 }.should == 2 - eval("(..10)").bsearch { |x| x >= 1 }.should == 1 - end - - it "works with infinity bounds" do - inf = Float::INFINITY - eval("(..inf)").bsearch { |x| true }.should == -inf - eval("(...inf)").bsearch { |x| true }.should == -inf - eval("(..-inf)").bsearch { |x| true }.should == -inf - eval("(...-inf)").bsearch { |x| true }.should == nil - end - end - - context "with a block returning negative, zero, positive numbers" do - it "returns nil if the block returns less than zero for every element" do - eval("(..5.0)").bsearch { |x| -1 }.should be_nil - eval("(...5.0)").bsearch { |x| -1 }.should be_nil - end - - it "returns nil if the block returns greater than zero for every element" do - eval("(..1.1)").bsearch { |x| 1 }.should be_nil - eval("(...1.1)").bsearch { |x| 1 }.should be_nil - end - - it "returns nil if the block never returns zero" do - eval("(..6.3)").bsearch { |x| x < 2 ? 1 : -1 }.should be_nil - end - - it "accepts (+/-)Float::INFINITY from the block" do - eval("(..5.0)").bsearch { |x| Float::INFINITY }.should be_nil - eval("(..7.0)").bsearch { |x| -Float::INFINITY }.should be_nil - end - - it "returns an element at an index for which block returns 0.0" do - result = eval("(..8.0)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 } - result.should == 2 - end - - it "returns an element at an index for which block returns 0" do - result = eval("(..8.0)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 } - result.should >= 1 - result.should <= 3 - end - - it "works with infinity bounds" do - inf = Float::INFINITY - eval("(..-inf)").bsearch { |x| 1 }.should == nil - eval("(...-inf)").bsearch { |x| 1 }.should == nil - eval("(..inf)").bsearch { |x| x == inf ? 0 : 1 }.should == inf - eval("(...inf)").bsearch { |x| x == inf ? 0 : 1 }.should == nil - eval("(..-inf)").bsearch { |x| x == -inf ? 0 : -1 }.should == -inf - eval("(...-inf)").bsearch { |x| x == -inf ? 0 : -1 }.should == nil - eval("(..inf)").bsearch { |x| 3 - x }.should == 3 - eval("(...inf)").bsearch { |x| 3 - x }.should == 3 - end + context "with a block returning negative, zero, positive numbers" do + it "returns nil if the block returns less than zero for every element" do + (..5.0).bsearch { |x| -1 }.should be_nil + (...5.0).bsearch { |x| -1 }.should be_nil + end + + it "returns nil if the block returns greater than zero for every element" do + (..1.1).bsearch { |x| 1 }.should be_nil + (...1.1).bsearch { |x| 1 }.should be_nil + end + + it "returns nil if the block never returns zero" do + (..6.3).bsearch { |x| x < 2 ? 1 : -1 }.should be_nil + end + + it "accepts (+/-)Float::INFINITY from the block" do + (..5.0).bsearch { |x| Float::INFINITY }.should be_nil + (..7.0).bsearch { |x| -Float::INFINITY }.should be_nil end + + it "returns an element at an index for which block returns 0.0" do + result = (..8.0).bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 } + result.should == 2 + end + + it "returns an element at an index for which block returns 0" do + result = (..8.0).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 } + result.should >= 1 + result.should <= 3 + end + + it "works with infinity bounds" do + inf = Float::INFINITY + (..-inf).bsearch { |x| 1 }.should == nil + (...-inf).bsearch { |x| 1 }.should == nil + (..inf).bsearch { |x| x == inf ? 0 : 1 }.should == inf + (...inf).bsearch { |x| x == inf ? 0 : 1 }.should == nil + (..-inf).bsearch { |x| x == -inf ? 0 : -1 }.should == -inf + (...-inf).bsearch { |x| x == -inf ? 0 : -1 }.should == nil + (..inf).bsearch { |x| 3 - x }.should == 3 + (...inf).bsearch { |x| 3 - x }.should == 3 + end + end + + it "returns enumerator when block not passed" do + (..-0.1).bsearch.kind_of?(Enumerator).should == true end end end diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb index e795026230..65878aaabe 100644 --- a/spec/ruby/core/range/case_compare_spec.rb +++ b/spec/ruby/core/range/case_compare_spec.rb @@ -8,8 +8,12 @@ describe "Range#===" do (range === RangeSpecs::WithoutSucc.new(2)).should == true end - ruby_version_is "2.7" do - it_behaves_like :range_cover_and_include, :=== - it_behaves_like :range_cover, :=== + it_behaves_like :range_cover_and_include, :=== + it_behaves_like :range_cover, :=== + + ruby_bug "#19533", "3.2"..."3.3" do + it "returns true on any value if begin and end are both nil" do + (nil..nil).should === 1 + end end end diff --git a/spec/ruby/core/range/clone_spec.rb b/spec/ruby/core/range/clone_spec.rb new file mode 100644 index 0000000000..cf6ce74da0 --- /dev/null +++ b/spec/ruby/core/range/clone_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../spec_helper' + +describe "Range#clone" do + it "duplicates the range" do + original = (1..3) + copy = original.clone + copy.begin.should == 1 + copy.end.should == 3 + copy.should_not.exclude_end? + copy.should_not.equal? original + + original = ("a"..."z") + copy = original.clone + copy.begin.should == "a" + copy.end.should == "z" + copy.should.exclude_end? + copy.should_not.equal? original + end + + it "maintains the frozen state" do + (1..2).clone.frozen?.should == (1..2).frozen? + (1..).clone.frozen?.should == (1..).frozen? + Range.new(1, 2).clone.frozen?.should == Range.new(1, 2).frozen? + Class.new(Range).new(1, 2).clone.frozen?.should == Class.new(Range).new(1, 2).frozen? + end +end diff --git a/spec/ruby/core/range/count_spec.rb b/spec/ruby/core/range/count_spec.rb index f6f60fa054..24d4a9caf3 100644 --- a/spec/ruby/core/range/count_spec.rb +++ b/spec/ruby/core/range/count_spec.rb @@ -1,14 +1,12 @@ require_relative '../../spec_helper' describe "Range#count" do - ruby_version_is "2.7" do - it "returns Infinity for beginless ranges without arguments or blocks" do - inf = Float::INFINITY - eval("('a'...)").count.should == inf - eval("(7..)").count.should == inf - eval("(...'a')").count.should == inf - eval("(...nil)").count.should == inf - eval("(..10.0)").count.should == inf - end + it "returns Infinity for beginless ranges without arguments or blocks" do + inf = Float::INFINITY + eval("('a'...)").count.should == inf + eval("(7..)").count.should == inf + (...'a').count.should == inf + (...nil).count.should == inf + (..10.0).count.should == inf end end diff --git a/spec/ruby/core/range/cover_spec.rb b/spec/ruby/core/range/cover_spec.rb index fa881607e9..eb7cddc967 100644 --- a/spec/ruby/core/range/cover_spec.rb +++ b/spec/ruby/core/range/cover_spec.rb @@ -7,4 +7,8 @@ describe "Range#cover?" do it_behaves_like :range_cover_and_include, :cover? it_behaves_like :range_cover, :cover? it_behaves_like :range_cover_subrange, :cover? + + it "covers U+9995 in the range U+0999..U+9999" do + ("\u{999}".."\u{9999}").cover?("\u{9995}").should be_true + end end diff --git a/spec/ruby/core/range/dup_spec.rb b/spec/ruby/core/range/dup_spec.rb index 6c9d0c954a..fab3c3f1b2 100644 --- a/spec/ruby/core/range/dup_spec.rb +++ b/spec/ruby/core/range/dup_spec.rb @@ -2,14 +2,22 @@ require_relative '../../spec_helper' describe "Range#dup" do it "duplicates the range" do - copy = (1..3).dup + original = (1..3) + copy = original.dup copy.begin.should == 1 copy.end.should == 3 copy.should_not.exclude_end? + copy.should_not.equal?(original) copy = ("a"..."z").dup copy.begin.should == "a" copy.end.should == "z" copy.should.exclude_end? end + + it "creates an unfrozen range" do + (1..2).dup.should_not.frozen? + (1..).dup.should_not.frozen? + Range.new(1, 2).dup.should_not.frozen? + end end diff --git a/spec/ruby/core/range/each_spec.rb b/spec/ruby/core/range/each_spec.rb index 6b33f57737..ecae17c881 100644 --- a/spec/ruby/core/range/each_spec.rb +++ b/spec/ruby/core/range/each_spec.rb @@ -58,10 +58,8 @@ describe "Range#each" do a.should == ["A", "B", "C", "D"] end - ruby_version_is "2.7" do - it "raises a TypeError beginless ranges" do - -> { eval("(..2)").each { |x| x } }.should raise_error(TypeError) - end + it "raises a TypeError beginless ranges" do + -> { (..2).each { |x| x } }.should raise_error(TypeError) end it "raises a TypeError if the first element does not respond to #succ" do diff --git a/spec/ruby/core/range/equal_value_spec.rb b/spec/ruby/core/range/equal_value_spec.rb index 0aaebfb59a..83dcf5cec8 100644 --- a/spec/ruby/core/range/equal_value_spec.rb +++ b/spec/ruby/core/range/equal_value_spec.rb @@ -12,9 +12,7 @@ describe "Range#==" do eval("(1.0..)").should == eval("(1.0..)") end - ruby_version_is "2.7" do - it "returns true if the endpoints are == for beginless ranges" do - eval("(...10)").should == eval("(...10)") - end + it "returns true if the endpoints are == for beginless ranges" do + (...10).should == (...10) end end diff --git a/spec/ruby/core/range/first_spec.rb b/spec/ruby/core/range/first_spec.rb index c5c90800ac..2af935f439 100644 --- a/spec/ruby/core/range/first_spec.rb +++ b/spec/ruby/core/range/first_spec.rb @@ -47,9 +47,7 @@ describe "Range#first" do -> { (2..3).first("1") }.should raise_error(TypeError) end - ruby_version_is "2.7" do - it "raises a RangeError when called on an beginless range" do - -> { eval("(..1)").first }.should raise_error(RangeError) - end + it "raises a RangeError when called on an beginless range" do + -> { (..1).first }.should raise_error(RangeError) end end diff --git a/spec/ruby/core/range/frozen_spec.rb b/spec/ruby/core/range/frozen_spec.rb new file mode 100644 index 0000000000..8dab5e5339 --- /dev/null +++ b/spec/ruby/core/range/frozen_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../spec_helper' + +# There is no Range#frozen? method but this feels like the best place for these specs +describe "Range#frozen?" do + it "is true for literal ranges" do + (1..2).should.frozen? + (1..).should.frozen? + (..1).should.frozen? + end + + it "is true for Range.new" do + Range.new(1, 2).should.frozen? + Range.new(1, nil).should.frozen? + Range.new(nil, 1).should.frozen? + end + + it "is false for instances of a subclass of Range" do + sub_range = Class.new(Range).new(1, 2) + sub_range.should_not.frozen? + end + + it "is false for Range.allocate" do + Range.allocate.should_not.frozen? + end +end diff --git a/spec/ruby/core/range/include_spec.rb b/spec/ruby/core/range/include_spec.rb index b2c7a54545..277de205d1 100644 --- a/spec/ruby/core/range/include_spec.rb +++ b/spec/ruby/core/range/include_spec.rb @@ -7,4 +7,8 @@ require_relative 'shared/cover' describe "Range#include?" do it_behaves_like :range_cover_and_include, :include? it_behaves_like :range_include, :include? + + it "does not include U+9995 in the range U+0999..U+9999" do + ("\u{999}".."\u{9999}").include?("\u{9995}").should be_false + end end diff --git a/spec/ruby/core/range/initialize_spec.rb b/spec/ruby/core/range/initialize_spec.rb index 8a6ca65daa..c653caf0c6 100644 --- a/spec/ruby/core/range/initialize_spec.rb +++ b/spec/ruby/core/range/initialize_spec.rb @@ -27,18 +27,9 @@ describe "Range#initialize" do -> { @range.send(:initialize, 1, 3, 5, 7, 9) }.should raise_error(ArgumentError) end - ruby_version_is ""..."3.0" do - it "raises a NameError if called on an already initialized Range" do - -> { (0..1).send(:initialize, 1, 3) }.should raise_error(NameError) - -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(NameError) - end - end - - ruby_version_is "3.0" do - it "raises a FrozenError if called on an already initialized Range" do - -> { (0..1).send(:initialize, 1, 3) }.should raise_error(FrozenError) - -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(FrozenError) - end + it "raises a FrozenError if called on an already initialized Range" do + -> { (0..1).send(:initialize, 1, 3) }.should raise_error(FrozenError) + -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(FrozenError) end it "raises an ArgumentError if arguments don't respond to <=>" do diff --git a/spec/ruby/core/range/inspect_spec.rb b/spec/ruby/core/range/inspect_spec.rb index f49882e6ce..072de123b7 100644 --- a/spec/ruby/core/range/inspect_spec.rb +++ b/spec/ruby/core/range/inspect_spec.rb @@ -17,29 +17,13 @@ describe "Range#inspect" do eval("(0.1...)").inspect.should == "0.1..." end - ruby_version_is '2.7' do - it "works for beginless ranges" do - eval("(..1)").inspect.should == "..1" - eval("(...0.1)").inspect.should == "...0.1" - end - - it "works for nil ... nil ranges" do - eval("(..nil)").inspect.should == "nil..nil" - eval("(nil...)").inspect.should == "nil...nil" - end + it "works for beginless ranges" do + (..1).inspect.should == "..1" + (...0.1).inspect.should == "...0.1" end - ruby_version_is ''...'2.7' do - it "returns a tainted string if either end is tainted" do - (("a".taint)..."c").inspect.tainted?.should be_true - ("a"...("c".taint)).inspect.tainted?.should be_true - ("a"..."c").taint.inspect.tainted?.should be_true - end - - it "returns a untrusted string if either end is untrusted" do - (("a".untrust)..."c").inspect.untrusted?.should be_true - ("a"...("c".untrust)).inspect.untrusted?.should be_true - ("a"..."c").untrust.inspect.untrusted?.should be_true - end + it "works for nil ... nil ranges" do + (..nil).inspect.should == "nil..nil" + eval("(nil...)").inspect.should == "nil...nil" end end diff --git a/spec/ruby/core/range/last_spec.rb b/spec/ruby/core/range/last_spec.rb index d7ef776b42..6698686dd5 100644 --- a/spec/ruby/core/range/last_spec.rb +++ b/spec/ruby/core/range/last_spec.rb @@ -8,6 +8,12 @@ describe "Range#last" do (1..5).last(3).should == [3, 4, 5] end + ruby_bug '#18994', '2.7'...'3.2' do + it "returns the specified number if elements for single element inclusive range" do + (1..1).last(1).should == [1] + end + end + it "returns an empty array for an empty Range" do (0...0).last(2).should == [] end diff --git a/spec/ruby/core/range/max_spec.rb b/spec/ruby/core/range/max_spec.rb index a970144d66..a3bbc31e7d 100644 --- a/spec/ruby/core/range/max_spec.rb +++ b/spec/ruby/core/range/max_spec.rb @@ -50,17 +50,15 @@ describe "Range#max" do -> { eval("(1..)").max }.should raise_error(RangeError) end - ruby_version_is "3.0" do - it "returns the end point for beginless ranges" do - eval("(..1)").max.should == 1 - eval("(..1.0)").max.should == 1.0 - end + it "returns the end point for beginless ranges" do + (..1).max.should == 1 + (..1.0).max.should == 1.0 + end - it "raises for an exclusive beginless range" do - -> { - eval("(...1)").max - }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value') - end + it "raises for an exclusive beginless range" do + -> { + (...1).max + }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value') end end @@ -97,9 +95,7 @@ describe "Range#max given a block" do (5...5).max {|x,y| x <=> y}.should be_nil end - ruby_version_is "2.7" do - it "raises RangeError when called with custom comparison method on an beginless range" do - -> { eval("(..1)").max {|a, b| a} }.should raise_error(RangeError) - end + it "raises RangeError when called with custom comparison method on an beginless range" do + -> { (..1).max {|a, b| a} }.should raise_error(RangeError) end end diff --git a/spec/ruby/core/range/min_spec.rb b/spec/ruby/core/range/min_spec.rb index 6e56cc733b..89310ee589 100644 --- a/spec/ruby/core/range/min_spec.rb +++ b/spec/ruby/core/range/min_spec.rb @@ -44,10 +44,8 @@ describe "Range#min" do eval("(1.0...)").min.should == 1.0 end - ruby_version_is "2.7" do - it "raises RangeError when called on an beginless range" do - -> { eval("(..1)").min }.should raise_error(RangeError) - end + it "raises RangeError when called on an beginless range" do + -> { (..1).min }.should raise_error(RangeError) end end diff --git a/spec/ruby/core/range/minmax_spec.rb b/spec/ruby/core/range/minmax_spec.rb index 1db9bfce38..6651ae3726 100644 --- a/spec/ruby/core/range/minmax_spec.rb +++ b/spec/ruby/core/range/minmax_spec.rb @@ -1,6 +1,5 @@ require_relative '../../spec_helper' -# These specs use Range.new instead of the literal notation for beginless Ranges so they parse fine on Ruby < 2.7 describe 'Range#minmax' do before(:each) do @x = mock('x') @@ -13,37 +12,26 @@ describe 'Range#minmax' do end describe 'on an inclusive range' do - ruby_version_is ''...'2.7' do - it 'should try to iterate endlessly on an endless range' do - @x.should_receive(:succ).once.and_return(@y) - range = (@x..) - - -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/) - end - end - - ruby_version_is '2.7' do - it 'should raise RangeError on an endless range without iterating the range' do - @x.should_not_receive(:succ) - - range = (@x..) + it 'should raise RangeError on an endless range without iterating the range' do + @x.should_not_receive(:succ) - -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') - end + range = (@x..) - it 'raises RangeError or ArgumentError on a beginless range' do - range = Range.new(nil, @x) + -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') + end - -> { range.minmax }.should raise_error(StandardError) { |e| - if RangeError === e - # error from #min - -> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range') - else - # error from #max - -> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed') - end - } - end + it 'raises RangeError or ArgumentError on a beginless range' do + range = (..@x) + + -> { range.minmax }.should raise_error(StandardError) { |e| + if RangeError === e + # error from #min + -> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range') + else + # error from #max + -> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed') + end + } end it 'should return beginning of range if beginning and end are equal without iterating the range' do @@ -58,34 +46,22 @@ describe 'Range#minmax' do (@y..@x).minmax.should == [nil, nil] end - ruby_version_is ''...'2.7' do - it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do - @x.should_receive(:succ).once.and_return(@y) - - (@x..@y).minmax.should == [@x, @y] - end - end - - ruby_version_is '2.7' do - it 'should return the minimum and maximum values for a non-numeric range without iterating the range' do - @x.should_not_receive(:succ) + it 'should return the minimum and maximum values for a non-numeric range without iterating the range' do + @x.should_not_receive(:succ) - (@x..@y).minmax.should == [@x, @y] - end + (@x..@y).minmax.should == [@x, @y] end it 'should return the minimum and maximum values for a numeric range' do (1..3).minmax.should == [1, 3] end - ruby_version_is '2.7' do - it 'should return the minimum and maximum values for a numeric range without iterating the range' do - # We cannot set expectations on integers, - # so we "prevent" iteration by picking a value that would iterate until the spec times out. - range_end = Float::INFINITY + it 'should return the minimum and maximum values for a numeric range without iterating the range' do + # We cannot set expectations on integers, + # so we "prevent" iteration by picking a value that would iterate until the spec times out. + range_end = Float::INFINITY - (1..range_end).minmax.should == [1, range_end] - end + (1..range_end).minmax.should == [1, range_end] end it 'should return the minimum and maximum values according to the provided block by iterating the range' do @@ -96,69 +72,53 @@ describe 'Range#minmax' do end describe 'on an exclusive range' do - ruby_version_is ''...'2.7' do - # Endless ranges introduced in 2.6 - it 'should try to iterate endlessly on an endless range' do - @x.should_receive(:succ).once.and_return(@y) - range = (@x...) + it 'should raise RangeError on an endless range' do + @x.should_not_receive(:succ) + range = (@x...) - -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/) - end + -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') end - ruby_version_is '2.7' do - it 'should raise RangeError on an endless range' do - @x.should_not_receive(:succ) - range = (@x...) - - -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') - end - - it 'should raise RangeError on a beginless range' do - range = Range.new(nil, @x, true) + it 'should raise RangeError on a beginless range' do + range = (...@x) - -> { range.minmax }.should raise_error(RangeError, - /cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/) - end + -> { range.minmax }.should raise_error(RangeError, + /cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/) end - ruby_bug "#17014", "2.7.0"..."3.0" do - it 'should return nil pair if beginning and end are equal without iterating the range' do - @x.should_not_receive(:succ) + it 'should return nil pair if beginning and end are equal without iterating the range' do + @x.should_not_receive(:succ) - (@x...@x).minmax.should == [nil, nil] - end + (@x...@x).minmax.should == [nil, nil] + end - it 'should return nil pair if beginning is greater than end without iterating the range' do - @y.should_not_receive(:succ) + it 'should return nil pair if beginning is greater than end without iterating the range' do + @y.should_not_receive(:succ) - (@y...@x).minmax.should == [nil, nil] - end + (@y...@x).minmax.should == [nil, nil] + end - it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do - @x.should_receive(:succ).once.and_return(@y) + it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do + @x.should_receive(:succ).once.and_return(@y) - (@x...@y).minmax.should == [@x, @x] - end + (@x...@y).minmax.should == [@x, @x] end it 'should return the minimum and maximum values for a numeric range' do (1...3).minmax.should == [1, 2] end - ruby_version_is '2.7' do - it 'should return the minimum and maximum values for a numeric range without iterating the range' do - # We cannot set expectations on integers, - # so we "prevent" iteration by picking a value that would iterate until the spec times out. - range_end = bignum_value + it 'should return the minimum and maximum values for a numeric range without iterating the range' do + # We cannot set expectations on integers, + # so we "prevent" iteration by picking a value that would iterate until the spec times out. + range_end = bignum_value - (1...range_end).minmax.should == [1, range_end - 1] - end + (1...range_end).minmax.should == [1, range_end - 1] + end - it 'raises TypeError if the end value is not an integer' do - range = (0...Float::INFINITY) - -> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value') - end + it 'raises TypeError if the end value is not an integer' do + range = (0...Float::INFINITY) + -> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value') end it 'should return the minimum and maximum values according to the provided block by iterating the range' do diff --git a/spec/ruby/core/range/new_spec.rb b/spec/ruby/core/range/new_spec.rb index a4de4963e7..3cab887799 100644 --- a/spec/ruby/core/range/new_spec.rb +++ b/spec/ruby/core/range/new_spec.rb @@ -42,24 +42,16 @@ describe "Range.new" do end describe "beginless/endless range" do - ruby_version_is ""..."2.7" do - it "does not allow range without left boundary" do - -> { Range.new(nil, 1) }.should raise_error(ArgumentError, /bad value for range/) - end + it "allows beginless left boundary" do + range = Range.new(nil, 1) + range.begin.should == nil end - ruby_version_is "2.7" do - it "allows beginless left boundary" do - range = Range.new(nil, 1) - range.begin.should == nil - end - - it "distinguishes ranges with included and excluded right boundary" do - range_exclude = Range.new(nil, 1, true) - range_include = Range.new(nil, 1, false) + it "distinguishes ranges with included and excluded right boundary" do + range_exclude = Range.new(nil, 1, true) + range_include = Range.new(nil, 1, false) - range_exclude.should_not == range_include - end + range_exclude.should_not == range_include end it "allows endless right boundary" do @@ -73,5 +65,13 @@ describe "Range.new" do range_exclude.should_not == range_include end + + it "creates a frozen range if the class is Range.class" do + Range.new(1, 2).should.frozen? + end + + it "does not create a frozen range if the class is not Range.class" do + Class.new(Range).new(1, 2).should_not.frozen? + end end end diff --git a/spec/ruby/core/range/shared/cover.rb b/spec/ruby/core/range/shared/cover.rb index f3c7d22668..0b41a26455 100644 --- a/spec/ruby/core/range/shared/cover.rb +++ b/spec/ruby/core/range/shared/cover.rb @@ -151,45 +151,43 @@ describe :range_cover_subrange, shared: true do end end - ruby_version_is "2.7" do - it "allows self to be a beginless range" do - eval("(...10)").send(@method, (3..7)).should be_true - eval("(...10)").send(@method, (3..15)).should be_false + it "allows self to be a beginless range" do + (...10).send(@method, (3..7)).should be_true + (...10).send(@method, (3..15)).should be_false - eval("(..7.9)").send(@method, (2.5..6.5)).should be_true - eval("(..7.9)").send(@method, (2.5..8.5)).should be_false + (..7.9).send(@method, (2.5..6.5)).should be_true + (..7.9).send(@method, (2.5..8.5)).should be_false - eval("(..'i')").send(@method, ('d'..'f')).should be_true - eval("(..'i')").send(@method, ('d'..'z')).should be_false - end + (..'i').send(@method, ('d'..'f')).should be_true + (..'i').send(@method, ('d'..'z')).should be_false + end - it "allows self to be a endless range" do - eval("(0...)").send(@method, (3..7)).should be_true - eval("(5...)").send(@method, (3..15)).should be_false + it "allows self to be a endless range" do + eval("(0...)").send(@method, (3..7)).should be_true + eval("(5...)").send(@method, (3..15)).should be_false - eval("(1.1..)").send(@method, (2.5..6.5)).should be_true - eval("(3.3..)").send(@method, (2.5..8.5)).should be_false + eval("(1.1..)").send(@method, (2.5..6.5)).should be_true + eval("(3.3..)").send(@method, (2.5..8.5)).should be_false - eval("('a'..)").send(@method, ('d'..'f')).should be_true - eval("('p'..)").send(@method, ('d'..'z')).should be_false - end + eval("('a'..)").send(@method, ('d'..'f')).should be_true + eval("('p'..)").send(@method, ('d'..'z')).should be_false + end - it "accepts beginless range argument" do - eval("(..10)").send(@method, eval("(...10)")).should be_true - (0..10).send(@method, eval("(...10)")).should be_false + it "accepts beginless range argument" do + (..10).send(@method, (...10)).should be_true + (0..10).send(@method, (...10)).should be_false - (1.1..7.9).send(@method, eval("(...10.5)")).should be_false + (1.1..7.9).send(@method, (...10.5)).should be_false - ('c'..'i').send(@method, eval("(..'i')")).should be_false - end + ('c'..'i').send(@method, (..'i')).should be_false + end - it "accepts endless range argument" do - eval("(0..)").send(@method, eval("(0...)")).should be_true - (0..10).send(@method, eval("(0...)")).should be_false + it "accepts endless range argument" do + eval("(0..)").send(@method, eval("(0...)")).should be_true + (0..10).send(@method, eval("(0...)")).should be_false - (1.1..7.9).send(@method, eval("(0.8...)")).should be_false + (1.1..7.9).send(@method, eval("(0.8...)")).should be_false - ('c'..'i').send(@method, eval("('a'..)")).should be_false - end + ('c'..'i').send(@method, eval("('a'..)")).should be_false end end diff --git a/spec/ruby/core/range/shared/cover_and_include.rb b/spec/ruby/core/range/shared/cover_and_include.rb index e978e39af5..f36a2cef8b 100644 --- a/spec/ruby/core/range/shared/cover_and_include.rb +++ b/spec/ruby/core/range/shared/cover_and_include.rb @@ -24,11 +24,9 @@ describe :range_cover_and_include, shared: true do eval("(0.5...)").send(@method, 2.4).should == true end - ruby_version_is "2.7" do - it "returns true if other is an element of self for beginless ranges" do - eval("(..10)").send(@method, 2.4).should == true - eval("(...10.5)").send(@method, 2.4).should == true - end + it "returns true if other is an element of self for beginless ranges" do + (..10).send(@method, 2.4).should == true + (...10.5).send(@method, 2.4).should == true end it "compares values using <=>" do @@ -59,7 +57,6 @@ describe :range_cover_and_include, shared: true do it "returns true if argument is less than the last value of the range and greater than the first value" do (20..30).send(@method, 28).should be_true ('e'..'h').send(@method, 'g').should be_true - ("\u{999}".."\u{9999}").send @method, "\u{9995}" end it "returns true if argument is sole element in the range" do diff --git a/spec/ruby/core/range/size_spec.rb b/spec/ruby/core/range/size_spec.rb index 0019c5ff00..a1fe3ce17d 100644 --- a/spec/ruby/core/range/size_spec.rb +++ b/spec/ruby/core/range/size_spec.rb @@ -4,42 +4,93 @@ describe "Range#size" do it "returns the number of elements in the range" do (1..16).size.should == 16 (1...16).size.should == 15 - - (1.0..16.0).size.should == 16 - (1.0...16.0).size.should == 15 - (1.0..15.9).size.should == 15 - (1.1..16.0).size.should == 15 - (1.1..15.9).size.should == 15 end it "returns 0 if last is less than first" do (16..0).size.should == 0 - (16.0..0.0).size.should == 0 - (Float::INFINITY..0).size.should == 0 end it 'returns Float::INFINITY for increasing, infinite ranges' do (0..Float::INFINITY).size.should == Float::INFINITY - (-Float::INFINITY..0).size.should == Float::INFINITY - (-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY end it 'returns Float::INFINITY for endless ranges if the start is numeric' do eval("(1..)").size.should == Float::INFINITY - eval("(0.5...)").size.should == Float::INFINITY end it 'returns nil for endless ranges if the start is not numeric' do eval("('z'..)").size.should == nil - eval("([]...)").size.should == nil end - ruby_version_is "2.7" do + ruby_version_is ""..."3.2" do it 'returns Float::INFINITY for all beginless ranges' do - eval("(..1)").size.should == Float::INFINITY - eval("(...0.5)").size.should == Float::INFINITY - eval("(..nil)").size.should == Float::INFINITY - eval("(...'o')").size.should == Float::INFINITY + (..1).size.should == Float::INFINITY + (...0.5).size.should == Float::INFINITY + (..nil).size.should == Float::INFINITY + (...'o').size.should == Float::INFINITY + end + end + + ruby_version_is "3.2"..."3.4" do + it 'returns Float::INFINITY for all beginless ranges if the end is numeric' do + (..1).size.should == Float::INFINITY + (...0.5).size.should == Float::INFINITY + end + + it 'returns nil for all beginless ranges if the end is not numeric' do + (...'o').size.should == nil + end + + it 'returns nil if the start and the end is both nil' do + (nil..nil).size.should == nil + end + end + + ruby_version_is ""..."3.4" do + it "returns the number of elements in the range" do + (1.0..16.0).size.should == 16 + (1.0...16.0).size.should == 15 + (1.0..15.9).size.should == 15 + (1.1..16.0).size.should == 15 + (1.1..15.9).size.should == 15 + end + + it "returns 0 if last is less than first" do + (16.0..0.0).size.should == 0 + (Float::INFINITY..0).size.should == 0 + end + + it 'returns Float::INFINITY for increasing, infinite ranges' do + (-Float::INFINITY..0).size.should == Float::INFINITY + (-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY + end + + it 'returns Float::INFINITY for endless ranges if the start is numeric' do + eval("(0.5...)").size.should == Float::INFINITY + end + + it 'returns nil for endless ranges if the start is not numeric' do + eval("([]...)").size.should == nil + end + end + + ruby_version_is "3.4" do + it 'raises TypeError if a range is not iterable' do + -> { (1.0..16.0).size }.should raise_error(TypeError, /can't iterate from/) + -> { (1.0...16.0).size }.should raise_error(TypeError, /can't iterate from/) + -> { (1.0..15.9).size }.should raise_error(TypeError, /can't iterate from/) + -> { (1.1..16.0).size }.should raise_error(TypeError, /can't iterate from/) + -> { (1.1..15.9).size }.should raise_error(TypeError, /can't iterate from/) + -> { (16.0..0.0).size }.should raise_error(TypeError, /can't iterate from/) + -> { (Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/) + -> { (-Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/) + -> { (-Float::INFINITY..Float::INFINITY).size }.should raise_error(TypeError, /can't iterate from/) + -> { (..1).size }.should raise_error(TypeError, /can't iterate from/) + -> { (...0.5).size }.should raise_error(TypeError, /can't iterate from/) + -> { (..nil).size }.should raise_error(TypeError, /can't iterate from/) + -> { (...'o').size }.should raise_error(TypeError, /can't iterate from/) + -> { eval("(0.5...)").size }.should raise_error(TypeError, /can't iterate from/) + -> { eval("([]...)").size }.should raise_error(TypeError, /can't iterate from/) end end diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb index 4c69073854..64ea3de4ed 100644 --- a/spec/ruby/core/range/step_spec.rb +++ b/spec/ruby/core/range/step_spec.rb @@ -377,48 +377,21 @@ describe "Range#step" do end describe "when no block is given" do - ruby_version_is "3.0" do - it "raises an ArgumentError if step is 0" do - -> { (-1..1).step(0) }.should raise_error(ArgumentError) - end + it "raises an ArgumentError if step is 0" do + -> { (-1..1).step(0) }.should raise_error(ArgumentError) end describe "returned Enumerator" do describe "size" do - ruby_version_is ""..."3.0" do - it "raises a TypeError if step does not respond to #to_int" do - obj = mock("Range#step non-integer") - enum = (1..2).step(obj) - -> { enum.size }.should raise_error(TypeError) - end - - it "raises a TypeError if #to_int does not return an Integer" do - obj = mock("Range#step non-integer") - obj.should_receive(:to_int).and_return("1") - enum = (1..2).step(obj) - - -> { enum.size }.should raise_error(TypeError) - end + it "raises a TypeError if step does not respond to #to_int" do + obj = mock("Range#step non-integer") + -> { (1..2).step(obj) }.should raise_error(TypeError) end - ruby_version_is "3.0" do - it "raises a TypeError if step does not respond to #to_int" do - obj = mock("Range#step non-integer") - -> { (1..2).step(obj) }.should raise_error(TypeError) - end - - it "raises a TypeError if #to_int does not return an Integer" do - obj = mock("Range#step non-integer") - obj.should_receive(:to_int).and_return("1") - -> { (1..2).step(obj) }.should raise_error(TypeError) - end - end - - ruby_version_is ""..."3.0" do - it "returns Float::INFINITY for zero step" do - (-1..1).step(0).size.should == Float::INFINITY - (-1..1).step(0.0).size.should == Float::INFINITY - end + it "raises a TypeError if #to_int does not return an Integer" do + obj = mock("Range#step non-integer") + obj.should_receive(:to_int).and_return("1") + -> { (1..2).step(obj) }.should raise_error(TypeError) end it "returns the ceil of range size divided by the number of steps" do @@ -474,42 +447,45 @@ describe "Range#step" do end end + # We use .take below to ensure the enumerator works + # because that's an Enumerable method and so it uses the Enumerator behavior + # not just a method overridden in Enumerator::ArithmeticSequence. describe "type" do context "when both begin and end are numerics" do it "returns an instance of Enumerator::ArithmeticSequence" do (1..10).step.class.should == Enumerator::ArithmeticSequence + (1..10).step(3).take(4).should == [1, 4, 7, 10] end end - ruby_version_is "2.7" do - context "when begin is not defined and end is numeric" do - it "returns an instance of Enumerator::ArithmeticSequence" do - eval("(..10)").step.class.should == Enumerator::ArithmeticSequence - end + context "when begin is not defined and end is numeric" do + it "returns an instance of Enumerator::ArithmeticSequence" do + (..10).step.class.should == Enumerator::ArithmeticSequence end end context "when range is endless" do it "returns an instance of Enumerator::ArithmeticSequence when begin is numeric" do (1..).step.class.should == Enumerator::ArithmeticSequence + (1..).step(2).take(3).should == [1, 3, 5] end it "returns an instance of Enumerator when begin is not numeric" do ("a"..).step.class.should == Enumerator + ("a"..).step(2).take(3).should == %w[a c e] end end - ruby_version_is "2.7" do - context "when range is beginless and endless" do - it "returns an instance of Enumerator" do - Range.new(nil, nil).step.class.should == Enumerator - end + context "when range is beginless and endless" do + it "returns an instance of Enumerator" do + Range.new(nil, nil).step.class.should == Enumerator end end context "when begin and end are not numerics" do it "returns an instance of Enumerator" do ("a".."z").step.class.should == Enumerator + ("a".."z").step(3).take(4).should == %w[a d g j] end end end diff --git a/spec/ruby/core/range/to_a_spec.rb b/spec/ruby/core/range/to_a_spec.rb index 52ebc02941..b1d3de32db 100644 --- a/spec/ruby/core/range/to_a_spec.rb +++ b/spec/ruby/core/range/to_a_spec.rb @@ -33,9 +33,7 @@ describe "Range#to_a" do -> { eval("(1..)").to_a }.should raise_error(RangeError) end - ruby_version_is "2.7" do - it "throws an exception for beginless ranges" do - -> { eval("(..1)").to_a }.should raise_error(TypeError) - end + it "throws an exception for beginless ranges" do + -> { (..1).to_a }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/range/to_s_spec.rb b/spec/ruby/core/range/to_s_spec.rb index 581c2e7d90..460c330912 100644 --- a/spec/ruby/core/range/to_s_spec.rb +++ b/spec/ruby/core/range/to_s_spec.rb @@ -16,24 +16,8 @@ describe "Range#to_s" do eval("(1.0...)").to_s.should == "1.0..." end - ruby_version_is "2.7" do - it "can show beginless ranges" do - eval("(..1)").to_s.should == "..1" - eval("(...1.0)").to_s.should == "...1.0" - end - end - - ruby_version_is ''...'2.7' do - it "returns a tainted string if either end is tainted" do - (("a".taint)..."c").to_s.tainted?.should be_true - ("a"...("c".taint)).to_s.tainted?.should be_true - ("a"..."c").taint.to_s.tainted?.should be_true - end - - it "returns a untrusted string if either end is untrusted" do - (("a".untrust)..."c").to_s.untrusted?.should be_true - ("a"...("c".untrust)).to_s.untrusted?.should be_true - ("a"..."c").untrust.to_s.untrusted?.should be_true - end + it "can show beginless ranges" do + (..1).to_s.should == "..1" + (...1.0).to_s.should == "...1.0" end end |