mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
bf1a6771f3
The implementation of Range#minmax added in d5c60214c4
causes the
following incorrect behaviour:
('a'...'c').minmax => ["a", ["a", "b"]]
instead of
('a'...'c').minmax => ["a", "b"]
This is because the C implementation of Range#minmax (range_minmax)
directly delegates to the C implementation of Range#min (range_min) and
Range#max (range_max), without changing the execution context.
Range#max's C implementation (range_max), when given a non-numeric
exclusive range, delegates to super, which is meant to call
Enumerable#max. However, because range_max is called directly by
range_minmax, super calls Enumerable#minmax instead, causing the
incorrect nesting.
Perhaps it is possible to change the execution context in an optimized
manner, but the simplest solution seems to be to just explicitly
delegate from Range#minmax to Range#min and Range#max.
966 lines
28 KiB
Ruby
966 lines
28 KiB
Ruby
# frozen_string_literal: false
|
|
require 'test/unit'
|
|
require 'delegate'
|
|
require 'timeout'
|
|
require 'bigdecimal'
|
|
require 'rbconfig/sizeof'
|
|
|
|
class TestRange < Test::Unit::TestCase
|
|
def test_new
|
|
assert_equal((0..2), Range.new(0, 2))
|
|
assert_equal((0..2), Range.new(0, 2, false))
|
|
assert_equal((0...2), Range.new(0, 2, true))
|
|
|
|
assert_raise(ArgumentError) { (1.."3") }
|
|
|
|
assert_equal((0..nil), Range.new(0, nil, false))
|
|
assert_equal((0...nil), Range.new(0, nil, true))
|
|
|
|
obj = Object.new
|
|
def obj.<=>(other)
|
|
raise RuntimeError, "cmp"
|
|
end
|
|
assert_raise_with_message(RuntimeError, "cmp") { (obj..3) }
|
|
end
|
|
|
|
def test_frozen_initialize
|
|
r = Range.allocate
|
|
r.freeze
|
|
assert_raise(FrozenError){r.__send__(:initialize, 1, 2)}
|
|
end
|
|
|
|
def test_range_string
|
|
# XXX: Is this really the test of Range?
|
|
assert_equal([], ("a" ... "a").to_a)
|
|
assert_equal(["a"], ("a" .. "a").to_a)
|
|
assert_equal(["a"], ("a" ... "b").to_a)
|
|
assert_equal(["a", "b"], ("a" .. "b").to_a)
|
|
assert_equal([*"a".."z", "aa"], ("a"..).take(27))
|
|
end
|
|
|
|
def test_range_numeric_string
|
|
assert_equal(["6", "7", "8"], ("6".."8").to_a, "[ruby-talk:343187]")
|
|
assert_equal(["6", "7"], ("6"..."8").to_a)
|
|
assert_equal(["9", "10"], ("9".."10").to_a)
|
|
assert_equal(["9", "10"], ("9"..).take(2))
|
|
assert_equal(["09", "10"], ("09".."10").to_a, "[ruby-dev:39361]")
|
|
assert_equal(["9", "10"], (SimpleDelegator.new("9").."10").to_a)
|
|
assert_equal(["9", "10"], (SimpleDelegator.new("9")..).take(2))
|
|
assert_equal(["9", "10"], ("9"..SimpleDelegator.new("10")).to_a)
|
|
end
|
|
|
|
def test_range_symbol
|
|
assert_equal([:a, :b], (:a .. :b).to_a)
|
|
end
|
|
|
|
def test_evaluation_order
|
|
arr = [1,2]
|
|
r = (arr.shift)..(arr.shift)
|
|
assert_equal(1..2, r, "[ruby-dev:26383]")
|
|
end
|
|
|
|
class DuckRange
|
|
def initialize(b,e,excl=false)
|
|
@begin = b
|
|
@end = e
|
|
@excl = excl
|
|
end
|
|
attr_reader :begin, :end
|
|
|
|
def exclude_end?
|
|
@excl
|
|
end
|
|
end
|
|
|
|
def test_duckrange
|
|
assert_equal("bc", "abcd"[DuckRange.new(1,2)])
|
|
end
|
|
|
|
def test_min
|
|
assert_equal(1, (1..2).min)
|
|
assert_equal(nil, (2..1).min)
|
|
assert_equal(1, (1...2).min)
|
|
assert_equal(1, (1..).min)
|
|
assert_raise(RangeError) { (..1).min }
|
|
assert_raise(RangeError) { (...1).min }
|
|
|
|
assert_equal(1.0, (1.0..2.0).min)
|
|
assert_equal(nil, (2.0..1.0).min)
|
|
assert_equal(1, (1.0...2.0).min)
|
|
assert_equal(1, (1.0..).min)
|
|
|
|
assert_equal(0, (0..0).min)
|
|
assert_equal(nil, (0...0).min)
|
|
|
|
assert_equal([0,1,2], (0..10).min(3))
|
|
assert_equal([0,1], (0..1).min(3))
|
|
assert_equal([0,1,2], (0..).min(3))
|
|
assert_raise(RangeError) { (..1).min(3) }
|
|
assert_raise(RangeError) { (...1).min(3) }
|
|
|
|
assert_raise(RangeError) { (0..).min {|a, b| a <=> b } }
|
|
end
|
|
|
|
def test_max
|
|
assert_equal(2, (1..2).max)
|
|
assert_equal(nil, (2..1).max)
|
|
assert_equal(1, (1...2).max)
|
|
assert_raise(RangeError) { (1..).max }
|
|
assert_raise(RangeError) { (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_raise(TypeError) { (1.5...2).max }
|
|
|
|
assert_equal(-0x80000002, ((-0x80000002)...(-0x80000001)).max)
|
|
|
|
assert_equal(0, (0..0).max)
|
|
assert_equal(nil, (0...0).max)
|
|
|
|
assert_equal([10,9,8], (0..10).max(3))
|
|
assert_equal([9,8,7], (0...10).max(3))
|
|
assert_raise(RangeError) { (1..).max(3) }
|
|
assert_raise(RangeError) { (1...).max(3) }
|
|
|
|
assert_raise(RangeError) { (..0).min {|a, b| a <=> b } }
|
|
end
|
|
|
|
def test_minmax
|
|
assert_equal([1, 2], (1..2).minmax)
|
|
assert_equal([nil, nil], (2..1).minmax)
|
|
assert_equal([1, 1], (1...2).minmax)
|
|
assert_raise(RangeError) { (1..).minmax }
|
|
assert_raise(RangeError) { (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_raise(TypeError) { (1.5...2).minmax }
|
|
|
|
assert_equal([-0x80000002, -0x80000002], ((-0x80000002)...(-0x80000001)).minmax)
|
|
|
|
assert_equal([0, 0], (0..0).minmax)
|
|
assert_equal([nil, nil], (0...0).minmax)
|
|
|
|
assert_equal([2, 1], (1..2).minmax{|a, b| b <=> a})
|
|
|
|
assert_equal(['a', 'c'], ('a'..'c').minmax)
|
|
assert_equal(['a', 'b'], ('a'...'c').minmax)
|
|
end
|
|
|
|
def test_initialize_twice
|
|
r = eval("1..2")
|
|
assert_raise(NameError) { r.instance_eval { initialize 3, 4 } }
|
|
assert_raise(NameError) { r.instance_eval { initialize_copy 3..4 } }
|
|
end
|
|
|
|
def test_uninitialized_range
|
|
r = Range.allocate
|
|
s = Marshal.dump(r)
|
|
r = Marshal.load(s)
|
|
assert_nothing_raised { r.instance_eval { initialize 5, 6} }
|
|
end
|
|
|
|
def test_marshal
|
|
r = 1..2
|
|
assert_equal(r, Marshal.load(Marshal.dump(r)))
|
|
r = 1...2
|
|
assert_equal(r, Marshal.load(Marshal.dump(r)))
|
|
r = (1..)
|
|
assert_equal(r, Marshal.load(Marshal.dump(r)))
|
|
r = (1...)
|
|
assert_equal(r, Marshal.load(Marshal.dump(r)))
|
|
end
|
|
|
|
def test_bad_value
|
|
assert_raise(ArgumentError) { (1 .. :a) }
|
|
end
|
|
|
|
def test_exclude_end
|
|
assert_not_predicate(0..1, :exclude_end?)
|
|
assert_predicate(0...1, :exclude_end?)
|
|
assert_not_predicate(0.., :exclude_end?)
|
|
assert_predicate(0..., :exclude_end?)
|
|
end
|
|
|
|
def test_eq
|
|
r = (0..1)
|
|
assert_equal(r, r)
|
|
assert_equal(r, (0..1))
|
|
assert_not_equal(r, 0)
|
|
assert_not_equal(r, (1..2))
|
|
assert_not_equal(r, (0..2))
|
|
assert_not_equal(r, (0...1))
|
|
assert_not_equal(r, (0..nil))
|
|
subclass = Class.new(Range)
|
|
assert_equal(r, subclass.new(0,1))
|
|
|
|
r = (0..nil)
|
|
assert_equal(r, r)
|
|
assert_equal(r, (0..nil))
|
|
assert_not_equal(r, 0)
|
|
assert_not_equal(r, (0...nil))
|
|
subclass = Class.new(Range)
|
|
assert_equal(r, subclass.new(0,nil))
|
|
end
|
|
|
|
def test_eql
|
|
r = (0..1)
|
|
assert_operator(r, :eql?, r)
|
|
assert_operator(r, :eql?, 0..1)
|
|
assert_not_operator(r, :eql?, 0)
|
|
assert_not_operator(r, :eql?, 1..2)
|
|
assert_not_operator(r, :eql?, 0..2)
|
|
assert_not_operator(r, :eql?, 0...1)
|
|
subclass = Class.new(Range)
|
|
assert_operator(r, :eql?, subclass.new(0,1))
|
|
|
|
r = (0..nil)
|
|
assert_operator(r, :eql?, r)
|
|
assert_operator(r, :eql?, 0..nil)
|
|
assert_not_operator(r, :eql?, 0)
|
|
assert_not_operator(r, :eql?, 0...nil)
|
|
subclass = Class.new(Range)
|
|
assert_operator(r, :eql?, subclass.new(0,nil))
|
|
end
|
|
|
|
def test_hash
|
|
assert_kind_of(Integer, (0..1).hash)
|
|
assert_equal((0..1).hash, (0..1).hash)
|
|
assert_not_equal((0..1).hash, (0...1).hash)
|
|
assert_equal((0..nil).hash, (0..nil).hash)
|
|
assert_not_equal((0..nil).hash, (0...nil).hash)
|
|
assert_kind_of(String, (0..1).hash.to_s)
|
|
end
|
|
|
|
def test_step
|
|
a = []
|
|
(0..10).step {|x| a << x }
|
|
assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)
|
|
|
|
a = []
|
|
(0..).step {|x| a << x; break if a.size == 10 }
|
|
assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], a)
|
|
|
|
a = []
|
|
(0..10).step(2) {|x| a << x }
|
|
assert_equal([0, 2, 4, 6, 8, 10], a)
|
|
|
|
a = []
|
|
(0..).step(2) {|x| a << x; break if a.size == 10 }
|
|
assert_equal([0, 2, 4, 6, 8, 10, 12, 14, 16, 18], a)
|
|
|
|
assert_kind_of(Enumerator::ArithmeticSequence, (0..10).step)
|
|
assert_kind_of(Enumerator::ArithmeticSequence, (0..10).step(2))
|
|
assert_kind_of(Enumerator::ArithmeticSequence, (0..10).step(0.5))
|
|
assert_kind_of(Enumerator::ArithmeticSequence, (10..0).step(-1))
|
|
assert_kind_of(Enumerator::ArithmeticSequence, (..10).step(2))
|
|
assert_kind_of(Enumerator::ArithmeticSequence, (1..).step(2))
|
|
|
|
assert_raise(ArgumentError) { (0..10).step(-1) { } }
|
|
assert_raise(ArgumentError) { (0..10).step(0) { } }
|
|
assert_raise(ArgumentError) { (0..).step(-1) { } }
|
|
assert_raise(ArgumentError) { (0..).step(0) { } }
|
|
|
|
a = []
|
|
("a" .. "z").step(2) {|x| a << x }
|
|
assert_equal(%w(a c e g i k m o q s u w y), a)
|
|
|
|
a = []
|
|
("a" .. ).step(2) {|x| a << x; break if a.size == 13 }
|
|
assert_equal(%w(a c e g i k m o q s u w y), a)
|
|
|
|
a = []
|
|
("a" .. "z").step(2**32) {|x| a << x }
|
|
assert_equal(["a"], a)
|
|
|
|
a = []
|
|
(:a .. :z).step(2) {|x| a << x }
|
|
assert_equal(%i(a c e g i k m o q s u w y), a)
|
|
|
|
a = []
|
|
(:a .. ).step(2) {|x| a << x; break if a.size == 13 }
|
|
assert_equal(%i(a c e g i k m o q s u w y), a)
|
|
|
|
a = []
|
|
(:a .. :z).step(2**32) {|x| a << x }
|
|
assert_equal([:a], a)
|
|
|
|
a = []
|
|
(2**32-1 .. 2**32+1).step(2) {|x| a << x }
|
|
assert_equal([4294967295, 4294967297], a)
|
|
zero = (2**32).coerce(0).first
|
|
assert_raise(ArgumentError) { (2**32-1 .. 2**32+1).step(zero) { } }
|
|
a = []
|
|
(2**32-1 .. ).step(2) {|x| a << x; break if a.size == 2 }
|
|
assert_equal([4294967295, 4294967297], a)
|
|
|
|
max = RbConfig::LIMITS["FIXNUM_MAX"]
|
|
a = []
|
|
(max..).step {|x| a << x; break if a.size == 2 }
|
|
assert_equal([max, max+1], a)
|
|
a = []
|
|
(max..).step(max) {|x| a << x; break if a.size == 4 }
|
|
assert_equal([max, 2*max, 3*max, 4*max], a)
|
|
|
|
o1 = Object.new
|
|
o2 = Object.new
|
|
def o1.<=>(x); -1; end
|
|
def o2.<=>(x); 0; end
|
|
assert_raise(TypeError) { (o1..o2).step(1) { } }
|
|
assert_raise(TypeError) { (o1..).step(1) { } }
|
|
|
|
class << o1; self; end.class_eval do
|
|
define_method(:succ) { o2 }
|
|
end
|
|
a = []
|
|
(o1..o2).step(1) {|x| a << x }
|
|
assert_equal([o1, o2], a)
|
|
|
|
a = []
|
|
(o1...o2).step(1) {|x| a << x }
|
|
assert_equal([o1], a)
|
|
|
|
assert_nothing_raised("[ruby-dev:34557]") { (0..2).step(0.5) {|x| } }
|
|
|
|
a = []
|
|
(0..2).step(0.5) {|x| a << x }
|
|
assert_equal([0, 0.5, 1.0, 1.5, 2.0], a)
|
|
|
|
a = []
|
|
(0..).step(0.5) {|x| a << x; break if a.size == 5 }
|
|
assert_equal([0, 0.5, 1.0, 1.5, 2.0], a)
|
|
|
|
a = []
|
|
(0x40000000..0x40000002).step(0.5) {|x| a << x }
|
|
assert_equal([1073741824, 1073741824.5, 1073741825.0, 1073741825.5, 1073741826], a)
|
|
|
|
o = Object.new
|
|
def o.to_int() 1 end
|
|
assert_nothing_raised("[ruby-dev:34558]") { (0..2).step(o) {|x| } }
|
|
|
|
o = Object.new
|
|
class << o
|
|
def to_str() "a" end
|
|
def <=>(other) to_str <=> other end
|
|
end
|
|
|
|
a = []
|
|
(o.."c").step(1) {|x| a << x}
|
|
assert_equal(["a", "b", "c"], a)
|
|
a = []
|
|
(o..).step(1) {|x| a << x; break if a.size >= 3}
|
|
assert_equal(["a", "b", "c"], a)
|
|
end
|
|
|
|
def test_step_bug15537
|
|
assert_equal([10.0, 9.0, 8.0, 7.0], (10 ..).step(-1.0).take(4))
|
|
assert_equal([10.0, 9.0, 8.0, 7.0], (10.0 ..).step(-1).take(4))
|
|
end
|
|
|
|
def test_percent_step
|
|
aseq = (1..10) % 2
|
|
assert_equal(Enumerator::ArithmeticSequence, aseq.class)
|
|
assert_equal(1, aseq.begin)
|
|
assert_equal(10, aseq.end)
|
|
assert_equal(2, aseq.step)
|
|
assert_equal([1, 3, 5, 7, 9], aseq.to_a)
|
|
end
|
|
|
|
def test_step_ruby_core_35753
|
|
assert_equal(6, (1...6.3).step.to_a.size)
|
|
assert_equal(5, (1.1...6).step.to_a.size)
|
|
assert_equal(5, (1...6).step(1.1).to_a.size)
|
|
assert_equal(3, (1.0...5.4).step(1.5).to_a.size)
|
|
assert_equal(3, (1.0...5.5).step(1.5).to_a.size)
|
|
assert_equal(4, (1.0...5.6).step(1.5).to_a.size)
|
|
end
|
|
|
|
def test_each
|
|
a = []
|
|
(0..10).each {|x| a << x }
|
|
assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)
|
|
|
|
a = []
|
|
(0..).each {|x| a << x; break if a.size == 10 }
|
|
assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], a)
|
|
|
|
o1 = Object.new
|
|
o2 = Object.new
|
|
def o1.setcmp(v) @cmpresult = v end
|
|
o1.setcmp(-1)
|
|
def o1.<=>(x); @cmpresult; end
|
|
def o2.setcmp(v) @cmpresult = v end
|
|
o2.setcmp(0)
|
|
def o2.<=>(x); @cmpresult; end
|
|
class << o1; self; end.class_eval do
|
|
define_method(:succ) { o2 }
|
|
end
|
|
|
|
r1 = (o1..o2)
|
|
r2 = (o1...o2)
|
|
|
|
a = []
|
|
r1.each {|x| a << x }
|
|
assert_equal([o1, o2], a)
|
|
|
|
a = []
|
|
r2.each {|x| a << x }
|
|
assert_equal([o1], a)
|
|
|
|
o2.setcmp(1)
|
|
|
|
a = []
|
|
r1.each {|x| a << x }
|
|
assert_equal([o1], a)
|
|
|
|
o2.setcmp(nil)
|
|
|
|
a = []
|
|
r1.each {|x| a << x }
|
|
assert_equal([o1], a)
|
|
|
|
o1.setcmp(nil)
|
|
|
|
a = []
|
|
r2.each {|x| a << x }
|
|
assert_equal([], a)
|
|
|
|
o = Object.new
|
|
class << o
|
|
def to_str() "a" end
|
|
def <=>(other) to_str <=> other end
|
|
end
|
|
|
|
a = []
|
|
(o.."c").each {|x| a << x}
|
|
assert_equal(["a", "b", "c"], a)
|
|
a = []
|
|
(o..).each {|x| a << x; break if a.size >= 3}
|
|
assert_equal(["a", "b", "c"], a)
|
|
end
|
|
|
|
def test_begin_end
|
|
assert_equal(0, (0..1).begin)
|
|
assert_equal(1, (0..1).end)
|
|
assert_equal(1, (0...1).end)
|
|
assert_equal(0, (0..nil).begin)
|
|
assert_equal(nil, (0..nil).end)
|
|
assert_equal(nil, (0...nil).end)
|
|
end
|
|
|
|
def test_first_last
|
|
assert_equal([0, 1, 2], (0..10).first(3))
|
|
assert_equal([8, 9, 10], (0..10).last(3))
|
|
assert_equal(0, (0..10).first)
|
|
assert_equal(10, (0..10).last)
|
|
assert_equal("a", ("a".."c").first)
|
|
assert_equal("c", ("a".."c").last)
|
|
assert_equal(0, (2..0).last)
|
|
|
|
assert_equal([0, 1, 2], (0...10).first(3))
|
|
assert_equal([7, 8, 9], (0...10).last(3))
|
|
assert_equal(0, (0...10).first)
|
|
assert_equal(10, (0...10).last)
|
|
assert_equal("a", ("a"..."c").first)
|
|
assert_equal("c", ("a"..."c").last)
|
|
assert_equal(0, (2...0).last)
|
|
|
|
assert_equal([0, 1, 2], (0..nil).first(3))
|
|
assert_equal(0, (0..nil).first)
|
|
assert_equal("a", ("a"..nil).first)
|
|
assert_raise(RangeError) { (0..nil).last }
|
|
assert_raise(RangeError) { (0..nil).last(3) }
|
|
assert_raise(RangeError) { (nil..0).first }
|
|
assert_raise(RangeError) { (nil..0).first(3) }
|
|
|
|
assert_equal([0, 1, 2], (0..10).first(3.0))
|
|
assert_equal([8, 9, 10], (0..10).last(3.0))
|
|
assert_raise(TypeError) { (0..10).first("3") }
|
|
assert_raise(TypeError) { (0..10).last("3") }
|
|
class << (o = Object.new)
|
|
def to_int; 3; end
|
|
end
|
|
assert_equal([0, 1, 2], (0..10).first(o))
|
|
assert_equal([8, 9, 10], (0..10).last(o))
|
|
|
|
assert_raise(ArgumentError) { (0..10).first(-1) }
|
|
assert_raise(ArgumentError) { (0..10).last(-1) }
|
|
end
|
|
|
|
def test_last_with_redefine_each
|
|
assert_in_out_err([], <<-'end;', ['true'], [])
|
|
class Range
|
|
remove_method :each
|
|
def each(&b)
|
|
[1, 2, 3, 4, 5].each(&b)
|
|
end
|
|
end
|
|
puts [3, 4, 5] == (1..10).last(3)
|
|
end;
|
|
end
|
|
|
|
def test_to_s
|
|
assert_equal("0..1", (0..1).to_s)
|
|
assert_equal("0...1", (0...1).to_s)
|
|
assert_equal("0..", (0..nil).to_s)
|
|
assert_equal("0...", (0...nil).to_s)
|
|
end
|
|
|
|
def test_inspect
|
|
assert_equal("0..1", (0..1).inspect)
|
|
assert_equal("0...1", (0...1).inspect)
|
|
assert_equal("0..", (0..nil).inspect)
|
|
assert_equal("0...", (0...nil).inspect)
|
|
assert_equal("..1", (nil..1).inspect)
|
|
assert_equal("...1", (nil...1).inspect)
|
|
assert_equal("nil..nil", (nil..nil).inspect)
|
|
assert_equal("nil...nil", (nil...nil).inspect)
|
|
end
|
|
|
|
def test_eqq
|
|
assert_operator(0..10, :===, 5)
|
|
assert_not_operator(0..10, :===, 11)
|
|
assert_operator(5..nil, :===, 11)
|
|
assert_not_operator(5..nil, :===, 0)
|
|
end
|
|
|
|
def test_eqq_string
|
|
assert_operator('A'..'Z', :===, 'ANA')
|
|
assert_not_operator('A'..'Z', :===, 'ana')
|
|
assert_operator('A'.., :===, 'ANA')
|
|
assert_operator(..'Z', :===, 'ANA')
|
|
assert_operator(nil..nil, :===, 'ANA')
|
|
end
|
|
|
|
def test_eqq_time
|
|
bug11113 = '[ruby-core:69052] [Bug #11113]'
|
|
t = Time.now
|
|
assert_nothing_raised(TypeError, bug11113) {
|
|
assert_operator(t..(t+10), :===, t+5)
|
|
assert_operator(t.., :===, t+5)
|
|
assert_not_operator(t.., :===, t-5)
|
|
}
|
|
end
|
|
|
|
def test_eqq_non_linear
|
|
bug12003 = '[ruby-core:72908] [Bug #12003]'
|
|
c = Class.new {
|
|
attr_reader :value
|
|
|
|
def initialize(value)
|
|
@value = value
|
|
end
|
|
|
|
def succ
|
|
self.class.new(@value.succ)
|
|
end
|
|
|
|
def ==(other)
|
|
@value == other.value
|
|
end
|
|
|
|
def <=>(other)
|
|
@value <=> other.value
|
|
end
|
|
}
|
|
assert_operator(c.new(0)..c.new(10), :===, c.new(5), bug12003)
|
|
end
|
|
|
|
def test_eqq_non_iteratable
|
|
k = Class.new do
|
|
include Comparable
|
|
attr_reader :i
|
|
def initialize(i) @i = i; end
|
|
def <=>(o); i <=> o.i; end
|
|
end
|
|
assert_operator(k.new(0)..k.new(2), :===, k.new(1))
|
|
end
|
|
|
|
def test_include
|
|
assert_include("a".."z", "c")
|
|
assert_not_include("a".."z", "5")
|
|
assert_include("a"..."z", "y")
|
|
assert_not_include("a"..."z", "z")
|
|
assert_not_include("a".."z", "cc")
|
|
assert_include("a".., "c")
|
|
assert_not_include("a".., "5")
|
|
assert_include(0...10, 5)
|
|
assert_include(5..., 10)
|
|
assert_not_include(5..., 0)
|
|
end
|
|
|
|
def test_cover
|
|
assert_operator("a".."z", :cover?, "c")
|
|
assert_not_operator("a".."z", :cover?, "5")
|
|
assert_operator("a"..."z", :cover?, "y")
|
|
assert_not_operator("a"..."z", :cover?, "z")
|
|
assert_operator("a".."z", :cover?, "cc")
|
|
assert_not_operator(5..., :cover?, 0)
|
|
assert_not_operator(5..., :cover?, "a")
|
|
assert_operator(5.., :cover?, 10)
|
|
|
|
assert_operator(2..5, :cover?, 2..5)
|
|
assert_operator(2...6, :cover?, 2...6)
|
|
assert_operator(2...6, :cover?, 2..5)
|
|
assert_operator(2..5, :cover?, 2...6)
|
|
assert_operator(2..5, :cover?, 2..4)
|
|
assert_operator(2..5, :cover?, 2...4)
|
|
assert_operator(2..5, :cover?, 2...5)
|
|
assert_operator(2..5, :cover?, 3..5)
|
|
assert_operator(2..5, :cover?, 3..4)
|
|
assert_operator(2..5, :cover?, 3...6)
|
|
assert_operator(2...6, :cover?, 2...5)
|
|
assert_operator(2...6, :cover?, 2..5)
|
|
assert_operator(2..6, :cover?, 2...6)
|
|
assert_operator(2.., :cover?, 2..)
|
|
assert_operator(2.., :cover?, 3..)
|
|
assert_operator(1.., :cover?, 1..10)
|
|
assert_operator(..2, :cover?, ..2)
|
|
assert_operator(..2, :cover?, ..1)
|
|
assert_operator(..2, :cover?, 0..1)
|
|
assert_operator(2.0..5.0, :cover?, 2..3)
|
|
assert_operator(2..5, :cover?, 2.0..3.0)
|
|
assert_operator(2..5, :cover?, 2.0...3.0)
|
|
assert_operator(2..5, :cover?, 2.0...5.0)
|
|
assert_operator(2.0..5.0, :cover?, 2.0...3.0)
|
|
assert_operator(2.0..5.0, :cover?, 2.0...5.0)
|
|
assert_operator('aa'..'zz', :cover?, 'aa'...'bb')
|
|
|
|
assert_not_operator(2..5, :cover?, 1..5)
|
|
assert_not_operator(2...6, :cover?, 1..5)
|
|
assert_not_operator(2..5, :cover?, 1...6)
|
|
assert_not_operator(1..3, :cover?, 1...6)
|
|
assert_not_operator(2..5, :cover?, 2..6)
|
|
assert_not_operator(2...6, :cover?, 2..6)
|
|
assert_not_operator(2...6, :cover?, 2...7)
|
|
assert_not_operator(2..3, :cover?, 1..4)
|
|
assert_not_operator(1..2, :cover?, 1.0..3.0)
|
|
assert_not_operator(1.0..2.9, :cover?, 1.0..3.0)
|
|
assert_not_operator(1..2, :cover?, 4..3)
|
|
assert_not_operator(2..1, :cover?, 1..2)
|
|
assert_not_operator(1...2, :cover?, 1...3)
|
|
assert_not_operator(2.., :cover?, 1..)
|
|
assert_not_operator(2.., :cover?, 1..10)
|
|
assert_not_operator(2.., :cover?, ..10)
|
|
assert_not_operator(1..10, :cover?, 1..)
|
|
assert_not_operator(1..10, :cover?, ..1)
|
|
assert_not_operator(1..5, :cover?, 3..2)
|
|
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)
|
|
end
|
|
|
|
def test_beg_len
|
|
o = Object.new
|
|
assert_raise(TypeError) { [][o] }
|
|
class << o; attr_accessor :begin end
|
|
o.begin = -10
|
|
assert_raise(TypeError) { [][o] }
|
|
class << o; attr_accessor :end end
|
|
o.end = 0
|
|
assert_raise(TypeError) { [][o] }
|
|
def o.exclude_end=(v) @exclude_end = v end
|
|
def o.exclude_end?() @exclude_end end
|
|
o.exclude_end = false
|
|
assert_nil([0][o])
|
|
assert_raise(RangeError) { [0][o] = 1 }
|
|
class << o
|
|
private :begin, :end
|
|
end
|
|
o.begin = 10
|
|
o.end = 10
|
|
assert_nil([0][o])
|
|
o.begin = 0
|
|
assert_equal([0], [0][o])
|
|
o.begin = 2
|
|
o.end = 0
|
|
assert_equal([], [0, 1, 2][o])
|
|
end
|
|
|
|
class CyclicRange < Range
|
|
def <=>(other); true; end
|
|
end
|
|
def test_cyclic_range_inspect
|
|
o = CyclicRange.allocate
|
|
o.instance_eval { initialize(o, 1) }
|
|
assert_equal("(... .. ...)..1", o.inspect)
|
|
end
|
|
|
|
def test_comparison_when_recursive
|
|
x = CyclicRange.allocate; x.send(:initialize, x, 1)
|
|
y = CyclicRange.allocate; y.send(:initialize, y, 1)
|
|
Timeout.timeout(1) {
|
|
assert_equal x, y
|
|
assert_operator x, :eql?, y
|
|
}
|
|
|
|
z = CyclicRange.allocate; z.send(:initialize, z, :another)
|
|
Timeout.timeout(1) {
|
|
assert_not_equal x, z
|
|
assert_not_operator x, :eql?, z
|
|
}
|
|
|
|
x = CyclicRange.allocate
|
|
y = CyclicRange.allocate
|
|
x.send(:initialize, y, 1)
|
|
y.send(:initialize, x, 1)
|
|
Timeout.timeout(1) {
|
|
assert_equal x, y
|
|
assert_operator x, :eql?, y
|
|
}
|
|
|
|
x = CyclicRange.allocate
|
|
z = CyclicRange.allocate
|
|
x.send(:initialize, z, 1)
|
|
z.send(:initialize, x, :other)
|
|
Timeout.timeout(1) {
|
|
assert_not_equal x, z
|
|
assert_not_operator x, :eql?, z
|
|
}
|
|
end
|
|
|
|
def test_size
|
|
assert_equal 42, (1..42).size
|
|
assert_equal 41, (1...42).size
|
|
assert_equal 6, (1...6.3).size
|
|
assert_equal 5, (1.1...6).size
|
|
assert_equal 42, (1..42).each.size
|
|
assert_nil ("a"..."z").size
|
|
|
|
assert_equal Float::INFINITY, (1...).size
|
|
assert_equal Float::INFINITY, (1.0...).size
|
|
assert_equal Float::INFINITY, (...1).size
|
|
assert_equal Float::INFINITY, (...1.0).size
|
|
assert_nil ("a"...).size
|
|
end
|
|
|
|
def test_bsearch_typechecks_return_values
|
|
assert_raise(TypeError) do
|
|
(1..42).bsearch{ "not ok" }
|
|
end
|
|
c = eval("class C\u{309a 26a1 26c4 1f300};self;end")
|
|
assert_raise_with_message(TypeError, /C\u{309a 26a1 26c4 1f300}/) do
|
|
(1..42).bsearch {c.new}
|
|
end
|
|
assert_equal (1..42).bsearch{}, (1..42).bsearch{false}
|
|
end
|
|
|
|
def test_bsearch_with_no_block
|
|
enum = (42...666).bsearch
|
|
assert_nil enum.size
|
|
assert_equal 200, enum.each{|x| x >= 200 }
|
|
end
|
|
|
|
def test_bsearch_for_other_numerics
|
|
assert_raise(TypeError) {
|
|
(Rational(-1,2)..Rational(9,4)).bsearch
|
|
}
|
|
assert_raise(TypeError) {
|
|
(BigDecimal('0.5')..BigDecimal('2.25')).bsearch
|
|
}
|
|
end
|
|
|
|
def test_bsearch_for_fixnum
|
|
ary = [3, 4, 7, 9, 12]
|
|
assert_equal(0, (0...ary.size).bsearch {|i| ary[i] >= 2 })
|
|
assert_equal(1, (0...ary.size).bsearch {|i| ary[i] >= 4 })
|
|
assert_equal(2, (0...ary.size).bsearch {|i| ary[i] >= 6 })
|
|
assert_equal(3, (0...ary.size).bsearch {|i| ary[i] >= 8 })
|
|
assert_equal(4, (0...ary.size).bsearch {|i| ary[i] >= 10 })
|
|
assert_equal(nil, (0...ary.size).bsearch {|i| ary[i] >= 100 })
|
|
assert_equal(0, (0...ary.size).bsearch {|i| true })
|
|
assert_equal(nil, (0...ary.size).bsearch {|i| false })
|
|
|
|
ary = [0, 100, 100, 100, 200]
|
|
assert_equal(1, (0...ary.size).bsearch {|i| ary[i] >= 100 })
|
|
|
|
assert_equal(1_000_001, (0...).bsearch {|i| i > 1_000_000 })
|
|
assert_equal( -999_999, (...0).bsearch {|i| i > -1_000_000 })
|
|
end
|
|
|
|
def test_bsearch_for_float
|
|
inf = Float::INFINITY
|
|
assert_in_delta(10.0, (0.0...100.0).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
|
|
assert_in_delta(10.0, (0.0...inf).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
|
|
assert_in_delta(-10.0, (-inf..100.0).bsearch {|x| x >= 0 || Math.log(-x / 10) < 0 }, 0.0001)
|
|
assert_in_delta(10.0, (-inf..inf).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
|
|
assert_equal(nil, (-inf..5).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
|
|
|
|
assert_in_delta(10.0, (-inf.. 10).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
|
|
assert_equal(nil, (-inf...10).bsearch {|x| x > 0 && Math.log(x / 10) >= 0 }, 0.0001)
|
|
|
|
assert_equal(nil, (-inf..inf).bsearch { false })
|
|
assert_equal(-inf, (-inf..inf).bsearch { true })
|
|
|
|
assert_equal(inf, (0..inf).bsearch {|x| x == inf })
|
|
assert_equal(nil, (0...inf).bsearch {|x| x == inf })
|
|
|
|
v = (-inf..0).bsearch {|x| x != -inf }
|
|
assert_operator(-Float::MAX, :>=, v)
|
|
assert_operator(-inf, :<, v)
|
|
|
|
v = (0.0..1.0).bsearch {|x| x > 0 } # the nearest positive value to 0.0
|
|
assert_in_delta(0, v, 0.0001)
|
|
assert_operator(0, :<, v)
|
|
assert_equal(0.0, (-1.0..0.0).bsearch {|x| x >= 0 })
|
|
assert_equal(nil, (-1.0...0.0).bsearch {|x| x >= 0 })
|
|
|
|
v = (0..Float::MAX).bsearch {|x| x >= Float::MAX }
|
|
assert_in_delta(Float::MAX, v)
|
|
assert_equal(nil, v.infinite?)
|
|
|
|
v = (0..inf).bsearch {|x| x >= Float::MAX }
|
|
assert_in_delta(Float::MAX, v)
|
|
assert_equal(nil, v.infinite?)
|
|
|
|
v = (-Float::MAX..0).bsearch {|x| x > -Float::MAX }
|
|
assert_operator(-Float::MAX, :<, v)
|
|
assert_equal(nil, v.infinite?)
|
|
|
|
v = (-inf..0).bsearch {|x| x >= -Float::MAX }
|
|
assert_in_delta(-Float::MAX, v)
|
|
assert_equal(nil, v.infinite?)
|
|
|
|
v = (-inf..0).bsearch {|x| x > -Float::MAX }
|
|
assert_operator(-Float::MAX, :<, v)
|
|
assert_equal(nil, v.infinite?)
|
|
|
|
assert_in_delta(1.0, (0.0..inf).bsearch {|x| Math.log(x) >= 0 })
|
|
assert_in_delta(7.0, (0.0..10).bsearch {|x| 7.0 - x })
|
|
|
|
assert_equal( 1_000_000.0.next_float, (0.0..).bsearch {|x| x > 1_000_000 })
|
|
assert_equal(-1_000_000.0.next_float, (..0.0).bsearch {|x| x > -1_000_000 })
|
|
end
|
|
|
|
def check_bsearch_values(range, search, a)
|
|
from, to = range.begin, range.end
|
|
cmp = range.exclude_end? ? :< : :<=
|
|
r = nil
|
|
|
|
a.for "(0) trivial test" do
|
|
r = Range.new(to, from, range.exclude_end?).bsearch do |x|
|
|
fail "#{to}, #{from}, #{range.exclude_end?}, #{x}"
|
|
end
|
|
assert_nil r
|
|
|
|
r = (to...to).bsearch do
|
|
fail
|
|
end
|
|
assert_nil r
|
|
end
|
|
|
|
# prepare for others
|
|
yielded = []
|
|
r = range.bsearch do |val|
|
|
yielded << val
|
|
val >= search
|
|
end
|
|
|
|
a.for "(1) log test" do
|
|
max = case from
|
|
when Float then 65
|
|
when Integer then Math.log(to-from+(range.exclude_end? ? 0 : 1), 2).to_i + 1
|
|
end
|
|
assert_operator yielded.size, :<=, max
|
|
end
|
|
|
|
a.for "(2) coverage test" do
|
|
expect = case
|
|
when search < from
|
|
from
|
|
when search.send(cmp, to)
|
|
search
|
|
else
|
|
nil
|
|
end
|
|
assert_equal expect, r
|
|
end
|
|
|
|
a.for "(3) uniqueness test" do
|
|
assert_nil yielded.uniq!
|
|
end
|
|
|
|
a.for "(4) end of range test" do
|
|
case
|
|
when range.exclude_end?
|
|
assert_not_include yielded, to
|
|
assert_not_equal r, to
|
|
when search >= to
|
|
assert_include yielded, to
|
|
assert_equal search == to ? to : nil, r
|
|
end
|
|
end
|
|
|
|
a.for "(5) start of range test" do
|
|
if search <= from
|
|
assert_include yielded, from
|
|
assert_equal from, r
|
|
end
|
|
end
|
|
|
|
a.for "(6) out of range test" do
|
|
yielded.each do |val|
|
|
assert_operator from, :<=, val
|
|
assert_send [val, cmp, to]
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_range_bsearch_for_floats
|
|
ints = [-1 << 100, -123456789, -42, -1, 0, 1, 42, 123456789, 1 << 100]
|
|
floats = [-Float::INFINITY, -Float::MAX, -42.0, -4.2, -Float::EPSILON, -Float::MIN, 0.0, Float::MIN, Float::EPSILON, Math::PI, 4.2, 42.0, Float::MAX, Float::INFINITY]
|
|
|
|
all_assertions do |a|
|
|
[ints, floats].each do |values|
|
|
values.combination(2).to_a.product(values).each do |(from, to), search|
|
|
check_bsearch_values(from..to, search, a)
|
|
check_bsearch_values(from...to, search, a)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_bsearch_for_bignum
|
|
bignum = 2**100
|
|
ary = [3, 4, 7, 9, 12]
|
|
assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 2 })
|
|
assert_equal(bignum + 1, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 4 })
|
|
assert_equal(bignum + 2, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 6 })
|
|
assert_equal(bignum + 3, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 8 })
|
|
assert_equal(bignum + 4, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 10 })
|
|
assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 100 })
|
|
assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| true })
|
|
assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| false })
|
|
assert_equal(bignum * 2 + 1, (bignum...).bsearch {|i| i > bignum * 2 })
|
|
assert_equal(-bignum * 2 + 1, (...-bignum).bsearch {|i| i > -bignum * 2 })
|
|
|
|
assert_raise(TypeError) { ("a".."z").bsearch {} }
|
|
end
|
|
|
|
def test_each_no_blockarg
|
|
a = "a"
|
|
def a.upto(x, e, &b)
|
|
super {|y| b.call(y) {|z| assert(false)}}
|
|
end
|
|
(a.."c").each {|x, &b| assert_nil(b)}
|
|
end
|
|
|
|
def test_to_a
|
|
assert_equal([1,2,3,4,5], (1..5).to_a)
|
|
assert_equal([1,2,3,4], (1...5).to_a)
|
|
assert_raise(RangeError) { (1..).to_a }
|
|
end
|
|
|
|
def test_beginless_range_iteration
|
|
assert_raise(TypeError) { (..1).each { } }
|
|
end
|
|
|
|
def test_count
|
|
assert_equal(Float::INFINITY, (1..).count)
|
|
end
|
|
end
|