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_enum.rb
Jeremy Evans a5cff7cc5d Make Enumerable#each_cons return object if over size
This behavior changed in dfb47bbd17,
but only for normal exit, not for early exit.  Fix it for early
exit as well.

While here, fix example code in documentation so that it doesn't
indicate that the method returns nil.
2021-11-16 19:31:35 -08:00

1324 lines
38 KiB
Ruby

# frozen_string_literal: false
require 'test/unit'
EnvUtil.suppress_warning {require 'continuation'}
require 'stringio'
class TestEnumerable < Test::Unit::TestCase
def setup
@obj = Object.new
class << @obj
include Enumerable
def each
yield 1
yield 2
yield 3
yield 1
yield 2
self
end
end
@empty = Object.new
class << @empty
attr_reader :block
include Enumerable
def each(&block)
@block = block
self
end
end
@verbose = $VERBOSE
end
def teardown
$VERBOSE = @verbose
end
def test_grep_v
assert_equal([3], @obj.grep_v(1..2))
a = []
@obj.grep_v(2) {|x| a << x }
assert_equal([1, 3, 1], a)
a = []
lambda = ->(x, i) {a << [x, i]}
@obj.each_with_index.grep_v(proc{|x,i|x!=2}, &lambda)
assert_equal([[2, 1], [2, 4]], a)
end
def test_grep
assert_equal([1, 2, 1, 2], @obj.grep(1..2))
a = []
@obj.grep(2) {|x| a << x }
assert_equal([2, 2], a)
bug5801 = '[ruby-dev:45041]'
@empty.grep(//)
block = @empty.block
assert_nothing_raised(bug5801) {100.times {block.call}}
a = []
lambda = ->(x, i) {a << [x, i]}
@obj.each_with_index.grep(proc{|x,i|x==2}, &lambda)
assert_equal([[2, 1], [2, 4]], a)
end
def test_grep_optimization
bug17030 = '[ruby-core:99156]'
'set last match' =~ /set last (.*)/
assert_equal([:a, 'b', :c], [:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/), bug17030)
assert_equal(['z', 42, nil], [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/), bug17030)
assert_equal('match', $1, bug17030)
regexp = Regexp.new('x')
assert_equal([], @obj.grep(regexp), bug17030) # sanity check
def regexp.===(other)
true
end
assert_equal([1, 2, 3, 1, 2], @obj.grep(regexp), bug17030)
o = Object.new
def o.to_str
'hello'
end
assert_same(o, [o].grep(/ll/).first, bug17030)
end
def test_count
assert_equal(5, @obj.count)
assert_equal(2, @obj.count(1))
assert_equal(3, @obj.count {|x| x % 2 == 1 })
assert_equal(2, assert_warning(/given block not used/) {@obj.count(1) {|x| x % 2 == 1 }})
assert_raise(ArgumentError) { @obj.count(0, 1) }
if RUBY_ENGINE == "ruby"
en = Class.new {
include Enumerable
alias :size :count
def each
yield 1
end
}
assert_equal(1, en.new.count, '[ruby-core:24794]')
end
end
def test_find
assert_equal(2, @obj.find {|x| x % 2 == 0 })
assert_equal(nil, @obj.find {|x| false })
assert_equal(:foo, @obj.find(proc { :foo }) {|x| false })
cond = ->(x, i) { x % 2 == 0 }
assert_equal([2, 1], @obj.each_with_index.find(&cond))
end
def test_find_index
assert_equal(1, @obj.find_index(2))
assert_equal(1, @obj.find_index {|x| x % 2 == 0 })
assert_equal(nil, @obj.find_index {|x| false })
assert_raise(ArgumentError) { @obj.find_index(0, 1) }
assert_equal(1, assert_warning(/given block not used/) {@obj.find_index(2) {|x| x == 1 }})
end
def test_find_all
assert_equal([1, 3, 1], @obj.find_all {|x| x % 2 == 1 })
cond = ->(x, i) { x % 2 == 1 }
assert_equal([[1, 0], [3, 2], [1, 3]], @obj.each_with_index.find_all(&cond))
end
def test_reject
assert_equal([2, 3, 2], @obj.reject {|x| x < 2 })
cond = ->(x, i) {x < 2}
assert_equal([[2, 1], [3, 2], [2, 4]], @obj.each_with_index.reject(&cond))
end
def test_to_a
assert_equal([1, 2, 3, 1, 2], @obj.to_a)
end
def test_to_a_keywords
@obj.singleton_class.remove_method(:each)
def @obj.each(foo:) yield foo end
assert_equal([1], @obj.to_a(foo: 1))
end
def test_to_a_size_symbol
sym = Object.new
class << sym
include Enumerable
def each
self
end
def size
:size
end
end
assert_equal([], sym.to_a)
end
def test_to_a_size_infinity
inf = Object.new
class << inf
include Enumerable
def each
self
end
def size
Float::INFINITY
end
end
assert_equal([], inf.to_a)
end
StubToH = Object.new.tap do |obj|
def obj.each(*args)
yield(*args)
yield [:key, :value]
yield :other_key, :other_value
kvp = Object.new
def kvp.to_ary
[:obtained, :via_to_ary]
end
yield kvp
end
obj.extend Enumerable
obj.freeze
end
def test_to_h
obj = StubToH
assert_equal({
:hello => :world,
:key => :value,
:other_key => :other_value,
:obtained => :via_to_ary,
}, obj.to_h(:hello, :world))
e = assert_raise(TypeError) {
obj.to_h(:not_an_array)
}
assert_equal "wrong element type Symbol (expected array)", e.message
e = assert_raise(ArgumentError) {
obj.to_h([1])
}
assert_equal "element has wrong array length (expected 2, was 1)", e.message
end
def test_to_h_block
obj = StubToH
assert_equal({
"hello" => "world",
"key" => "value",
"other_key" => "other_value",
"obtained" => "via_to_ary",
}, obj.to_h(:hello, :world) {|k, v| [k.to_s, v.to_s]})
e = assert_raise(TypeError) {
obj.to_h {:not_an_array}
}
assert_equal "wrong element type Symbol (expected array)", e.message
e = assert_raise(ArgumentError) {
obj.to_h {[1]}
}
assert_equal "element has wrong array length (expected 2, was 1)", e.message
end
def test_inject
assert_equal(12, @obj.inject {|z, x| z * x })
assert_equal(48, @obj.inject {|z, x| z * 2 + x })
assert_equal(12, @obj.inject(:*))
assert_equal(24, @obj.inject(2) {|z, x| z * x })
assert_equal(24, assert_warning(/given block not used/) {@obj.inject(2, :*) {|z, x| z * x }})
assert_equal(nil, @empty.inject() {9})
end
FIXNUM_MIN = RbConfig::LIMITS['FIXNUM_MIN']
FIXNUM_MAX = RbConfig::LIMITS['FIXNUM_MAX']
def test_inject_array_mul
assert_equal(nil, [].inject(:*))
assert_equal(5, [5].inject(:*))
assert_equal(35, [5, 7].inject(:*))
assert_equal(3, [].inject(3, :*))
assert_equal(15, [5].inject(3, :*))
assert_equal(105, [5, 7].inject(3, :*))
end
def test_inject_array_plus
assert_equal(3, [3].inject(:+))
assert_equal(8, [3, 5].inject(:+))
assert_equal(15, [3, 5, 7].inject(:+))
assert_float_equal(15.0, [3, 5, 7.0].inject(:+))
assert_equal(2*FIXNUM_MAX, Array.new(2, FIXNUM_MAX).inject(:+))
assert_equal(3*FIXNUM_MAX, Array.new(3, FIXNUM_MAX).inject(:+))
assert_equal(2*(FIXNUM_MAX+1), Array.new(2, FIXNUM_MAX+1).inject(:+))
assert_equal(10*FIXNUM_MAX, Array.new(10, FIXNUM_MAX).inject(:+))
assert_equal(0, ([FIXNUM_MAX, 1, -FIXNUM_MAX, -1]*10).inject(:+))
assert_equal(FIXNUM_MAX*10, ([FIXNUM_MAX+1, -1]*10).inject(:+))
assert_equal(2*FIXNUM_MIN, Array.new(2, FIXNUM_MIN).inject(:+))
assert_equal(3*FIXNUM_MIN, Array.new(3, FIXNUM_MIN).inject(:+))
assert_equal((FIXNUM_MAX+1).to_f, [FIXNUM_MAX, 1, 0.0].inject(:+))
assert_float_equal(10.0, [3.0, 5].inject(2.0, :+))
assert_float_equal((FIXNUM_MAX+1).to_f, [0.0, FIXNUM_MAX+1].inject(:+))
assert_equal(2.0+3.0i, [2.0, 3.0i].inject(:+))
end
def test_inject_op_redefined
assert_separately([], "#{<<~"end;"}\n""end")
k = Class.new do
include Enumerable
def each
yield 1
yield 2
yield 3
end
end
all_assertions_foreach("", *%i[+ * / - %]) do |op|
bug = '[ruby-dev:49510] [Bug#12178] should respect redefinition'
begin
Integer.class_eval do
alias_method :orig, op
define_method(op) do |x|
0
end
end
assert_equal(0, k.new.inject(op), bug)
ensure
Integer.class_eval do
undef_method op
alias_method op, :orig
end
end
end;
end
def test_inject_op_private
assert_separately([], "#{<<~"end;"}\n""end")
k = Class.new do
include Enumerable
def each
yield 1
yield 2
yield 3
end
end
all_assertions_foreach("", *%i[+ * / - %]) do |op|
bug = '[ruby-core:81349] [Bug #13592] should respect visibility'
assert_raise_with_message(NoMethodError, /private method/, bug) do
begin
Integer.class_eval do
private op
end
k.new.inject(op)
ensure
Integer.class_eval do
public op
end
end
end
end;
end
def test_inject_array_op_redefined
assert_separately([], "#{<<~"end;"}\n""end")
all_assertions_foreach("", *%i[+ * / - %]) do |op|
bug = '[ruby-dev:49510] [Bug#12178] should respect redefinition'
begin
Integer.class_eval do
alias_method :orig, op
define_method(op) do |x|
0
end
end
assert_equal(0, [1,2,3].inject(op), bug)
ensure
Integer.class_eval do
undef_method op
alias_method op, :orig
end
end
end;
end
def test_inject_array_op_private
assert_separately([], "#{<<~"end;"}\n""end")
all_assertions_foreach("", *%i[+ * / - %]) do |op|
bug = '[ruby-core:81349] [Bug #13592] should respect visibility'
assert_raise_with_message(NoMethodError, /private method/, bug) do
begin
Integer.class_eval do
private op
end
[1,2,3].inject(op)
ensure
Integer.class_eval do
public op
end
end
end
end;
end
def test_refine_Enumerable_then_include
assert_separately([], "#{<<~"end;"}\n")
module RefinementBug
refine Enumerable do
def refined_method
:rm
end
end
end
using RefinementBug
class A
include Enumerable
end
assert_equal(:rm, [].refined_method)
end;
end
def test_partition
assert_equal([[1, 3, 1], [2, 2]], @obj.partition {|x| x % 2 == 1 })
cond = ->(x, i) { x % 2 == 1 }
assert_equal([[[1, 0], [3, 2], [1, 3]], [[2, 1], [2, 4]]], @obj.each_with_index.partition(&cond))
end
def test_group_by
h = { 1 => [1, 1], 2 => [2, 2], 3 => [3] }
assert_equal(h, @obj.group_by {|x| x })
h = {1=>[[1, 0], [1, 3]], 2=>[[2, 1], [2, 4]], 3=>[[3, 2]]}
cond = ->(x, i) { x }
assert_equal(h, @obj.each_with_index.group_by(&cond))
end
def test_tally
h = {1 => 2, 2 => 2, 3 => 1}
assert_equal(h, @obj.tally)
h = {1 => 5, 2 => 2, 3 => 1, 4 => "x"}
assert_equal(h, @obj.tally({1 => 3, 4 => "x"}))
assert_raise(TypeError) do
@obj.tally({1 => ""})
end
h = {1 => 2, 2 => 2, 3 => 1}
assert_same(h, @obj.tally(h))
h = {1 => 2, 2 => 2, 3 => 1}.freeze
assert_raise(FrozenError) do
@obj.tally(h)
end
assert_equal({1 => 2, 2 => 2, 3 => 1}, h)
hash_convertible = Object.new
def hash_convertible.to_hash
{1 => 3, 4 => "x"}
end
assert_equal({1 => 5, 2 => 2, 3 => 1, 4 => "x"}, @obj.tally(hash_convertible))
hash_convertible = Object.new
def hash_convertible.to_hash
{1 => 3, 4 => "x"}.freeze
end
assert_raise(FrozenError) do
@obj.tally(hash_convertible)
end
assert_equal({1 => 3, 4 => "x"}, hash_convertible.to_hash)
assert_raise(TypeError) do
@obj.tally(BasicObject.new)
end
h = {1 => 2, 2 => 2, 3 => 1}
assert_equal(h, @obj.tally(Hash.new(100)))
assert_equal(h, @obj.tally(Hash.new {100}))
end
def test_first
assert_equal(1, @obj.first)
assert_equal([1, 2, 3], @obj.first(3))
assert_nil(@empty.first)
assert_equal([], @empty.first(10))
bug5801 = '[ruby-dev:45041]'
assert_in_out_err([], <<-'end;', [], /unexpected break/, bug5801)
empty = Object.new
class << empty
attr_reader :block
include Enumerable
def each(&block)
@block = block
self
end
end
empty.first
empty.block.call
end;
end
def test_sort
assert_equal([1, 1, 2, 2, 3], @obj.sort)
assert_equal([3, 2, 2, 1, 1], @obj.sort {|x, y| y <=> x })
end
def test_sort_by
assert_equal([3, 2, 2, 1, 1], @obj.sort_by {|x| -x })
assert_equal((1..300).to_a.reverse, (1..300).sort_by {|x| -x })
cond = ->(x, i) { [-x, i] }
assert_equal([[3, 2], [2, 1], [2, 4], [1, 0], [1, 3]], @obj.each_with_index.sort_by(&cond))
end
def test_all
assert_equal(true, @obj.all? {|x| x <= 3 })
assert_equal(false, @obj.all? {|x| x < 3 })
assert_equal(true, @obj.all?)
assert_equal(false, [true, true, false].all?)
assert_equal(true, [].all?)
assert_equal(true, @empty.all?)
assert_equal(true, @obj.all?(Integer))
assert_equal(false, @obj.all?(1..2))
end
def test_all_with_unused_block
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
[1, 2].all?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
(1..2).all?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
3.times.all?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
{a: 1, b: 2}.all?([:b, 2]) {|x| x == 4 }
EOS
end
def test_any
assert_equal(true, @obj.any? {|x| x >= 3 })
assert_equal(false, @obj.any? {|x| x > 3 })
assert_equal(true, @obj.any?)
assert_equal(false, [false, false, false].any?)
assert_equal(false, [].any?)
assert_equal(false, @empty.any?)
assert_equal(true, @obj.any?(1..2))
assert_equal(false, @obj.any?(Float))
assert_equal(false, [1, 42].any?(Float))
assert_equal(true, [1, 4.2].any?(Float))
assert_equal(false, {a: 1, b: 2}.any?(->(kv) { kv == [:foo, 42] }))
assert_equal(true, {a: 1, b: 2}.any?(->(kv) { kv == [:b, 2] }))
end
def test_any_with_unused_block
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
[1, 23].any?(1) {|x| x == 1 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
(1..2).any?(34) {|x| x == 2 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
3.times.any?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
{a: 1, b: 2}.any?([:b, 2]) {|x| x == 4 }
EOS
end
def test_one
assert(@obj.one? {|x| x == 3 })
assert(!(@obj.one? {|x| x == 1 }))
assert(!(@obj.one? {|x| x == 4 }))
assert(@obj.one?(3..4))
assert(!(@obj.one?(1..2)))
assert(!(@obj.one?(4..5)))
assert(%w{ant bear cat}.one? {|word| word.length == 4})
assert(!(%w{ant bear cat}.one? {|word| word.length > 4}))
assert(!(%w{ant bear cat}.one? {|word| word.length < 4}))
assert(%w{ant bear cat}.one?(/b/))
assert(!(%w{ant bear cat}.one?(/t/)))
assert(!([ nil, true, 99 ].one?))
assert([ nil, true, false ].one?)
assert(![].one?)
assert(!@empty.one?)
assert([ nil, true, 99 ].one?(Integer))
end
def test_one_with_unused_block
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
[1, 2].one?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
(1..2).one?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
3.times.one?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
{a: 1, b: 2}.one?([:b, 2]) {|x| x == 4 }
EOS
end
def test_none
assert(@obj.none? {|x| x == 4 })
assert(!(@obj.none? {|x| x == 1 }))
assert(!(@obj.none? {|x| x == 3 }))
assert(@obj.none?(4..5))
assert(!(@obj.none?(1..3)))
assert(%w{ant bear cat}.none? {|word| word.length == 5})
assert(!(%w{ant bear cat}.none? {|word| word.length >= 4}))
assert(%w{ant bear cat}.none?(/d/))
assert(!(%w{ant bear cat}.none?(/b/)))
assert([].none?)
assert([nil].none?)
assert([nil,false].none?)
assert(![nil,false,true].none?)
assert(@empty.none?)
end
def test_none_with_unused_block
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
[1, 2].none?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
(1..2).none?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
3.times.none?(1) {|x| x == 3 }
EOS
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
{a: 1, b: 2}.none?([:b, 2]) {|x| x == 4 }
EOS
end
def test_min
assert_equal(1, @obj.min)
assert_equal(3, @obj.min {|a,b| b <=> a })
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
assert_equal([3, 2], @obj.each_with_index.min(&cond))
enum = %w(albatross dog horse).to_enum
assert_equal("albatross", enum.min)
assert_equal("dog", enum.min {|a,b| a.length <=> b.length })
assert_equal(1, [3,2,1].to_enum.min)
assert_equal(%w[albatross dog], enum.min(2))
assert_equal(%w[dog horse],
enum.min(2) {|a,b| a.length <=> b.length })
assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].to_enum.min(2))
assert_equal([2, 4, 6, 7], [2, 4, 8, 6, 7].to_enum.min(4))
end
def test_max
assert_equal(3, @obj.max)
assert_equal(1, @obj.max {|a,b| b <=> a })
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
assert_equal([1, 3], @obj.each_with_index.max(&cond))
enum = %w(albatross dog horse).to_enum
assert_equal("horse", enum.max)
assert_equal("albatross", enum.max {|a,b| a.length <=> b.length })
assert_equal(1, [3,2,1].to_enum.max{|a,b| b <=> a })
assert_equal(%w[horse dog], enum.max(2))
assert_equal(%w[albatross horse],
enum.max(2) {|a,b| a.length <=> b.length })
assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].to_enum.max(2))
end
def test_minmax
assert_equal([1, 3], @obj.minmax)
assert_equal([3, 1], @obj.minmax {|a,b| b <=> a })
ary = %w(albatross dog horse)
assert_equal(["albatross", "horse"], ary.minmax)
assert_equal(["dog", "albatross"], ary.minmax {|a,b| a.length <=> b.length })
assert_equal([1, 3], [2,3,1].minmax)
assert_equal([3, 1], [2,3,1].minmax {|a,b| b <=> a })
assert_equal([1, 3], [2,2,3,3,1,1].minmax)
assert_equal([nil, nil], [].minmax)
end
def test_min_by
assert_equal(3, @obj.min_by {|x| -x })
cond = ->(x, i) { -x }
assert_equal([3, 2], @obj.each_with_index.min_by(&cond))
a = %w(albatross dog horse)
assert_equal("dog", a.min_by {|x| x.length })
assert_equal(3, [2,3,1].min_by {|x| -x })
assert_equal(%w[dog horse], a.min_by(2) {|x| x.length })
assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].min_by(2) {|x| x})
end
def test_max_by
assert_equal(1, @obj.max_by {|x| -x })
cond = ->(x, i) { -x }
assert_equal([1, 0], @obj.each_with_index.max_by(&cond))
a = %w(albatross dog horse)
assert_equal("albatross", a.max_by {|x| x.length })
assert_equal(1, [2,3,1].max_by {|x| -x })
assert_equal(%w[albatross horse], a.max_by(2) {|x| x.length })
assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].max_by(2) {|x| x})
end
def test_minmax_by
assert_equal([3, 1], @obj.minmax_by {|x| -x })
cond = ->(x, i) { -x }
assert_equal([[3, 2], [1, 0]], @obj.each_with_index.minmax_by(&cond))
a = %w(albatross dog horse)
assert_equal(["dog", "albatross"], a.minmax_by {|x| x.length })
assert_equal([3, 1], [2,3,1].minmax_by {|x| -x })
end
def test_member
assert(@obj.member?(1))
assert(!(@obj.member?(4)))
assert([1,2,3].member?(1))
assert(!([1,2,3].member?(4)))
end
class Foo
include Enumerable
def each
yield 1
yield 1,2
end
end
def test_each_with_index
a = []
@obj.each_with_index {|x, i| a << [x, i] }
assert_equal([[1,0],[2,1],[3,2],[1,3],[2,4]], a)
hash = Hash.new
%w(cat dog wombat).each_with_index do |item, index|
hash[item] = index
end
assert_equal({"cat"=>0, "wombat"=>2, "dog"=>1}, hash)
assert_equal([[1, 0], [[1, 2], 1]], Foo.new.each_with_index.to_a)
end
def test_each_with_object
obj = [0, 1]
ret = (1..10).each_with_object(obj) {|i, memo|
memo[0] += i
memo[1] *= i
}
assert_same(obj, ret)
assert_equal([55, 3628800], ret)
assert_equal([[1, nil], [[1, 2], nil]], Foo.new.each_with_object(nil).to_a)
end
def test_each_entry
assert_equal([1, 2, 3], [1, 2, 3].each_entry.to_a)
assert_equal([1, [1, 2]], Foo.new.each_entry.to_a)
a = []
cond = ->(x, i) { a << x }
@obj.each_with_index.each_entry(&cond)
assert_equal([1, 2, 3, 1, 2], a)
end
def test_each_slice
ary = []
(1..10).each_slice(3) {|a| ary << a}
assert_equal([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], ary)
bug9749 = '[ruby-core:62060] [Bug #9749]'
ary.clear
(1..10).each_slice(3, &lambda {|a, *| ary << a})
assert_equal([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], ary, bug9749)
ary.clear
(1..10).each_slice(10) {|a| ary << a}
assert_equal([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]], ary)
ary.clear
(1..10).each_slice(11) {|a| ary << a}
assert_equal([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]], ary)
assert_equal(1..10, (1..10).each_slice(3) { })
assert_equal([], [].each_slice(3) { })
end
def test_each_cons
ary = []
(1..5).each_cons(3) {|a| ary << a}
assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5]], ary)
bug9749 = '[ruby-core:62060] [Bug #9749]'
ary.clear
(1..5).each_cons(3, &lambda {|a, *| ary << a})
assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5]], ary, bug9749)
ary.clear
(1..5).each_cons(5) {|a| ary << a}
assert_equal([[1, 2, 3, 4, 5]], ary)
ary.clear
(1..5).each_cons(6) {|a| ary << a}
assert_empty(ary)
assert_equal(1..5, (1..5).each_cons(3) { })
assert_equal([], [].each_cons(3) { })
end
def test_zip
assert_equal([[1,1],[2,2],[3,3],[1,1],[2,2]], @obj.zip(@obj))
assert_equal([["a",1],["b",2],["c",3]], ["a", "b", "c"].zip(@obj))
a = []
result = @obj.zip([:a, :b, :c]) {|x,y| a << [x, y] }
assert_nil result
assert_equal([[1,:a],[2,:b],[3,:c],[1,nil],[2,nil]], a)
a = []
cond = ->((x, i), y) { a << [x, y, i] }
@obj.each_with_index.zip([:a, :b, :c], &cond)
assert_equal([[1,:a,0],[2,:b,1],[3,:c,2],[1,nil,3],[2,nil,4]], a)
a = []
@obj.zip({a: "A", b: "B", c: "C"}) {|x,y| a << [x, y] }
assert_equal([[1,[:a,"A"]],[2,[:b,"B"]],[3,[:c,"C"]],[1,nil],[2,nil]], a)
ary = Object.new
def ary.to_a; [1, 2]; end
assert_raise(TypeError) {%w(a b).zip(ary)}
def ary.each; [3, 4].each{|e|yield e}; end
assert_equal([[1, 3], [2, 4], [3, nil], [1, nil], [2, nil]], @obj.zip(ary))
def ary.to_ary; [5, 6]; end
assert_equal([[1, 5], [2, 6], [3, nil], [1, nil], [2, nil]], @obj.zip(ary))
obj = eval("class C\u{1f5ff}; self; end").new
assert_raise_with_message(TypeError, /C\u{1f5ff}/) {(1..1).zip(obj)}
end
def test_take
assert_equal([1,2,3], @obj.take(3))
end
def test_take_while
assert_equal([1,2], @obj.take_while {|x| x <= 2})
cond = ->(x, i) {x <= 2}
assert_equal([[1, 0], [2, 1]], @obj.each_with_index.take_while(&cond))
bug5801 = '[ruby-dev:45040]'
@empty.take_while {true}
block = @empty.block
assert_nothing_raised(bug5801) {100.times {block.call}}
end
def test_drop
assert_equal([3,1,2], @obj.drop(2))
end
def test_drop_while
assert_equal([3,1,2], @obj.drop_while {|x| x <= 2})
cond = ->(x, i) {x <= 2}
assert_equal([[3, 2], [1, 3], [2, 4]], @obj.each_with_index.drop_while(&cond))
end
def test_cycle
assert_equal([1,2,3,1,2,1,2,3,1,2], @obj.cycle.take(10))
a = []
@obj.cycle(2) {|x| a << x}
assert_equal([1,2,3,1,2,1,2,3,1,2], a)
a = []
cond = ->(x, i) {a << x}
@obj.each_with_index.cycle(2, &cond)
assert_equal([1,2,3,1,2,1,2,3,1,2], a)
end
def test_callcc
assert_raise(RuntimeError) do
c = nil
@obj.sort_by {|x| callcc {|c2| c ||= c2 }; x }
c.call
end
assert_raise(RuntimeError) do
c = nil
o = Object.new
class << o; self; end.class_eval do
define_method(:<=>) do |x|
callcc {|c2| c ||= c2 }
0
end
end
[o, o].sort_by {|x| x }
c.call
end
assert_raise(RuntimeError) do
c = nil
o = Object.new
class << o; self; end.class_eval do
define_method(:<=>) do |x|
callcc {|c2| c ||= c2 }
0
end
end
[o, o, o].sort_by {|x| x }
c.call
end
assert_raise_with_message(RuntimeError, /reentered/) do
i = 0
c = nil
o = Object.new
class << o; self; end.class_eval do
define_method(:<=>) do |x|
callcc {|c2| c ||= c2 }
i += 1
0
end
end
[o, o].min(1)
assert_operator(i, :<=, 5, "infinite loop")
c.call
end
end
def test_reverse_each
assert_equal([2,1,3,2,1], @obj.reverse_each.to_a)
end
def test_reverse_each_memory_corruption
bug16354 = '[ruby-dev:50867]'
assert_normal_exit %q{
size = 1000
(0...size).reverse_each do |i|
i.inspect
ObjectSpace.each_object(Array) do |a|
a.clear if a.length == size
end
end
}, bug16354
end
def test_chunk
e = [].chunk {|elt| true }
assert_equal([], e.to_a)
e = @obj.chunk {|elt| elt & 2 == 0 ? false : true }
assert_equal([[false, [1]], [true, [2, 3]], [false, [1]], [true, [2]]], e.to_a)
e = @obj.chunk {|elt| elt < 3 ? :_alone : true }
assert_equal([[:_alone, [1]],
[:_alone, [2]],
[true, [3]],
[:_alone, [1]],
[:_alone, [2]]], e.to_a)
e = @obj.chunk {|elt| elt == 3 ? :_separator : true }
assert_equal([[true, [1, 2]],
[true, [1, 2]]], e.to_a)
e = @obj.chunk {|elt| elt == 3 ? nil : true }
assert_equal([[true, [1, 2]],
[true, [1, 2]]], e.to_a)
e = @obj.chunk {|elt| :_foo }
assert_raise(RuntimeError) { e.to_a }
e = @obj.chunk.with_index {|elt, i| elt - i }
assert_equal([[1, [1, 2, 3]],
[-2, [1, 2]]], e.to_a)
assert_equal(4, (0..3).chunk.size)
end
def test_slice_before
e = [].slice_before {|elt| true }
assert_equal([], e.to_a)
e = @obj.slice_before {|elt| elt.even? }
assert_equal([[1], [2,3,1], [2]], e.to_a)
e = @obj.slice_before {|elt| elt.odd? }
assert_equal([[1,2], [3], [1,2]], e.to_a)
ss = %w[abc defg h ijk l mno pqr st u vw xy z]
assert_equal([%w[abc defg h], %w[ijk l], %w[mno], %w[pqr st u vw xy z]],
ss.slice_before(/\A...\z/).to_a)
assert_warning("") {ss.slice_before(/\A...\z/).to_a}
end
def test_slice_after0
assert_raise(ArgumentError) { [].slice_after }
end
def test_slice_after1
e = [].slice_after {|a| flunk "should not be called" }
assert_equal([], e.to_a)
e = [1,2].slice_after(1)
assert_equal([[1], [2]], e.to_a)
e = [1,2].slice_after(3)
assert_equal([[1, 2]], e.to_a)
[true, false].each {|b|
block_results = [true, b]
e = [1,2].slice_after {|a| block_results.shift }
assert_equal([[1], [2]], e.to_a)
assert_equal([], block_results)
block_results = [false, b]
e = [1,2].slice_after {|a| block_results.shift }
assert_equal([[1, 2]], e.to_a)
assert_equal([], block_results)
}
end
def test_slice_after_both_pattern_and_block
assert_raise(ArgumentError) { [].slice_after(1) {|a| true } }
end
def test_slice_after_continuation_lines
lines = ["foo\n", "bar\\\n", "baz\n", "\n", "qux\n"]
e = lines.slice_after(/[^\\]\n\z/)
assert_equal([["foo\n"], ["bar\\\n", "baz\n"], ["\n", "qux\n"]], e.to_a)
end
def test_slice_before_empty_line
lines = ["foo", "", "bar"]
e = lines.slice_after(/\A\s*\z/)
assert_equal([["foo", ""], ["bar"]], e.to_a)
end
def test_slice_when_0
e = [].slice_when {|a, b| flunk "should not be called" }
assert_equal([], e.to_a)
end
def test_slice_when_1
e = [1].slice_when {|a, b| flunk "should not be called" }
assert_equal([[1]], e.to_a)
end
def test_slice_when_2
e = [1,2].slice_when {|a,b|
assert_equal(1, a)
assert_equal(2, b)
true
}
assert_equal([[1], [2]], e.to_a)
e = [1,2].slice_when {|a,b|
assert_equal(1, a)
assert_equal(2, b)
false
}
assert_equal([[1, 2]], e.to_a)
end
def test_slice_when_3
block_invocations = [
lambda {|a, b|
assert_equal(1, a)
assert_equal(2, b)
true
},
lambda {|a, b|
assert_equal(2, a)
assert_equal(3, b)
false
}
]
e = [1,2,3].slice_when {|a,b|
block_invocations.shift.call(a, b)
}
assert_equal([[1], [2, 3]], e.to_a)
assert_equal([], block_invocations)
end
def test_slice_when_noblock
assert_raise(ArgumentError) { [].slice_when }
end
def test_slice_when_contiguously_increasing_integers
e = [1,4,9,10,11,12,15,16,19,20,21].slice_when {|i, j| i+1 != j }
assert_equal([[1], [4], [9,10,11,12], [15,16], [19,20,21]], e.to_a)
end
def test_chunk_while_contiguously_increasing_integers
e = [1,4,9,10,11,12,15,16,19,20,21].chunk_while {|i, j| i+1 == j }
assert_equal([[1], [4], [9,10,11,12], [15,16], [19,20,21]], e.to_a)
end
def test_detect
@obj = ('a'..'z')
assert_equal('c', @obj.detect {|x| x == 'c' })
proc = Proc.new {|x| x == 'c' }
assert_equal('c', @obj.detect(&proc))
lambda = ->(x) { x == 'c' }
assert_equal('c', @obj.detect(&lambda))
assert_equal(['c',2], @obj.each_with_index.detect {|x, i| x == 'c' })
proc2 = Proc.new {|x, i| x == 'c' }
assert_equal(['c',2], @obj.each_with_index.detect(&proc2))
bug9605 = '[ruby-core:61340]'
lambda2 = ->(x, i) { x == 'c' }
assert_equal(['c',2], @obj.each_with_index.detect(&lambda2), bug9605)
end
def test_select
@obj = ('a'..'z')
assert_equal(['c'], @obj.select {|x| x == 'c' })
proc = Proc.new {|x| x == 'c' }
assert_equal(['c'], @obj.select(&proc))
lambda = ->(x) { x == 'c' }
assert_equal(['c'], @obj.select(&lambda))
assert_equal([['c',2]], @obj.each_with_index.select {|x, i| x == 'c' })
proc2 = Proc.new {|x, i| x == 'c' }
assert_equal([['c',2]], @obj.each_with_index.select(&proc2))
bug9605 = '[ruby-core:61340]'
lambda2 = ->(x, i) { x == 'c' }
assert_equal([['c',2]], @obj.each_with_index.select(&lambda2), bug9605)
end
def test_map
@obj = ('a'..'e')
assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map {|x| x.upcase })
proc = Proc.new {|x| x.upcase }
assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map(&proc))
lambda = ->(x) { x.upcase }
assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map(&lambda))
assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
@obj.each_with_index.map {|x, i| [x.upcase, i] })
proc2 = Proc.new {|x, i| [x.upcase, i] }
assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
@obj.each_with_index.map(&proc2))
lambda2 = ->(x, i) { [x.upcase, i] }
assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
@obj.each_with_index.map(&lambda2))
hash = { a: 'hoge', b: 'fuga' }
lambda = -> (k, v) { "#{k}:#{v}" }
assert_equal ["a:hoge", "b:fuga"], hash.map(&lambda)
end
def test_flat_map
@obj = [[1,2], [3,4]]
assert_equal([2,4,6,8], @obj.flat_map {|i| i.map{|j| j*2} })
proc = Proc.new {|i| i.map{|j| j*2} }
assert_equal([2,4,6,8], @obj.flat_map(&proc))
lambda = ->(i) { i.map{|j| j*2} }
assert_equal([2,4,6,8], @obj.flat_map(&lambda))
assert_equal([[1,2],0,[3,4],1],
@obj.each_with_index.flat_map {|x, i| [x,i] })
proc2 = Proc.new {|x, i| [x,i] }
assert_equal([[1,2],0,[3,4],1],
@obj.each_with_index.flat_map(&proc2))
lambda2 = ->(x, i) { [x,i] }
assert_equal([[1,2],0,[3,4],1],
@obj.each_with_index.flat_map(&lambda2))
end
def assert_typed_equal(e, v, cls, msg=nil)
assert_kind_of(cls, v, msg)
assert_equal(e, v, msg)
end
def assert_int_equal(e, v, msg=nil)
assert_typed_equal(e, v, Integer, msg)
end
def assert_rational_equal(e, v, msg=nil)
assert_typed_equal(e, v, Rational, msg)
end
def assert_float_equal(e, v, msg=nil)
assert_typed_equal(e, v, Float, msg)
end
def assert_complex_equal(e, v, msg=nil)
assert_typed_equal(e, v, Complex, msg)
end
def test_sum
class << (enum = Object.new)
include Enumerable
def each
yield 3
yield 5
yield 7
end
end
assert_int_equal(15, enum.sum)
assert_int_equal(0, [].each.sum)
assert_int_equal(3, [3].each.sum)
assert_int_equal(8, [3, 5].each.sum)
assert_int_equal(15, [3, 5, 7].each.sum)
assert_rational_equal(8r, [3, 5r].each.sum)
assert_float_equal(15.0, [3, 5, 7.0].each.sum)
assert_float_equal(15.0, [3, 5r, 7.0].each.sum)
assert_complex_equal(8r + 1i, [3, 5r, 1i].each.sum)
assert_complex_equal(15.0 + 1i, [3, 5r, 7.0, 1i].each.sum)
assert_int_equal(2*FIXNUM_MAX, Array.new(2, FIXNUM_MAX).each.sum)
assert_int_equal(2*(FIXNUM_MAX+1), Array.new(2, FIXNUM_MAX+1).each.sum)
assert_int_equal(10*FIXNUM_MAX, Array.new(10, FIXNUM_MAX).each.sum)
assert_int_equal(0, ([FIXNUM_MAX, 1, -FIXNUM_MAX, -1]*10).each.sum)
assert_int_equal(FIXNUM_MAX*10, ([FIXNUM_MAX+1, -1]*10).each.sum)
assert_int_equal(2*FIXNUM_MIN, Array.new(2, FIXNUM_MIN).each.sum)
assert_float_equal(0.0, [].each.sum(0.0))
assert_float_equal(3.0, [3].each.sum(0.0))
assert_float_equal(3.5, [3].each.sum(0.5))
assert_float_equal(8.5, [3.5, 5].each.sum)
assert_float_equal(10.5, [2, 8.5].each.sum)
assert_float_equal((FIXNUM_MAX+1).to_f, [FIXNUM_MAX, 1, 0.0].each.sum)
assert_float_equal((FIXNUM_MAX+1).to_f, [0.0, FIXNUM_MAX+1].each.sum)
assert_rational_equal(3/2r, [1/2r, 1].each.sum)
assert_rational_equal(5/6r, [1/2r, 1/3r].each.sum)
assert_equal(2.0+3.0i, [2.0, 3.0i].each.sum)
assert_int_equal(13, [1, 2].each.sum(10))
assert_int_equal(16, [1, 2].each.sum(10) {|v| v * 2 })
yielded = []
three = SimpleDelegator.new(3)
ary = [1, 2.0, three]
assert_float_equal(12.0, ary.each.sum {|x| yielded << x; x * 2 })
assert_equal(ary, yielded)
assert_raise(TypeError) { [Object.new].each.sum }
large_number = 100000000
small_number = 1e-9
until (large_number + small_number) == large_number
small_number /= 10
end
assert_float_equal(large_number+(small_number*10), [large_number, *[small_number]*10].each.sum)
assert_float_equal(large_number+(small_number*10), [large_number/1r, *[small_number]*10].each.sum)
assert_float_equal(large_number+(small_number*11), [small_number, large_number/1r, *[small_number]*10].each.sum)
assert_float_equal(small_number, [large_number, small_number, -large_number].each.sum)
k = Class.new do
include Enumerable
def initialize(*values)
@values = values
end
def each(&block)
@values.each(&block)
end
end
assert_equal(+Float::INFINITY, k.new(0.0, +Float::INFINITY).sum)
assert_equal(+Float::INFINITY, k.new(+Float::INFINITY, 0.0).sum)
assert_equal(-Float::INFINITY, k.new(0.0, -Float::INFINITY).sum)
assert_equal(-Float::INFINITY, k.new(-Float::INFINITY, 0.0).sum)
assert_predicate(k.new(-Float::INFINITY, Float::INFINITY).sum, :nan?)
assert_equal("abc", ["a", "b", "c"].each.sum(""))
assert_equal([1, [2], 3], [[1], [[2]], [3]].each.sum([]))
end
def test_hash_sum
histogram = { 1 => 6, 2 => 4, 3 => 3, 4 => 7, 5 => 5, 6 => 4 }
assert_equal(100, histogram.sum {|v, n| v * n })
end
def test_range_sum
assert_int_equal(55, (1..10).sum)
assert_float_equal(55.0, (1..10).sum(0.0))
assert_int_equal(90, (5..10).sum {|v| v * 2 })
assert_float_equal(90.0, (5..10).sum(0.0) {|v| v * 2 })
assert_int_equal(0, (2..0).sum)
assert_int_equal(5, (2..0).sum(5))
assert_int_equal(2, (2..2).sum)
assert_int_equal(42, (2...2).sum(42))
not_a_range = Class.new do
include Enumerable # Defines the `#sum` method
def each
yield 2
yield 4
yield 6
end
def begin; end
def end; end
end
assert_equal(12, not_a_range.new.sum)
end
def test_uniq
src = [1, 1, 1, 1, 2, 2, 3, 4, 5, 6]
assert_equal([1, 2, 3, 4, 5, 6], src.uniq.to_a)
olympics = {
1896 => 'Athens',
1900 => 'Paris',
1904 => 'Chicago',
1906 => 'Athens',
1908 => 'Rome',
}
assert_equal([[1896, "Athens"], [1900, "Paris"], [1904, "Chicago"], [1908, "Rome"]],
olympics.uniq{|k,v| v})
assert_equal([1, 2, 3, 4, 5, 10], (1..100).uniq{|x| (x**2) % 10 }.first(6))
assert_equal([1, [1, 2]], Foo.new.to_enum.uniq)
end
def test_compact
class << (enum = Object.new)
include Enumerable
def each
yield 3
yield nil
yield 7
yield 9
yield nil
end
end
assert_equal([3, 7, 9], enum.compact)
end
def test_transient_heap_sort_by
klass = Class.new do
include Comparable
attr_reader :i
def initialize e
@i = e
end
def <=> other
GC.start
i <=> other.i
end
end
assert_equal [1, 2, 3, 4, 5], (1..5).sort_by{|e| klass.new e}
end
def test_filter_map
@obj = (1..8).to_a
assert_equal([4, 8, 12, 16], @obj.filter_map { |i| i * 2 if i.even? })
assert_equal([2, 4, 6, 8, 10, 12, 14, 16], @obj.filter_map { |i| i * 2 })
assert_equal([0, 0, 0, 0, 0, 0, 0, 0], @obj.filter_map { 0 })
assert_equal([], @obj.filter_map { false })
assert_equal([], @obj.filter_map { nil })
assert_instance_of(Enumerator, @obj.filter_map)
end
end