1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Fix Range#{max,minmax} for range with integer beginning and non-integer end

Previously, for inclusive ranges, the max would show up as the
end of the range, even though the end was not an integer and would
not be the maximum value.  For exclusive ranges, max/minmax would
previously raise a TypeError, even though it is possible to get the
correct maximum.

This change to max/minmax also uncovered a similar error in cover?,
which calls max in certain cases, so adjust the code there so that
cover? still works as expected.

Fixes [Bug #17017]
This commit is contained in:
Jeremy Evans 2020-07-13 10:09:38 -07:00 committed by GitHub
parent a1bcfbe30c
commit 8900a25581
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
Notes: git 2020-07-14 02:10:03 +09:00
Merged: https://github.com/ruby/ruby/pull/3306

Merged-By: jeremyevans <code@jeremyevans.net>
2 changed files with 29 additions and 5 deletions

17
range.c
View file

@ -1234,6 +1234,13 @@ range_max(int argc, VALUE *argv, VALUE range)
if (c > 0)
return Qnil;
if (EXCL(range)) {
if (RB_INTEGER_TYPE_P(b) && !RB_INTEGER_TYPE_P(e)) {
VALUE end = e;
e = rb_funcall(e, rb_intern("floor"), 0);
if (!RTEST(rb_funcall(e, rb_intern("=="), 1, end))) {
return e;
}
}
if (!RB_INTEGER_TYPE_P(e)) {
rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
}
@ -1246,6 +1253,9 @@ range_max(int argc, VALUE *argv, VALUE range)
}
return rb_funcall(e, '-', 1, INT2FIX(1));
}
if (RB_INTEGER_TYPE_P(b) && !RB_INTEGER_TYPE_P(e)) {
e = rb_funcall(e, rb_intern("floor"), 0);
}
return e;
}
}
@ -1593,9 +1603,14 @@ r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val)
else if (cmp_end >= 0) {
return TRUE;
}
if (RB_INTEGER_TYPE_P(val_beg) && RB_INTEGER_TYPE_P(beg) &&
RB_INTEGER_TYPE_P(val_end) != RB_INTEGER_TYPE_P(end)) {
val_max = val_end;
}
else {
val_max = rb_rescue2(r_call_max, val, 0, Qnil, rb_eTypeError, (VALUE)0);
if (val_max == Qnil) return FALSE;
}
return r_less(end, val_max) >= 0;
}

View file

@ -107,11 +107,13 @@ class TestRange < Test::Unit::TestCase
assert_equal(1, (1...2).max)
assert_raise(RangeError) { (1..).max }
assert_raise(RangeError) { (1...).max }
assert_equal(2, (1..2.1).max)
assert_equal(2, (1...2.1).max)
assert_equal(2.0, (1.0..2.0).max)
assert_equal(nil, (2.0..1.0).max)
assert_raise(TypeError) { (1.0...2.0).max }
assert_raise(TypeError) { (1...1.5).max }
assert_equal(1, (1...1.5).max)
assert_raise(TypeError) { (1.5...2).max }
assert_equal(-0x80000002, ((-0x80000002)...(-0x80000001)).max)
@ -133,11 +135,13 @@ class TestRange < Test::Unit::TestCase
assert_equal([1, 1], (1...2).minmax)
assert_raise(RangeError) { (1..).minmax }
assert_raise(RangeError) { (1...).minmax }
assert_equal([1, 2], (1..2.1).minmax)
assert_equal([1, 2], (1...2.1).minmax)
assert_equal([1.0, 2.0], (1.0..2.0).minmax)
assert_equal([nil, nil], (2.0..1.0).minmax)
assert_raise(TypeError) { (1.0...2.0).minmax }
assert_raise(TypeError) { (1...1.5).minmax }
assert_equal([1, 1], (1..1.5).minmax)
assert_raise(TypeError) { (1.5...2).minmax }
assert_equal([-0x80000002, -0x80000002], ((-0x80000002)...(-0x80000001)).minmax)
@ -652,7 +656,12 @@ class TestRange < Test::Unit::TestCase
assert_not_operator(1..10, :cover?, 3...2)
assert_not_operator(1..10, :cover?, 3...3)
assert_not_operator('aa'..'zz', :cover?, 'aa'...'zzz')
assert_not_operator(1..10, :cover?, 1...10.1)
assert_not_operator(1...10.1, :cover?, 1..10.1)
assert_operator(1..10.1, :cover?, 1...10.1)
assert_operator(1..10.1, :cover?, 1...10)
assert_operator(1..10.1, :cover?, 1..10)
end
def test_beg_len