Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Range#minmax specs #777

Merged
merged 4 commits into from
Nov 13, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 170 additions & 0 deletions core/range/minmax_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
require_relative '../../spec_helper'

# These specs use Range.new instead of the literal notation so they parse fine on Ruby < 2.6
describe 'Range#minmax' do
before(:each) do
@x = mock('x')
@y = mock('y')

@x.should_receive(:<=>).with(@y).any_number_of_times.and_return(-1) # x < y
@x.should_receive(:<=>).with(@x).any_number_of_times.and_return(0) # x == x
@y.should_receive(:<=>).with(@x).any_number_of_times.and_return(1) # y > x
@y.should_receive(:<=>).with(@y).any_number_of_times.and_return(0) # y == y
end

describe 'on an inclusive range' do
ruby_version_is '2.6'...'2.7' do
it 'should try to iterate endlessly on an endless range' do
@x.should_receive(:succ).once.and_return(@y)
range = Range.new(@x, nil)
eregon marked this conversation as resolved.
Show resolved Hide resolved

-> { 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 = Range.new(@x, nil)

-> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
end

it 'raises RangeError or ArgumentError on a beginless range' do
range = Range.new(nil, @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
end

it 'should return begining of range if beginning and end are equal without iterating the range' do
@x.should_not_receive(:succ)

(@x..@x).minmax.should == [@x, @x]
end

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

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
eregon marked this conversation as resolved.
Show resolved Hide resolved
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)

(@x..@y).minmax.should == [@x, @y]
end
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

(1..range_end).minmax.should == [1, range_end]
end
end

it 'should return the minimum and maximum values according to the provided block by iterating the range' do
@x.should_receive(:succ).once.and_return(@y)

(@x..@y).minmax { |x, y| - (x <=> y) }.should == [@y, @x]
end
end

describe 'on an exclusive range' do
ruby_version_is '2.6'...'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 = Range.new(@x, nil, true)

-> { 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' do
@x.should_not_receive(:succ)
range = Range.new(@x, nil, true)

-> { 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)

-> { 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
eregon marked this conversation as resolved.
Show resolved Hide resolved
end

ruby_bug "#17014", "2.7.0"..."2.8" do
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

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

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
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

(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
end

it 'should return the minimum and maximum values according to the provided block by iterating the range' do
@x.should_receive(:succ).once.and_return(@y)

(@x...@y).minmax { |x, y| - (x <=> y) }.should == [@x, @x]
end
end
end