diff options
Diffstat (limited to 'spec/ruby/core/enumerable')
66 files changed, 3320 insertions, 0 deletions
diff --git a/spec/ruby/core/enumerable/all_spec.rb b/spec/ruby/core/enumerable/all_spec.rb new file mode 100644 index 0000000000..bfde584260 --- /dev/null +++ b/spec/ruby/core/enumerable/all_spec.rb @@ -0,0 +1,121 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#all?" do + + before :each do + @enum = EnumerableSpecs::Numerous.new + @empty = EnumerableSpecs::Empty.new() + @enum1 = [0, 1, 2, -1] + @enum2 = [nil, false, true] + end + + it "always returns true on empty enumeration" do + @empty.all?.should == true + @empty.all? { nil }.should == true + + [].all?.should == true + [].all? { false }.should == true + + {}.all?.should == true + {}.all? { nil }.should == true + end + + it "does not hide exceptions out of #each" do + lambda { + EnumerableSpecs::ThrowingEach.new.all? + }.should raise_error(RuntimeError) + + lambda { + EnumerableSpecs::ThrowingEach.new.all? { false } + }.should raise_error(RuntimeError) + end + + describe "with no block" do + it "returns true if no elements are false or nil" do + @enum.all?.should == true + @enum1.all?.should == true + @enum2.all?.should == false + + EnumerableSpecs::Numerous.new('a','b','c').all?.should == true + EnumerableSpecs::Numerous.new(0, "x", true).all?.should == true + end + + it "returns false if there are false or nil elements" do + EnumerableSpecs::Numerous.new(false).all?.should == false + EnumerableSpecs::Numerous.new(false, false).all?.should == false + + EnumerableSpecs::Numerous.new(nil).all?.should == false + EnumerableSpecs::Numerous.new(nil, nil).all?.should == false + + EnumerableSpecs::Numerous.new(1, nil, 2).all?.should == false + EnumerableSpecs::Numerous.new(0, "x", false, true).all?.should == false + @enum2.all?.should == false + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMultiWithFalse.new + multi.all?.should be_true + end + + end + + describe "with block" do + it "returns true if the block never returns false or nil" do + @enum.all? { true }.should == true + @enum1.all?{ |o| o < 5 }.should == true + @enum1.all?{ |o| 5 }.should == true + end + + it "returns false if the block ever returns false or nil" do + @enum.all? { false }.should == false + @enum.all? { nil }.should == false + @enum1.all?{ |o| o > 2 }.should == false + + EnumerableSpecs::Numerous.new.all? { |i| i > 5 }.should == false + EnumerableSpecs::Numerous.new.all? { |i| i == 3 ? nil : true }.should == false + end + + it "stops iterating once the return value is determined" do + yielded = [] + EnumerableSpecs::Numerous.new(:one, :two, :three).all? do |e| + yielded << e + false + end.should == false + yielded.should == [:one] + + yielded = [] + EnumerableSpecs::Numerous.new(true, true, false, true).all? do |e| + yielded << e + e + end.should == false + yielded.should == [true, true, false] + + yielded = [] + EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).all? do |e| + yielded << e + e + end.should == true + yielded.should == [1, 2, 3, 4, 5] + end + + it "does not hide exceptions out of the block" do + lambda { + @enum.all? { raise "from block" } + }.should raise_error(RuntimeError) + end + + it "gathers initial args as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.all? {|e| !(Array === e) }.should be_true + end + + it "yields multiple arguments when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + yielded = [] + multi.all? {|e, i| yielded << [e, i] } + yielded.should == [[1, 2], [3, 4], [6, 7]] + end + + end +end diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb new file mode 100644 index 0000000000..4f7af68b07 --- /dev/null +++ b/spec/ruby/core/enumerable/any_spec.rb @@ -0,0 +1,141 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#any?" do + before :each do + @enum = EnumerableSpecs::Numerous.new + @empty = EnumerableSpecs::Empty.new() + @enum1 = [0, 1, 2, -1] + @enum2 = [nil, false, true] + end + + it "always returns false on empty enumeration" do + @empty.any?.should == false + @empty.any? { nil }.should == false + + [].any?.should == false + [].any? { false }.should == false + + {}.any?.should == false + {}.any? { nil }.should == false + end + + it "raises an ArgumentError when any arguments provided" do + lambda { @enum.any?(Proc.new {}) }.should raise_error(ArgumentError) + lambda { @enum.any?(nil) }.should raise_error(ArgumentError) + lambda { @empty.any?(1) }.should raise_error(ArgumentError) + lambda { @enum1.any?(1) {} }.should raise_error(ArgumentError) + lambda { @enum2.any?(1, 2, 3) {} }.should raise_error(ArgumentError) + end + + it "does not hide exceptions out of #each" do + lambda { + EnumerableSpecs::ThrowingEach.new.any? + }.should raise_error(RuntimeError) + + lambda { + EnumerableSpecs::ThrowingEach.new.any? { false } + }.should raise_error(RuntimeError) + end + + describe "with no block" do + it "returns true if any element is not false or nil" do + @enum.any?.should == true + @enum1.any?.should == true + @enum2.any?.should == true + EnumerableSpecs::Numerous.new(true).any?.should == true + EnumerableSpecs::Numerous.new('a','b','c').any?.should == true + EnumerableSpecs::Numerous.new('a','b','c', nil).any?.should == true + EnumerableSpecs::Numerous.new(1, nil, 2).any?.should == true + EnumerableSpecs::Numerous.new(1, false).any?.should == true + EnumerableSpecs::Numerous.new(false, nil, 1, false).any?.should == true + EnumerableSpecs::Numerous.new(false, 0, nil).any?.should == true + end + + it "returns false if all elements are false or nil" do + EnumerableSpecs::Numerous.new(false).any?.should == false + EnumerableSpecs::Numerous.new(false, false).any?.should == false + EnumerableSpecs::Numerous.new(nil).any?.should == false + EnumerableSpecs::Numerous.new(nil, nil).any?.should == false + EnumerableSpecs::Numerous.new(nil, false, nil).any?.should == false + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMultiWithFalse.new + multi.any?.should be_true + end + end + + describe "with block" do + it "returns true if the block ever returns other than false or nil" do + @enum.any? { true } == true + @enum.any? { 0 } == true + @enum.any? { 1 } == true + + @enum1.any? { Object.new } == true + @enum1.any?{ |o| o < 1 }.should == true + @enum1.any?{ |o| 5 }.should == true + + @enum2.any? { |i| i == nil }.should == true + end + + it "any? should return false if the block never returns other than false or nil" do + @enum.any? { false }.should == false + @enum.any? { nil }.should == false + + @enum1.any?{ |o| o < -10 }.should == false + @enum1.any?{ |o| nil }.should == false + + @enum2.any? { |i| i == :stuff }.should == false + end + + it "stops iterating once the return value is determined" do + yielded = [] + EnumerableSpecs::Numerous.new(:one, :two, :three).any? do |e| + yielded << e + false + end.should == false + yielded.should == [:one, :two, :three] + + yielded = [] + EnumerableSpecs::Numerous.new(true, true, false, true).any? do |e| + yielded << e + e + end.should == true + yielded.should == [true] + + yielded = [] + EnumerableSpecs::Numerous.new(false, nil, false, true, false).any? do |e| + yielded << e + e + end.should == true + yielded.should == [false, nil, false, true] + + yielded = [] + EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).any? do |e| + yielded << e + e + end.should == true + yielded.should == [1] + end + + it "does not hide exceptions out of the block" do + lambda { + @enum.any? { raise "from block" } + }.should raise_error(RuntimeError) + end + + it "gathers initial args as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.any? {|e| e == 1 }.should be_true + end + + it "yields multiple arguments when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + yielded = [] + multi.any? {|e, i| yielded << [e, i] } + yielded.should == [[1, 2]] + end + + end +end diff --git a/spec/ruby/core/enumerable/chunk_spec.rb b/spec/ruby/core/enumerable/chunk_spec.rb new file mode 100644 index 0000000000..9d658010e1 --- /dev/null +++ b/spec/ruby/core/enumerable/chunk_spec.rb @@ -0,0 +1,100 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#chunk" do + before do + ScratchPad.record [] + end + + ruby_version_is ""..."2.4" do + it "raises an ArgumentError if called without a block" do + lambda do + EnumerableSpecs::Numerous.new.chunk + end.should raise_error(ArgumentError) + end + end + + ruby_version_is "2.4" do + it "returns an Enumerator if called without a block" do + chunk = EnumerableSpecs::Numerous.new(1, 2, 3, 1, 2).chunk + chunk.should be_an_instance_of(Enumerator) + result = chunk.with_index {|elt, i| elt - i }.to_a + result.should == [[1, [1, 2, 3]], [-2, [1, 2]]] + end + end + + it "returns an Enumerator if given a block" do + EnumerableSpecs::Numerous.new.chunk {}.should be_an_instance_of(Enumerator) + end + + it "yields the current element and the current chunk to the block" do + e = EnumerableSpecs::Numerous.new(1, 2, 3) + e.chunk { |x| ScratchPad << x }.to_a + ScratchPad.recorded.should == [1, 2, 3] + end + + it "returns elements of the Enumerable in an Array of Arrays, [v, ary], where 'ary' contains the consecutive elements for which the block returned the value 'v'" do + e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 3, 2, 1) + result = e.chunk { |x| x < 3 && 1 || 0 }.to_a + result.should == [[1, [1, 2]], [0, [3]], [1, [2]], [0, [3]], [1, [2, 1]]] + end + + it "returns elements for which the block returns :_alone in separate Arrays" do + e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 1) + result = e.chunk { |x| x < 2 && :_alone }.to_a + result.should == [[:_alone, [1]], [false, [2, 3, 2]], [:_alone, [1]]] + end + + it "does not return elements for which the block returns :_separator" do + e = EnumerableSpecs::Numerous.new(1, 2, 3, 3, 2, 1) + result = e.chunk { |x| x == 2 ? :_separator : 1 }.to_a + result.should == [[1, [1]], [1, [3, 3]], [1, [1]]] + end + + it "does not return elements for which the block returns nil" do + e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 1) + result = e.chunk { |x| x == 2 ? nil : 1 }.to_a + result.should == [[1, [1]], [1, [3]], [1, [1]]] + end + + it "raises a RuntimeError if the block returns a Symbol starting with an underscore other than :_alone or :_separator" do + e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 1) + lambda { e.chunk { |x| :_arbitrary }.to_a }.should raise_error(RuntimeError) + end + + ruby_version_is ""..."2.3" do + describe "with [initial_state]" do + it "yields an element and an object value-equal but not identical to the object passed to #chunk" do + e = EnumerableSpecs::Numerous.new(1) + value = "value" + + e.chunk(value) do |x, v| + x.should == 1 + v.should == value + v.should_not equal(value) + end.to_a + end + + it "does not yield the object passed to #chunk if it is nil" do + e = EnumerableSpecs::Numerous.new(1) + e.chunk(nil) { |*x| ScratchPad << x }.to_a + ScratchPad.recorded.should == [[1]] + end + end + end + + ruby_version_is "2.3" do + it "does not accept arguments" do + e = EnumerableSpecs::Numerous.new(1, 2, 3) + lambda { + e.chunk(1) {} + }.should raise_error(ArgumentError) + end + end + + it 'returned Enumerator size returns nil' do + e = EnumerableSpecs::NumerousWithSize.new(1, 2, 3, 2, 1) + enum = e.chunk { |x| true } + enum.size.should == nil + end +end diff --git a/spec/ruby/core/enumerable/chunk_while_spec.rb b/spec/ruby/core/enumerable/chunk_while_spec.rb new file mode 100644 index 0000000000..a5cbdc3348 --- /dev/null +++ b/spec/ruby/core/enumerable/chunk_while_spec.rb @@ -0,0 +1,44 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +ruby_version_is "2.3" do + describe "Enumerable#chunk_while" do + before :each do + ary = [10, 9, 7, 6, 4, 3, 2, 1] + @enum = EnumerableSpecs::Numerous.new(*ary) + @result = @enum.chunk_while { |i, j| i - 1 == j } + @enum_length = ary.length + end + + context "when given a block" do + it "returns an enumerator" do + @result.should be_an_instance_of(Enumerator) + end + + it "splits chunks between adjacent elements i and j where the block returns false" do + @result.to_a.should == [[10, 9], [7, 6], [4, 3, 2, 1]] + end + + it "calls the block for length of the receiver enumerable minus one times" do + times_called = 0 + @enum.chunk_while do |i, j| + times_called += 1 + i - 1 == j + end.to_a + times_called.should == (@enum_length - 1) + end + end + + context "when not given a block" do + it "raises an ArgumentError" do + lambda { @enum.chunk_while }.should raise_error(ArgumentError) + end + end + + context "on a single-element array" do + it "ignores the block and returns an enumerator that yields [element]" do + [1].chunk_while {|x| x.even?}.to_a.should == [[1]] + end + end + end +end diff --git a/spec/ruby/core/enumerable/collect_concat_spec.rb b/spec/ruby/core/enumerable/collect_concat_spec.rb new file mode 100644 index 0000000000..6f21012060 --- /dev/null +++ b/spec/ruby/core/enumerable/collect_concat_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/collect_concat', __FILE__) + +describe "Enumerable#collect_concat" do + it_behaves_like(:enumerable_collect_concat , :collect_concat) +end diff --git a/spec/ruby/core/enumerable/collect_spec.rb b/spec/ruby/core/enumerable/collect_spec.rb new file mode 100644 index 0000000000..a830eef9f7 --- /dev/null +++ b/spec/ruby/core/enumerable/collect_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/collect', __FILE__) + +describe "Enumerable#collect" do + it_behaves_like(:enumerable_collect , :collect) +end diff --git a/spec/ruby/core/enumerable/count_spec.rb b/spec/ruby/core/enumerable/count_spec.rb new file mode 100644 index 0000000000..9d1e08f3a9 --- /dev/null +++ b/spec/ruby/core/enumerable/count_spec.rb @@ -0,0 +1,59 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#count" do + before :each do + @elements = [1, 2, 4, 2] + @numerous = EnumerableSpecs::Numerous.new(*@elements) + end + + describe "when no argument or a block" do + it "returns size" do + @numerous.count.should == 4 + end + + describe "with a custom size method" do + before :each do + class << @numerous + def size + :any_object + end + end + end + + it "ignores the custom size method" do + @numerous.count.should == 4 + end + end + end + + it "counts nils if given nil as an argument" do + EnumerableSpecs::Numerous.new(nil, nil, nil, false).count(nil).should == 3 + end + + it "accepts an argument for comparison using ==" do + @numerous.count(2).should == 2 + end + + it "uses a block for comparison" do + @numerous.count{|x| x%2==0 }.should == 3 + end + + it "ignores the block when given an argument" do + -> { + @numerous.count(4){|x| x%2==0 }.should == 1 + }.should complain(/given block not used/) + end + + describe "when each yields multiple values" do + it "gathers initial args as elements" do + multi = EnumerableSpecs::YieldsMulti.new + multi.count {|e| e == 1 }.should == 1 + end + + it "accepts an argument for comparison using ==" do + multi = EnumerableSpecs::YieldsMulti.new + multi.count([1, 2]).should == 1 + end + end +end diff --git a/spec/ruby/core/enumerable/cycle_spec.rb b/spec/ruby/core/enumerable/cycle_spec.rb new file mode 100644 index 0000000000..2f5760992d --- /dev/null +++ b/spec/ruby/core/enumerable/cycle_spec.rb @@ -0,0 +1,104 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumeratorized', __FILE__) + +describe "Enumerable#cycle" do + describe "passed no argument or nil" do + it "loops indefinitely" do + [[],[nil]].each do |args| + bomb = 10 + EnumerableSpecs::Numerous.new.cycle(*args) do + bomb -= 1 + break 42 if bomb <= 0 + end.should == 42 + bomb.should == 0 + end + end + + it "returns nil if there are no elements" do + out = EnumerableSpecs::Empty.new.cycle { break :nope } + out.should be_nil + end + + it "yields successive elements of the array repeatedly" do + b = [] + EnumerableSpecs::Numerous.new(1,2,3).cycle do |elem| + b << elem + break if b.size == 7 + end + b.should == [1,2,3,1,2,3,1] + end + + it "calls each at most once" do + enum = EnumerableSpecs::EachCounter.new(1, 2) + enum.cycle.first(6).should == [1,2,1,2,1,2] + enum.times_called.should == 1 + end + + it "yields only when necessary" do + enum = EnumerableSpecs::EachCounter.new(10, 20, 30) + enum.cycle { |x| break if x == 20} + enum.times_yielded.should == 2 + end + end + + describe "passed a number n as an argument" do + it "returns nil and does nothing for non positive n" do + EnumerableSpecs::ThrowingEach.new.cycle(0) {}.should be_nil + EnumerableSpecs::NoEach.new.cycle(-22) {}.should be_nil + end + + it "calls each at most once" do + enum = EnumerableSpecs::EachCounter.new(1, 2) + enum.cycle(3).to_a.should == [1,2,1,2,1,2] + enum.times_called.should == 1 + end + + it "yields only when necessary" do + enum = EnumerableSpecs::EachCounter.new(10, 20, 30) + enum.cycle(3) { |x| break if x == 20} + enum.times_yielded.should == 2 + end + + it "tries to convert n to an Integer using #to_int" do + enum = EnumerableSpecs::Numerous.new(3, 2, 1) + enum.cycle(2.3).to_a.should == [3, 2, 1, 3, 2, 1] + + obj = mock('to_int') + obj.should_receive(:to_int).and_return(2) + enum.cycle(obj).to_a.should == [3, 2, 1, 3, 2, 1] + end + + it "raises a TypeError when the passed n can be coerced to Integer" do + enum = EnumerableSpecs::Numerous.new + lambda{ enum.cycle("cat"){} }.should raise_error(TypeError) + end + + it "raises an ArgumentError if more arguments are passed" do + enum = EnumerableSpecs::Numerous.new + lambda{ enum.cycle(1, 2) {} }.should raise_error(ArgumentError) + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.cycle(2).to_a.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9], [1, 2], [3, 4, 5], [6, 7, 8, 9]] + end + end + + describe "Enumerable with size" do + before :all do + @object = EnumerableSpecs::NumerousWithSize.new(1, 2, 3, 4) + @empty_object = EnumerableSpecs::EmptyWithSize.new + end + it_should_behave_like :enumeratorized_with_cycle_size + end + + describe "Enumerable with no size" do + before :all do + @object = EnumerableSpecs::Numerous.new(1, 2, 3, 4) + @method = :cycle + end + it_should_behave_like :enumeratorized_with_unknown_size + end + +end diff --git a/spec/ruby/core/enumerable/detect_spec.rb b/spec/ruby/core/enumerable/detect_spec.rb new file mode 100644 index 0000000000..f69e456052 --- /dev/null +++ b/spec/ruby/core/enumerable/detect_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/find', __FILE__) + +describe "Enumerable#detect" do + it_behaves_like(:enumerable_find , :detect) +end diff --git a/spec/ruby/core/enumerable/drop_spec.rb b/spec/ruby/core/enumerable/drop_spec.rb new file mode 100644 index 0000000000..1bcdc0ee9a --- /dev/null +++ b/spec/ruby/core/enumerable/drop_spec.rb @@ -0,0 +1,43 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#drop" do + before :each do + @enum = EnumerableSpecs::Numerous.new(3, 2, 1, :go) + end + + it "requires exactly one argument" do + lambda{ @enum.drop{} }.should raise_error(ArgumentError) + lambda{ @enum.drop(1, 2){} }.should raise_error(ArgumentError) + end + + describe "passed a number n as an argument" do + it "raises ArgumentError if n < 0" do + lambda{ @enum.drop(-1) }.should raise_error(ArgumentError) + end + + it "tries to convert n to an Integer using #to_int" do + @enum.drop(2.3).should == [1, :go] + + obj = mock('to_int') + obj.should_receive(:to_int).and_return(2) + @enum.drop(obj).should == [1, :go] + end + + it "returns [] for empty enumerables" do + EnumerableSpecs::Empty.new.drop(0).should == [] + EnumerableSpecs::Empty.new.drop(2).should == [] + end + + it "returns [] if dropping all" do + @enum.drop(5).should == [] + EnumerableSpecs::Numerous.new(3, 2, 1, :go).drop(4).should == [] + end + + it "raises a TypeError when the passed n can be coerced to Integer" do + lambda{ @enum.drop("hat") }.should raise_error(TypeError) + lambda{ @enum.drop(nil) }.should raise_error(TypeError) + end + + end +end diff --git a/spec/ruby/core/enumerable/drop_while_spec.rb b/spec/ruby/core/enumerable/drop_while_spec.rb new file mode 100644 index 0000000000..731b9588e4 --- /dev/null +++ b/spec/ruby/core/enumerable/drop_while_spec.rb @@ -0,0 +1,50 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#drop_while" do + before :each do + @enum = EnumerableSpecs::Numerous.new(3, 2, 1, :go) + end + + it "returns an Enumerator if no block given" do + @enum.drop_while.should be_an_instance_of(Enumerator) + end + + it "returns no/all elements for {true/false} block" do + @enum.drop_while{true}.should == [] + @enum.drop_while{false}.should == @enum.to_a + end + + it "accepts returns other than true/false" do + @enum.drop_while{1}.should == [] + @enum.drop_while{nil}.should == @enum.to_a + end + + it "passes elements to the block until the first false" do + a = [] + @enum.drop_while{|obj| (a << obj).size < 3}.should == [1, :go] + a.should == [3, 2, 1] + end + + it "will only go through what's needed" do + enum = EnumerableSpecs::EachCounter.new(1,2,3,4) + enum.drop_while { |x| + break 42 if x == 3 + true + }.should == 42 + enum.times_yielded.should == 3 + end + + it "doesn't return self when it could" do + a = [1,2,3] + a.drop_while{false}.should_not equal(a) + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.drop_while {|e| e != [6, 7, 8, 9] }.should == [[6, 7, 8, 9]] + end + + it_behaves_like :enumerable_enumeratorized_with_unknown_size, :drop_while +end diff --git a/spec/ruby/core/enumerable/each_cons_spec.rb b/spec/ruby/core/enumerable/each_cons_spec.rb new file mode 100644 index 0000000000..6720199bc3 --- /dev/null +++ b/spec/ruby/core/enumerable/each_cons_spec.rb @@ -0,0 +1,99 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumeratorized', __FILE__) + +describe "Enumerable#each_cons" do + before :each do + @enum = EnumerableSpecs::Numerous.new(4,3,2,1) + @in_threes = [[4,3,2],[3,2,1]] + end + + it "passes element groups to the block" do + acc = [] + @enum.each_cons(3){|g| acc << g}.should be_nil + acc.should == @in_threes + end + + it "raises an ArgumentError if there is not a single parameter > 0" do + lambda{ @enum.each_cons(0){} }.should raise_error(ArgumentError) + lambda{ @enum.each_cons(-2){} }.should raise_error(ArgumentError) + lambda{ @enum.each_cons{} }.should raise_error(ArgumentError) + lambda{ @enum.each_cons(2,2){} }.should raise_error(ArgumentError) + lambda{ @enum.each_cons(0) }.should raise_error(ArgumentError) + lambda{ @enum.each_cons(-2) }.should raise_error(ArgumentError) + lambda{ @enum.each_cons }.should raise_error(ArgumentError) + lambda{ @enum.each_cons(2,2) }.should raise_error(ArgumentError) + end + + it "tries to convert n to an Integer using #to_int" do + acc = [] + @enum.each_cons(3.3){|g| acc << g}.should == nil + acc.should == @in_threes + + obj = mock('to_int') + obj.should_receive(:to_int).and_return(3) + @enum.each_cons(obj){|g| break g.length}.should == 3 + end + + it "works when n is >= full length" do + full = @enum.to_a + acc = [] + @enum.each_cons(full.length){|g| acc << g} + acc.should == [full] + acc = [] + @enum.each_cons(full.length+1){|g| acc << g} + acc.should == [] + end + + it "yields only as much as needed" do + cnt = EnumerableSpecs::EachCounter.new(1, 2, :stop, "I said stop!", :got_it) + cnt.each_cons(2) {|g| break 42 if g[-1] == :stop }.should == 42 + cnt.times_yielded.should == 3 + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.each_cons(2).to_a.should == [[[1, 2], [3, 4, 5]], [[3, 4, 5], [6, 7, 8, 9]]] + end + + describe "when no block is given" do + it "returns an enumerator" do + e = @enum.each_cons(3) + e.should be_an_instance_of(Enumerator) + e.to_a.should == @in_threes + end + + describe "Enumerable with size" do + describe "returned Enumerator" do + describe "size" do + it "returns enum size - each_cons argument + 1" do + enum = EnumerableSpecs::NumerousWithSize.new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + enum.each_cons(10).size.should == 1 + enum.each_cons(9).size.should == 2 + enum.each_cons(3).size.should == 8 + enum.each_cons(2).size.should == 9 + enum.each_cons(1).size.should == 10 + end + + it "returns 0 when the argument is larger than self" do + enum = EnumerableSpecs::NumerousWithSize.new(1, 2, 3) + enum.each_cons(20).size.should == 0 + end + + it "returns 0 when the enum is empty" do + enum = EnumerableSpecs::EmptyWithSize.new + enum.each_cons(10).size.should == 0 + end + end + end + end + + describe "Enumerable with no size" do + before :all do + @object = EnumerableSpecs::Numerous.new(1, 2, 3, 4) + @method = [:each_cons, 8] + end + it_should_behave_like :enumeratorized_with_unknown_size + end + end +end diff --git a/spec/ruby/core/enumerable/each_entry_spec.rb b/spec/ruby/core/enumerable/each_entry_spec.rb new file mode 100644 index 0000000000..05d181a998 --- /dev/null +++ b/spec/ruby/core/enumerable/each_entry_spec.rb @@ -0,0 +1,41 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#each_entry" do + before :each do + ScratchPad.record [] + @enum = EnumerableSpecs::YieldsMixed.new + @entries = [1, [2], [3,4], [5,6,7], [8,9], nil, []] + end + + it "yields multiple arguments as an array" do + acc = [] + @enum.each_entry {|g| acc << g}.should equal(@enum) + acc.should == @entries + end + + it "returns an enumerator if no block" do + e = @enum.each_entry + e.should be_an_instance_of(Enumerator) + e.to_a.should == @entries + end + + it "passes through the values yielded by #each_with_index" do + [:a, :b].each_with_index.each_entry { |x, i| ScratchPad << [x, i] } + ScratchPad.recorded.should == [[:a, 0], [:b, 1]] + end + + it "raises an ArgumentError when extra arguments" do + lambda { @enum.each_entry("one").to_a }.should raise_error(ArgumentError) + lambda { @enum.each_entry("one"){}.to_a }.should raise_error(ArgumentError) + end + + it "passes extra arguments to #each" do + enum = EnumerableSpecs::EachCounter.new(1, 2) + enum.each_entry(:foo, "bar").to_a.should == [1,2] + enum.arguments_passed.should == [:foo, "bar"] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :each_entry +end diff --git a/spec/ruby/core/enumerable/each_slice_spec.rb b/spec/ruby/core/enumerable/each_slice_spec.rb new file mode 100644 index 0000000000..62503fe206 --- /dev/null +++ b/spec/ruby/core/enumerable/each_slice_spec.rb @@ -0,0 +1,101 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumeratorized', __FILE__) + +describe "Enumerable#each_slice" do + before :each do + @enum = EnumerableSpecs::Numerous.new(7,6,5,4,3,2,1) + @sliced = [[7,6,5],[4,3,2],[1]] + end + + it "passes element groups to the block" do + acc = [] + @enum.each_slice(3){|g| acc << g}.should be_nil + acc.should == @sliced + end + + it "raises an ArgumentError if there is not a single parameter > 0" do + lambda{ @enum.each_slice(0){} }.should raise_error(ArgumentError) + lambda{ @enum.each_slice(-2){} }.should raise_error(ArgumentError) + lambda{ @enum.each_slice{} }.should raise_error(ArgumentError) + lambda{ @enum.each_slice(2,2){} }.should raise_error(ArgumentError) + lambda{ @enum.each_slice(0) }.should raise_error(ArgumentError) + lambda{ @enum.each_slice(-2) }.should raise_error(ArgumentError) + lambda{ @enum.each_slice }.should raise_error(ArgumentError) + lambda{ @enum.each_slice(2,2) }.should raise_error(ArgumentError) + end + + it "tries to convert n to an Integer using #to_int" do + acc = [] + @enum.each_slice(3.3){|g| acc << g}.should == nil + acc.should == @sliced + + obj = mock('to_int') + obj.should_receive(:to_int).and_return(3) + @enum.each_slice(obj){|g| break g.length}.should == 3 + end + + it "works when n is >= full length" do + full = @enum.to_a + acc = [] + @enum.each_slice(full.length){|g| acc << g} + acc.should == [full] + acc = [] + @enum.each_slice(full.length+1){|g| acc << g} + acc.should == [full] + end + + it "yields only as much as needed" do + cnt = EnumerableSpecs::EachCounter.new(1, 2, :stop, "I said stop!", :got_it) + cnt.each_slice(2) {|g| break 42 if g[0] == :stop }.should == 42 + cnt.times_yielded.should == 4 + end + + it "returns an enumerator if no block" do + e = @enum.each_slice(3) + e.should be_an_instance_of(Enumerator) + e.to_a.should == @sliced + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.each_slice(2).to_a.should == [[[1, 2], [3, 4, 5]], [[6, 7, 8, 9]]] + end + + describe "when no block is given" do + it "returns an enumerator" do + e = @enum.each_slice(3) + e.should be_an_instance_of(Enumerator) + e.to_a.should == @sliced + end + + describe "Enumerable with size" do + describe "returned Enumerator" do + describe "size" do + it "returns the ceil of Enumerable size divided by the argument value" do + enum = EnumerableSpecs::NumerousWithSize.new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + enum.each_slice(10).size.should == 1 + enum.each_slice(9).size.should == 2 + enum.each_slice(3).size.should == 4 + enum.each_slice(2).size.should == 5 + enum.each_slice(1).size.should == 10 + end + + it "returns 0 when the Enumerable is empty" do + enum = EnumerableSpecs::EmptyWithSize.new + enum.each_slice(10).size.should == 0 + end + end + end + end + + describe "Enumerable with no size" do + before :all do + @object = EnumerableSpecs::Numerous.new(1, 2, 3, 4) + @method = [:each_slice, 8] + end + it_should_behave_like :enumeratorized_with_unknown_size + end + end + +end diff --git a/spec/ruby/core/enumerable/each_with_index_spec.rb b/spec/ruby/core/enumerable/each_with_index_spec.rb new file mode 100644 index 0000000000..9884e71167 --- /dev/null +++ b/spec/ruby/core/enumerable/each_with_index_spec.rb @@ -0,0 +1,53 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#each_with_index" do + + before :each do + @b = EnumerableSpecs::Numerous.new(2, 5, 3, 6, 1, 4) + end + + it "passes each element and its index to block" do + @a = [] + @b.each_with_index { |o, i| @a << [o, i] } + @a.should == [[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]] + end + + it "provides each element to the block" do + acc = [] + obj = EnumerableSpecs::EachDefiner.new() + res = obj.each_with_index {|a,i| acc << [a,i]} + acc.should == [] + obj.should == res + end + + it "provides each element to the block and its index" do + acc = [] + res = @b.each_with_index {|a,i| acc << [a,i]} + [[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]].should == acc + res.should eql(@b) + end + + it "binds splat arguments properly" do + acc = [] + res = @b.each_with_index { |*b| c,d = b; acc << c; acc << d } + [2, 0, 5, 1, 3, 2, 6, 3, 1, 4, 4, 5].should == acc + res.should eql(@b) + end + + it "returns an enumerator if no block" do + e = @b.each_with_index + e.should be_an_instance_of(Enumerator) + e.to_a.should == [[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]] + end + + it "passes extra parameters to each" do + count = EnumerableSpecs::EachCounter.new(:apple) + e = count.each_with_index(:foo, :bar) + e.to_a.should == [[:apple, 0]] + count.arguments_passed.should == [:foo, :bar] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :each_with_index +end diff --git a/spec/ruby/core/enumerable/each_with_object_spec.rb b/spec/ruby/core/enumerable/each_with_object_spec.rb new file mode 100644 index 0000000000..13a7c1c66d --- /dev/null +++ b/spec/ruby/core/enumerable/each_with_object_spec.rb @@ -0,0 +1,41 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#each_with_object" do + before :each do + @values = [2, 5, 3, 6, 1, 4] + @enum = EnumerableSpecs::Numerous.new(*@values) + @initial = "memo" + end + + it "passes each element and its argument to the block" do + acc = [] + @enum.each_with_object(@initial) do |elem, obj| + obj.should equal(@initial) + obj = 42 + acc << elem + end.should equal(@initial) + acc.should == @values + end + + it "returns an enumerator if no block" do + acc = [] + e = @enum.each_with_object(@initial) + e.each do |elem, obj| + obj.should equal(@initial) + obj = 42 + acc << elem + end.should equal(@initial) + acc.should == @values + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + array = [] + multi.each_with_object(array) { |elem, obj| obj << elem } + array.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, [:each_with_object, []] +end diff --git a/spec/ruby/core/enumerable/entries_spec.rb b/spec/ruby/core/enumerable/entries_spec.rb new file mode 100644 index 0000000000..94eceee713 --- /dev/null +++ b/spec/ruby/core/enumerable/entries_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/entries', __FILE__) + +describe "Enumerable#entries" do + it_behaves_like(:enumerable_entries , :entries) +end diff --git a/spec/ruby/core/enumerable/find_all_spec.rb b/spec/ruby/core/enumerable/find_all_spec.rb new file mode 100644 index 0000000000..3d587d7709 --- /dev/null +++ b/spec/ruby/core/enumerable/find_all_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/find_all', __FILE__) + +describe "Enumerable#find_all" do + it_behaves_like(:enumerable_find_all , :find_all) +end diff --git a/spec/ruby/core/enumerable/find_index_spec.rb b/spec/ruby/core/enumerable/find_index_spec.rb new file mode 100644 index 0000000000..c118a61fcf --- /dev/null +++ b/spec/ruby/core/enumerable/find_index_spec.rb @@ -0,0 +1,89 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#find_index" do + before :each do + @elements = [2, 4, 6, 8, 10] + @numerous = EnumerableSpecs::Numerous.new(*@elements) + @yieldsmixed = EnumerableSpecs::YieldsMixed2.new + end + + it "passes each entry in enum to block while block when block is false" do + visited_elements = [] + @numerous.find_index do |element| + visited_elements << element + false + end + visited_elements.should == @elements + end + + it "returns nil when the block is false" do + @numerous.find_index {|e| false }.should == nil + end + + it "returns the first index for which the block is not false" do + @elements.each_with_index do |element, index| + @numerous.find_index {|e| e > element - 1 }.should == index + end + end + + it "returns the first index found" do + repeated = [10, 11, 11, 13, 11, 13, 10, 10, 13, 11] + numerous_repeat = EnumerableSpecs::Numerous.new(*repeated) + repeated.each do |element| + numerous_repeat.find_index(element).should == element - 10 + end + end + + it "returns nil when the element not found" do + @numerous.find_index(-1).should == nil + end + + it "ignores the block if an argument is given" do + -> { + @numerous.find_index(-1) {|e| true }.should == nil + }.should complain(/given block not used/) + end + + it "returns an Enumerator if no block given" do + @numerous.find_index.should be_an_instance_of(Enumerator) + end + + it "uses #== for testing equality" do + [2].to_enum.find_index(2.0).should == 0 + [2.0].to_enum.find_index(2).should == 0 + end + + describe "without block" do + it "gathers whole arrays as elements when each yields multiple" do + @yieldsmixed.find_index([0, 1, 2]).should == 3 + end + end + + describe "with block" do + before :each do + ScratchPad.record [] + end + + after :each do + ScratchPad.clear + end + + describe "given a single yield parameter" do + it "passes first element to the parameter" do + @yieldsmixed.find_index {|a| ScratchPad << a; false } + ScratchPad.recorded.should == EnumerableSpecs::YieldsMixed2.first_yields + end + end + + describe "given a greedy yield parameter" do + it "passes a gathered array to the parameter" do + @yieldsmixed.find_index {|*args| ScratchPad << args; false } + ScratchPad.recorded.should == EnumerableSpecs::YieldsMixed2.greedy_yields + end + end + end + + it_behaves_like :enumerable_enumeratorized_with_unknown_size, :find_index +end diff --git a/spec/ruby/core/enumerable/find_spec.rb b/spec/ruby/core/enumerable/find_spec.rb new file mode 100644 index 0000000000..62e1194537 --- /dev/null +++ b/spec/ruby/core/enumerable/find_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/find', __FILE__) + +describe "Enumerable#find" do + it_behaves_like(:enumerable_find , :find) +end diff --git a/spec/ruby/core/enumerable/first_spec.rb b/spec/ruby/core/enumerable/first_spec.rb new file mode 100644 index 0000000000..a85550ee3b --- /dev/null +++ b/spec/ruby/core/enumerable/first_spec.rb @@ -0,0 +1,28 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/take', __FILE__) + +describe "Enumerable#first" do + it "returns the first element" do + EnumerableSpecs::Numerous.new.first.should == 2 + EnumerableSpecs::Empty.new.first.should == nil + end + + it "returns nil if self is empty" do + EnumerableSpecs::Empty.new.first.should == nil + end + + it 'returns a gathered array from yield parameters' do + EnumerableSpecs::YieldsMulti.new.to_enum.first.should == [1, 2] + EnumerableSpecs::YieldsMixed2.new.to_enum.first.should == nil + end + + it "raises a RangeError when passed a Bignum" do + enum = EnumerableSpecs::Empty.new + lambda { enum.first(bignum_value) }.should raise_error(RangeError) + end + + describe "when passed an argument" do + it_behaves_like :enumerable_take, :first + end +end diff --git a/spec/ruby/core/enumerable/fixtures/classes.rb b/spec/ruby/core/enumerable/fixtures/classes.rb new file mode 100644 index 0000000000..26a8aff8e2 --- /dev/null +++ b/spec/ruby/core/enumerable/fixtures/classes.rb @@ -0,0 +1,331 @@ +module EnumerableSpecs + + class Numerous + include Enumerable + def initialize(*list) + @list = list.empty? ? [2, 5, 3, 6, 1, 4] : list + end + + def each + @list.each { |i| yield i } + end + end + + class NumerousWithSize < Numerous + def size + @list.size + end + end + + class EachCounter < Numerous + attr_reader :times_called, :times_yielded, :arguments_passed + def initialize(*list) + super(*list) + @times_yielded = @times_called = 0 + end + + def each(*arg) + @times_called += 1 + @times_yielded = 0 + @arguments_passed = arg + @list.each do |i| + @times_yielded +=1 + yield i + end + end + end + + class Empty + include Enumerable + def each + end + end + + class EmptyWithSize + include Enumerable + def each + end + def size + 0 + end + end + + class ThrowingEach + include Enumerable + def each + raise "from each" + end + end + + class NoEach + include Enumerable + end + + # (Legacy form rubycon) + class EachDefiner + + include Enumerable + + attr_reader :arr + + def initialize(*arr) + @arr = arr + end + + def each + i = 0 + loop do + break if i == @arr.size + yield @arr[i] + i += 1 + end + end + + end + + class SortByDummy + def initialize(s) + @s = s + end + + def s + @s + end + end + + class ComparesByVowelCount + + attr_accessor :value, :vowels + + def self.wrap(*args) + args.map {|element| ComparesByVowelCount.new(element)} + end + + def initialize(string) + self.value = string + self.vowels = string.gsub(/[^aeiou]/, '').size + end + + def <=>(other) + self.vowels <=> other.vowels + end + + end + + class InvalidComparable + def <=>(other) + "Not Valid" + end + end + + class ArrayConvertable + attr_accessor :called + def initialize(*values) + @values = values + end + + def to_a + self.called = :to_a + @values + end + + def to_ary + self.called = :to_ary + @values + end + end + + class EnumConvertable + attr_accessor :called + attr_accessor :sym + def initialize(delegate) + @delegate = delegate + end + + def to_enum(sym) + self.called = :to_enum + self.sym = sym + @delegate.to_enum(sym) + end + + def respond_to_missing?(*args) + @delegate.respond_to?(*args) + end + end + + class Equals + def initialize(obj) + @obj = obj + end + def ==(other) + @obj == other + end + end + + class YieldsMulti + include Enumerable + def each + yield 1,2 + yield 3,4,5 + yield 6,7,8,9 + end + end + + class YieldsMultiWithFalse + include Enumerable + def each + yield false,2 + yield false,4,5 + yield false,7,8,9 + end + end + + class YieldsMultiWithSingleTrue + include Enumerable + def each + yield false,2 + yield true,4,5 + yield false,7,8,9 + end + end + + class YieldsMixed + include Enumerable + def each + yield 1 + yield [2] + yield 3,4 + yield 5,6,7 + yield [8,9] + yield nil + yield [] + end + end + + class YieldsMixed2 + include Enumerable + + def self.first_yields + [nil, 0, 0, 0, 0, nil, :default_arg, [], [], [0], [0, 1], [0, 1, 2]] + end + + def self.gathered_yields + [nil, 0, [0, 1], [0, 1, 2], [0, 1, 2], nil, :default_arg, [], [], [0], [0, 1], [0, 1, 2]] + end + + def self.gathered_yields_with_args(arg, *args) + [nil, 0, [0, 1], [0, 1, 2], [0, 1, 2], nil, arg, args, [], [0], [0, 1], [0, 1, 2]] + end + + def self.greedy_yields + [[], [0], [0, 1], [0, 1, 2], [0, 1, 2], [nil], [:default_arg], [[]], [[]], [[0]], [[0, 1]], [[0, 1, 2]]] + end + + def each(arg=:default_arg, *args) + yield + yield 0 + yield 0, 1 + yield 0, 1, 2 + yield(*[0, 1, 2]) + yield nil + yield arg + yield args + yield [] + yield [0] + yield [0, 1] + yield [0, 1, 2] + end + end + + class ReverseComparable + include Comparable + def initialize(num) + @num = num + end + + attr_accessor :num + + # Reverse comparison + def <=>(other) + other.num <=> @num + end + end + + class ComparableWithFixnum + include Comparable + def initialize(num) + @num = num + end + + def <=>(fixnum) + @num <=> fixnum + end + end + + class Uncomparable + def <=>(obj) + nil + end + end + + class Undupable + attr_reader :initialize_called, :initialize_dup_called + def dup + raise "Can't, sorry" + end + + def clone + raise "Can't, either, sorry" + end + + def initialize + @initialize_dup = true + end + + def initialize_dup(arg) + @initialize_dup_called = true + end + end + + class Freezy + include Enumerable + + def each + yield 1 + yield 2 + end + + def to_a + super.freeze + end + end + + class MapReturnsEnumerable + include Enumerable + + class EnumerableMapping + include Enumerable + + def initialize(items, block) + @items = items + @block = block + end + + def each + @items.each do |i| + yield @block.call(i) + end + end + end + + def each + yield 1 + yield 2 + yield 3 + end + + def map(&block) + EnumerableMapping.new(self, block) + end + end +end # EnumerableSpecs utility classes diff --git a/spec/ruby/core/enumerable/flat_map_spec.rb b/spec/ruby/core/enumerable/flat_map_spec.rb new file mode 100644 index 0000000000..aaddeed05d --- /dev/null +++ b/spec/ruby/core/enumerable/flat_map_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/collect_concat', __FILE__) + +describe "Enumerable#flat_map" do + it_behaves_like(:enumerable_collect_concat , :flat_map) +end diff --git a/spec/ruby/core/enumerable/grep_spec.rb b/spec/ruby/core/enumerable/grep_spec.rb new file mode 100644 index 0000000000..777d5e538e --- /dev/null +++ b/spec/ruby/core/enumerable/grep_spec.rb @@ -0,0 +1,52 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#grep" do + before :each do + @a = EnumerableSpecs::EachDefiner.new( 2, 4, 6, 8, 10) + end + + it "grep without a block should return an array of all elements === pattern" do + class EnumerableSpecGrep; def ===(obj); obj == '2'; end; end + + EnumerableSpecs::Numerous.new('2', 'a', 'nil', '3', false).grep(EnumerableSpecGrep.new).should == ['2'] + end + + it "grep with a block should return an array of elements === pattern passed through block" do + class EnumerableSpecGrep2; def ===(obj); /^ca/ =~ obj; end; end + + EnumerableSpecs::Numerous.new("cat", "coat", "car", "cadr", "cost").grep(EnumerableSpecGrep2.new) { |i| i.upcase }.should == ["CAT", "CAR", "CADR"] + end + + it "grep the enumerable (rubycon legacy)" do + EnumerableSpecs::EachDefiner.new().grep(1).should == [] + @a.grep(3..7).should == [4,6] + @a.grep(3..7) {|a| a+1}.should == [5,7] + end + + it "can use $~ in the block when used with a Regexp" do + ary = ["aba", "aba"] + ary.grep(/a(b)a/) { $1 }.should == ["b", "b"] + end + + describe "with a block" do + before :each do + @numerous = EnumerableSpecs::Numerous.new(*(0..9).to_a) + def (@odd_matcher = BasicObject.new).===(obj) + obj.odd? + end + end + + it "returns an Array of matched elements that mapped by the block" do + @numerous.grep(@odd_matcher) { |n| n * 2 }.should == [2, 6, 10, 14, 18] + end + + it "calls the block with gathered array when yielded with multiple arguments" do + EnumerableSpecs::YieldsMixed2.new.grep(Object){ |e| e }.should == EnumerableSpecs::YieldsMixed2.gathered_yields + end + + it "raises an ArgumentError when not given a pattern" do + -> { @numerous.grep { |e| e } }.should raise_error(ArgumentError) + end + end +end diff --git a/spec/ruby/core/enumerable/grep_v_spec.rb b/spec/ruby/core/enumerable/grep_v_spec.rb new file mode 100644 index 0000000000..05c43a43ef --- /dev/null +++ b/spec/ruby/core/enumerable/grep_v_spec.rb @@ -0,0 +1,43 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +ruby_version_is "2.3" do + describe "Enumerable#grep_v" do + before :each do + @numerous = EnumerableSpecs::Numerous.new(*(0..9).to_a) + def (@odd_matcher = BasicObject.new).===(obj) + obj.odd? + end + end + + describe "without block" do + it "returns an Array of matched elements" do + @numerous.grep_v(@odd_matcher).should == [0, 2, 4, 6, 8] + end + + it "compares pattern with gathered array when yielded with multiple arguments" do + (unmatcher = Object.new).stub!(:===).and_return(false) + EnumerableSpecs::YieldsMixed2.new.grep_v(unmatcher).should == EnumerableSpecs::YieldsMixed2.gathered_yields + end + + it "raises an ArgumentError when not given a pattern" do + -> { @numerous.grep_v }.should raise_error(ArgumentError) + end + end + + describe "with block" do + it "returns an Array of matched elements that mapped by the block" do + @numerous.grep_v(@odd_matcher) { |n| n * 2 }.should == [0, 4, 8, 12, 16] + end + + it "calls the block with gathered array when yielded with multiple arguments" do + (unmatcher = Object.new).stub!(:===).and_return(false) + EnumerableSpecs::YieldsMixed2.new.grep_v(unmatcher){ |e| e }.should == EnumerableSpecs::YieldsMixed2.gathered_yields + end + + it "raises an ArgumentError when not given a pattern" do + -> { @numerous.grep_v { |e| e } }.should raise_error(ArgumentError) + end + end + end +end diff --git a/spec/ruby/core/enumerable/group_by_spec.rb b/spec/ruby/core/enumerable/group_by_spec.rb new file mode 100644 index 0000000000..3513512ebf --- /dev/null +++ b/spec/ruby/core/enumerable/group_by_spec.rb @@ -0,0 +1,45 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#group_by" do + it "returns a hash with values grouped according to the block" do + e = EnumerableSpecs::Numerous.new("foo", "bar", "baz") + h = e.group_by { |word| word[0..0].to_sym } + h.should == { f: ["foo"], b: ["bar", "baz"]} + end + + it "returns an empty hash for empty enumerables" do + EnumerableSpecs::Empty.new.group_by { |x| x}.should == {} + end + + it "returns a hash without default_proc" do + e = EnumerableSpecs::Numerous.new("foo", "bar", "baz") + h = e.group_by { |word| word[0..0].to_sym } + h[:some].should be_nil + h.default_proc.should be_nil + h.default.should be_nil + end + + it "returns an Enumerator if called without a block" do + EnumerableSpecs::Numerous.new.group_by.should be_an_instance_of(Enumerator) + end + + it "gathers whole arrays as elements when each yields multiple" do + e = EnumerableSpecs::YieldsMulti.new + h = e.group_by { |i| i } + h.should == { [1, 2] => [[1, 2]], + [6, 7, 8, 9] => [[6, 7, 8, 9]], + [3, 4, 5] => [[3, 4, 5]] } + end + + it "returns a tainted hash if self is tainted" do + EnumerableSpecs::Empty.new.taint.group_by {}.tainted?.should be_true + end + + it "returns an untrusted hash if self is untrusted" do + EnumerableSpecs::Empty.new.untrust.group_by {}.untrusted?.should be_true + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :group_by +end diff --git a/spec/ruby/core/enumerable/include_spec.rb b/spec/ruby/core/enumerable/include_spec.rb new file mode 100644 index 0000000000..2cc0b6e83a --- /dev/null +++ b/spec/ruby/core/enumerable/include_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/include', __FILE__) + +describe "Enumerable#include?" do + it_behaves_like(:enumerable_include, :include?) +end diff --git a/spec/ruby/core/enumerable/inject_spec.rb b/spec/ruby/core/enumerable/inject_spec.rb new file mode 100644 index 0000000000..289a451552 --- /dev/null +++ b/spec/ruby/core/enumerable/inject_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/inject', __FILE__) + +describe "Enumerable#inject" do + it_behaves_like :enumerable_inject, :inject +end diff --git a/spec/ruby/core/enumerable/lazy_spec.rb b/spec/ruby/core/enumerable/lazy_spec.rb new file mode 100644 index 0000000000..f989fb947e --- /dev/null +++ b/spec/ruby/core/enumerable/lazy_spec.rb @@ -0,0 +1,10 @@ +# -*- encoding: us-ascii -*- + +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#lazy" do + it "returns an instance of Enumerator::Lazy" do + EnumerableSpecs::Numerous.new.lazy.should be_an_instance_of(Enumerator::Lazy) + end +end diff --git a/spec/ruby/core/enumerable/map_spec.rb b/spec/ruby/core/enumerable/map_spec.rb new file mode 100644 index 0000000000..b2ddf1eb9d --- /dev/null +++ b/spec/ruby/core/enumerable/map_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/collect', __FILE__) + +describe "Enumerable#map" do + it_behaves_like(:enumerable_collect , :map) +end diff --git a/spec/ruby/core/enumerable/max_by_spec.rb b/spec/ruby/core/enumerable/max_by_spec.rb new file mode 100644 index 0000000000..4058cf0a40 --- /dev/null +++ b/spec/ruby/core/enumerable/max_by_spec.rb @@ -0,0 +1,81 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#max_by" do + it "returns an enumerator if no block" do + EnumerableSpecs::Numerous.new(42).max_by.should be_an_instance_of(Enumerator) + end + + it "returns nil if #each yields no objects" do + EnumerableSpecs::Empty.new.max_by {|o| o.nonesuch }.should == nil + end + + it "returns the object for whom the value returned by block is the largest" do + EnumerableSpecs::Numerous.new(*%w[1 2 3]).max_by {|obj| obj.to_i }.should == '3' + EnumerableSpecs::Numerous.new(*%w[three five]).max_by {|obj| obj.length }.should == 'three' + end + + it "returns the object that appears first in #each in case of a tie" do + a, b, c = '1', '2', '2' + EnumerableSpecs::Numerous.new(a, b, c).max_by {|obj| obj.to_i }.should equal(b) + end + + it "uses max.<=>(current) to determine order" do + a, b, c = (1..3).map{|n| EnumerableSpecs::ReverseComparable.new(n)} + + # Just using self here to avoid additional complexity + EnumerableSpecs::Numerous.new(a, b, c).max_by {|obj| obj }.should == a + end + + it "is able to return the maximum for enums that contain nils" do + enum = EnumerableSpecs::Numerous.new(nil, nil, true) + enum.max_by {|o| o.nil? ? 0 : 1 }.should == true + enum.max_by {|o| o.nil? ? 1 : 0 }.should == nil + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.max_by {|e| e.size}.should == [6, 7, 8, 9] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :max_by + + context "when called with an argument n" do + before :each do + @enum = EnumerableSpecs::Numerous.new(101, 55, 1, 20, 33, 500, 60) + end + + context "without a block" do + it "returns an enumerator" do + @enum.max_by(2).should be_an_instance_of(Enumerator) + end + end + + context "with a block" do + it "returns an array containing the maximum n elements based on the block's value" do + result = @enum.max_by(3) { |i| i.to_s } + result.should == [60, 55, 500] + end + + context "on a enumerable of length x where x < n" do + it "returns an array containing the maximum n elements of length n" do + result = @enum.max_by(500) { |i| i.to_s } + result.length.should == 7 + end + end + + context "when n is negative" do + it "raises an ArgumentError" do + lambda { @enum.max_by(-1) { |i| i.to_s } }.should raise_error(ArgumentError) + end + end + end + + context "when n is nil" do + it "returns the maximum element" do + @enum.max_by(nil) { |i| i.to_s }.should == 60 + end + end + end +end diff --git a/spec/ruby/core/enumerable/max_spec.rb b/spec/ruby/core/enumerable/max_spec.rb new file mode 100644 index 0000000000..e283a5d0e2 --- /dev/null +++ b/spec/ruby/core/enumerable/max_spec.rb @@ -0,0 +1,119 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#max" do + before :each do + @e_strs = EnumerableSpecs::EachDefiner.new("333", "22", "666666", "1", "55555", "1010101010") + @e_ints = EnumerableSpecs::EachDefiner.new( 333, 22, 666666, 55555, 1010101010) + end + + it "returns the maximum element" do + EnumerableSpecs::Numerous.new.max.should == 6 + end + + it "returns the maximum element (basics cases)" do + EnumerableSpecs::EachDefiner.new(55).max.should == 55 + + EnumerableSpecs::EachDefiner.new(11,99).max.should == 99 + EnumerableSpecs::EachDefiner.new(99,11).max.should == 99 + EnumerableSpecs::EachDefiner.new(2, 33, 4, 11).max.should == 33 + + EnumerableSpecs::EachDefiner.new(1,2,3,4,5).max.should == 5 + EnumerableSpecs::EachDefiner.new(5,4,3,2,1).max.should == 5 + EnumerableSpecs::EachDefiner.new(1,4,3,5,2).max.should == 5 + EnumerableSpecs::EachDefiner.new(5,5,5,5,5).max.should == 5 + + EnumerableSpecs::EachDefiner.new("aa","tt").max.should == "tt" + EnumerableSpecs::EachDefiner.new("tt","aa").max.should == "tt" + EnumerableSpecs::EachDefiner.new("2","33","4","11").max.should == "4" + + @e_strs.max.should == "666666" + @e_ints.max.should == 1010101010 + end + + it "returns nil for an empty Enumerable" do + EnumerableSpecs::EachDefiner.new.max.should == nil + end + + it "raises a NoMethodError for elements without #<=>" do + lambda do + EnumerableSpecs::EachDefiner.new(BasicObject.new, BasicObject.new).max + end.should raise_error(NoMethodError) + end + + it "raises an ArgumentError for incomparable elements" do + lambda do + EnumerableSpecs::EachDefiner.new(11,"22").max + end.should raise_error(ArgumentError) + lambda do + EnumerableSpecs::EachDefiner.new(11,12,22,33).max{|a, b| nil} + end.should raise_error(ArgumentError) + end + + context "when passed a block" do + it "returns the maximum element" do + EnumerableSpecs::EachDefiner.new("2","33","4","11").max {|a,b| a <=> b }.should == "4" + EnumerableSpecs::EachDefiner.new( 2 , 33 , 4 , 11 ).max {|a,b| a <=> b }.should == 33 + + EnumerableSpecs::EachDefiner.new("2","33","4","11").max {|a,b| b <=> a }.should == "11" + EnumerableSpecs::EachDefiner.new( 2 , 33 , 4 , 11 ).max {|a,b| b <=> a }.should == 2 + + @e_strs.max {|a,b| a.length <=> b.length }.should == "1010101010" + + @e_strs.max {|a,b| a <=> b }.should == "666666" + @e_strs.max {|a,b| a.to_i <=> b.to_i }.should == "1010101010" + + @e_ints.max {|a,b| a <=> b }.should == 1010101010 + @e_ints.max {|a,b| a.to_s <=> b.to_s }.should == 666666 + end + end + + it "returns the maximum for enumerables that contain nils" do + arr = EnumerableSpecs::Numerous.new(nil, nil, true) + arr.max { |a, b| + x = a.nil? ? 1 : a ? 0 : -1 + y = b.nil? ? 1 : b ? 0 : -1 + x <=> y + }.should == nil + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.max.should == [6, 7, 8, 9] + end + + context "when called with an argument n" do + context "without a block" do + it "returns an array containing the maximum n elements" do + result = @e_ints.max(2) + result.should == [1010101010, 666666] + end + end + + context "with a block" do + it "returns an array containing the maximum n elements" do + result = @e_ints.max(2) { |a, b| a * 2 <=> b * 2 } + result.should == [1010101010, 666666] + end + end + + context "on a enumerable of length x where x < n" do + it "returns an array containing the maximum n elements of length x" do + result = @e_ints.max(500) + result.length.should == 5 + end + end + + context "that is negative" do + it "raises an ArgumentError" do + lambda { @e_ints.max(-1) }.should raise_error(ArgumentError) + end + end + end + + context "that is nil" do + it "returns the maximum element" do + @e_ints.max(nil).should == 1010101010 + end + end +end diff --git a/spec/ruby/core/enumerable/member_spec.rb b/spec/ruby/core/enumerable/member_spec.rb new file mode 100644 index 0000000000..862c949817 --- /dev/null +++ b/spec/ruby/core/enumerable/member_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/include', __FILE__) + +describe "Enumerable#member?" do + it_behaves_like(:enumerable_include, :member?) +end diff --git a/spec/ruby/core/enumerable/min_by_spec.rb b/spec/ruby/core/enumerable/min_by_spec.rb new file mode 100644 index 0000000000..24fe995f09 --- /dev/null +++ b/spec/ruby/core/enumerable/min_by_spec.rb @@ -0,0 +1,81 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#min_by" do + it "returns an enumerator if no block" do + EnumerableSpecs::Numerous.new(42).min_by.should be_an_instance_of(Enumerator) + end + + it "returns nil if #each yields no objects" do + EnumerableSpecs::Empty.new.min_by {|o| o.nonesuch }.should == nil + end + + it "returns the object for whom the value returned by block is the smallest" do + EnumerableSpecs::Numerous.new(*%w[3 2 1]).min_by {|obj| obj.to_i }.should == '1' + EnumerableSpecs::Numerous.new(*%w[five three]).min_by {|obj| obj.length }.should == 'five' + end + + it "returns the object that appears first in #each in case of a tie" do + a, b, c = '2', '1', '1' + EnumerableSpecs::Numerous.new(a, b, c).min_by {|obj| obj.to_i }.should equal(b) + end + + it "uses min.<=>(current) to determine order" do + a, b, c = (1..3).map{|n| EnumerableSpecs::ReverseComparable.new(n)} + + # Just using self here to avoid additional complexity + EnumerableSpecs::Numerous.new(a, b, c).min_by {|obj| obj }.should == c + end + + it "is able to return the minimum for enums that contain nils" do + enum = EnumerableSpecs::Numerous.new(nil, nil, true) + enum.min_by {|o| o.nil? ? 0 : 1 }.should == nil + enum.min_by {|o| o.nil? ? 1 : 0 }.should == true + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.min_by {|e| e.size}.should == [1, 2] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :min_by + + context "when called with an argument n" do + before :each do + @enum = EnumerableSpecs::Numerous.new(101, 55, 1, 20, 33, 500, 60) + end + + context "without a block" do + it "returns an enumerator" do + @enum.min_by(2).should be_an_instance_of(Enumerator) + end + end + + context "with a block" do + it "returns an array containing the minimum n elements based on the block's value" do + result = @enum.min_by(3) { |i| i.to_s } + result.should == [1, 101, 20] + end + + context "on a enumerable of length x where x < n" do + it "returns an array containing the minimum n elements of length n" do + result = @enum.min_by(500) { |i| i.to_s } + result.length.should == 7 + end + end + + context "when n is negative" do + it "raises an ArgumentError" do + lambda { @enum.min_by(-1) { |i| i.to_s } }.should raise_error(ArgumentError) + end + end + end + + context "when n is nil" do + it "returns the minimum element" do + @enum.min_by(nil) { |i| i.to_s }.should == 1 + end + end + end +end diff --git a/spec/ruby/core/enumerable/min_spec.rb b/spec/ruby/core/enumerable/min_spec.rb new file mode 100644 index 0000000000..f56d0420c9 --- /dev/null +++ b/spec/ruby/core/enumerable/min_spec.rb @@ -0,0 +1,123 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#min" do + before :each do + @e_strs = EnumerableSpecs::EachDefiner.new("333", "22", "666666", "1", "55555", "1010101010") + @e_ints = EnumerableSpecs::EachDefiner.new( 333, 22, 666666, 55555, 1010101010) + end + + it "min should return the minimum element" do + EnumerableSpecs::Numerous.new.min.should == 1 + end + + it "returns the minimum (basic cases)" do + EnumerableSpecs::EachDefiner.new(55).min.should == 55 + + EnumerableSpecs::EachDefiner.new(11,99).min.should == 11 + EnumerableSpecs::EachDefiner.new(99,11).min.should == 11 + EnumerableSpecs::EachDefiner.new(2, 33, 4, 11).min.should == 2 + + EnumerableSpecs::EachDefiner.new(1,2,3,4,5).min.should == 1 + EnumerableSpecs::EachDefiner.new(5,4,3,2,1).min.should == 1 + EnumerableSpecs::EachDefiner.new(4,1,3,5,2).min.should == 1 + EnumerableSpecs::EachDefiner.new(5,5,5,5,5).min.should == 5 + + EnumerableSpecs::EachDefiner.new("aa","tt").min.should == "aa" + EnumerableSpecs::EachDefiner.new("tt","aa").min.should == "aa" + EnumerableSpecs::EachDefiner.new("2","33","4","11").min.should == "11" + + @e_strs.min.should == "1" + @e_ints.min.should == 22 + end + + it "returns nil for an empty Enumerable" do + EnumerableSpecs::EachDefiner.new.min.should be_nil + end + + it "raises a NoMethodError for elements without #<=>" do + lambda do + EnumerableSpecs::EachDefiner.new(BasicObject.new, BasicObject.new).min + end.should raise_error(NoMethodError) + end + + it "raises an ArgumentError for incomparable elements" do + lambda do + EnumerableSpecs::EachDefiner.new(11,"22").min + end.should raise_error(ArgumentError) + lambda do + EnumerableSpecs::EachDefiner.new(11,12,22,33).min{|a, b| nil} + end.should raise_error(ArgumentError) + end + + it "returns the minimum when using a block rule" do + EnumerableSpecs::EachDefiner.new("2","33","4","11").min {|a,b| a <=> b }.should == "11" + EnumerableSpecs::EachDefiner.new( 2 , 33 , 4 , 11 ).min {|a,b| a <=> b }.should == 2 + + EnumerableSpecs::EachDefiner.new("2","33","4","11").min {|a,b| b <=> a }.should == "4" + EnumerableSpecs::EachDefiner.new( 2 , 33 , 4 , 11 ).min {|a,b| b <=> a }.should == 33 + + EnumerableSpecs::EachDefiner.new( 1, 2, 3, 4 ).min {|a,b| 15 }.should == 1 + + EnumerableSpecs::EachDefiner.new(11,12,22,33).min{|a, b| 2 }.should == 11 + @i = -2 + EnumerableSpecs::EachDefiner.new(11,12,22,33).min{|a, b| @i += 1 }.should == 12 + + @e_strs.min {|a,b| a.length <=> b.length }.should == "1" + + @e_strs.min {|a,b| a <=> b }.should == "1" + @e_strs.min {|a,b| a.to_i <=> b.to_i }.should == "1" + + @e_ints.min {|a,b| a <=> b }.should == 22 + @e_ints.min {|a,b| a.to_s <=> b.to_s }.should == 1010101010 + end + + it "returns the minimum for enumerables that contain nils" do + arr = EnumerableSpecs::Numerous.new(nil, nil, true) + arr.min { |a, b| + x = a.nil? ? -1 : a ? 0 : 1 + y = b.nil? ? -1 : b ? 0 : 1 + x <=> y + }.should == nil + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.min.should == [1, 2] + end + + context "when called with an argument n" do + context "without a block" do + it "returns an array containing the minimum n elements" do + result = @e_ints.min(2) + result.should == [22, 333] + end + end + + context "with a block" do + it "returns an array containing the minimum n elements" do + result = @e_ints.min(2) { |a, b| a * 2 <=> b * 2 } + result.should == [22, 333] + end + end + + context "on a enumerable of length x where x < n" do + it "returns an array containing the minimum n elements of length x" do + result = @e_ints.min(500) + result.length.should == 5 + end + end + + context "that is negative" do + it "raises an ArgumentError" do + lambda { @e_ints.min(-1) }.should raise_error(ArgumentError) + end + end + end + + context "that is nil" do + it "returns the minimum element" do + @e_ints.min(nil).should == 22 + end + end +end diff --git a/spec/ruby/core/enumerable/minmax_by_spec.rb b/spec/ruby/core/enumerable/minmax_by_spec.rb new file mode 100644 index 0000000000..c92eb381a4 --- /dev/null +++ b/spec/ruby/core/enumerable/minmax_by_spec.rb @@ -0,0 +1,44 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#minmax_by" do + it "returns an enumerator if no block" do + EnumerableSpecs::Numerous.new(42).minmax_by.should be_an_instance_of(Enumerator) + end + + it "returns nil if #each yields no objects" do + EnumerableSpecs::Empty.new.minmax_by {|o| o.nonesuch }.should == [nil, nil] + end + + it "returns the object for whom the value returned by block is the largest" do + EnumerableSpecs::Numerous.new(*%w[1 2 3]).minmax_by {|obj| obj.to_i }.should == ['1', '3'] + EnumerableSpecs::Numerous.new(*%w[three five]).minmax_by {|obj| obj.length }.should == ['five', 'three'] + end + + it "returns the object that appears first in #each in case of a tie" do + a, b, c, d = '1', '1', '2', '2' + mm = EnumerableSpecs::Numerous.new(a, b, c, d).minmax_by {|obj| obj.to_i } + mm[0].should equal(a) + mm[1].should equal(c) + end + + it "uses min/max.<=>(current) to determine order" do + a, b, c = (1..3).map{|n| EnumerableSpecs::ReverseComparable.new(n)} + + # Just using self here to avoid additional complexity + EnumerableSpecs::Numerous.new(a, b, c).minmax_by {|obj| obj }.should == [c, a] + end + + it "is able to return the maximum for enums that contain nils" do + enum = EnumerableSpecs::Numerous.new(nil, nil, true) + enum.minmax_by {|o| o.nil? ? 0 : 1 }.should == [nil, true] + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.minmax_by {|e| e.size}.should == [[1, 2], [6, 7, 8, 9]] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :minmax_by +end diff --git a/spec/ruby/core/enumerable/minmax_spec.rb b/spec/ruby/core/enumerable/minmax_spec.rb new file mode 100644 index 0000000000..10bc9b68e4 --- /dev/null +++ b/spec/ruby/core/enumerable/minmax_spec.rb @@ -0,0 +1,44 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#minmax" do + before :each do + @enum = EnumerableSpecs::Numerous.new(6, 4, 5, 10, 8) + + @strs = EnumerableSpecs::Numerous.new("333", "2", "60", "55555", "1010", "111") + end + + it "min should return the minimum element" do + @enum.minmax.should == [4, 10] + @strs.minmax.should == ["1010", "60" ] + end + + it "returns [nil, nil] for an empty Enumerable" do + EnumerableSpecs::Empty.new.minmax.should == [nil, nil] + end + + it "raises an ArgumentError when elements are incomparable" do + lambda do + EnumerableSpecs::Numerous.new(11,"22").minmax + end.should raise_error(ArgumentError) + lambda do + EnumerableSpecs::Numerous.new(11,12,22,33).minmax{|a, b| nil} + end.should raise_error(ArgumentError) + end + + it "raises a NoMethodError for elements without #<=>" do + lambda do + EnumerableSpecs::Numerous.new(BasicObject.new, BasicObject.new).minmax + end.should raise_error(NoMethodError) + end + + it "returns the minimum when using a block rule" do + @enum.minmax {|a,b| b <=> a }.should == [10, 4] + @strs.minmax {|a,b| a.length <=> b.length }.should == ["2", "55555"] + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.minmax.should == [[1, 2], [6, 7, 8, 9]] + end +end diff --git a/spec/ruby/core/enumerable/none_spec.rb b/spec/ruby/core/enumerable/none_spec.rb new file mode 100644 index 0000000000..0646c13b34 --- /dev/null +++ b/spec/ruby/core/enumerable/none_spec.rb @@ -0,0 +1,57 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#none?" do + it "returns true if none of the elements in self are true" do + e = EnumerableSpecs::Numerous.new(false, nil, false) + e.none?.should be_true + end + + it "returns false if at least one of the elements in self are true" do + e = EnumerableSpecs::Numerous.new(false, nil, true, false) + e.none?.should be_false + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMultiWithFalse.new + multi.none?.should be_false + end +end + +describe "Enumerable#none? with a block" do + before :each do + @e = EnumerableSpecs::Numerous.new(1,1,2,3,4) + end + + it "passes each element to the block in turn until it returns true" do + acc = [] + @e.none? {|e| acc << e; false } + acc.should == [1,1,2,3,4] + end + + it "stops passing elements to the block when it returns true" do + acc = [] + @e.none? {|e| acc << e; e == 3 ? true : false } + acc.should == [1,1,2,3] + end + + it "returns true if the block never returns true" do + @e.none? {|e| false }.should be_true + end + + it "returns false if the block ever returns true" do + @e.none? {|e| e == 3 ? true : false }.should be_false + end + + it "gathers initial args as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.none? {|e| e == [1, 2] }.should be_true + end + + it "yields multiple arguments when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + yielded = [] + multi.none? {|e, i| yielded << [e, i] } + yielded.should == [[1, 2]] + end +end diff --git a/spec/ruby/core/enumerable/one_spec.rb b/spec/ruby/core/enumerable/one_spec.rb new file mode 100644 index 0000000000..818d4663a4 --- /dev/null +++ b/spec/ruby/core/enumerable/one_spec.rb @@ -0,0 +1,49 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#one?" do + describe "when passed a block" do + it "returns true if block returns true once" do + [:a, :b, :c].one? { |s| s == :a }.should be_true + end + + it "returns false if the block returns true more than once" do + [:a, :b, :c].one? { |s| s == :a || s == :b }.should be_false + end + + it "returns false if the block only returns false" do + [:a, :b, :c].one? { |s| s == :d }.should be_false + end + + it "gathers initial args as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.one? {|e| e == 1 }.should be_true + end + + it "yields multiple arguments when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + yielded = [] + multi.one? {|e, i| yielded << [e, i] } + yielded.should == [[1, 2], [3, 4]] + end + end + + describe "when not passed a block" do + it "returns true if only one element evaluates to true" do + [false, nil, true].one?.should be_true + end + + it "returns false if two elements evaluate to true" do + [false, :value, nil, true].one?.should be_false + end + + it "returns false if all elements evaluate to false" do + [false, nil, false].one?.should be_false + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMultiWithSingleTrue.new + multi.one?.should be_false + end + end +end diff --git a/spec/ruby/core/enumerable/partition_spec.rb b/spec/ruby/core/enumerable/partition_spec.rb new file mode 100644 index 0000000000..4319a9328f --- /dev/null +++ b/spec/ruby/core/enumerable/partition_spec.rb @@ -0,0 +1,20 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#partition" do + it "returns two arrays, the first containing elements for which the block is true, the second containing the rest" do + EnumerableSpecs::Numerous.new.partition { |i| i % 2 == 0 }.should == [[2, 6, 4], [5, 3, 1]] + end + + it "returns an Enumerator if called without a block" do + EnumerableSpecs::Numerous.new.partition.should be_an_instance_of(Enumerator) + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.partition {|e| e == [3, 4, 5] }.should == [[[3, 4, 5]], [[1, 2], [6, 7, 8, 9]]] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :partition +end diff --git a/spec/ruby/core/enumerable/reduce_spec.rb b/spec/ruby/core/enumerable/reduce_spec.rb new file mode 100644 index 0000000000..8afecb2a8e --- /dev/null +++ b/spec/ruby/core/enumerable/reduce_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/inject', __FILE__) + +describe "Enumerable#reduce" do + it_behaves_like :enumerable_inject, :reduce +end diff --git a/spec/ruby/core/enumerable/reject_spec.rb b/spec/ruby/core/enumerable/reject_spec.rb new file mode 100644 index 0000000000..3dbfb07067 --- /dev/null +++ b/spec/ruby/core/enumerable/reject_spec.rb @@ -0,0 +1,25 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#reject" do + it "returns an array of the elements for which block is false" do + EnumerableSpecs::Numerous.new.reject { |i| i > 3 }.should == [2, 3, 1] + entries = (1..10).to_a + numerous = EnumerableSpecs::Numerous.new(*entries) + numerous.reject {|i| i % 2 == 0 }.should == [1,3,5,7,9] + numerous.reject {|i| true }.should == [] + numerous.reject {|i| false }.should == entries + end + + it "returns an Enumerator if called without a block" do + EnumerableSpecs::Numerous.new.reject.should be_an_instance_of(Enumerator) + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.reject {|e| e == [3, 4, 5] }.should == [[1, 2], [6, 7, 8, 9]] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :reject +end diff --git a/spec/ruby/core/enumerable/reverse_each_spec.rb b/spec/ruby/core/enumerable/reverse_each_spec.rb new file mode 100644 index 0000000000..62c3c0daef --- /dev/null +++ b/spec/ruby/core/enumerable/reverse_each_spec.rb @@ -0,0 +1,26 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#reverse_each" do + it "traverses enum in reverse order and pass each element to block" do + a=[] + EnumerableSpecs::Numerous.new.reverse_each { |i| a << i } + a.should == [4, 1, 6, 3, 5, 2] + end + + it "returns an Enumerator if no block given" do + enum = EnumerableSpecs::Numerous.new.reverse_each + enum.should be_an_instance_of(Enumerator) + enum.to_a.should == [4, 1, 6, 3, 5, 2] + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + yielded = [] + multi.reverse_each {|e| yielded << e } + yielded.should == [[6, 7, 8, 9], [3, 4, 5], [1, 2]] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :reverse_each +end diff --git a/spec/ruby/core/enumerable/select_spec.rb b/spec/ruby/core/enumerable/select_spec.rb new file mode 100644 index 0000000000..b4da35c754 --- /dev/null +++ b/spec/ruby/core/enumerable/select_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/find_all', __FILE__) + +describe "Enumerable#select" do + it_behaves_like(:enumerable_find_all , :select) +end diff --git a/spec/ruby/core/enumerable/shared/collect.rb b/spec/ruby/core/enumerable/shared/collect.rb new file mode 100644 index 0000000000..f66c539904 --- /dev/null +++ b/spec/ruby/core/enumerable/shared/collect.rb @@ -0,0 +1,32 @@ +require File.expand_path('../enumerable_enumeratorized', __FILE__) + +describe :enumerable_collect, shared: true do + before :each do + ScratchPad.record [] + end + + it "returns a new array with the results of passing each element to block" do + entries = [0, 1, 3, 4, 5, 6] + numerous = EnumerableSpecs::Numerous.new(*entries) + numerous.send(@method) { |i| i % 2 }.should == [0, 1, 1, 0, 1, 0] + numerous.send(@method) { |i| i }.should == entries + end + + it "passes through the values yielded by #each_with_index" do + [:a, :b].each_with_index.send(@method) { |x, i| ScratchPad << [x, i]; nil } + ScratchPad.recorded.should == [[:a, 0], [:b, 1]] + end + + it "gathers initial args as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.send(@method) {|e| e}.should == [1,3,6] + end + + it "returns an enumerator when no block given" do + enum = EnumerableSpecs::Numerous.new.send(@method) + enum.should be_an_instance_of(Enumerator) + enum.each { |i| -i }.should == [-2, -5, -3, -6, -1, -4] + end + + it_should_behave_like :enumerable_enumeratorized_with_origin_size +end diff --git a/spec/ruby/core/enumerable/shared/collect_concat.rb b/spec/ruby/core/enumerable/shared/collect_concat.rb new file mode 100644 index 0000000000..54e10692eb --- /dev/null +++ b/spec/ruby/core/enumerable/shared/collect_concat.rb @@ -0,0 +1,54 @@ +require File.expand_path('../enumerable_enumeratorized', __FILE__) + +describe :enumerable_collect_concat, shared: true do + it "yields elements to the block and flattens one level" do + numerous = EnumerableSpecs::Numerous.new(1, [2, 3], [4, [5, 6]], {foo: :bar}) + numerous.send(@method) { |i| i }.should == [1, 2, 3, 4, [5, 6], {foo: :bar}] + end + + it "appends non-Array elements that do not define #to_ary" do + obj = mock("to_ary undefined") + + numerous = EnumerableSpecs::Numerous.new(1, obj, 2) + numerous.send(@method) { |i| i }.should == [1, obj, 2] + end + + it "concatenates the result of calling #to_ary if it returns an Array" do + obj = mock("to_ary defined") + obj.should_receive(:to_ary).and_return([:a, :b]) + + numerous = EnumerableSpecs::Numerous.new(1, obj, 2) + numerous.send(@method) { |i| i }.should == [1, :a, :b, 2] + end + + it "does not call #to_a" do + obj = mock("to_ary undefined") + obj.should_not_receive(:to_a) + + numerous = EnumerableSpecs::Numerous.new(1, obj, 2) + numerous.send(@method) { |i| i }.should == [1, obj, 2] + end + + it "appends an element that defines #to_ary that returns nil" do + obj = mock("to_ary defined") + obj.should_receive(:to_ary).and_return(nil) + + numerous = EnumerableSpecs::Numerous.new(1, obj, 2) + numerous.send(@method) { |i| i }.should == [1, obj, 2] + end + + it "raises a TypeError if an element defining #to_ary does not return an Array or nil" do + obj = mock("to_ary defined") + obj.should_receive(:to_ary).and_return("array") + + lambda { [1, obj, 3].send(@method) { |i| i } }.should raise_error(TypeError) + end + + it "returns an enumerator when no block given" do + enum = EnumerableSpecs::Numerous.new(1, 2).send(@method) + enum.should be_an_instance_of(Enumerator) + enum.each{ |i| [i] * i }.should == [1, 2, 2] + end + + it_should_behave_like :enumerable_enumeratorized_with_origin_size +end diff --git a/spec/ruby/core/enumerable/shared/entries.rb b/spec/ruby/core/enumerable/shared/entries.rb new file mode 100644 index 0000000000..f52844cb45 --- /dev/null +++ b/spec/ruby/core/enumerable/shared/entries.rb @@ -0,0 +1,24 @@ +describe :enumerable_entries, shared: true do + it "returns an array containing the elements" do + numerous = EnumerableSpecs::Numerous.new(1, nil, 'a', 2, false, true) + numerous.send(@method).should == [1, nil, "a", 2, false, true] + end + + it "passes through the values yielded by #each_with_index" do + [:a, :b].each_with_index.send(@method).should == [[:a, 0], [:b, 1]] + end + + it "passes arguments to each" do + count = EnumerableSpecs::EachCounter.new(1, 2, 3) + count.send(@method, :hello, "world").should == [1, 2, 3] + count.arguments_passed.should == [:hello, "world"] + end + + it "returns a tainted array if self is tainted" do + EnumerableSpecs::Empty.new.taint.send(@method).tainted?.should be_true + end + + it "returns an untrusted array if self is untrusted" do + EnumerableSpecs::Empty.new.untrust.send(@method).untrusted?.should be_true + end +end diff --git a/spec/ruby/core/enumerable/shared/enumerable_enumeratorized.rb b/spec/ruby/core/enumerable/shared/enumerable_enumeratorized.rb new file mode 100644 index 0000000000..b03ce9ed4e --- /dev/null +++ b/spec/ruby/core/enumerable/shared/enumerable_enumeratorized.rb @@ -0,0 +1,33 @@ +require File.expand_path('../enumeratorized', __FILE__) + +describe :enumerable_enumeratorized_with_unknown_size, shared: true do + describe "Enumerable with size" do + before :all do + @object = EnumerableSpecs::NumerousWithSize.new(1, 2, 3, 4) + end + it_should_behave_like :enumeratorized_with_unknown_size + end + + describe "Enumerable with no size" do + before :all do + @object = EnumerableSpecs::Numerous.new(1, 2, 3, 4) + end + it_should_behave_like :enumeratorized_with_unknown_size + end +end + +describe :enumerable_enumeratorized_with_origin_size, shared: true do + describe "Enumerable with size" do + before :all do + @object = EnumerableSpecs::NumerousWithSize.new(1, 2, 3, 4) + end + it_should_behave_like :enumeratorized_with_origin_size + end + + describe "Enumerable with no size" do + before :all do + @object = EnumerableSpecs::Numerous.new(1, 2, 3, 4) + end + it_should_behave_like :enumeratorized_with_unknown_size + end +end diff --git a/spec/ruby/core/enumerable/shared/enumeratorized.rb b/spec/ruby/core/enumerable/shared/enumeratorized.rb new file mode 100644 index 0000000000..05d27b5783 --- /dev/null +++ b/spec/ruby/core/enumerable/shared/enumeratorized.rb @@ -0,0 +1,42 @@ +describe :enumeratorized_with_unknown_size, shared: true do + describe "when no block is given" do + describe "returned Enumerator" do + it "size returns nil" do + @object.send(*@method).size.should == nil + end + end + end +end + +describe :enumeratorized_with_origin_size, shared: true do + describe "when no block is given" do + describe "returned Enumerator" do + it "size returns the enumerable size" do + @object.send(*@method).size.should == @object.size + end + end + end +end + +describe :enumeratorized_with_cycle_size, shared: true do + describe "when no block is given" do + describe "returned Enumerator" do + describe "size" do + it "should be the result of multiplying the enumerable size by the argument passed" do + @object.cycle(2).size.should == @object.size * 2 + @object.cycle(7).size.should == @object.size * 7 + @object.cycle(0).size.should == 0 + @empty_object.cycle(2).size.should == 0 + end + + it "should be zero when the argument passed is 0 or less" do + @object.cycle(-1).size.should == 0 + end + + it "should be Float::INFINITY when no argument is passed" do + @object.cycle.size.should == Float::INFINITY + end + end + end + end +end diff --git a/spec/ruby/core/enumerable/shared/find.rb b/spec/ruby/core/enumerable/shared/find.rb new file mode 100644 index 0000000000..4cbbf07be0 --- /dev/null +++ b/spec/ruby/core/enumerable/shared/find.rb @@ -0,0 +1,73 @@ +require File.expand_path('../enumerable_enumeratorized', __FILE__) + +describe :enumerable_find, shared: true do + # #detect and #find are aliases, so we only need one function + before :each do + ScratchPad.record [] + @elements = [2, 4, 6, 8, 10] + @numerous = EnumerableSpecs::Numerous.new(*@elements) + @empty = [] + end + + it "passes each entry in enum to block while block when block is false" do + visited_elements = [] + @numerous.send(@method) do |element| + visited_elements << element + false + end + visited_elements.should == @elements + end + + it "returns nil when the block is false and there is no ifnone proc given" do + @numerous.send(@method) {|e| false }.should == nil + end + + it "returns the first element for which the block is not false" do + @elements.each do |element| + @numerous.send(@method) {|e| e > element - 1 }.should == element + end + end + + it "returns the value of the ifnone proc if the block is false" do + fail_proc = lambda { "cheeseburgers" } + @numerous.send(@method, fail_proc) {|e| false }.should == "cheeseburgers" + end + + it "doesn't call the ifnone proc if an element is found" do + fail_proc = lambda { raise "This shouldn't have been called" } + @numerous.send(@method, fail_proc) {|e| e == @elements.first }.should == 2 + end + + it "calls the ifnone proc only once when the block is false" do + times = 0 + fail_proc = lambda { times += 1; raise if times > 1; "cheeseburgers" } + @numerous.send(@method, fail_proc) {|e| false }.should == "cheeseburgers" + end + + it "calls the ifnone proc when there are no elements" do + fail_proc = lambda { "yay" } + @empty.send(@method, fail_proc) {|e| true}.should == "yay" + end + + it "passes through the values yielded by #each_with_index" do + [:a, :b].each_with_index.send(@method) { |x, i| ScratchPad << [x, i]; nil } + ScratchPad.recorded.should == [[:a, 0], [:b, 1]] + end + + it "returns an enumerator when no block given" do + @numerous.send(@method).should be_an_instance_of(Enumerator) + end + + it "passes the ifnone proc to the enumerator" do + times = 0 + fail_proc = lambda { times += 1; raise if times > 1; "cheeseburgers" } + @numerous.send(@method, fail_proc).each {|e| false }.should == "cheeseburgers" + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.send(@method) {|e| e == [1, 2] }.should == [1, 2] + end + + it_should_behave_like :enumerable_enumeratorized_with_unknown_size +end diff --git a/spec/ruby/core/enumerable/shared/find_all.rb b/spec/ruby/core/enumerable/shared/find_all.rb new file mode 100644 index 0000000000..3e15c68e9f --- /dev/null +++ b/spec/ruby/core/enumerable/shared/find_all.rb @@ -0,0 +1,31 @@ +require File.expand_path('../enumerable_enumeratorized', __FILE__) + +describe :enumerable_find_all, shared: true do + before :each do + ScratchPad.record [] + @elements = (1..10).to_a + @numerous = EnumerableSpecs::Numerous.new(*@elements) + end + + it "returns all elements for which the block is not false" do + @numerous.send(@method) {|i| i % 3 == 0 }.should == [3, 6, 9] + @numerous.send(@method) {|i| true }.should == @elements + @numerous.send(@method) {|i| false }.should == [] + end + + it "returns an enumerator when no block given" do + @numerous.send(@method).should be_an_instance_of(Enumerator) + end + + it "passes through the values yielded by #each_with_index" do + [:a, :b].each_with_index.send(@method) { |x, i| ScratchPad << [x, i] } + ScratchPad.recorded.should == [[:a, 0], [:b, 1]] + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.send(@method) {|e| e == [3, 4, 5] }.should == [[3, 4, 5]] + end + + it_should_behave_like :enumerable_enumeratorized_with_origin_size +end diff --git a/spec/ruby/core/enumerable/shared/include.rb b/spec/ruby/core/enumerable/shared/include.rb new file mode 100644 index 0000000000..569f350fd5 --- /dev/null +++ b/spec/ruby/core/enumerable/shared/include.rb @@ -0,0 +1,34 @@ +describe :enumerable_include, shared: true do + it "returns true if any element == argument for numbers" do + class EnumerableSpecIncludeP; def ==(obj) obj == 5; end; end + + elements = (0..5).to_a + EnumerableSpecs::Numerous.new(*elements).send(@method,5).should == true + EnumerableSpecs::Numerous.new(*elements).send(@method,10).should == false + EnumerableSpecs::Numerous.new(*elements).send(@method,EnumerableSpecIncludeP.new).should == true + end + + it "returns true if any element == argument for other objects" do + class EnumerableSpecIncludeP11; def ==(obj); obj == '11'; end; end + + elements = ('0'..'5').to_a + [EnumerableSpecIncludeP11.new] + EnumerableSpecs::Numerous.new(*elements).send(@method,'5').should == true + EnumerableSpecs::Numerous.new(*elements).send(@method,'10').should == false + EnumerableSpecs::Numerous.new(*elements).send(@method,EnumerableSpecIncludeP11.new).should == true + EnumerableSpecs::Numerous.new(*elements).send(@method,'11').should == true + end + + + it "returns true if any member of enum equals obj when == compare different classes (legacy rubycon)" do + # equality is tested with == + EnumerableSpecs::Numerous.new(2,4,6,8,10).send(@method, 2.0).should == true + EnumerableSpecs::Numerous.new(2,4,[6,8],10).send(@method, [6, 8]).should == true + EnumerableSpecs::Numerous.new(2,4,[6,8],10).send(@method, [6.0, 8.0]).should == true + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.send(@method, [1,2]).should be_true + end + +end diff --git a/spec/ruby/core/enumerable/shared/inject.rb b/spec/ruby/core/enumerable/shared/inject.rb new file mode 100644 index 0000000000..12e0665dda --- /dev/null +++ b/spec/ruby/core/enumerable/shared/inject.rb @@ -0,0 +1,69 @@ +describe :enumerable_inject, shared: true do + it "with argument takes a block with an accumulator (with argument as initial value) and the current element. Value of block becomes new accumulator" do + a = [] + EnumerableSpecs::Numerous.new.send(@method, 0) { |memo, i| a << [memo, i]; i } + a.should == [[0, 2], [2, 5], [5, 3], [3, 6], [6, 1], [1, 4]] + EnumerableSpecs::EachDefiner.new(true, true, true).send(@method, nil) {|result, i| i && result}.should == nil + end + + it "produces an array of the accumulator and the argument when given a block with a *arg" do + a = [] + [1,2].send(@method, 0) {|*args| a << args; args[0] + args[1]} + a.should == [[0, 1], [1, 2]] + end + + it "can take two argument" do + EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-).should == 4 + end + + it "ignores the block if two arguments" do + EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-){ raise "we never get here"}.should == 4 + end + + it "can take a symbol argument" do + EnumerableSpecs::Numerous.new(10, 1, 2, 3).send(@method, :-).should == 4 + end + + it "without argument takes a block with an accumulator (with first element as initial value) and the current element. Value of block becomes new accumulator" do + a = [] + EnumerableSpecs::Numerous.new.send(@method) { |memo, i| a << [memo, i]; i } + a.should == [[2, 5], [5, 3], [3, 6], [6, 1], [1, 4]] + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.send(@method, []) {|acc, e| acc << e }.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] + end + + it "with inject arguments(legacy rubycon)" do + # with inject argument + EnumerableSpecs::EachDefiner.new().send(@method, 1) {|acc,x| 999 }.should == 1 + EnumerableSpecs::EachDefiner.new(2).send(@method, 1) {|acc,x| 999 }.should == 999 + EnumerableSpecs::EachDefiner.new(2).send(@method, 1) {|acc,x| acc }.should == 1 + EnumerableSpecs::EachDefiner.new(2).send(@method, 1) {|acc,x| x }.should == 2 + + EnumerableSpecs::EachDefiner.new(1,2,3,4).send(@method, 100) {|acc,x| acc + x }.should == 110 + EnumerableSpecs::EachDefiner.new(1,2,3,4).send(@method, 100) {|acc,x| acc * x }.should == 2400 + + EnumerableSpecs::EachDefiner.new('a','b','c').send(@method, "z") {|result, i| i+result}.should == "cbaz" + end + + it "without inject arguments(legacy rubycon)" do + # no inject argument + EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| 999 } .should == 2 + EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| acc }.should == 2 + EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| x }.should == 2 + + EnumerableSpecs::EachDefiner.new(1,2,3,4).send(@method) {|acc,x| acc + x }.should == 10 + EnumerableSpecs::EachDefiner.new(1,2,3,4).send(@method) {|acc,x| acc * x }.should == 24 + + EnumerableSpecs::EachDefiner.new('a','b','c').send(@method) {|result, i| i+result}.should == "cba" + EnumerableSpecs::EachDefiner.new(3, 4, 5).send(@method) {|result, i| result*i}.should == 60 + EnumerableSpecs::EachDefiner.new([1], 2, 'a','b').send(@method){|r,i| r<<i}.should == [1, 2, 'a', 'b'] + + end + + it "returns nil when fails(legacy rubycon)" do + EnumerableSpecs::EachDefiner.new().send(@method) {|acc,x| 999 }.should == nil + end +end diff --git a/spec/ruby/core/enumerable/shared/take.rb b/spec/ruby/core/enumerable/shared/take.rb new file mode 100644 index 0000000000..bf2536acda --- /dev/null +++ b/spec/ruby/core/enumerable/shared/take.rb @@ -0,0 +1,63 @@ +describe :enumerable_take, shared: true do + before :each do + @values = [4,3,2,1,0,-1] + @enum = EnumerableSpecs::Numerous.new(*@values) + end + + it "returns the first count elements if given a count" do + @enum.send(@method, 2).should == [4, 3] + @enum.send(@method, 4).should == [4, 3, 2, 1] # See redmine #1686 ! + end + + it "returns an empty array when passed count on an empty array" do + empty = EnumerableSpecs::Empty.new + empty.send(@method, 0).should == [] + empty.send(@method, 1).should == [] + empty.send(@method, 2).should == [] + end + + it "returns an empty array when passed count == 0" do + @enum.send(@method, 0).should == [] + end + + it "returns an array containing the first element when passed count == 1" do + @enum.send(@method, 1).should == [4] + end + + it "raises an ArgumentError when count is negative" do + lambda { @enum.send(@method, -1) }.should raise_error(ArgumentError) + end + + it "returns the entire array when count > length" do + @enum.send(@method, 100).should == @values + @enum.send(@method, 8).should == @values # See redmine #1686 ! + end + + it "tries to convert the passed argument to an Integer using #to_int" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(3).at_most(:twice) # called twice, no apparent reason. See redmine #1554 + @enum.send(@method, obj).should == [4, 3, 2] + end + + it "raises a TypeError if the passed argument is not numeric" do + lambda { @enum.send(@method, nil) }.should raise_error(TypeError) + lambda { @enum.send(@method, "a") }.should raise_error(TypeError) + + obj = mock("nonnumeric") + lambda { @enum.send(@method, obj) }.should raise_error(TypeError) + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.send(@method, 1).should == [[1, 2]] + end + + it "consumes only what is needed" do + thrower = EnumerableSpecs::ThrowingEach.new + thrower.send(@method, 0).should == [] + counter = EnumerableSpecs::EachCounter.new(1,2,3,4) + counter.send(@method, 2).should == [1,2] + counter.times_called.should == 1 + counter.times_yielded.should == 2 + end +end diff --git a/spec/ruby/core/enumerable/slice_after_spec.rb b/spec/ruby/core/enumerable/slice_after_spec.rb new file mode 100644 index 0000000000..a199b9f1ed --- /dev/null +++ b/spec/ruby/core/enumerable/slice_after_spec.rb @@ -0,0 +1,61 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#slice_after" do + before :each do + @enum = EnumerableSpecs::Numerous.new(7, 6, 5, 4, 3, 2, 1) + end + + describe "when given an argument and no block" do + it "calls === on the argument to determine when to yield" do + arg = mock("filter") + arg.should_receive(:===).and_return(false, true, false, false, false, true, false) + e = @enum.slice_after(arg) + e.should be_an_instance_of(Enumerator) + e.to_a.should == [[7, 6], [5, 4, 3, 2], [1]] + end + + it "doesn't yield an empty array if the filter matches the first entry or the last entry" do + arg = mock("filter") + arg.should_receive(:===).and_return(true).exactly(7) + e = @enum.slice_after(arg) + e.to_a.should == [[7], [6], [5], [4], [3], [2], [1]] + end + + it "uses standard boolean as a test" do + arg = mock("filter") + arg.should_receive(:===).and_return(false, :foo, nil, false, false, 42, false) + e = @enum.slice_after(arg) + e.to_a.should == [[7, 6], [5, 4, 3, 2], [1]] + end + end + + describe "when given a block" do + describe "and no argument" do + it "calls the block to determine when to yield" do + e = @enum.slice_after{ |i| i == 6 || i == 2 } + e.should be_an_instance_of(Enumerator) + e.to_a.should == [[7, 6], [5, 4, 3, 2], [1]] + end + end + + describe "and an argument" do + it "raises an ArgumentError" do + lambda { @enum.slice_after(42) { |i| i == 6 } }.should raise_error(ArgumentError) + end + end + end + + it "raises an ArgumentError when given an incorrect number of arguments" do + lambda { @enum.slice_after("one", "two") }.should raise_error(ArgumentError) + lambda { @enum.slice_after }.should raise_error(ArgumentError) + end +end + +describe "when an iterator method yields more than one value" do + it "processes all yielded values" do + enum = EnumerableSpecs::YieldsMulti.new + result = enum.slice_after { |i| i == [3, 4, 5] }.to_a + result.should == [[[1, 2], [3, 4, 5]], [[6, 7, 8, 9]]] + end +end diff --git a/spec/ruby/core/enumerable/slice_before_spec.rb b/spec/ruby/core/enumerable/slice_before_spec.rb new file mode 100644 index 0000000000..1594372d32 --- /dev/null +++ b/spec/ruby/core/enumerable/slice_before_spec.rb @@ -0,0 +1,87 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#slice_before" do + before :each do + @enum = EnumerableSpecs::Numerous.new(7,6,5,4,3,2,1) + end + + describe "when given an argument and no block" do + it "calls === on the argument to determine when to yield" do + arg = mock "filter" + arg.should_receive(:===).and_return(false, true, false, false, false, true, false) + e = @enum.slice_before(arg) + e.should be_an_instance_of(Enumerator) + e.to_a.should == [[7], [6, 5, 4, 3], [2, 1]] + end + + it "doesn't yield an empty array if the filter matches the first entry or the last entry" do + arg = mock "filter" + arg.should_receive(:===).and_return(true).exactly(7) + e = @enum.slice_before(arg) + e.to_a.should == [[7], [6], [5], [4], [3], [2], [1]] + end + + it "uses standard boolean as a test" do + arg = mock "filter" + arg.should_receive(:===).and_return(false, :foo, nil, false, false, 42, false) + e = @enum.slice_before(arg) + e.to_a.should == [[7], [6, 5, 4, 3], [2, 1]] + end + end + + describe "when given a block" do + describe "and no argument" do + it "calls the block to determine when to yield" do + e = @enum.slice_before{|i| i == 6 || i == 2} + e.should be_an_instance_of(Enumerator) + e.to_a.should == [[7], [6, 5, 4, 3], [2, 1]] + end + end + + ruby_version_is ""..."2.3" do + describe "and an argument" do + it "calls the block with a copy of that argument" do + arg = [:foo] + first = nil + e = @enum.slice_before(arg) do |i, init| + init.should == arg + init.should_not equal(arg) + first = init + i == 6 || i == 2 + end + e.should be_an_instance_of(Enumerator) + e.to_a.should == [[7], [6, 5, 4, 3], [2, 1]] + e = @enum.slice_before(arg) do |i, init| + init.should_not equal(first) + end + e.to_a + end + end + end + + ruby_version_is "2.3" do + it "does not accept arguments" do + lambda { + @enum.slice_before(1) {} + }.should raise_error(ArgumentError) + end + end + end + + it "raises an ArgumentError when given an incorrect number of arguments" do + lambda { @enum.slice_before("one", "two") }.should raise_error(ArgumentError) + lambda { @enum.slice_before }.should raise_error(ArgumentError) + end + + describe "when an iterator method yields more than one value" do + it "processes all yielded values" do + enum = EnumerableSpecs::YieldsMulti.new + result = enum.slice_before { |i| i == [3, 4, 5] }.to_a + result.should == [[[1, 2]], [[3, 4, 5], [6, 7, 8, 9]]] + end + end + + it_behaves_like :enumerable_enumeratorized_with_unknown_size, [:slice_before, 3] +end diff --git a/spec/ruby/core/enumerable/slice_when_spec.rb b/spec/ruby/core/enumerable/slice_when_spec.rb new file mode 100644 index 0000000000..593e623b1b --- /dev/null +++ b/spec/ruby/core/enumerable/slice_when_spec.rb @@ -0,0 +1,54 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#slice_when" do + before :each do + ary = [10, 9, 7, 6, 4, 3, 2, 1] + @enum = EnumerableSpecs::Numerous.new(*ary) + @result = @enum.slice_when { |i, j| i - 1 != j } + @enum_length = ary.length + end + + context "when given a block" do + it "returns an enumerator" do + @result.should be_an_instance_of(Enumerator) + end + + it "splits chunks between adjacent elements i and j where the block returns true" do + @result.to_a.should == [[10, 9], [7, 6], [4, 3, 2, 1]] + end + + it "calls the block for length of the receiver enumerable minus one times" do + times_called = 0 + @enum.slice_when do |i, j| + times_called += 1 + i - 1 != j + end.to_a + times_called.should == (@enum_length - 1) + end + + it "doesn't yield an empty array if the block matches the first or the last time" do + @enum.slice_when { true }.to_a.should == [[10], [9], [7], [6], [4], [3], [2], [1]] + end + + it "doesn't yield an empty array on a small enumerable" do + EnumerableSpecs::Empty.new.slice_when { raise }.to_a.should == [] + EnumerableSpecs::Numerous.new(42).slice_when { raise }.to_a.should == [[42]] + end + end + + context "when not given a block" do + it "raises an ArgumentError" do + lambda { @enum.slice_when }.should raise_error(ArgumentError) + end + end + + describe "when an iterator method yields more than one value" do + it "processes all yielded values" do + def foo + yield 1, 2 + end + to_enum(:foo).slice_when { true }.to_a.should == [[[1, 2]]] + end + end +end diff --git a/spec/ruby/core/enumerable/sort_by_spec.rb b/spec/ruby/core/enumerable/sort_by_spec.rb new file mode 100644 index 0000000000..f7df8659a8 --- /dev/null +++ b/spec/ruby/core/enumerable/sort_by_spec.rb @@ -0,0 +1,36 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#sort_by" do + it "returns an array of elements ordered by the result of block" do + a = EnumerableSpecs::Numerous.new("once", "upon", "a", "time") + a.sort_by { |i| i[0] }.should == ["a", "once", "time", "upon"] + end + + it "sorts the object by the given attribute" do + a = EnumerableSpecs::SortByDummy.new("fooo") + b = EnumerableSpecs::SortByDummy.new("bar") + + ar = [a, b].sort_by { |d| d.s } + ar.should == [b, a] + end + + it "returns an Enumerator when a block is not supplied" do + a = EnumerableSpecs::Numerous.new("a","b") + a.sort_by.should be_an_instance_of(Enumerator) + a.to_a.should == ["a", "b"] + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.sort_by {|e| e.size}.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] + end + + it "returns an array of elements when a block is supplied and #map returns an enumerable" do + b = EnumerableSpecs::MapReturnsEnumerable.new + b.sort_by{ |x| -x }.should == [3, 2, 1] + end + + it_behaves_like :enumerable_enumeratorized_with_origin_size, :sort_by +end diff --git a/spec/ruby/core/enumerable/sort_spec.rb b/spec/ruby/core/enumerable/sort_spec.rb new file mode 100644 index 0000000000..a39fa7ed34 --- /dev/null +++ b/spec/ruby/core/enumerable/sort_spec.rb @@ -0,0 +1,54 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#sort" do + it "sorts by the natural order as defined by <=>" do + EnumerableSpecs::Numerous.new.sort.should == [1, 2, 3, 4, 5, 6] + sorted = EnumerableSpecs::ComparesByVowelCount.wrap("a" * 1, "a" * 2, "a"*3, "a"*4, "a"*5) + EnumerableSpecs::Numerous.new(sorted[2],sorted[0],sorted[1],sorted[3],sorted[4]).sort.should == sorted + end + + it "yields elements to the provided block" do + EnumerableSpecs::Numerous.new.sort { |a, b| b <=> a }.should == [6, 5, 4, 3, 2, 1] + EnumerableSpecs::Numerous.new(2,0,1,3,4).sort { |n, m| -(n <=> m) }.should == [4,3,2,1,0] + end + + it "raises a NoMethodError if elements do not define <=>" do + lambda do + EnumerableSpecs::Numerous.new(BasicObject.new, BasicObject.new, BasicObject.new).sort + end.should raise_error(NoMethodError) + end + + it "sorts enumerables that contain nils" do + arr = EnumerableSpecs::Numerous.new(nil, true, nil, false, nil, true, nil, false, nil) + arr.sort { |a, b| + x = a ? -1 : a.nil? ? 0 : 1 + y = b ? -1 : b.nil? ? 0 : 1 + x <=> y + }.should == [true, true, nil, nil, nil, nil, nil, false, false] + end + + it "compare values returned by block with 0" do + EnumerableSpecs::Numerous.new.sort { |n, m| -(n+m) * (n <=> m) }.should == [6, 5, 4, 3, 2, 1] + EnumerableSpecs::Numerous.new.sort { |n, m| + EnumerableSpecs::ComparableWithFixnum.new(-(n+m) * (n <=> m)) + }.should == [6, 5, 4, 3, 2, 1] + lambda { + EnumerableSpecs::Numerous.new.sort { |n, m| (n <=> m).to_s } + }.should raise_error(ArgumentError) + end + + it "raises an error if objects can't be compared" do + a=EnumerableSpecs::Numerous.new(EnumerableSpecs::Uncomparable.new, EnumerableSpecs::Uncomparable.new) + lambda {a.sort}.should raise_error(ArgumentError) + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.sort {|a, b| a.first <=> b.first}.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] + end + + it "doesn't raise an error if #to_a returns a frozen Array" do + EnumerableSpecs::Freezy.new.sort.should == [1,2] + end +end diff --git a/spec/ruby/core/enumerable/sum_spec.rb b/spec/ruby/core/enumerable/sum_spec.rb new file mode 100644 index 0000000000..4881039a8d --- /dev/null +++ b/spec/ruby/core/enumerable/sum_spec.rb @@ -0,0 +1,30 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +ruby_version_is '2.4' do + describe 'Enumerable#sum' do + before :each do + @enum = Object.new.to_enum + class << @enum + def each + yield 0 + yield(-1) + yield 2 + yield 2/3r + end + end + end + + it 'returns amount of the elements with taking an argument as the initial value' do + @enum.sum(10).should == 35/3r + end + + it 'gives 0 as a default argument' do + @enum.sum.should == 5/3r + end + + it 'takes a block to transform the elements' do + @enum.sum { |element| element * 2 }.should == 10/3r + end + end +end diff --git a/spec/ruby/core/enumerable/take_spec.rb b/spec/ruby/core/enumerable/take_spec.rb new file mode 100644 index 0000000000..71bf77050c --- /dev/null +++ b/spec/ruby/core/enumerable/take_spec.rb @@ -0,0 +1,13 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/take', __FILE__) + +describe "Enumerable#take" do + it "requires an argument" do + lambda{ EnumerableSpecs::Numerous.new.take}.should raise_error(ArgumentError) + end + + describe "when passed an argument" do + it_behaves_like :enumerable_take, :take + end +end diff --git a/spec/ruby/core/enumerable/take_while_spec.rb b/spec/ruby/core/enumerable/take_while_spec.rb new file mode 100644 index 0000000000..990d16209a --- /dev/null +++ b/spec/ruby/core/enumerable/take_while_spec.rb @@ -0,0 +1,51 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/enumerable_enumeratorized', __FILE__) + +describe "Enumerable#take_while" do + before :each do + @enum = EnumerableSpecs::Numerous.new(3, 2, 1, :go) + end + + it "returns an Enumerator if no block given" do + @enum.take_while.should be_an_instance_of(Enumerator) + end + + it "returns no/all elements for {true/false} block" do + @enum.take_while{true}.should == @enum.to_a + @enum.take_while{false}.should == [] + end + + it "accepts returns other than true/false" do + @enum.take_while{1}.should == @enum.to_a + @enum.take_while{nil}.should == [] + end + + it "passes elements to the block until the first false" do + a = [] + @enum.take_while{|obj| (a << obj).size < 3}.should == [3, 2] + a.should == [3, 2, 1] + end + + it "will only go through what's needed" do + enum = EnumerableSpecs::EachCounter.new(4, 3, 2, 1, :stop) + enum.take_while { |x| + break 42 if x == 3 + true + }.should == 42 + enum.times_yielded.should == 2 + end + + it "doesn't return self when it could" do + a = [1,2,3] + a.take_while{true}.should_not equal(a) + end + + it "calls the block with initial args when yielded with multiple arguments" do + yields = [] + EnumerableSpecs::YieldsMixed.new.take_while{ |v| yields << v } + yields.should == [1, [2], 3, 5, [8, 9], nil, []] + end + + it_behaves_like :enumerable_enumeratorized_with_unknown_size, :take_while +end diff --git a/spec/ruby/core/enumerable/to_a_spec.rb b/spec/ruby/core/enumerable/to_a_spec.rb new file mode 100644 index 0000000000..b14a3c7a1a --- /dev/null +++ b/spec/ruby/core/enumerable/to_a_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) +require File.expand_path('../shared/entries', __FILE__) + +describe "Enumerable#to_a" do + it_behaves_like(:enumerable_entries , :to_a) +end diff --git a/spec/ruby/core/enumerable/to_h_spec.rb b/spec/ruby/core/enumerable/to_h_spec.rb new file mode 100644 index 0000000000..b5b301b882 --- /dev/null +++ b/spec/ruby/core/enumerable/to_h_spec.rb @@ -0,0 +1,46 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#to_h" do + it "converts empty enumerable to empty hash" do + enum = EnumerableSpecs::EachDefiner.new + enum.to_h.should == {} + end + + it "converts yielded [key, value] pairs to a hash" do + enum = EnumerableSpecs::EachDefiner.new([:a, 1], [:b, 2]) + enum.to_h.should == { a: 1, b: 2 } + end + + it "uses the last value of a duplicated key" do + enum = EnumerableSpecs::EachDefiner.new([:a, 1], [:b, 2], [:a, 3]) + enum.to_h.should == { a: 3, b: 2 } + end + + it "calls #to_ary on contents" do + pair = mock('to_ary') + pair.should_receive(:to_ary).and_return([:b, 2]) + enum = EnumerableSpecs::EachDefiner.new([:a, 1], pair) + enum.to_h.should == { a: 1, b: 2 } + end + + it "forwards arguments to #each" do + enum = Object.new + def enum.each(*args) + yield(*args) + yield([:b, 2]) + end + enum.extend Enumerable + enum.to_h(:a, 1).should == { a: 1, b: 2 } + end + + it "raises TypeError if an element is not an array" do + enum = EnumerableSpecs::EachDefiner.new(:x) + lambda { enum.to_h }.should raise_error(TypeError) + end + + it "raises ArgumentError if an element is not a [key, value] pair" do + enum = EnumerableSpecs::EachDefiner.new([:x]) + lambda { enum.to_h }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/core/enumerable/uniq_spec.rb b/spec/ruby/core/enumerable/uniq_spec.rb new file mode 100644 index 0000000000..0ede0170ce --- /dev/null +++ b/spec/ruby/core/enumerable/uniq_spec.rb @@ -0,0 +1,29 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +ruby_version_is '2.4' do + describe 'Enumerable#uniq' do + it 'returns an array that contains only unique elements' do + [0, 1, 2, 3].to_enum.uniq { |n| n.even? }.should == [0, 1] + end + + context 'when yielded with multiple arguments' do + before :each do + @enum = Object.new.to_enum + class << @enum + def each + yield 0, 'foo' + yield 1, 'FOO' + yield 2, 'bar' + end + end + end + + ruby_bug '#13669', ''...'2.5' do + it 'returns all yield arguments as an array' do + @enum.uniq { |_, label| label.downcase }.should == [[0, 'foo'], [2, 'bar']] + end + end + end + end +end diff --git a/spec/ruby/core/enumerable/zip_spec.rb b/spec/ruby/core/enumerable/zip_spec.rb new file mode 100644 index 0000000000..2d090f335c --- /dev/null +++ b/spec/ruby/core/enumerable/zip_spec.rb @@ -0,0 +1,42 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Enumerable#zip" do + + it "combines each element of the receiver with the element of the same index in arrays given as arguments" do + EnumerableSpecs::Numerous.new(1,2,3).zip([4,5,6],[7,8,9]).should == [[1,4,7],[2,5,8],[3,6,9]] + EnumerableSpecs::Numerous.new(1,2,3).zip.should == [[1],[2],[3]] + end + + it "passes each element of the result array to a block and return nil if a block is given" do + expected = [[1,4,7],[2,5,8],[3,6,9]] + EnumerableSpecs::Numerous.new(1,2,3).zip([4,5,6],[7,8,9]) do |result_component| + result_component.should == expected.shift + end.should == nil + expected.size.should == 0 + end + + it "fills resulting array with nils if an argument array is too short" do + EnumerableSpecs::Numerous.new(1,2,3).zip([4,5,6], [7,8]).should == [[1,4,7],[2,5,8],[3,6,nil]] + end + + it "converts arguments to arrays using #to_ary" do + convertable = EnumerableSpecs::ArrayConvertable.new(4,5,6) + EnumerableSpecs::Numerous.new(1,2,3).zip(convertable).should == [[1,4],[2,5],[3,6]] + convertable.called.should == :to_ary + end + + it "converts arguments to enums using #to_enum" do + convertable = EnumerableSpecs::EnumConvertable.new(4..6) + EnumerableSpecs::Numerous.new(1,2,3).zip(convertable).should == [[1,4],[2,5],[3,6]] + convertable.called.should == :to_enum + convertable.sym.should == :each + end + + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.zip(multi).should == [[[1, 2], [1, 2]], [[3, 4, 5], [3, 4, 5]], [[6, 7, 8, 9], [6, 7, 8, 9]]] + end + +end + |