1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/ruby/test_range.rb
Sam Bostock bf1a6771f3 Fix non-numeric exclusive Range#minmax bug
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.
2020-07-04 10:02:24 -07:00

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