diff options
Diffstat (limited to 'spec/ruby/core/array')
114 files changed, 2711 insertions, 1531 deletions
diff --git a/spec/ruby/core/array/all_spec.rb b/spec/ruby/core/array/all_spec.rb new file mode 100644 index 0000000000..680e8c26fa --- /dev/null +++ b/spec/ruby/core/array/all_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' +require_relative 'shared/iterable_and_tolerating_size_increasing' + +describe "Array#all?" do + @value_to_return = -> _ { true } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :all? + + it "ignores the block if there is an argument" do + -> { + ['bar', 'foobar'].all?(/bar/) { false }.should == true + }.should complain(/given block not used/) + end +end diff --git a/spec/ruby/core/array/allocate_spec.rb b/spec/ruby/core/array/allocate_spec.rb index a1800e7e16..04f7c0d0ad 100644 --- a/spec/ruby/core/array/allocate_spec.rb +++ b/spec/ruby/core/array/allocate_spec.rb @@ -14,6 +14,6 @@ describe "Array.allocate" do end it "does not accept any arguments" do - lambda { Array.allocate(1) }.should raise_error(ArgumentError) + -> { Array.allocate(1) }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/core/array/any_spec.rb b/spec/ruby/core/array/any_spec.rb index 2fa5353e99..b51ce62f0f 100644 --- a/spec/ruby/core/array/any_spec.rb +++ b/spec/ruby/core/array/any_spec.rb @@ -1,24 +1,28 @@ require_relative '../../spec_helper' +require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#any?" do describe 'with no block given (a default block of { |x| x } is implicit)' do it "is false if the array is empty" do empty_array = [] - empty_array.any?.should == false + empty_array.should_not.any? end it "is false if the array is not empty, but all the members of the array are falsy" do falsy_array = [false, nil, false] - falsy_array.any?.should == false + falsy_array.should_not.any? end it "is true if the array has any truthy members" do not_empty_array = ['anything', nil] - not_empty_array.any?.should == true + not_empty_array.should.any? end end describe 'with a block given' do + @value_to_return = -> _ { false } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :any? + it 'is false if the array is empty' do empty_array = [] empty_array.any? {|v| 1 == 1 }.should == false @@ -34,4 +38,12 @@ describe "Array#any?" do array_with_members.any? {|v| v == 42 }.should == false end end + + describe 'when given a pattern argument' do + it "ignores the block if there is an argument" do + -> { + ['bar', 'foobar'].any?(/bar/) { false }.should == true + }.should complain(/given block not used/) + end + end end diff --git a/spec/ruby/core/array/append_spec.rb b/spec/ruby/core/array/append_spec.rb index 08ea814d89..c12473dc07 100644 --- a/spec/ruby/core/array/append_spec.rb +++ b/spec/ruby/core/array/append_spec.rb @@ -30,13 +30,11 @@ describe "Array#<<" do a.should == [:foo] end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array << 5 }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array << 5 }.should raise_error(FrozenError) end end -ruby_version_is "2.5" do - describe "Array#append" do - it_behaves_like :array_push, :append - end +describe "Array#append" do + it_behaves_like :array_push, :append end diff --git a/spec/ruby/core/array/assoc_spec.rb b/spec/ruby/core/array/assoc_spec.rb index f8479d763c..f0be3de795 100644 --- a/spec/ruby/core/array/assoc_spec.rb +++ b/spec/ruby/core/array/assoc_spec.rb @@ -6,7 +6,7 @@ describe "Array#assoc" do s1 = ["colors", "red", "blue", "green"] s2 = [:letters, "a", "b", "c"] s3 = [4] - s4 = ["colors", "cyan", "yellow", "magenda"] + s4 = ["colors", "cyan", "yellow", "magenta"] s5 = [:letters, "a", "i", "u"] s_nil = [nil, nil] a = [s1, s2, s3, s4, s5, s_nil] @@ -37,4 +37,16 @@ describe "Array#assoc" do a.assoc(s1.first).should equal(s1) a.assoc(s2.first).should equal(s2) end + + it "calls to_ary on non-array elements" do + s1 = [1, 2] + s2 = ArraySpecs::ArrayConvertible.new(2, 3) + a = [s1, s2] + + s1.should_not_receive(:to_ary) + a.assoc(s1.first).should equal(s1) + + a.assoc(2).should == [2, 3] + s2.called.should equal(:to_ary) + end end diff --git a/spec/ruby/core/array/at_spec.rb b/spec/ruby/core/array/at_spec.rb index d237c9508a..8bc789fef7 100644 --- a/spec/ruby/core/array/at_spec.rb +++ b/spec/ruby/core/array/at_spec.rb @@ -47,10 +47,10 @@ describe "Array#at" do end it "raises a TypeError when the passed argument can't be coerced to Integer" do - lambda { [].at("cat") }.should raise_error(TypeError) + -> { [].at("cat") }.should raise_error(TypeError) end it "raises an ArgumentError when 2 or more arguments are passed" do - lambda { [:a, :b].at(0,1) }.should raise_error(ArgumentError) + -> { [:a, :b].at(0,1) }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/core/array/bsearch_index_spec.rb b/spec/ruby/core/array/bsearch_index_spec.rb index a075d06ed3..94d85b37f3 100644 --- a/spec/ruby/core/array/bsearch_index_spec.rb +++ b/spec/ruby/core/array/bsearch_index_spec.rb @@ -21,7 +21,7 @@ describe "Array#bsearch_index" do end it "raises a TypeError when block returns a String" do - lambda { [1, 2, 3].bsearch_index { "not ok" } }.should raise_error(TypeError) + -> { [1, 2, 3].bsearch_index { "not ok" } }.should raise_error(TypeError) end it "returns nil when block is empty" do @@ -63,10 +63,6 @@ describe "Array#bsearch_index" do @array.bsearch_index { |x| -1 }.should be_nil end - it "returns the middle element when block always returns zero" do - @array.bsearch_index { |x| 0 }.should == 2 - end - context "magnitude does not effect the result" do it "returns the index of any matched elements where element is between 4n <= xn < 8n" do [1, 2].should include(@array.bsearch_index { |x| (1 - x / 4) * (2**100) }) @@ -77,7 +73,7 @@ describe "Array#bsearch_index" do @array.bsearch_index { |x| (-1) * (2**100) }.should be_nil end - it "handles values from Bignum#coerce" do + it "handles values from Integer#coerce" do [1, 2].should include(@array.bsearch_index { |x| (2**100).coerce((1 - x / 4) * (2**100)).first }) end end diff --git a/spec/ruby/core/array/bsearch_spec.rb b/spec/ruby/core/array/bsearch_spec.rb index 57b95fb934..8fa6245dbf 100644 --- a/spec/ruby/core/array/bsearch_spec.rb +++ b/spec/ruby/core/array/bsearch_spec.rb @@ -9,11 +9,11 @@ describe "Array#bsearch" do it_behaves_like :enumeratorized_with_unknown_size, :bsearch, [1,2,3] it "raises a TypeError if the block returns an Object" do - lambda { [1].bsearch { Object.new } }.should raise_error(TypeError) + -> { [1].bsearch { Object.new } }.should raise_error(TypeError) end it "raises a TypeError if the block returns a String" do - lambda { [1].bsearch { "1" } }.should raise_error(TypeError) + -> { [1].bsearch { "1" } }.should raise_error(TypeError) end context "with a block returning true or false" do diff --git a/spec/ruby/core/array/clear_spec.rb b/spec/ruby/core/array/clear_spec.rb index 8cba1f9e27..81ba56e01e 100644 --- a/spec/ruby/core/array/clear_spec.rb +++ b/spec/ruby/core/array/clear_spec.rb @@ -16,33 +16,17 @@ describe "Array#clear" do it "leaves the Array empty" do a = [1] a.clear - a.empty?.should == true + a.should.empty? a.size.should == 0 end - it "keeps tainted status" do - a = [1] - a.taint - a.tainted?.should be_true - a.clear - a.tainted?.should be_true - end - it "does not accept any arguments" do - lambda { [1].clear(true) }.should raise_error(ArgumentError) - end - - it "keeps untrusted status" do - a = [1] - a.untrust - a.untrusted?.should be_true - a.clear - a.untrusted?.should be_true + -> { [1].clear(true) }.should raise_error(ArgumentError) end - it "raises a #{frozen_error_class} on a frozen array" do + it "raises a FrozenError on a frozen array" do a = [1] a.freeze - lambda { a.clear }.should raise_error(frozen_error_class) + -> { a.clear }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/clone_spec.rb b/spec/ruby/core/array/clone_spec.rb index 803e746e02..e22a6c6d53 100644 --- a/spec/ruby/core/array/clone_spec.rb +++ b/spec/ruby/core/array/clone_spec.rb @@ -12,8 +12,8 @@ describe "Array#clone" do aa = a.clone bb = b.clone - aa.frozen?.should == true - bb.frozen?.should == false + aa.should.frozen? + bb.should_not.frozen? end it "copies singleton methods" do diff --git a/spec/ruby/core/array/compact_spec.rb b/spec/ruby/core/array/compact_spec.rb index 4818217be1..83b3fa2a89 100644 --- a/spec/ruby/core/array/compact_spec.rb +++ b/spec/ruby/core/array/compact_spec.rb @@ -21,18 +21,6 @@ describe "Array#compact" do it "does not return subclass instance for Array subclasses" do ArraySpecs::MyArray[1, 2, 3, nil].compact.should be_an_instance_of(Array) end - - it "does not keep tainted status even if all elements are removed" do - a = [nil, nil] - a.taint - a.compact.tainted?.should be_false - end - - it "does not keep untrusted status even if all elements are removed" do - a = [nil, nil] - a.untrust - a.compact.untrusted?.should be_false - end end describe "Array#compact!" do @@ -57,21 +45,7 @@ describe "Array#compact!" do [1, 2, false, 3].compact!.should == nil end - it "keeps tainted status even if all elements are removed" do - a = [nil, nil] - a.taint - a.compact! - a.tainted?.should be_true - end - - it "keeps untrusted status even if all elements are removed" do - a = [nil, nil] - a.untrust - a.compact! - a.untrusted?.should be_true - end - - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.compact! }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.compact! }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/concat_spec.rb b/spec/ruby/core/array/concat_spec.rb index 91adb8b745..f3cab9c17c 100644 --- a/spec/ruby/core/array/concat_spec.rb +++ b/spec/ruby/core/array/concat_spec.rb @@ -32,69 +32,13 @@ describe "Array#concat" do [].concat(obj).should == [5, 6, 7] end - it "raises a #{frozen_error_class} when Array is frozen and modification occurs" do - lambda { ArraySpecs.frozen_array.concat [1] }.should raise_error(frozen_error_class) + it "raises a FrozenError when Array is frozen and modification occurs" do + -> { ArraySpecs.frozen_array.concat [1] }.should raise_error(FrozenError) end # see [ruby-core:23666] - it "raises a #{frozen_error_class} when Array is frozen and no modification occurs" do - lambda { ArraySpecs.frozen_array.concat([]) }.should raise_error(frozen_error_class) - end - - it "keeps tainted status" do - ary = [1, 2] - ary.taint - ary.concat([3]) - ary.tainted?.should be_true - ary.concat([]) - ary.tainted?.should be_true - end - - it "is not infected by the other" do - ary = [1,2] - other = [3]; other.taint - ary.tainted?.should be_false - ary.concat(other) - ary.tainted?.should be_false - end - - it "keeps the tainted status of elements" do - ary = [ Object.new, Object.new, Object.new ] - ary.each {|x| x.taint } - - ary.concat([ Object.new ]) - ary[0].tainted?.should be_true - ary[1].tainted?.should be_true - ary[2].tainted?.should be_true - ary[3].tainted?.should be_false - end - - it "keeps untrusted status" do - ary = [1, 2] - ary.untrust - ary.concat([3]) - ary.untrusted?.should be_true - ary.concat([]) - ary.untrusted?.should be_true - end - - it "is not infected untrustedness by the other" do - ary = [1,2] - other = [3]; other.untrust - ary.untrusted?.should be_false - ary.concat(other) - ary.untrusted?.should be_false - end - - it "keeps the untrusted status of elements" do - ary = [ Object.new, Object.new, Object.new ] - ary.each {|x| x.untrust } - - ary.concat([ Object.new ]) - ary[0].untrusted?.should be_true - ary[1].untrusted?.should be_true - ary[2].untrusted?.should be_true - ary[3].untrusted?.should be_false + it "raises a FrozenError when Array is frozen and no modification occurs" do + -> { ArraySpecs.frozen_array.concat([]) }.should raise_error(FrozenError) end it "appends elements to an Array with enough capacity that has been shifted" do diff --git a/spec/ruby/core/array/count_spec.rb b/spec/ruby/core/array/count_spec.rb index eaf275aeb7..e778233c16 100644 --- a/spec/ruby/core/array/count_spec.rb +++ b/spec/ruby/core/array/count_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#count" do it "returns the number of elements" do @@ -12,4 +13,14 @@ describe "Array#count" do it "returns the number of element for which the block evaluates to true" do [:a, :b, :c].count { |s| s != :b }.should == 2 end + + it "ignores the block if there is an argument" do + -> { + [:a, :b, :b, :c].count(:b) { |e| e.size > 10 }.should == 2 + }.should complain(/given block not used/) + end + + context "when a block argument given" do + it_behaves_like :array_iterable_and_tolerating_size_increasing, :count + end end diff --git a/spec/ruby/core/array/cycle_spec.rb b/spec/ruby/core/array/cycle_spec.rb index 018005abb4..7219b49883 100644 --- a/spec/ruby/core/array/cycle_spec.rb +++ b/spec/ruby/core/array/cycle_spec.rb @@ -6,7 +6,7 @@ describe "Array#cycle" do ScratchPad.record [] @array = [1, 2, 3] - @prc = lambda { |x| ScratchPad << x } + @prc = -> x { ScratchPad << x } end it "does not yield and returns nil when the array is empty and passed value is an integer" do @@ -46,13 +46,13 @@ describe "Array#cycle" do end it "does not rescue StopIteration when not passed a count" do - lambda do + -> do @array.cycle { raise StopIteration } end.should raise_error(StopIteration) end it "does not rescue StopIteration when passed a count" do - lambda do + -> do @array.cycle(3) { raise StopIteration } end.should raise_error(StopIteration) end @@ -74,23 +74,23 @@ describe "Array#cycle" do count = mock("cycle count 2") count.should_receive(:to_int).and_return("2") - lambda { @array.cycle(count, &@prc) }.should raise_error(TypeError) + -> { @array.cycle(count, &@prc) }.should raise_error(TypeError) end it "raises a TypeError if passed a String" do - lambda { @array.cycle("4") { } }.should raise_error(TypeError) + -> { @array.cycle("4") { } }.should raise_error(TypeError) end it "raises a TypeError if passed an Object" do - lambda { @array.cycle(mock("cycle count")) { } }.should raise_error(TypeError) + -> { @array.cycle(mock("cycle count")) { } }.should raise_error(TypeError) end it "raises a TypeError if passed true" do - lambda { @array.cycle(true) { } }.should raise_error(TypeError) + -> { @array.cycle(true) { } }.should raise_error(TypeError) end it "raises a TypeError if passed false" do - lambda { @array.cycle(false) { } }.should raise_error(TypeError) + -> { @array.cycle(false) { } }.should raise_error(TypeError) end before :all do diff --git a/spec/ruby/core/array/deconstruct_spec.rb b/spec/ruby/core/array/deconstruct_spec.rb new file mode 100644 index 0000000000..ad67abe47b --- /dev/null +++ b/spec/ruby/core/array/deconstruct_spec.rb @@ -0,0 +1,9 @@ +require_relative '../../spec_helper' + +describe "Array#deconstruct" do + it "returns self" do + array = [1] + + array.deconstruct.should equal array + end +end diff --git a/spec/ruby/core/array/delete_at_spec.rb b/spec/ruby/core/array/delete_at_spec.rb index 021554c76a..80ec643702 100644 --- a/spec/ruby/core/array/delete_at_spec.rb +++ b/spec/ruby/core/array/delete_at_spec.rb @@ -35,27 +35,7 @@ describe "Array#delete_at" do a.delete_at(-2).should == 1 end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { [1,2,3].freeze.delete_at(0) }.should raise_error(frozen_error_class) - end - - it "keeps tainted status" do - ary = [1, 2] - ary.taint - ary.tainted?.should be_true - ary.delete_at(0) - ary.tainted?.should be_true - ary.delete_at(0) # now empty - ary.tainted?.should be_true - end - - it "keeps untrusted status" do - ary = [1, 2] - ary.untrust - ary.untrusted?.should be_true - ary.delete_at(0) - ary.untrusted?.should be_true - ary.delete_at(0) # now empty - ary.untrusted?.should be_true + it "raises a FrozenError on a frozen array" do + -> { [1,2,3].freeze.delete_at(0) }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/delete_if_spec.rb b/spec/ruby/core/array/delete_if_spec.rb index 12a7d1662d..10972eee0e 100644 --- a/spec/ruby/core/array/delete_if_spec.rb +++ b/spec/ruby/core/array/delete_if_spec.rb @@ -2,6 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/enumeratorize' require_relative 'shared/delete_if' +require_relative 'shared/iterable_and_tolerating_size_increasing' require_relative '../enumerable/shared/enumeratorized' describe "Array#delete_if" do @@ -39,28 +40,43 @@ describe "Array#delete_if" do @a.freeze.delete_if.should be_an_instance_of(Enumerator) end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.delete_if {} }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.delete_if {} }.should raise_error(FrozenError) end - it "raises a #{frozen_error_class} on an empty frozen array" do - lambda { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(frozen_error_class) + it "raises a FrozenError on an empty frozen array" do + -> { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(FrozenError) end - it "keeps tainted status" do - @a.taint - @a.tainted?.should be_true - @a.delete_if{ true } - @a.tainted?.should be_true + it "does not truncate the array is the block raises an exception" do + a = [1, 2, 3] + begin + a.delete_if { raise StandardError, 'Oops' } + rescue + end + + a.should == [1, 2, 3] end - it "keeps untrusted status" do - @a.untrust - @a.untrusted?.should be_true - @a.delete_if{ true } - @a.untrusted?.should be_true + it "only removes elements for which the block returns true, keeping the element which raised an error." do + a = [1, 2, 3, 4] + begin + a.delete_if do |e| + case e + when 2 then true + when 3 then raise StandardError, 'Oops' + else false + end + end + rescue StandardError + end + + a.should == [1, 3, 4] end it_behaves_like :enumeratorized_with_origin_size, :delete_if, [1,2,3] it_behaves_like :delete_if, :delete_if + + @value_to_return = -> _ { false } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :delete_if end diff --git a/spec/ruby/core/array/delete_spec.rb b/spec/ruby/core/array/delete_spec.rb index 62476f489b..dddbbe6bd3 100644 --- a/spec/ruby/core/array/delete_spec.rb +++ b/spec/ruby/core/array/delete_spec.rb @@ -40,27 +40,7 @@ describe "Array#delete" do [1, 2, 3].freeze.delete(0).should == nil end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { [1, 2, 3].freeze.delete(1) }.should raise_error(frozen_error_class) - end - - it "keeps tainted status" do - a = [1, 2] - a.taint - a.tainted?.should be_true - a.delete(2) - a.tainted?.should be_true - a.delete(1) # now empty - a.tainted?.should be_true - end - - it "keeps untrusted status" do - a = [1, 2] - a.untrust - a.untrusted?.should be_true - a.delete(2) - a.untrusted?.should be_true - a.delete(1) # now empty - a.untrusted?.should be_true + it "raises a FrozenError on a frozen array" do + -> { [1, 2, 3].freeze.delete(1) }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/difference_spec.rb b/spec/ruby/core/array/difference_spec.rb index a357657967..9f7d4c4a1a 100644 --- a/spec/ruby/core/array/difference_spec.rb +++ b/spec/ruby/core/array/difference_spec.rb @@ -2,23 +2,21 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/difference' -ruby_version_is "2.6" do - describe "Array#difference" do - it_behaves_like :array_binary_difference, :difference +describe "Array#difference" do + it_behaves_like :array_binary_difference, :difference - it "returns a copy when called without any parameter" do - x = [1, 2, 3, 2] - x.difference.should == x - x.difference.should_not equal x - end + it "returns a copy when called without any parameter" do + x = [1, 2, 3, 2] + x.difference.should == x + x.difference.should_not equal x + end - it "does not return subclass instances for Array subclasses" do - ArraySpecs::MyArray[1, 2, 3].difference.should be_an_instance_of(Array) - end + it "does not return subclass instances for Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].difference.should be_an_instance_of(Array) + end - it "accepts multiple arguments" do - x = [1, 2, 3, 1] - x.difference([], [0, 1], [3, 4], [3]).should == [2] - end + it "accepts multiple arguments" do + x = [1, 2, 3, 1] + x.difference([], [0, 1], [3, 4], [3]).should == [2] end end diff --git a/spec/ruby/core/array/dig_spec.rb b/spec/ruby/core/array/dig_spec.rb index 1ace4893ee..f2d8ff47fd 100644 --- a/spec/ruby/core/array/dig_spec.rb +++ b/spec/ruby/core/array/dig_spec.rb @@ -20,20 +20,20 @@ describe "Array#dig" do end it "raises a TypeError for a non-numeric index" do - lambda { + -> { ['a'].dig(:first) }.should raise_error(TypeError) end it "raises a TypeError if any intermediate step does not respond to #dig" do a = [1, 2] - lambda { + -> { a.dig(0, 1) }.should raise_error(TypeError) end it "raises an ArgumentError if no arguments provided" do - lambda { + -> { [10].dig() }.should raise_error(ArgumentError) end diff --git a/spec/ruby/core/array/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb index 1bd2e6cc25..5926c291b8 100644 --- a/spec/ruby/core/array/drop_spec.rb +++ b/spec/ruby/core/array/drop_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe "Array#drop" do it "removes the specified number of elements from the start of the array" do @@ -6,7 +7,7 @@ describe "Array#drop" do end it "raises an ArgumentError if the number of elements specified is negative" do - lambda { [1, 2].drop(-3) }.should raise_error(ArgumentError) + -> { [1, 2].drop(-3) }.should raise_error(ArgumentError) end it "returns an empty Array if all elements are dropped" do @@ -30,4 +31,26 @@ describe "Array#drop" do ary.shift ary.drop(1).should == [2] 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(2) + + [1, 2, 3].drop(obj).should == [3] + end + + it "raises a TypeError when the passed argument can't be coerced to Integer" do + -> { [1, 2].drop("cat") }.should raise_error(TypeError) + end + + it "raises a TypeError when the passed argument isn't an integer and #to_int returns non-Integer" do + obj = mock("to_int") + obj.should_receive(:to_int).and_return("cat") + + -> { [1, 2].drop(obj) }.should raise_error(TypeError) + end + + it 'returns a Array instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array) + end end diff --git a/spec/ruby/core/array/drop_while_spec.rb b/spec/ruby/core/array/drop_while_spec.rb index cfb6b1e267..bd46e8b882 100644 --- a/spec/ruby/core/array/drop_while_spec.rb +++ b/spec/ruby/core/array/drop_while_spec.rb @@ -1,6 +1,11 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#drop_while" do + @value_to_return = -> _ { true } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :drop_while + it "removes elements from the start of the array while the block evaluates to true" do [1, 2, 3, 4].drop_while { |n| n < 4 }.should == [4] end @@ -12,4 +17,8 @@ describe "Array#drop_while" do it "removes elements from the start of the array until the block returns false" do [1, 2, 3, false, 5].drop_while { |n| n }.should == [false, 5] end + + it 'returns a Array instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array) + end end diff --git a/spec/ruby/core/array/each_index_spec.rb b/spec/ruby/core/array/each_index_spec.rb index 51af5842c4..3a4bca9251 100644 --- a/spec/ruby/core/array/each_index_spec.rb +++ b/spec/ruby/core/array/each_index_spec.rb @@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized' # Modifying a collection while the contents are being iterated # gives undefined behavior. See -# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633 +# https://blade.ruby-lang.org/ruby-core/23633 describe "Array#each_index" do before :each do @@ -40,3 +40,19 @@ describe "Array#each_index" do it_behaves_like :enumeratorize, :each_index it_behaves_like :enumeratorized_with_origin_size, :each_index, [1,2,3] end + +describe "Array#each_index" do + it "tolerates increasing an array size during iteration" do + array = [:a, :b, :c] + ScratchPad.record [] + i = 0 + + array.each_index do |index| + ScratchPad << index + array << i if i < 100 + i += 1 + end + + ScratchPad.recorded.should == (0..102).to_a # element indices + end +end diff --git a/spec/ruby/core/array/each_spec.rb b/spec/ruby/core/array/each_spec.rb index 256647d61e..f4b5b758d0 100644 --- a/spec/ruby/core/array/each_spec.rb +++ b/spec/ruby/core/array/each_spec.rb @@ -1,11 +1,13 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/enumeratorize' +require_relative 'shared/iterable_and_tolerating_size_increasing' require_relative '../enumerable/shared/enumeratorized' -# Modifying a collection while the contents are being iterated -# gives undefined behavior. See -# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633 +# Mutating the array while it is being iterated is discouraged as it can result in confusing behavior. +# Yet a Ruby implementation must not crash in such a case, and following the simple CRuby behavior makes sense. +# CRuby simply reads the array storage and checks the size for every iteration; +# like `i = 0; while i < size; yield self[i]; i += 1; end` describe "Array#each" do it "yields each element to the block" do @@ -15,6 +17,34 @@ describe "Array#each" do a.should == [1, 2, 3] end + it "yields each element to the block even if the array is changed during iteration" do + a = [1, 2, 3, 4, 5] + iterated = [] + a.each { |x| iterated << x; a << x+5 if x.even? } + iterated.should == [1, 2, 3, 4, 5, 7, 9] + end + + it "yields only elements that are still in the array" do + a = [0, 1, 2, 3, 4] + iterated = [] + a.each { |x| iterated << x; a.pop if x.even? } + iterated.should == [0, 1, 2] + end + + it "yields elements based on an internal index" do + a = [0, 1, 2, 3, 4] + iterated = [] + a.each { |x| iterated << x; a.shift if x.even? } + iterated.should == [0, 2, 4] + end + + it "yields the same element multiple times if inserting while iterating" do + a = [1, 2] + iterated = [] + a.each { |x| iterated << x; a.unshift(0) if a.size == 2 } + iterated.should == [1, 1, 2] + end + it "yields each element to a block that takes multiple arguments" do a = [[1, 2], :a, [3, 4]] b = [] @@ -46,3 +76,7 @@ describe "Array#each" do it_behaves_like :enumeratorize, :each it_behaves_like :enumeratorized_with_origin_size, :each, [1,2,3] end + +describe "Array#each" do + it_behaves_like :array_iterable_and_tolerating_size_increasing, :each +end diff --git a/spec/ruby/core/array/element_set_spec.rb b/spec/ruby/core/array/element_set_spec.rb index 9992e4d32b..df5ca9582e 100644 --- a/spec/ruby/core/array/element_set_spec.rb +++ b/spec/ruby/core/array/element_set_spec.rb @@ -36,6 +36,7 @@ describe "Array#[]=" do a[3, 2] = ['a', 'b', 'c', 'd'] a.should == [2, 2, 3, "a", "b", "c", "d", 6] end + it "replaces the section defined by [start,length] with the given values" do a = [1, 2, 3, 4, 5, 6] a[3, 2] = 'a', 'b', 'c', 'd' @@ -94,8 +95,8 @@ describe "Array#[]=" do it "checks frozen before attempting to coerce arguments" do a = [1,2,3,4].freeze - lambda {a[:foo] = 1}.should raise_error(frozen_error_class) - lambda {a[:foo, :bar] = 1}.should raise_error(frozen_error_class) + -> {a[:foo] = 1}.should raise_error(FrozenError) + -> {a[:foo, :bar] = 1}.should raise_error(FrozenError) end it "sets elements in the range arguments when passed ranges" do @@ -169,6 +170,7 @@ describe "Array#[]=" do ary[1...1] = [] ary.should == [1, 2, 3] end + it "does nothing if the section defined by range has negative width and the rhs is an empty array" do ary = [1, 2, 3, 4, 5] ary[1...0] = [] @@ -195,25 +197,25 @@ describe "Array#[]=" do a[to .. from] = ["x"] a.should == [1, "a", "b", "x", "c", 4] - lambda { a["a" .. "b"] = [] }.should raise_error(TypeError) - lambda { a[from .. "b"] = [] }.should raise_error(TypeError) + -> { a["a" .. "b"] = [] }.should raise_error(TypeError) + -> { a[from .. "b"] = [] }.should raise_error(TypeError) end it "raises an IndexError when passed indexes out of bounds" do a = [1, 2, 3, 4] - lambda { a[-5] = "" }.should raise_error(IndexError) - lambda { a[-5, -1] = "" }.should raise_error(IndexError) - lambda { a[-5, 0] = "" }.should raise_error(IndexError) - lambda { a[-5, 1] = "" }.should raise_error(IndexError) - lambda { a[-5, 2] = "" }.should raise_error(IndexError) - lambda { a[-5, 10] = "" }.should raise_error(IndexError) - - lambda { a[-5..-5] = "" }.should raise_error(RangeError) - lambda { a[-5...-5] = "" }.should raise_error(RangeError) - lambda { a[-5..-4] = "" }.should raise_error(RangeError) - lambda { a[-5...-4] = "" }.should raise_error(RangeError) - lambda { a[-5..10] = "" }.should raise_error(RangeError) - lambda { a[-5...10] = "" }.should raise_error(RangeError) + -> { a[-5] = "" }.should raise_error(IndexError) + -> { a[-5, -1] = "" }.should raise_error(IndexError) + -> { a[-5, 0] = "" }.should raise_error(IndexError) + -> { a[-5, 1] = "" }.should raise_error(IndexError) + -> { a[-5, 2] = "" }.should raise_error(IndexError) + -> { a[-5, 10] = "" }.should raise_error(IndexError) + + -> { a[-5..-5] = "" }.should raise_error(RangeError) + -> { a[-5...-5] = "" }.should raise_error(RangeError) + -> { a[-5..-4] = "" }.should raise_error(RangeError) + -> { a[-5...-4] = "" }.should raise_error(RangeError) + -> { a[-5..10] = "" }.should raise_error(RangeError) + -> { a[-5...10] = "" }.should raise_error(RangeError) # ok a[0..-9] = [1] @@ -236,8 +238,8 @@ describe "Array#[]=" do ary.should == [5, 6, 7] end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array[0, 0] = [] }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array[0, 0] = [] }.should raise_error(FrozenError) end end @@ -284,6 +286,12 @@ describe "Array#[]= with [index, count]" do (a[2, 3] = [4, 5]).should == [4, 5] end + it "accepts a frozen String literal as RHS" do + a = ['a', 'b', 'c'] + a[0, 2] = 'd'.freeze + a.should == ['d', 'c'] + end + it "just sets the section defined by [start,length] to nil even if the rhs is nil" do a = ['a', 'b', 'c', 'd', 'e'] a[1, 3] = nil @@ -323,6 +331,10 @@ describe "Array#[]= with [index, count]" do b = [1, 2, 3, 4, 5] b[10, 0] = [1] a.should == [1, 2, 3, 4, 5, nil, nil, nil, nil, nil, 1] + + c = [1, 2, 3, 4, 5] + c[10, 0] = [] + c.should == [1, 2, 3, 4, 5, nil, nil, nil, nil, nil] end it "inserts other section in place defined by idx" do @@ -337,12 +349,12 @@ describe "Array#[]= with [index, count]" do it "raises an IndexError when passed start and negative length" do a = [1, 2, 3, 4] - lambda { a[-2, -1] = "" }.should raise_error(IndexError) - lambda { a[0, -1] = "" }.should raise_error(IndexError) - lambda { a[2, -1] = "" }.should raise_error(IndexError) - lambda { a[4, -1] = "" }.should raise_error(IndexError) - lambda { a[10, -1] = "" }.should raise_error(IndexError) - lambda { [1, 2, 3, 4, 5][2, -1] = [7, 8] }.should raise_error(IndexError) + -> { a[-2, -1] = "" }.should raise_error(IndexError) + -> { a[0, -1] = "" }.should raise_error(IndexError) + -> { a[2, -1] = "" }.should raise_error(IndexError) + -> { a[4, -1] = "" }.should raise_error(IndexError) + -> { a[10, -1] = "" }.should raise_error(IndexError) + -> { [1, 2, 3, 4, 5][2, -1] = [7, 8] }.should raise_error(IndexError) end end @@ -396,6 +408,14 @@ describe "Array#[]= with [m..n]" do a.should == [1, 2, 3, 8, 4, 5] end + it "inserts at the end if m > the array size" do + a = [1, 2, 3] + a[3..3] = [4] + a.should == [1, 2, 3, 4] + a[5..7] = [6] + a.should == [1, 2, 3, 4, nil, 6] + end + describe "Range subclasses" do before :each do @range_incl = ArraySpecs::MyRange.new(1, 2) @@ -425,6 +445,87 @@ describe "Array#[]= with [m..n]" do end end +describe "Array#[]= with [m..]" do + it "just sets the section defined by range to nil even if the rhs is nil" do + a = [1, 2, 3, 4, 5] + a[eval("(2..)")] = nil + a.should == [1, 2, nil] + end + + it "just sets the section defined by range to nil if m and n < 0 and the rhs is nil" do + a = [1, 2, 3, 4, 5] + a[eval("(-3..)")] = nil + a.should == [1, 2, nil] + end + + it "replaces the section defined by range" do + a = [6, 5, 4, 3, 2, 1] + a[eval("(3...)")] = 9 + a.should == [6, 5, 4, 9] + a[eval("(2..)")] = [7, 7, 7] + a.should == [6, 5, 7, 7, 7] + end + + it "replaces the section if m and n < 0" do + a = [1, 2, 3, 4, 5] + a[eval("(-3..)")] = [7, 8, 9] + a.should == [1, 2, 7, 8, 9] + end + + it "inserts at the end if m > the array size" do + a = [1, 2, 3] + a[eval("(3..)")] = [4] + a.should == [1, 2, 3, 4] + a[eval("(5..)")] = [6] + a.should == [1, 2, 3, 4, nil, 6] + end +end + +describe "Array#[]= with [..n] and [...n]" do + it "just sets the section defined by range to nil even if the rhs is nil" do + a = [1, 2, 3, 4, 5] + a[(..2)] = nil + a.should == [nil, 4, 5] + a[(...2)] = nil + a.should == [nil, 5] + end + + it "just sets the section defined by range to nil if n < 0 and the rhs is nil" do + a = [1, 2, 3, 4, 5] + a[(..-3)] = nil + a.should == [nil, 4, 5] + a[(...-1)] = [nil, 5] + end + + it "replaces the section defined by range" do + a = [6, 5, 4, 3, 2, 1] + a[(...3)] = 9 + a.should == [9, 3, 2, 1] + a[(..2)] = [7, 7, 7, 7, 7] + a.should == [7, 7, 7, 7, 7, 1] + end + + it "replaces the section if n < 0" do + a = [1, 2, 3, 4, 5] + a[(..-2)] = [7, 8, 9] + a.should == [7, 8, 9, 5] + end + + it "replaces everything if n > the array size" do + a = [1, 2, 3] + a[(...7)] = [4] + a.should == [4] + end + + it "inserts at the beginning if n < negative the array size" do + a = [1, 2, 3] + a[(..-7)] = [4] + a.should == [4, 1, 2, 3] + a[(...-10)] = [6] + a.should == [6, 4, 1, 2, 3] + end +end + describe "Array#[] after a shift" do it "works for insertion" do a = [1,2] diff --git a/spec/ruby/core/array/empty_spec.rb b/spec/ruby/core/array/empty_spec.rb index b5f3e8ed48..f70b1b6ebe 100644 --- a/spec/ruby/core/array/empty_spec.rb +++ b/spec/ruby/core/array/empty_spec.rb @@ -3,8 +3,8 @@ require_relative 'fixtures/classes' describe "Array#empty?" do it "returns true if the array has no elements" do - [].empty?.should == true - [1].empty?.should == false - [1, 2].empty?.should == false + [].should.empty? + [1].should_not.empty? + [1, 2].should_not.empty? end end diff --git a/spec/ruby/core/array/fetch_spec.rb b/spec/ruby/core/array/fetch_spec.rb index ccca463935..b81c0b48d7 100644 --- a/spec/ruby/core/array/fetch_spec.rb +++ b/spec/ruby/core/array/fetch_spec.rb @@ -12,9 +12,9 @@ describe "Array#fetch" do end it "raises an IndexError if there is no element at index" do - lambda { [1, 2, 3].fetch(3) }.should raise_error(IndexError) - lambda { [1, 2, 3].fetch(-4) }.should raise_error(IndexError) - lambda { [].fetch(0) }.should raise_error(IndexError) + -> { [1, 2, 3].fetch(3) }.should raise_error(IndexError) + -> { [1, 2, 3].fetch(-4) }.should raise_error(IndexError) + -> { [].fetch(0) }.should raise_error(IndexError) end it "returns default if there is no element at index if passed a default value" do @@ -37,7 +37,7 @@ describe "Array#fetch" do end it "gives precedence to the default block over the default argument" do - lambda { + -> { @result = [1, 2, 3].fetch(9, :foo) { |i| i * i } }.should complain(/block supersedes default value argument/) @result.should == 81 @@ -50,6 +50,6 @@ describe "Array#fetch" do end it "raises a TypeError when the passed argument can't be coerced to Integer" do - lambda { [].fetch("cat") }.should raise_error(TypeError) + -> { [].fetch("cat") }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/array/fetch_values_spec.rb b/spec/ruby/core/array/fetch_values_spec.rb new file mode 100644 index 0000000000..cf377b3b71 --- /dev/null +++ b/spec/ruby/core/array/fetch_values_spec.rb @@ -0,0 +1,55 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "Array#fetch_values" do + before :each do + @array = [:a, :b, :c] + end + + ruby_version_is "3.4" do + describe "with matched indexes" do + it "returns the values for indexes" do + @array.fetch_values(0).should == [:a] + @array.fetch_values(0, 2).should == [:a, :c] + @array.fetch_values(-1).should == [:c] + end + + it "returns the values for indexes ordered in the order of the requested indexes" do + @array.fetch_values(2, 0).should == [:c, :a] + end + end + + describe "with unmatched indexes" do + it "raises a index error if no block is provided" do + -> { @array.fetch_values(0, 1, 44) }.should raise_error(IndexError, "index 44 outside of array bounds: -3...3") + end + + it "returns the default value from block" do + @array.fetch_values(44) { |index| "`#{index}' is not found" }.should == ["`44' is not found"] + @array.fetch_values(0, 44) { |index| "`#{index}' is not found" }.should == [:a, "`44' is not found"] + end + end + + describe "without keys" do + it "returns an empty Array" do + @array.fetch_values.should == [] + end + 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(2) + @array.fetch_values(obj).should == [:c] + end + + it "does not support a Range object as argument" do + -> { + @array.fetch_values(1..2) + }.should raise_error(TypeError, "no implicit conversion of Range into Integer") + end + + it "raises a TypeError when the passed argument can't be coerced to Integer" do + -> { [].fetch_values("cat") }.should raise_error(TypeError, "no implicit conversion of String into Integer") + end + end +end diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb index f953613c26..2c3b5d9e84 100644 --- a/spec/ruby/core/array/fill_spec.rb +++ b/spec/ruby/core/array/fill_spec.rb @@ -3,7 +3,7 @@ require_relative 'fixtures/classes' describe "Array#fill" do before :all do - @never_passed = lambda do |i| + @never_passed = -> i do raise ExpectationNotMetError, "the control path should not pass here" end end @@ -21,7 +21,7 @@ describe "Array#fill" do it "does not replicate the filler" do ary = [1, 2, 3, 4] - str = "x" + str = +"x" ary.fill(str).should == [str, str, str, str] str << "y" ary.should == [str, str, str, str] @@ -43,34 +43,72 @@ describe "Array#fill" do [nil, nil, nil, nil].fill { |i| i * 2 }.should == [0, 2, 4, 6] end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.fill('x') }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.fill('x') }.should raise_error(FrozenError) end - it "raises a #{frozen_error_class} on an empty frozen array" do - lambda { ArraySpecs.empty_frozen_array.fill('x') }.should raise_error(frozen_error_class) + it "raises a FrozenError on an empty frozen array" do + -> { ArraySpecs.empty_frozen_array.fill('x') }.should raise_error(FrozenError) end it "raises an ArgumentError if 4 or more arguments are passed when no block given" do - lambda { [].fill('a') }.should_not raise_error(ArgumentError) - - lambda { [].fill('a', 1) }.should_not raise_error(ArgumentError) - - lambda { [].fill('a', 1, 2) }.should_not raise_error(ArgumentError) - lambda { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError) + [].fill('a').should == [] + [].fill('a', 1).should == [] + [].fill('a', 1, 2).should == [nil, 'a', 'a'] + -> { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError) end it "raises an ArgumentError if no argument passed and no block given" do - lambda { [].fill }.should raise_error(ArgumentError) + -> { [].fill }.should raise_error(ArgumentError) end it "raises an ArgumentError if 3 or more arguments are passed when a block given" do - lambda { [].fill() {|i|} }.should_not raise_error(ArgumentError) + [].fill() {|i|}.should == [] + [].fill(1) {|i|}.should == [] + [].fill(1, 2) {|i|}.should == [nil, nil, nil] + -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError) + end + + it "does not truncate the array is the block raises an exception" do + a = [1, 2, 3] + begin + a.fill { raise StandardError, 'Oops' } + rescue + end - lambda { [].fill(1) {|i|} }.should_not raise_error(ArgumentError) + a.should == [1, 2, 3] + end + + it "only changes elements before error is raised, keeping the element which raised an error." do + a = [1, 2, 3, 4] + begin + a.fill do |i| + case i + when 0 then -1 + when 1 then -2 + when 2 then raise StandardError, 'Oops' + else 0 + end + end + rescue StandardError + end - lambda { [].fill(1, 2) {|i|} }.should_not raise_error(ArgumentError) - lambda { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError) + a.should == [-1, -2, 3, 4] + end + + it "tolerates increasing an array size during iteration" do + array = [:a, :b, :c] + ScratchPad.record [] + i = 0 + + array.fill do |index| + ScratchPad << index + array << i if i < 100 + i++ + index + end + + ScratchPad.recorded.should == [0, 1, 2] end end @@ -169,25 +207,25 @@ describe "Array#fill with (filler, index, length)" do [1, 2, 3, 4, 5].fill(-2, -2, &@never_passed).should == [1, 2, 3, 4, 5] end - # See: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17481 + # See: https://blade.ruby-lang.org/ruby-core/17481 it "does not raise an exception if the given length is negative and its absolute value does not exceed the index" do - lambda { [1, 2, 3, 4].fill('a', 3, -1)}.should_not raise_error(ArgumentError) - lambda { [1, 2, 3, 4].fill('a', 3, -2)}.should_not raise_error(ArgumentError) - lambda { [1, 2, 3, 4].fill('a', 3, -3)}.should_not raise_error(ArgumentError) + [1, 2, 3, 4].fill('a', 3, -1).should == [1, 2, 3, 4] + [1, 2, 3, 4].fill('a', 3, -2).should == [1, 2, 3, 4] + [1, 2, 3, 4].fill('a', 3, -3).should == [1, 2, 3, 4] - lambda { [1, 2, 3, 4].fill(3, -1, &@never_passed)}.should_not raise_error(ArgumentError) - lambda { [1, 2, 3, 4].fill(3, -2, &@never_passed)}.should_not raise_error(ArgumentError) - lambda { [1, 2, 3, 4].fill(3, -3, &@never_passed)}.should_not raise_error(ArgumentError) + [1, 2, 3, 4].fill(3, -1, &@never_passed).should == [1, 2, 3, 4] + [1, 2, 3, 4].fill(3, -2, &@never_passed).should == [1, 2, 3, 4] + [1, 2, 3, 4].fill(3, -3, &@never_passed).should == [1, 2, 3, 4] end it "does not raise an exception even if the given length is negative and its absolute value exceeds the index" do - lambda { [1, 2, 3, 4].fill('a', 3, -4)}.should_not raise_error(ArgumentError) - lambda { [1, 2, 3, 4].fill('a', 3, -5)}.should_not raise_error(ArgumentError) - lambda { [1, 2, 3, 4].fill('a', 3, -10000)}.should_not raise_error(ArgumentError) + [1, 2, 3, 4].fill('a', 3, -4).should == [1, 2, 3, 4] + [1, 2, 3, 4].fill('a', 3, -5).should == [1, 2, 3, 4] + [1, 2, 3, 4].fill('a', 3, -10000).should == [1, 2, 3, 4] - lambda { [1, 2, 3, 4].fill(3, -4, &@never_passed)}.should_not raise_error(ArgumentError) - lambda { [1, 2, 3, 4].fill(3, -5, &@never_passed)}.should_not raise_error(ArgumentError) - lambda { [1, 2, 3, 4].fill(3, -10000, &@never_passed)}.should_not raise_error(ArgumentError) + [1, 2, 3, 4].fill(3, -4, &@never_passed).should == [1, 2, 3, 4] + [1, 2, 3, 4].fill(3, -5, &@never_passed).should == [1, 2, 3, 4] + [1, 2, 3, 4].fill(3, -10000, &@never_passed).should == [1, 2, 3, 4] end it "tries to convert the second and third arguments to Integers using #to_int" do @@ -199,17 +237,24 @@ describe "Array#fill with (filler, index, length)" do end it "raises a TypeError if the index is not numeric" do - lambda { [].fill 'a', true }.should raise_error(TypeError) + -> { [].fill 'a', true }.should raise_error(TypeError) obj = mock('nonnumeric') - lambda { [].fill('a', obj) }.should raise_error(TypeError) + -> { [].fill('a', obj) }.should raise_error(TypeError) + end + + it "raises a TypeError when the length is not numeric" do + -> { [1, 2, 3].fill("x", 1, "foo") }.should raise_error(TypeError, /no implicit conversion of String into Integer/) + -> { [1, 2, 3].fill("x", 1, :"foo") }.should raise_error(TypeError, /no implicit conversion of Symbol into Integer/) + -> { [1, 2, 3].fill("x", 1, Object.new) }.should raise_error(TypeError, /no implicit conversion of Object into Integer/) end not_supported_on :opal do it "raises an ArgumentError or RangeError for too-large sizes" do + error_types = [RangeError, ArgumentError] arr = [1, 2, 3] - lambda { arr.fill(10, 1, fixnum_max) }.should raise_error(ArgumentError) - lambda { arr.fill(10, 1, bignum_value) }.should raise_error(RangeError) + -> { arr.fill(10, 1, fixnum_max) }.should raise_error { |err| error_types.should include(err.class) } + -> { arr.fill(10, 1, bignum_value) }.should raise_error(RangeError) end end end @@ -239,7 +284,7 @@ describe "Array#fill with (filler, range)" do end it "raises a TypeError with range and length argument" do - lambda { [].fill('x', 0 .. 2, 5) }.should raise_error(TypeError) + -> { [].fill('x', 0 .. 2, 5) }.should raise_error(TypeError) end it "replaces elements between the (-m)th to the last and the (n+1)th from the first if given an range m..n where m < 0 and n >= 0" do @@ -291,13 +336,13 @@ describe "Array#fill with (filler, range)" do end it "raises an exception if some of the given range lies before the first of the array" do - lambda { [1, 2, 3].fill('x', -5..-3) }.should raise_error(RangeError) - lambda { [1, 2, 3].fill('x', -5...-3) }.should raise_error(RangeError) - lambda { [1, 2, 3].fill('x', -5..-4) }.should raise_error(RangeError) + -> { [1, 2, 3].fill('x', -5..-3) }.should raise_error(RangeError) + -> { [1, 2, 3].fill('x', -5...-3) }.should raise_error(RangeError) + -> { [1, 2, 3].fill('x', -5..-4) }.should raise_error(RangeError) - lambda { [1, 2, 3].fill(-5..-3, &@never_passed) }.should raise_error(RangeError) - lambda { [1, 2, 3].fill(-5...-3, &@never_passed) }.should raise_error(RangeError) - lambda { [1, 2, 3].fill(-5..-4, &@never_passed) }.should raise_error(RangeError) + -> { [1, 2, 3].fill(-5..-3, &@never_passed) }.should raise_error(RangeError) + -> { [1, 2, 3].fill(-5...-3, &@never_passed) }.should raise_error(RangeError) + -> { [1, 2, 3].fill(-5..-4, &@never_passed) }.should raise_error(RangeError) end it "tries to convert the start and end of the passed range to Integers using #to_int" do @@ -312,6 +357,18 @@ describe "Array#fill with (filler, range)" do it "raises a TypeError if the start or end of the passed range is not numeric" do obj = mock('nonnumeric') def obj.<=>(rhs); rhs == self ? 0 : nil end - lambda { [].fill('a', obj..obj) }.should raise_error(TypeError) + -> { [].fill('a', obj..obj) }.should raise_error(TypeError) + end + + it "works with endless ranges" do + [1, 2, 3, 4].fill('x', eval("(1..)")).should == [1, 'x', 'x', 'x'] + [1, 2, 3, 4].fill('x', eval("(3...)")).should == [1, 2, 3, 'x'] + [1, 2, 3, 4].fill(eval("(1..)")) { |x| x + 2 }.should == [1, 3, 4, 5] + [1, 2, 3, 4].fill(eval("(3...)")) { |x| x + 2 }.should == [1, 2, 3, 5] + end + + it "works with beginless ranges" do + [1, 2, 3, 4].fill('x', (..2)).should == ["x", "x", "x", 4] + [1, 2, 3, 4].fill((...2)) { |x| x + 2 }.should == [2, 3, 3, 4] end end diff --git a/spec/ruby/core/array/filter_spec.rb b/spec/ruby/core/array/filter_spec.rb index ee4f71ca28..156ad14f9c 100644 --- a/spec/ruby/core/array/filter_spec.rb +++ b/spec/ruby/core/array/filter_spec.rb @@ -1,16 +1,14 @@ require_relative '../../spec_helper' require_relative 'shared/select' -ruby_version_is "2.6" do - describe "Array#filter" do - it_behaves_like :array_select, :filter - end - - describe "Array#filter!" do - it "returns nil if no changes were made in the array" do - [1, 2, 3].filter! { true }.should be_nil - end +describe "Array#filter" do + it_behaves_like :array_select, :filter +end - it_behaves_like :keep_if, :filter! +describe "Array#filter!" do + it "returns nil if no changes were made in the array" do + [1, 2, 3].filter! { true }.should be_nil end + + it_behaves_like :keep_if, :filter! end diff --git a/spec/ruby/core/array/first_spec.rb b/spec/ruby/core/array/first_spec.rb index 5a0a25aeef..66eeba6565 100644 --- a/spec/ruby/core/array/first_spec.rb +++ b/spec/ruby/core/array/first_spec.rb @@ -30,11 +30,11 @@ describe "Array#first" do end it "raises an ArgumentError when count is negative" do - lambda { [1, 2].first(-1) }.should raise_error(ArgumentError) + -> { [1, 2].first(-1) }.should raise_error(ArgumentError) end it "raises a RangeError when count is a Bignum" do - lambda { [].first(bignum_value) }.should raise_error(RangeError) + -> { [].first(bignum_value) }.should raise_error(RangeError) end it "returns the entire array when count > length" do @@ -66,11 +66,11 @@ describe "Array#first" do end it "raises a TypeError if the passed argument is not numeric" do - lambda { [1,2].first(nil) }.should raise_error(TypeError) - lambda { [1,2].first("a") }.should raise_error(TypeError) + -> { [1,2].first(nil) }.should raise_error(TypeError) + -> { [1,2].first("a") }.should raise_error(TypeError) obj = mock("nonnumeric") - lambda { [1,2].first(obj) }.should raise_error(TypeError) + -> { [1,2].first(obj) }.should raise_error(TypeError) end it "does not return subclass instance when passed count on Array subclasses" do diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb index 42071ed0cd..05283c0f74 100644 --- a/spec/ruby/core/array/fixtures/classes.rb +++ b/spec/ruby/core/array/fixtures/classes.rb @@ -40,6 +40,62 @@ module ArraySpecs a end + # Chi squared critical values for tests with n degrees of freedom at 99% confidence. + # Values obtained from NIST Engineering Statistic Handbook at + # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm + + CHI_SQUARED_CRITICAL_VALUES = [ + 0, + 6.635, 9.210, 11.345, 13.277, 15.086, 16.812, 18.475, 20.090, 21.666, 23.209, + 24.725, 26.217, 27.688, 29.141, 30.578, 32.000, 33.409, 34.805, 36.191, 37.566, + 38.932, 40.289, 41.638, 42.980, 44.314, 45.642, 46.963, 48.278, 49.588, 50.892, + 52.191, 53.486, 54.776, 56.061, 57.342, 58.619, 59.893, 61.162, 62.428, 63.691, + 64.950, 66.206, 67.459, 68.710, 69.957, 71.201, 72.443, 73.683, 74.919, 76.154, + 77.386, 78.616, 79.843, 81.069, 82.292, 83.513, 84.733, 85.950, 87.166, 88.379, + 89.591, 90.802, 92.010, 93.217, 94.422, 95.626, 96.828, 98.028, 99.228, 100.425, + 101.621, 102.816, 104.010, 105.202, 106.393, 107.583, 108.771, 109.958, 111.144, 112.329, + 113.512, 114.695, 115.876, 117.057, 118.236, 119.414, 120.591, 121.767, 122.942, 124.116, + 125.289, 126.462, 127.633, 128.803, 129.973, 131.141, 132.309, 133.476, 134.642, 135.807, + ] + + def self.measure_sample_fairness(size, samples, iters) + ary = Array.new(size) { |x| x } + expected = iters.fdiv size + (samples).times do |i| + chi_results = [] + 3.times do + counts = Array.new(size, 0) + iters.times do + x = ary.sample(samples)[i] + counts[x] += 1 + end + chi_squared = counts.sum {|count| (count - expected) ** 2} / expected + chi_results << chi_squared + break if chi_squared <= CHI_SQUARED_CRITICAL_VALUES[size] + end + + chi_results.min.should <= CHI_SQUARED_CRITICAL_VALUES[size] + end + end + + def self.measure_sample_fairness_large_sample_size(size, samples, iters) + ary = Array.new(size) { |x| x } + counts = Array.new(size, 0) + expected = (iters * samples).fdiv size + iters.times do + ary.sample(samples).each do |sample| + counts[sample] += 1 + end + end + chi_squared = counts.sum {|count| (count - expected) ** 2} / expected + + # Chi squared critical values for tests with 4 degrees of freedom + # Values obtained from NIST Engineering Statistic Handbook at + # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm + + chi_squared.should <= CHI_SQUARED_CRITICAL_VALUES[size] + end + class MyArray < Array # The #initialize method has a different signature than Array to help # catch places in the specs that do not assert the #initialize is not @@ -98,6 +154,16 @@ module ArraySpecs end end + class ArrayMethodMissing + def initialize(*values, &block) + @values = values; + end + + def method_missing(name, *args) + @values + end + end + class SortSame def <=>(other); 0; end def ==(other); true; end @@ -126,7 +192,7 @@ module ArraySpecs attr_accessor :order end - class ComparableWithFixnum + class ComparableWithInteger include Comparable def initialize(num) @num = num @@ -144,373 +210,377 @@ module ArraySpecs end def self.universal_pack_object - obj = mock("string float int") + obj = mock("string float int".freeze) obj.stub!(:to_int).and_return(1) obj.stub!(:to_str).and_return("1") obj.stub!(:to_f).and_return(1.0) obj end - LargeArray = ["test_create_table_with_force_true_does_not_drop_nonexisting_table", - "test_add_table", - "assert_difference", - "assert_operator", - "instance_variables", - "class", - "instance_variable_get", - "__class__", - "expects", - "assert_no_difference", - "name", - "assert_blank", - "assert_not_same", - "is_a?", - "test_add_table_with_decimals", - "test_create_table_with_timestamps_should_create_datetime_columns", - "assert_present", - "assert_no_match", - "__instance_of__", - "assert_deprecated", - "assert", - "assert_throws", - "kind_of?", - "try", - "__instance_variable_get__", - "object_id", - "timeout", - "instance_variable_set", - "assert_nothing_thrown", - "__instance_variable_set__", - "copy_object", - "test_create_table_with_timestamps_should_create_datetime_columns_with_options", - "assert_not_deprecated", - "assert_in_delta", - "id", - "copy_metaclass", - "test_create_table_without_a_block", - "dup", - "assert_not_nil", - "send", - "__instance_variables__", - "to_sql", - "mock", - "assert_send", - "instance_variable_defined?", - "clone", - "require", - "test_migrator", - "__instance_variable_defined_eh__", - "frozen?", - "test_add_column_not_null_with_default", - "freeze", - "test_migrator_one_up", - "test_migrator_one_down", - "singleton_methods", - "method_exists?", - "create_fixtures", - "test_migrator_one_up_one_down", - "test_native_decimal_insert_manual_vs_automatic", - "instance_exec", - "__is_a__", - "test_migrator_double_up", - "stub", - "private_methods", - "stubs", - "test_migrator_double_down", - "fixture_path", - "private_singleton_methods", - "stub_everything", - "test_migrator_one_up_with_exception_and_rollback", - "sequence", - "protected_methods", - "enum_for", - "test_finds_migrations", - "run_before_mocha", - "states", - "protected_singleton_methods", - "to_json", - "instance_values", - "==", - "mocha_setup", - "public_methods", - "test_finds_pending_migrations", - "mocha_verify", - "assert_kind_of", - "===", - "=~", - "test_relative_migrations", - "mocha_teardown", - "gem", - "mocha", - "test_only_loads_pending_migrations", - "test_add_column_with_precision_and_scale", - "require_or_load", - "eql?", - "require_dependency", - "test_native_types", - "test_target_version_zero_should_run_only_once", - "extend", - "to_matcher", - "unloadable", - "require_association", - "hash", - "__id__", - "load_dependency", - "equals", - "test_migrator_db_has_no_schema_migrations_table", - "test_migrator_verbosity", - "kind_of", - "to_yaml", - "to_bool", - "test_migrator_verbosity_off", - "taint", - "test_migrator_going_down_due_to_version_target", - "tainted?", - "mocha_inspect", - "test_migrator_rollback", - "vim", - "untaint", - "taguri=", - "test_migrator_forward", - "test_schema_migrations_table_name", - "test_proper_table_name", - "all_of", - "test_add_drop_table_with_prefix_and_suffix", - "_setup_callbacks", - "setup", - "Not", - "test_create_table_with_binary_column", - "assert_not_equal", - "enable_warnings", - "acts_like?", - "Rational", - "_removed_setup_callbacks", - "Table", - "bind", - "any_of", - "__method__", - "test_migrator_with_duplicates", - "_teardown_callbacks", - "method", - "test_migrator_with_duplicate_names", - "_removed_teardown_callbacks", - "any_parameters", - "test_migrator_with_missing_version_numbers", - "test_add_remove_single_field_using_string_arguments", - "test_create_table_with_custom_sequence_name", - "test_add_remove_single_field_using_symbol_arguments", - "_one_time_conditions_valid_14?", - "_one_time_conditions_valid_16?", - "run_callbacks", - "anything", - "silence_warnings", - "instance_variable_names", - "_fixture_path", - "copy_instance_variables_from", - "fixture_path?", - "has_entry", - "__marshal__", - "_fixture_table_names", - "__kind_of__", - "fixture_table_names?", - "test_add_rename", - "assert_equal", - "_fixture_class_names", - "fixture_class_names?", - "has_entries", - "_use_transactional_fixtures", - "people", - "test_rename_column_using_symbol_arguments", - "use_transactional_fixtures?", - "instance_eval", - "blank?", - "with_warnings", - "__nil__", - "load", - "metaclass", - "_use_instantiated_fixtures", - "has_key", - "class_eval", - "present?", - "test_rename_column", - "teardown", - "use_instantiated_fixtures?", - "method_name", - "silence_stderr", - "presence", - "test_rename_column_preserves_default_value_not_null", - "silence_stream", - "_pre_loaded_fixtures", - "__metaclass__", - "__fixnum__", - "pre_loaded_fixtures?", - "has_value", - "suppress", - "to_yaml_properties", - "test_rename_nonexistent_column", - "test_add_index", - "includes", - "find_correlate_in", - "equality_predicate_sql", - "assert_nothing_raised", - "let", - "not_predicate_sql", - "test_rename_column_with_sql_reserved_word", - "singleton_class", - "test_rename_column_with_an_index", - "display", - "taguri", - "to_yaml_style", - "test_remove_column_with_index", - "size", - "current_adapter?", - "test_remove_column_with_multi_column_index", - "respond_to?", - "test_change_type_of_not_null_column", - "is_a", - "to_a", - "test_rename_table_for_sqlite_should_work_with_reserved_words", - "require_library_or_gem", - "setup_fixtures", - "equal?", - "teardown_fixtures", - "nil?", - "fixture_table_names", - "fixture_class_names", - "test_create_table_without_id", - "use_transactional_fixtures", - "test_add_column_with_primary_key_attribute", - "repair_validations", - "use_instantiated_fixtures", - "instance_of?", - "test_create_table_adds_id", - "test_rename_table", - "pre_loaded_fixtures", - "to_enum", - "test_create_table_with_not_null_column", - "instance_of", - "test_change_column_nullability", - "optionally", - "test_rename_table_with_an_index", - "run", - "test_change_column", - "default_test", - "assert_raise", - "test_create_table_with_defaults", - "assert_nil", - "flunk", - "regexp_matches", - "duplicable?", - "reset_mocha", - "stubba_method", - "filter_backtrace", - "test_create_table_with_limits", - "responds_with", - "stubba_object", - "test_change_column_with_nil_default", - "assert_block", - "__show__", - "assert_date_from_db", - "__respond_to_eh__", - "run_in_transaction?", - "inspect", - "assert_sql", - "test_change_column_with_new_default", - "yaml_equivalent", - "build_message", - "to_s", - "test_change_column_default", - "assert_queries", - "pending", - "as_json", - "assert_no_queries", - "test_change_column_quotes_column_names", - "assert_match", - "test_keeping_default_and_notnull_constraint_on_change", - "methods", - "connection_allow_concurrency_setup", - "connection_allow_concurrency_teardown", - "test_create_table_with_primary_key_prefix_as_table_name_with_underscore", - "__send__", - "make_connection", - "assert_raises", - "tap", - "with_kcode", - "assert_instance_of", - "test_create_table_with_primary_key_prefix_as_table_name", - "assert_respond_to", - "test_change_column_default_to_null", - "assert_same", - "__extend__"] - - LargeTestArraySorted = ["test_add_column_not_null_with_default", - "test_add_column_with_precision_and_scale", - "test_add_column_with_primary_key_attribute", - "test_add_drop_table_with_prefix_and_suffix", - "test_add_index", - "test_add_remove_single_field_using_string_arguments", - "test_add_remove_single_field_using_symbol_arguments", - "test_add_rename", - "test_add_table", - "test_add_table_with_decimals", - "test_change_column", - "test_change_column_default", - "test_change_column_default_to_null", - "test_change_column_nullability", - "test_change_column_quotes_column_names", - "test_change_column_with_new_default", - "test_change_column_with_nil_default", - "test_change_type_of_not_null_column", - "test_create_table_adds_id", - "test_create_table_with_binary_column", - "test_create_table_with_custom_sequence_name", - "test_create_table_with_defaults", - "test_create_table_with_force_true_does_not_drop_nonexisting_table", - "test_create_table_with_limits", - "test_create_table_with_not_null_column", - "test_create_table_with_primary_key_prefix_as_table_name", - "test_create_table_with_primary_key_prefix_as_table_name_with_underscore", - "test_create_table_with_timestamps_should_create_datetime_columns", - "test_create_table_with_timestamps_should_create_datetime_columns_with_options", - "test_create_table_without_a_block", - "test_create_table_without_id", - "test_finds_migrations", - "test_finds_pending_migrations", - "test_keeping_default_and_notnull_constraint_on_change", - "test_migrator", - "test_migrator_db_has_no_schema_migrations_table", - "test_migrator_double_down", - "test_migrator_double_up", - "test_migrator_forward", - "test_migrator_going_down_due_to_version_target", - "test_migrator_one_down", - "test_migrator_one_up", - "test_migrator_one_up_one_down", - "test_migrator_one_up_with_exception_and_rollback", - "test_migrator_rollback", - "test_migrator_verbosity", - "test_migrator_verbosity_off", - "test_migrator_with_duplicate_names", - "test_migrator_with_duplicates", - "test_migrator_with_missing_version_numbers", - "test_native_decimal_insert_manual_vs_automatic", - "test_native_types", - "test_only_loads_pending_migrations", - "test_proper_table_name", - "test_relative_migrations", - "test_remove_column_with_index", - "test_remove_column_with_multi_column_index", - "test_rename_column", - "test_rename_column_preserves_default_value_not_null", - "test_rename_column_using_symbol_arguments", - "test_rename_column_with_an_index", - "test_rename_column_with_sql_reserved_word", - "test_rename_nonexistent_column", - "test_rename_table", - "test_rename_table_for_sqlite_should_work_with_reserved_words", - "test_rename_table_with_an_index", - "test_schema_migrations_table_name", - "test_target_version_zero_should_run_only_once"] + LargeArray = [ + "test_create_table_with_force_true_does_not_drop_nonexisting_table", + "test_add_table", + "assert_difference", + "assert_operator", + "instance_variables", + "class", + "instance_variable_get", + "__class__", + "expects", + "assert_no_difference", + "name", + "assert_blank", + "assert_not_same", + "is_a?", + "test_add_table_with_decimals", + "test_create_table_with_timestamps_should_create_datetime_columns", + "assert_present", + "assert_no_match", + "__instance_of__", + "assert_deprecated", + "assert", + "assert_throws", + "kind_of?", + "try", + "__instance_variable_get__", + "object_id", + "timeout", + "instance_variable_set", + "assert_nothing_thrown", + "__instance_variable_set__", + "copy_object", + "test_create_table_with_timestamps_should_create_datetime_columns_with_options", + "assert_not_deprecated", + "assert_in_delta", + "id", + "copy_metaclass", + "test_create_table_without_a_block", + "dup", + "assert_not_nil", + "send", + "__instance_variables__", + "to_sql", + "mock", + "assert_send", + "instance_variable_defined?", + "clone", + "require", + "test_migrator", + "__instance_variable_defined_eh__", + "frozen?", + "test_add_column_not_null_with_default", + "freeze", + "test_migrator_one_up", + "test_migrator_one_down", + "singleton_methods", + "method_exists?", + "create_fixtures", + "test_migrator_one_up_one_down", + "test_native_decimal_insert_manual_vs_automatic", + "instance_exec", + "__is_a__", + "test_migrator_double_up", + "stub", + "private_methods", + "stubs", + "test_migrator_double_down", + "fixture_path", + "private_singleton_methods", + "stub_everything", + "test_migrator_one_up_with_exception_and_rollback", + "sequence", + "protected_methods", + "enum_for", + "test_finds_migrations", + "run_before_mocha", + "states", + "protected_singleton_methods", + "to_json", + "instance_values", + "==", + "mocha_setup", + "public_methods", + "test_finds_pending_migrations", + "mocha_verify", + "assert_kind_of", + "===", + "=~", + "test_relative_migrations", + "mocha_teardown", + "gem", + "mocha", + "test_only_loads_pending_migrations", + "test_add_column_with_precision_and_scale", + "require_or_load", + "eql?", + "require_dependency", + "test_native_types", + "test_target_version_zero_should_run_only_once", + "extend", + "to_matcher", + "unloadable", + "require_association", + "hash", + "__id__", + "load_dependency", + "equals", + "test_migrator_db_has_no_schema_migrations_table", + "test_migrator_verbosity", + "kind_of", + "to_yaml", + "to_bool", + "test_migrator_verbosity_off", + "taint", + "test_migrator_going_down_due_to_version_target", + "tainted?", + "mocha_inspect", + "test_migrator_rollback", + "vim", + "untaint", + "taguri=", + "test_migrator_forward", + "test_schema_migrations_table_name", + "test_proper_table_name", + "all_of", + "test_add_drop_table_with_prefix_and_suffix", + "_setup_callbacks", + "setup", + "Not", + "test_create_table_with_binary_column", + "assert_not_equal", + "enable_warnings", + "acts_like?", + "Rational", + "_removed_setup_callbacks", + "Table", + "bind", + "any_of", + "__method__", + "test_migrator_with_duplicates", + "_teardown_callbacks", + "method", + "test_migrator_with_duplicate_names", + "_removed_teardown_callbacks", + "any_parameters", + "test_migrator_with_missing_version_numbers", + "test_add_remove_single_field_using_string_arguments", + "test_create_table_with_custom_sequence_name", + "test_add_remove_single_field_using_symbol_arguments", + "_one_time_conditions_valid_14?", + "_one_time_conditions_valid_16?", + "run_callbacks", + "anything", + "silence_warnings", + "instance_variable_names", + "_fixture_path", + "copy_instance_variables_from", + "fixture_path?", + "has_entry", + "__marshal__", + "_fixture_table_names", + "__kind_of__", + "fixture_table_names?", + "test_add_rename", + "assert_equal", + "_fixture_class_names", + "fixture_class_names?", + "has_entries", + "_use_transactional_fixtures", + "people", + "test_rename_column_using_symbol_arguments", + "use_transactional_fixtures?", + "instance_eval", + "blank?", + "with_warnings", + "__nil__", + "load", + "metaclass", + "_use_instantiated_fixtures", + "has_key", + "class_eval", + "present?", + "test_rename_column", + "teardown", + "use_instantiated_fixtures?", + "method_name", + "silence_stderr", + "presence", + "test_rename_column_preserves_default_value_not_null", + "silence_stream", + "_pre_loaded_fixtures", + "__metaclass__", + "__fixnum__", + "pre_loaded_fixtures?", + "has_value", + "suppress", + "to_yaml_properties", + "test_rename_nonexistent_column", + "test_add_index", + "includes", + "find_correlate_in", + "equality_predicate_sql", + "assert_nothing_raised", + "let", + "not_predicate_sql", + "test_rename_column_with_sql_reserved_word", + "singleton_class", + "test_rename_column_with_an_index", + "display", + "taguri", + "to_yaml_style", + "test_remove_column_with_index", + "size", + "current_adapter?", + "test_remove_column_with_multi_column_index", + "respond_to?", + "test_change_type_of_not_null_column", + "is_a", + "to_a", + "test_rename_table_for_sqlite_should_work_with_reserved_words", + "require_library_or_gem", + "setup_fixtures", + "equal?", + "teardown_fixtures", + "nil?", + "fixture_table_names", + "fixture_class_names", + "test_create_table_without_id", + "use_transactional_fixtures", + "test_add_column_with_primary_key_attribute", + "repair_validations", + "use_instantiated_fixtures", + "instance_of?", + "test_create_table_adds_id", + "test_rename_table", + "pre_loaded_fixtures", + "to_enum", + "test_create_table_with_not_null_column", + "instance_of", + "test_change_column_nullability", + "optionally", + "test_rename_table_with_an_index", + "run", + "test_change_column", + "default_test", + "assert_raise", + "test_create_table_with_defaults", + "assert_nil", + "flunk", + "regexp_matches", + "duplicable?", + "reset_mocha", + "stubba_method", + "filter_backtrace", + "test_create_table_with_limits", + "responds_with", + "stubba_object", + "test_change_column_with_nil_default", + "assert_block", + "__show__", + "assert_date_from_db", + "__respond_to_eh__", + "run_in_transaction?", + "inspect", + "assert_sql", + "test_change_column_with_new_default", + "yaml_equivalent", + "build_message", + "to_s", + "test_change_column_default", + "assert_queries", + "pending", + "as_json", + "assert_no_queries", + "test_change_column_quotes_column_names", + "assert_match", + "test_keeping_default_and_notnull_constraint_on_change", + "methods", + "connection_allow_concurrency_setup", + "connection_allow_concurrency_teardown", + "test_create_table_with_primary_key_prefix_as_table_name_with_underscore", + "__send__", + "make_connection", + "assert_raises", + "tap", + "with_kcode", + "assert_instance_of", + "test_create_table_with_primary_key_prefix_as_table_name", + "assert_respond_to", + "test_change_column_default_to_null", + "assert_same", + "__extend__", + ] + + LargeTestArraySorted = [ + "test_add_column_not_null_with_default", + "test_add_column_with_precision_and_scale", + "test_add_column_with_primary_key_attribute", + "test_add_drop_table_with_prefix_and_suffix", + "test_add_index", + "test_add_remove_single_field_using_string_arguments", + "test_add_remove_single_field_using_symbol_arguments", + "test_add_rename", + "test_add_table", + "test_add_table_with_decimals", + "test_change_column", + "test_change_column_default", + "test_change_column_default_to_null", + "test_change_column_nullability", + "test_change_column_quotes_column_names", + "test_change_column_with_new_default", + "test_change_column_with_nil_default", + "test_change_type_of_not_null_column", + "test_create_table_adds_id", + "test_create_table_with_binary_column", + "test_create_table_with_custom_sequence_name", + "test_create_table_with_defaults", + "test_create_table_with_force_true_does_not_drop_nonexisting_table", + "test_create_table_with_limits", + "test_create_table_with_not_null_column", + "test_create_table_with_primary_key_prefix_as_table_name", + "test_create_table_with_primary_key_prefix_as_table_name_with_underscore", + "test_create_table_with_timestamps_should_create_datetime_columns", + "test_create_table_with_timestamps_should_create_datetime_columns_with_options", + "test_create_table_without_a_block", + "test_create_table_without_id", + "test_finds_migrations", + "test_finds_pending_migrations", + "test_keeping_default_and_notnull_constraint_on_change", + "test_migrator", + "test_migrator_db_has_no_schema_migrations_table", + "test_migrator_double_down", + "test_migrator_double_up", + "test_migrator_forward", + "test_migrator_going_down_due_to_version_target", + "test_migrator_one_down", + "test_migrator_one_up", + "test_migrator_one_up_one_down", + "test_migrator_one_up_with_exception_and_rollback", + "test_migrator_rollback", + "test_migrator_verbosity", + "test_migrator_verbosity_off", + "test_migrator_with_duplicate_names", + "test_migrator_with_duplicates", + "test_migrator_with_missing_version_numbers", + "test_native_decimal_insert_manual_vs_automatic", + "test_native_types", + "test_only_loads_pending_migrations", + "test_proper_table_name", + "test_relative_migrations", + "test_remove_column_with_index", + "test_remove_column_with_multi_column_index", + "test_rename_column", + "test_rename_column_preserves_default_value_not_null", + "test_rename_column_using_symbol_arguments", + "test_rename_column_with_an_index", + "test_rename_column_with_sql_reserved_word", + "test_rename_nonexistent_column", + "test_rename_table", + "test_rename_table_for_sqlite_should_work_with_reserved_words", + "test_rename_table_with_an_index", + "test_schema_migrations_table_name", + "test_target_version_zero_should_run_only_once", + ] class PrivateToAry private diff --git a/spec/ruby/core/array/fixtures/encoded_strings.rb b/spec/ruby/core/array/fixtures/encoded_strings.rb index 5b85bd0e06..b5888d86ae 100644 --- a/spec/ruby/core/array/fixtures/encoded_strings.rb +++ b/spec/ruby/core/array/fixtures/encoded_strings.rb @@ -2,14 +2,14 @@ module ArraySpecs def self.array_with_usascii_and_7bit_utf8_strings [ - 'foo'.force_encoding('US-ASCII'), + 'foo'.dup.force_encoding('US-ASCII'), 'bar' ] end def self.array_with_usascii_and_utf8_strings [ - 'foo'.force_encoding('US-ASCII'), + 'foo'.dup.force_encoding('US-ASCII'), 'báz' ] end @@ -17,7 +17,7 @@ module ArraySpecs def self.array_with_7bit_utf8_and_usascii_strings [ 'bar', - 'foo'.force_encoding('US-ASCII') + 'foo'.dup.force_encoding('US-ASCII') ] end @@ -25,13 +25,13 @@ module ArraySpecs [ 'báz', 'bar', - 'foo'.force_encoding('US-ASCII') + 'foo'.dup.force_encoding('US-ASCII') ] end def self.array_with_usascii_and_utf8_strings [ - 'foo'.force_encoding('US-ASCII'), + 'foo'.dup.force_encoding('US-ASCII'), 'bar', 'báz' ] @@ -41,7 +41,7 @@ module ArraySpecs [ 'bar', 'báz', - 'foo'.force_encoding('BINARY') + 'foo'.dup.force_encoding('BINARY') ] end @@ -55,14 +55,14 @@ module ArraySpecs def self.array_with_usascii_and_7bit_binary_strings [ - 'bar'.force_encoding('US-ASCII'), - 'foo'.force_encoding('BINARY') + 'bar'.dup.force_encoding('US-ASCII'), + 'foo'.dup.force_encoding('BINARY') ] end def self.array_with_usascii_and_binary_strings [ - 'bar'.force_encoding('US-ASCII'), + 'bar'.dup.force_encoding('US-ASCII'), [255].pack('C').force_encoding('BINARY') ] end diff --git a/spec/ruby/core/array/flatten_spec.rb b/spec/ruby/core/array/flatten_spec.rb index 1b7361552a..8c97000c79 100644 --- a/spec/ruby/core/array/flatten_spec.rb +++ b/spec/ruby/core/array/flatten_spec.rb @@ -30,7 +30,7 @@ describe "Array#flatten" do it "raises a TypeError when the passed Object can't be converted to an Integer" do obj = mock("Not converted") - lambda { [ 1, 2, [3, [4, 5] ] ].flatten(obj) }.should raise_error(TypeError) + -> { [ 1, 2, [3, [4, 5] ] ].flatten(obj) }.should raise_error(TypeError) end it "does not call flatten on elements" do @@ -46,13 +46,13 @@ describe "Array#flatten" do it "raises an ArgumentError on recursive arrays" do x = [] x << x - lambda { x.flatten }.should raise_error(ArgumentError) + -> { x.flatten }.should raise_error(ArgumentError) x = [] y = [] x << y y << x - lambda { x.flatten }.should raise_error(ArgumentError) + -> { x.flatten }.should raise_error(ArgumentError) end it "flattens any element which responds to #to_ary, using the return value of said method" do @@ -75,11 +75,11 @@ describe "Array#flatten" do [[obj]].flatten(1) end - it "returns subclass instance for Array subclasses" do - ArraySpecs::MyArray[].flatten.should be_an_instance_of(ArraySpecs::MyArray) - ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(ArraySpecs::MyArray) - ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(ArraySpecs::MyArray) - ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == ArraySpecs::MyArray[1, 2, 3, 4] + it "returns Array instance for Array subclasses" do + ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array) + ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array) + ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array) + ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4] [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array) end @@ -106,23 +106,13 @@ describe "Array#flatten" do it "raises a TypeError if #to_ary does not return an Array" do @obj.should_receive(:to_ary).and_return(1) - lambda { [@obj].flatten }.should raise_error(TypeError) + -> { [@obj].flatten }.should raise_error(TypeError) end - ruby_version_is ""..."2.5" do - it "calls respond_to_missing?(:to_ary, false) to try coercing" do - def @obj.respond_to_missing?(*args) ScratchPad << args; false end - [@obj].flatten.should == [@obj] - ScratchPad.recorded.should == [[:to_ary, false]] - end - end - - ruby_version_is "2.5" do - it "calls respond_to_missing?(:to_ary, true) to try coercing" do - def @obj.respond_to_missing?(*args) ScratchPad << args; false end - [@obj].flatten.should == [@obj] - ScratchPad.recorded.should == [[:to_ary, true]] - end + it "calls respond_to_missing?(:to_ary, true) to try coercing" do + def @obj.respond_to_missing?(*args) ScratchPad << args; false end + [@obj].flatten.should == [@obj] + ScratchPad.recorded.should == [[:to_ary, true]] end it "does not call #to_ary if not defined when #respond_to_missing? returns false" do @@ -135,7 +125,7 @@ describe "Array#flatten" do it "calls #to_ary if not defined when #respond_to_missing? returns true" do def @obj.respond_to_missing?(name, priv) ScratchPad << name; true end - lambda { [@obj].flatten }.should raise_error(NoMethodError) + -> { [@obj].flatten }.should raise_error(NoMethodError) ScratchPad.recorded.should == [:to_ary] end @@ -145,14 +135,6 @@ describe "Array#flatten" do end end - it "returns a tainted array if self is tainted" do - [].taint.flatten.tainted?.should be_true - end - - it "returns an untrusted array if self is untrusted" do - [].untrust.flatten.untrusted?.should be_true - end - it "performs respond_to? and method_missing-aware checks when coercing elements to array" do bo = BasicObject.new [bo].flatten.should == [bo] @@ -226,7 +208,7 @@ describe "Array#flatten!" do it "raises a TypeError when the passed Object can't be converted to an Integer" do obj = mock("Not converted") - lambda { [ 1, 2, [3, [4, 5] ] ].flatten!(obj) }.should raise_error(TypeError) + -> { [ 1, 2, [3, [4, 5] ] ].flatten!(obj) }.should raise_error(TypeError) end it "does not call flatten! on elements" do @@ -242,13 +224,13 @@ describe "Array#flatten!" do it "raises an ArgumentError on recursive arrays" do x = [] x << x - lambda { x.flatten! }.should raise_error(ArgumentError) + -> { x.flatten! }.should raise_error(ArgumentError) x = [] y = [] x << y y << x - lambda { x.flatten! }.should raise_error(ArgumentError) + -> { x.flatten! }.should raise_error(ArgumentError) end it "flattens any elements which responds to #to_ary, using the return value of said method" do @@ -270,15 +252,15 @@ describe "Array#flatten!" do ary.should == [1, 2, 3] end - it "raises a #{frozen_error_class} on frozen arrays when the array is modified" do + it "raises a FrozenError on frozen arrays when the array is modified" do nested_ary = [1, 2, []] nested_ary.freeze - lambda { nested_ary.flatten! }.should raise_error(frozen_error_class) + -> { nested_ary.flatten! }.should raise_error(FrozenError) end # see [ruby-core:23663] - it "raises a #{frozen_error_class} on frozen arrays when the array would not be modified" do - lambda { ArraySpecs.frozen_array.flatten! }.should raise_error(frozen_error_class) - lambda { ArraySpecs.empty_frozen_array.flatten! }.should raise_error(frozen_error_class) + it "raises a FrozenError on frozen arrays when the array would not be modified" do + -> { ArraySpecs.frozen_array.flatten! }.should raise_error(FrozenError) + -> { ArraySpecs.empty_frozen_array.flatten! }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/frozen_spec.rb b/spec/ruby/core/array/frozen_spec.rb index bb4b2b4067..3ba54be46b 100644 --- a/spec/ruby/core/array/frozen_spec.rb +++ b/spec/ruby/core/array/frozen_spec.rb @@ -4,13 +4,13 @@ require_relative 'fixtures/classes' describe "Array#frozen?" do it "returns true if array is frozen" do a = [1, 2, 3] - a.frozen?.should == false + a.should_not.frozen? a.freeze - a.frozen?.should == true + a.should.frozen? end it "returns false for an array being sorted by #sort" do a = [1, 2, 3] - a.sort { |x,y| a.frozen?.should == false; x <=> y } + a.sort { |x,y| a.should_not.frozen?; x <=> y } end end diff --git a/spec/ruby/core/array/hash_spec.rb b/spec/ruby/core/array/hash_spec.rb index 638acff12b..f3bcc83fce 100644 --- a/spec/ruby/core/array/hash_spec.rb +++ b/spec/ruby/core/array/hash_spec.rb @@ -7,16 +7,16 @@ describe "Array#hash" do [[], [1, 2, 3]].each do |ary| ary.hash.should == ary.dup.hash - ary.hash.should be_an_instance_of(Fixnum) + ary.hash.should be_an_instance_of(Integer) end end it "properly handles recursive arrays" do empty = ArraySpecs.empty_recursive_array - lambda { empty.hash }.should_not raise_error + -> { empty.hash }.should_not raise_error array = ArraySpecs.recursive_array - lambda { array.hash }.should_not raise_error + -> { array.hash }.should_not raise_error end it "returns the same hash for equal recursive arrays" do diff --git a/spec/ruby/core/array/initialize_spec.rb b/spec/ruby/core/array/initialize_spec.rb index 350538a222..b9fa77b16e 100644 --- a/spec/ruby/core/array/initialize_spec.rb +++ b/spec/ruby/core/array/initialize_spec.rb @@ -24,21 +24,21 @@ describe "Array#initialize" do end it "raises an ArgumentError if passed 3 or more arguments" do - lambda do + -> do [1, 2].send :initialize, 1, 'x', true end.should raise_error(ArgumentError) - lambda do + -> do [1, 2].send(:initialize, 1, 'x', true) {} end.should raise_error(ArgumentError) end - it "raises a #{frozen_error_class} on frozen arrays" do - lambda do + it "raises a FrozenError on frozen arrays" do + -> do ArraySpecs.frozen_array.send :initialize - end.should raise_error(frozen_error_class) - lambda do + end.should raise_error(FrozenError) + -> do ArraySpecs.frozen_array.send :initialize, ArraySpecs.frozen_array - end.should raise_error(frozen_error_class) + end.should raise_error(FrozenError) end it "calls #to_ary to convert the value to an array, even if it's private" do @@ -53,7 +53,9 @@ describe "Array#initialize with no arguments" do end it "does not use the given block" do - lambda{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error + -> { + -> { [1, 2, 3].send(:initialize) { raise } }.should_not raise_error + }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true) end end @@ -64,7 +66,7 @@ describe "Array#initialize with (array)" do end it "does not use the given block" do - lambda{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error + ->{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error end it "calls #to_ary to convert the value to an array" do @@ -81,7 +83,7 @@ describe "Array#initialize with (array)" do end it "raises a TypeError if an Array type argument and a default object" do - lambda { [].send(:initialize, [1, 2], 1) }.should raise_error(TypeError) + -> { [].send(:initialize, [1, 2], 1) }.should raise_error(TypeError) end end @@ -103,12 +105,12 @@ describe "Array#initialize with (size, object=nil)" do end it "raises an ArgumentError if size is negative" do - lambda { [].send(:initialize, -1, :a) }.should raise_error(ArgumentError) - lambda { [].send(:initialize, -1) }.should raise_error(ArgumentError) + -> { [].send(:initialize, -1, :a) }.should raise_error(ArgumentError) + -> { [].send(:initialize, -1) }.should raise_error(ArgumentError) end it "raises an ArgumentError if size is too large" do - lambda { [].send(:initialize, fixnum_max+1) }.should raise_error(ArgumentError) + -> { [].send(:initialize, fixnum_max+1) }.should raise_error(ArgumentError) end it "calls #to_int to convert the size argument to an Integer when object is given" do @@ -126,7 +128,7 @@ describe "Array#initialize with (size, object=nil)" do it "raises a TypeError if the size argument is not an Integer type" do obj = mock('nonnumeric') obj.stub!(:to_ary).and_return([1, 2]) - lambda{ [].send(:initialize, obj, :a) }.should raise_error(TypeError) + ->{ [].send(:initialize, obj, :a) }.should raise_error(TypeError) end it "yields the index of the element and sets the element to the value of the block" do @@ -134,7 +136,7 @@ describe "Array#initialize with (size, object=nil)" do end it "uses the block value instead of using the default value" do - lambda { + -> { @result = [].send(:initialize, 3, :obj) { |i| i.to_s } }.should complain(/block supersedes default value argument/) @result.should == ['0', '1', '2'] diff --git a/spec/ruby/core/array/insert_spec.rb b/spec/ruby/core/array/insert_spec.rb index b65a14a6b7..9e1757f68b 100644 --- a/spec/ruby/core/array/insert_spec.rb +++ b/spec/ruby/core/array/insert_spec.rb @@ -46,8 +46,8 @@ describe "Array#insert" do end it "raises an IndexError if the negative index is out of bounds" do - lambda { [].insert(-2, 1) }.should raise_error(IndexError) - lambda { [1].insert(-3, 2) }.should raise_error(IndexError) + -> { [].insert(-2, 1) }.should raise_error(IndexError) + -> { [1].insert(-3, 2) }.should raise_error(IndexError) end it "does nothing of no object is passed" do @@ -64,15 +64,15 @@ describe "Array#insert" do end it "raises an ArgumentError if no argument passed" do - lambda { [].insert() }.should raise_error(ArgumentError) + -> { [].insert() }.should raise_error(ArgumentError) end - it "raises a #{frozen_error_class} on frozen arrays when the array is modified" do - lambda { ArraySpecs.frozen_array.insert(0, 'x') }.should raise_error(frozen_error_class) + it "raises a FrozenError on frozen arrays when the array is modified" do + -> { ArraySpecs.frozen_array.insert(0, 'x') }.should raise_error(FrozenError) end # see [ruby-core:23666] - it "raises a #{frozen_error_class} on frozen arrays when the array would not be modified" do - lambda { ArraySpecs.frozen_array.insert(0) }.should raise_error(frozen_error_class) + it "raises a FrozenError on frozen arrays when the array would not be modified" do + -> { ArraySpecs.frozen_array.insert(0) }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/intersect_spec.rb b/spec/ruby/core/array/intersect_spec.rb new file mode 100644 index 0000000000..456aa26c6e --- /dev/null +++ b/spec/ruby/core/array/intersect_spec.rb @@ -0,0 +1,64 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'Array#intersect?' do + describe 'when at least one element in two Arrays is the same' do + it 'returns true' do + [1, 2].intersect?([2, 3, 4]).should == true + [2, 3, 4].intersect?([1, 2]).should == true + end + end + + describe 'when there are no elements in common between two Arrays' do + it 'returns false' do + [0, 1, 2].intersect?([3, 4]).should == false + [3, 4].intersect?([0, 1, 2]).should == false + [3, 4].intersect?([]).should == false + [].intersect?([0, 1, 2]).should == false + end + end + + it "tries to convert the passed argument to an Array using #to_ary" do + obj = mock('[1,2,3]') + obj.should_receive(:to_ary).and_return([1, 2, 3]) + + [1, 2].intersect?(obj).should == true + end + + it "determines equivalence between elements in the sense of eql?" do + obj1 = mock('1') + obj2 = mock('2') + obj1.stub!(:hash).and_return(0) + obj2.stub!(:hash).and_return(0) + obj1.stub!(:eql?).and_return(true) + obj2.stub!(:eql?).and_return(true) + + [obj1].intersect?([obj2]).should == true + + obj1 = mock('3') + obj2 = mock('4') + obj1.stub!(:hash).and_return(0) + obj2.stub!(:hash).and_return(0) + obj1.stub!(:eql?).and_return(false) + obj2.stub!(:eql?).and_return(false) + + [obj1].intersect?([obj2]).should == false + end + + it "does not call to_ary on array subclasses" do + [5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true + end + + it "properly handles an identical item even when its #eql? isn't reflexive" do + x = mock('x') + x.stub!(:hash).and_return(42) + x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI. + + [x].intersect?([x]).should == true + end + + it "has semantic of !(a & b).empty?" do + [].intersect?([]).should == false + [nil].intersect?([nil]).should == true + end +end diff --git a/spec/ruby/core/array/intersection_spec.rb b/spec/ruby/core/array/intersection_spec.rb index 7bf2ec4dbe..e01a68d389 100644 --- a/spec/ruby/core/array/intersection_spec.rb +++ b/spec/ruby/core/array/intersection_spec.rb @@ -1,87 +1,19 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'shared/intersection' describe "Array#&" do - it "creates an array with elements common to both arrays (intersection)" do - ([] & []).should == [] - ([1, 2] & []).should == [] - ([] & [1, 2]).should == [] - ([ 1, 3, 5 ] & [ 1, 2, 3 ]).should == [1, 3] - end - - it "creates an array with no duplicates" do - ([ 1, 1, 3, 5 ] & [ 1, 2, 3 ]).uniq!.should == nil - end - - it "creates an array with elements in order they are first encountered" do - ([ 1, 2, 3, 2, 5 ] & [ 5, 2, 3, 4 ]).should == [2, 3, 5] - end - - it "does not modify the original Array" do - a = [1, 1, 3, 5] - (a & [1, 2, 3]).should == [1, 3] - a.should == [1, 1, 3, 5] - end - - it "properly handles recursive arrays" do - empty = ArraySpecs.empty_recursive_array - (empty & empty).should == empty - - (ArraySpecs.recursive_array & []).should == [] - ([] & ArraySpecs.recursive_array).should == [] - - (ArraySpecs.recursive_array & ArraySpecs.recursive_array).should == [1, 'two', 3.0, ArraySpecs.recursive_array] - end - - it "tries to convert the passed argument to an Array using #to_ary" do - obj = mock('[1,2,3]') - obj.should_receive(:to_ary).and_return([1, 2, 3]) - ([1, 2] & obj).should == ([1, 2]) - end - - it "determines equivalence between elements in the sense of eql?" do - not_supported_on :opal do - ([5.0, 4.0] & [5, 4]).should == [] - end - - str = "x" - ([str] & [str.dup]).should == [str] - - obj1 = mock('1') - obj2 = mock('2') - obj1.stub!(:hash).and_return(0) - obj2.stub!(:hash).and_return(0) - obj1.should_receive(:eql?).at_least(1).and_return(true) - obj2.stub!(:eql?).and_return(true) - - ([obj1] & [obj2]).should == [obj1] - ([obj1, obj1, obj2, obj2] & [obj2]).should == [obj1] - - obj1 = mock('3') - obj2 = mock('4') - obj1.stub!(:hash).and_return(0) - obj2.stub!(:hash).and_return(0) - obj1.should_receive(:eql?).at_least(1).and_return(false) + it_behaves_like :array_intersection, :& +end - ([obj1] & [obj2]).should == [] - ([obj1, obj1, obj2, obj2] & [obj2]).should == [obj2] - end +describe "Array#intersection" do + it_behaves_like :array_intersection, :intersection - it "does return subclass instances for Array subclasses" do - (ArraySpecs::MyArray[1, 2, 3] & []).should be_an_instance_of(Array) - (ArraySpecs::MyArray[1, 2, 3] & ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array) - ([] & ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array) + it "accepts multiple arguments" do + [1, 2, 3, 4].intersection([1, 2, 3], [2, 3, 4]).should == [2, 3] end - it "does not call to_ary on array subclasses" do - ([5, 6] & ArraySpecs::ToAryArray[1, 2, 5, 6]).should == [5, 6] - end - - it "properly handles an identical item even when its #eql? isn't reflexive" do - x = mock('x') - x.stub!(:hash).and_return(42) - x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI. - - ([x] & [x]).should == [x] + it "preserves elements order from original array" do + [1, 2, 3, 4].intersection([3, 2, 1]).should == [1, 2, 3] end end diff --git a/spec/ruby/core/array/join_spec.rb b/spec/ruby/core/array/join_spec.rb index 403bae7183..e78ea6f9e1 100644 --- a/spec/ruby/core/array/join_spec.rb +++ b/spec/ruby/core/array/join_spec.rb @@ -24,11 +24,11 @@ describe "Array#join" do it "raises a TypeError if the separator cannot be coerced to a String by calling #to_str" do obj = mock("not a string") - lambda { [1, 2].join(obj) }.should raise_error(TypeError) + -> { [1, 2].join(obj) }.should raise_error(TypeError) end it "raises a TypeError if passed false as the separator" do - lambda { [1, 2].join(false) }.should raise_error(TypeError) + -> { [1, 2].join(false) }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/array/keep_if_spec.rb b/spec/ruby/core/array/keep_if_spec.rb index bf2bdeaf91..40f7329b7c 100644 --- a/spec/ruby/core/array/keep_if_spec.rb +++ b/spec/ruby/core/array/keep_if_spec.rb @@ -1,3 +1,4 @@ +require_relative '../../spec_helper' require_relative 'shared/keep_if' describe "Array#keep_if" do diff --git a/spec/ruby/core/array/last_spec.rb b/spec/ruby/core/array/last_spec.rb index 9bf8648776..d6fefada09 100644 --- a/spec/ruby/core/array/last_spec.rb +++ b/spec/ruby/core/array/last_spec.rb @@ -28,7 +28,7 @@ describe "Array#last" do end it "raises an ArgumentError when count is negative" do - lambda { [1, 2].last(-1) }.should raise_error(ArgumentError) + -> { [1, 2].last(-1) }.should raise_error(ArgumentError) end it "returns the entire array when count > length" do @@ -60,11 +60,11 @@ describe "Array#last" do end it "raises a TypeError if the passed argument is not numeric" do - lambda { [1,2].last(nil) }.should raise_error(TypeError) - lambda { [1,2].last("a") }.should raise_error(TypeError) + -> { [1,2].last(nil) }.should raise_error(TypeError) + -> { [1,2].last("a") }.should raise_error(TypeError) obj = mock("nonnumeric") - lambda { [1,2].last(obj) }.should raise_error(TypeError) + -> { [1,2].last(obj) }.should raise_error(TypeError) end it "does not return subclass instance on Array subclasses" do diff --git a/spec/ruby/core/array/max_spec.rb b/spec/ruby/core/array/max_spec.rb index 329b691883..d1c64519d0 100644 --- a/spec/ruby/core/array/max_spec.rb +++ b/spec/ruby/core/array/max_spec.rb @@ -68,16 +68,16 @@ describe "Array#max" do end it "raises a NoMethodError for elements without #<=>" do - lambda do + -> do [BasicObject.new, BasicObject.new].max end.should raise_error(NoMethodError) end it "raises an ArgumentError for incomparable elements" do - lambda do + -> do [11,"22"].max end.should raise_error(ArgumentError) - lambda do + -> do [11,12,22,33].max{|a, b| nil} end.should raise_error(ArgumentError) end diff --git a/spec/ruby/core/array/min_spec.rb b/spec/ruby/core/array/min_spec.rb index 22a179d808..3bdef0dd00 100644 --- a/spec/ruby/core/array/min_spec.rb +++ b/spec/ruby/core/array/min_spec.rb @@ -68,16 +68,16 @@ describe "Array#min" do end it "raises a NoMethodError for elements without #<=>" do - lambda do + -> do [BasicObject.new, BasicObject.new].min end.should raise_error(NoMethodError) end it "raises an ArgumentError for incomparable elements" do - lambda do + -> do [11,"22"].min end.should raise_error(ArgumentError) - lambda do + -> do [11,12,22,33].min{|a, b| nil} end.should raise_error(ArgumentError) end diff --git a/spec/ruby/core/array/minmax_spec.rb b/spec/ruby/core/array/minmax_spec.rb new file mode 100644 index 0000000000..e11fe63347 --- /dev/null +++ b/spec/ruby/core/array/minmax_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../spec_helper' +require_relative '../../shared/enumerable/minmax' + +describe "Array#minmax" do + before :each do + @enum = [6, 4, 5, 10, 8] + @empty_enum = [] + @incomparable_enum = [BasicObject.new, BasicObject.new] + @incompatible_enum = [11, "22"] + @strs = ["333", "2", "60", "55555", "1010", "111"] + end + + it_behaves_like :enumerable_minmax, :minmax +end diff --git a/spec/ruby/core/array/multiply_spec.rb b/spec/ruby/core/array/multiply_spec.rb index f9ba20258a..eca51142fb 100644 --- a/spec/ruby/core/array/multiply_spec.rb +++ b/spec/ruby/core/array/multiply_spec.rb @@ -17,7 +17,7 @@ describe "Array#*" do it "raises a TypeError if the argument can neither be converted to a string nor an integer" do obj = mock('not a string or integer') - lambda{ [1,2] * obj }.should raise_error(TypeError) + ->{ [1,2] * obj }.should raise_error(TypeError) end it "converts the passed argument to a String rather than an Integer" do @@ -28,15 +28,15 @@ describe "Array#*" do end it "raises a TypeError is the passed argument is nil" do - lambda{ [1,2] * nil }.should raise_error(TypeError) + ->{ [1,2] * nil }.should raise_error(TypeError) end it "raises an ArgumentError when passed 2 or more arguments" do - lambda{ [1,2].send(:*, 1, 2) }.should raise_error(ArgumentError) + ->{ [1,2].send(:*, 1, 2) }.should raise_error(ArgumentError) end it "raises an ArgumentError when passed no arguments" do - lambda{ [1,2].send(:*) }.should raise_error(ArgumentError) + ->{ [1,2].send(:*) }.should raise_error(ArgumentError) end end @@ -65,8 +65,8 @@ describe "Array#* with an integer" do end it "raises an ArgumentError when passed a negative integer" do - lambda { [ 1, 2, 3 ] * -1 }.should raise_error(ArgumentError) - lambda { [] * -1 }.should raise_error(ArgumentError) + -> { [ 1, 2, 3 ] * -1 }.should raise_error(ArgumentError) + -> { [] * -1 }.should raise_error(ArgumentError) end describe "with a subclass of Array" do @@ -76,10 +76,10 @@ describe "Array#* with an integer" do @array = ArraySpecs::MyArray[1, 2, 3, 4, 5] end - it "returns a subclass instance" do - (@array * 0).should be_an_instance_of(ArraySpecs::MyArray) - (@array * 1).should be_an_instance_of(ArraySpecs::MyArray) - (@array * 2).should be_an_instance_of(ArraySpecs::MyArray) + it "returns an Array instance" do + (@array * 0).should be_an_instance_of(Array) + (@array * 1).should be_an_instance_of(Array) + (@array * 2).should be_an_instance_of(Array) end it "does not call #initialize on the subclass instance" do @@ -87,44 +87,6 @@ describe "Array#* with an integer" do ScratchPad.recorded.should be_nil end end - - it "copies the taint status of the original array even if the passed count is 0" do - ary = [1, 2, 3] - ary.taint - (ary * 0).tainted?.should == true - end - - it "copies the taint status of the original array even if the array is empty" do - ary = [] - ary.taint - (ary * 3).tainted?.should == true - end - - it "copies the taint status of the original array if the passed count is not 0" do - ary = [1, 2, 3] - ary.taint - (ary * 1).tainted?.should == true - (ary * 2).tainted?.should == true - end - - it "copies the untrusted status of the original array even if the passed count is 0" do - ary = [1, 2, 3] - ary.untrust - (ary * 0).untrusted?.should == true - end - - it "copies the untrusted status of the original array even if the array is empty" do - ary = [] - ary.untrust - (ary * 3).untrusted?.should == true - end - - it "copies the untrusted status of the original array if the passed count is not 0" do - ary = [1, 2, 3] - ary.untrust - (ary * 1).untrusted?.should == true - (ary * 2).untrusted?.should == true - end end describe "Array#* with a string" do diff --git a/spec/ruby/core/array/new_spec.rb b/spec/ruby/core/array/new_spec.rb index d5e4b5722f..b50a4857b0 100644 --- a/spec/ruby/core/array/new_spec.rb +++ b/spec/ruby/core/array/new_spec.rb @@ -11,10 +11,10 @@ describe "Array.new" do end it "raises an ArgumentError if passed 3 or more arguments" do - lambda do + -> do [1, 2].send :initialize, 1, 'x', true end.should raise_error(ArgumentError) - lambda do + -> do [1, 2].send(:initialize, 1, 'x', true) {} end.should raise_error(ArgumentError) end @@ -26,7 +26,9 @@ describe "Array.new with no arguments" do end it "does not use the given block" do - lambda{ Array.new { raise } }.should_not raise_error + -> { + -> { Array.new { raise } }.should_not raise_error + }.should complain(/warning: given block not used/, verbose: true) end end @@ -37,7 +39,7 @@ describe "Array.new with (array)" do end it "does not use the given block" do - lambda{ Array.new([1, 2]) { raise } }.should_not raise_error + ->{ Array.new([1, 2]) { raise } }.should_not raise_error end it "calls #to_ary to convert the value to an array" do @@ -54,7 +56,7 @@ describe "Array.new with (array)" do end it "raises a TypeError if an Array type argument and a default object" do - lambda { Array.new([1, 2], 1) }.should raise_error(TypeError) + -> { Array.new([1, 2], 1) }.should raise_error(TypeError) end end @@ -74,12 +76,12 @@ describe "Array.new with (size, object=nil)" do end it "raises an ArgumentError if size is negative" do - lambda { Array.new(-1, :a) }.should raise_error(ArgumentError) - lambda { Array.new(-1) }.should raise_error(ArgumentError) + -> { Array.new(-1, :a) }.should raise_error(ArgumentError) + -> { Array.new(-1) }.should raise_error(ArgumentError) end it "raises an ArgumentError if size is too large" do - lambda { Array.new(fixnum_max+1) }.should raise_error(ArgumentError) + -> { Array.new(fixnum_max+1) }.should raise_error(ArgumentError) end it "calls #to_int to convert the size argument to an Integer when object is given" do @@ -97,7 +99,7 @@ describe "Array.new with (size, object=nil)" do it "raises a TypeError if the size argument is not an Integer type" do obj = mock('nonnumeric') obj.stub!(:to_ary).and_return([1, 2]) - lambda{ Array.new(obj, :a) }.should raise_error(TypeError) + ->{ Array.new(obj, :a) }.should raise_error(TypeError) end it "yields the index of the element and sets the element to the value of the block" do @@ -105,7 +107,7 @@ describe "Array.new with (size, object=nil)" do end it "uses the block value instead of using the default value" do - lambda { + -> { @result = Array.new(3, :obj) { |i| i.to_s } }.should complain(/block supersedes default value argument/) @result.should == ['0', '1', '2'] diff --git a/spec/ruby/core/array/none_spec.rb b/spec/ruby/core/array/none_spec.rb new file mode 100644 index 0000000000..31cd8c46d6 --- /dev/null +++ b/spec/ruby/core/array/none_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' +require_relative 'shared/iterable_and_tolerating_size_increasing' + +describe "Array#none?" do + @value_to_return = -> _ { false } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :none? + + it "ignores the block if there is an argument" do + -> { + ['bar', 'foobar'].none?(/baz/) { true }.should == true + }.should complain(/given block not used/) + end +end diff --git a/spec/ruby/core/array/one_spec.rb b/spec/ruby/core/array/one_spec.rb new file mode 100644 index 0000000000..0c61907881 --- /dev/null +++ b/spec/ruby/core/array/one_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' +require_relative 'shared/iterable_and_tolerating_size_increasing' + +describe "Array#one?" do + @value_to_return = -> _ { false } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :one? + + it "ignores the block if there is an argument" do + -> { + ['bar', 'foobar'].one?(/foo/) { false }.should == true + }.should complain(/given block not used/) + end +end diff --git a/spec/ruby/core/array/pack/a_spec.rb b/spec/ruby/core/array/pack/a_spec.rb index 7af7a16c68..8245cd5470 100644 --- a/spec/ruby/core/array/pack/a_spec.rb +++ b/spec/ruby/core/array/pack/a_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/basic' @@ -12,11 +12,22 @@ describe "Array#pack with format 'A'" do it_behaves_like :array_pack_string, 'A' it_behaves_like :array_pack_taint, 'A' + it "calls #to_str to convert an Object to a String" do + obj = mock("pack A string") + obj.should_receive(:to_str).and_return("``abcdef") + [obj].pack("A*").should == "``abcdef" + end + + it "will not implicitly convert a number to a string" do + -> { [0].pack('A') }.should raise_error(TypeError) + -> { [0].pack('a') }.should raise_error(TypeError) + end + it "adds all the bytes to the output when passed the '*' modifier" do ["abc"].pack("A*").should == "abc" end - it "padds the output with spaces when the count exceeds the size of the String" do + it "pads the output with spaces when the count exceeds the size of the String" do ["abc"].pack("A6").should == "abc " end @@ -44,7 +55,7 @@ describe "Array#pack with format 'a'" do ["abc"].pack("a*").should == "abc" end - it "padds the output with NULL bytes when the count exceeds the size of the String" do + it "pads the output with NULL bytes when the count exceeds the size of the String" do ["abc"].pack("a6").should == "abc\x00\x00\x00" end diff --git a/spec/ruby/core/array/pack/at_spec.rb b/spec/ruby/core/array/pack/at_spec.rb index 3942677913..bb9801440a 100644 --- a/spec/ruby/core/array/pack/at_spec.rb +++ b/spec/ruby/core/array/pack/at_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/basic' diff --git a/spec/ruby/core/array/pack/b_spec.rb b/spec/ruby/core/array/pack/b_spec.rb index 872c1b88d5..247a9ca023 100644 --- a/spec/ruby/core/array/pack/b_spec.rb +++ b/spec/ruby/core/array/pack/b_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/basic' @@ -13,11 +13,16 @@ describe "Array#pack with format 'B'" do it_behaves_like :array_pack_taint, 'B' it "calls #to_str to convert an Object to a String" do - obj = mock("pack H string") + obj = mock("pack B string") obj.should_receive(:to_str).and_return("``abcdef") [obj].pack("B*").should == "\x2a" end + it "will not implicitly convert a number to a string" do + -> { [0].pack('B') }.should raise_error(TypeError) + -> { [0].pack('b') }.should raise_error(TypeError) + end + it "encodes one bit for each character starting with the most significant bit" do [ [["0"], "\x00"], [["1"], "\x80"] diff --git a/spec/ruby/core/array/pack/buffer_spec.rb b/spec/ruby/core/array/pack/buffer_spec.rb index a3a582996a..b77b2d1efa 100644 --- a/spec/ruby/core/array/pack/buffer_spec.rb +++ b/spec/ruby/core/array/pack/buffer_spec.rb @@ -13,37 +13,47 @@ describe "Array#pack with :buffer option" do it "adds result at the end of buffer content" do n = [ 65, 66, 67 ] # result without buffer is "ABC" - buffer = "" + buffer = +"" n.pack("ccc", buffer: buffer).should == "ABC" - buffer = "123" + buffer = +"123" n.pack("ccc", buffer: buffer).should == "123ABC" - buffer = "12345" + buffer = +"12345" n.pack("ccc", buffer: buffer).should == "12345ABC" end it "raises TypeError exception if buffer is not String" do - lambda { [65].pack("ccc", buffer: []) }.should raise_error( + -> { [65].pack("ccc", buffer: []) }.should raise_error( TypeError, "buffer must be String, not Array") end + it "raise FrozenError if buffer is frozen" do + -> { [65].pack("c", buffer: "frozen-string".freeze) }.should raise_error(FrozenError) + end + + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + [65, 66, 67].pack("ccc", buffer: buffer) + buffer.encoding.should == Encoding::ISO_8859_1 + end + context "offset (@) is specified" do it 'keeps buffer content if it is longer than offset' do n = [ 65, 66, 67 ] - buffer = "123456" + buffer = +"123456" n.pack("@3ccc", buffer: buffer).should == "123ABC" end it "fills the gap with \\0 if buffer content is shorter than offset" do n = [ 65, 66, 67 ] - buffer = "123" + buffer = +"123" n.pack("@6ccc", buffer: buffer).should == "123\0\0\0ABC" end it 'does not keep buffer content if it is longer than offset + result' do n = [ 65, 66, 67 ] - buffer = "1234567890" + buffer = +"1234567890" n.pack("@3ccc", buffer: buffer).should == "123ABC" end end diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb index 7200830331..47b71b663d 100644 --- a/spec/ruby/core/array/pack/c_spec.rb +++ b/spec/ruby/core/array/pack/c_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' @@ -45,8 +45,20 @@ describe :array_pack_8bit, shared: true do [1, 2, 3, 4, 5].pack(pack_format('*')).should == "\x01\x02\x03\x04\x05" end - it "ignores NULL bytes between directives" do - [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [1, 2, 3].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/comment_spec.rb b/spec/ruby/core/array/pack/comment_spec.rb index 254c827ccc..daf1cff06a 100644 --- a/spec/ruby/core/array/pack/comment_spec.rb +++ b/spec/ruby/core/array/pack/comment_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' diff --git a/spec/ruby/core/array/pack/h_spec.rb b/spec/ruby/core/array/pack/h_spec.rb index 85a875fc8b..ba188874ba 100644 --- a/spec/ruby/core/array/pack/h_spec.rb +++ b/spec/ruby/core/array/pack/h_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/basic' @@ -18,6 +18,11 @@ describe "Array#pack with format 'H'" do [obj].pack("H").should == "\xa0" end + it "will not implicitly convert a number to a string" do + -> { [0].pack('H') }.should raise_error(TypeError) + -> { [0].pack('h') }.should raise_error(TypeError) + end + it "encodes the first character as the most significant nibble when passed no count modifier" do ["ab"].pack("H").should == "\xa0" end diff --git a/spec/ruby/core/array/pack/l_spec.rb b/spec/ruby/core/array/pack/l_spec.rb index b446a7a36a..f6dfb1da83 100644 --- a/spec/ruby/core/array/pack/l_spec.rb +++ b/spec/ruby/core/array/pack/l_spec.rb @@ -29,7 +29,7 @@ describe "Array#pack with format 'L'" do it_behaves_like :array_pack_32bit_be, 'L>' end - platform_is wordsize: 32 do + platform_is c_long_size: 32 do describe "with modifier '<' and '_'" do it_behaves_like :array_pack_32bit_le, 'L<_' it_behaves_like :array_pack_32bit_le, 'L_<' @@ -51,7 +51,7 @@ describe "Array#pack with format 'L'" do end end - platform_is wordsize: 64 do + platform_is c_long_size: 64 do describe "with modifier '<' and '_'" do it_behaves_like :array_pack_64bit_le, 'L<_' it_behaves_like :array_pack_64bit_le, 'L_<' @@ -83,7 +83,7 @@ describe "Array#pack with format 'l'" do it_behaves_like :array_pack_32bit_be, 'l>' end - platform_is wordsize: 32 do + platform_is c_long_size: 32 do describe "with modifier '<' and '_'" do it_behaves_like :array_pack_32bit_le, 'l<_' it_behaves_like :array_pack_32bit_le, 'l_<' @@ -105,7 +105,7 @@ describe "Array#pack with format 'l'" do end end - platform_is wordsize: 64 do + platform_is c_long_size: 64 do describe "with modifier '<' and '_'" do it_behaves_like :array_pack_64bit_le, 'l<_' it_behaves_like :array_pack_64bit_le, 'l_<' @@ -137,7 +137,7 @@ little_endian do it_behaves_like :array_pack_32bit_le, 'l' end - platform_is wordsize: 32 do + platform_is c_long_size: 32 do describe "Array#pack with format 'L' with modifier '_'" do it_behaves_like :array_pack_32bit_le, 'L_' end @@ -155,7 +155,7 @@ little_endian do end end - platform_is wordsize: 64 do + platform_is c_long_size: 64 do describe "Array#pack with format 'L' with modifier '_'" do it_behaves_like :array_pack_64bit_le, 'L_' end @@ -183,7 +183,7 @@ big_endian do it_behaves_like :array_pack_32bit_be, 'l' end - platform_is wordsize: 32 do + platform_is c_long_size: 32 do describe "Array#pack with format 'L' with modifier '_'" do it_behaves_like :array_pack_32bit_be, 'L_' end @@ -201,7 +201,7 @@ big_endian do end end - platform_is wordsize: 64 do + platform_is c_long_size: 64 do describe "Array#pack with format 'L' with modifier '_'" do it_behaves_like :array_pack_64bit_be, 'L_' end diff --git a/spec/ruby/core/array/pack/m_spec.rb b/spec/ruby/core/array/pack/m_spec.rb index 40c2e3f1fa..a80f91275c 100644 --- a/spec/ruby/core/array/pack/m_spec.rb +++ b/spec/ruby/core/array/pack/m_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/basic' @@ -80,8 +80,16 @@ describe "Array#pack with format 'M'" do ].should be_computed_by(:pack, "M") end - it "encodes a tab followed by a newline with an encoded newline" do + it "encodes a tab at the end of a line with an encoded newline" do + ["\t"].pack("M").should == "\t=\n" ["\t\n"].pack("M").should == "\t=\n\n" + ["abc\t\nxyz"].pack("M").should == "abc\t=\n\nxyz=\n" + end + + it "encodes a space at the end of a line with an encoded newline" do + [" "].pack("M").should == " =\n" + [" \n"].pack("M").should == " =\n\n" + ["abc \nxyz"].pack("M").should == "abc =\n\nxyz=\n" end it "encodes 127..255 in hex format" do @@ -285,16 +293,16 @@ describe "Array#pack with format 'm'" do it "raises a TypeError if #to_str does not return a String" do obj = mock("pack m non-string") - lambda { [obj].pack("m") }.should raise_error(TypeError) + -> { [obj].pack("m") }.should raise_error(TypeError) end it "raises a TypeError if passed nil" do - lambda { [nil].pack("m") }.should raise_error(TypeError) + -> { [nil].pack("m") }.should raise_error(TypeError) end it "raises a TypeError if passed an Integer" do - lambda { [0].pack("m") }.should raise_error(TypeError) - lambda { [bignum_value].pack("m") }.should raise_error(TypeError) + -> { [0].pack("m") }.should raise_error(TypeError) + -> { [bignum_value].pack("m") }.should raise_error(TypeError) end it "does not emit a newline if passed zero as the count modifier" do diff --git a/spec/ruby/core/array/pack/p_spec.rb b/spec/ruby/core/array/pack/p_spec.rb index 857d403313..b023bf9110 100644 --- a/spec/ruby/core/array/pack/p_spec.rb +++ b/spec/ruby/core/array/pack/p_spec.rb @@ -15,16 +15,6 @@ describe "Array#pack with format 'P'" do ["hello"].pack("P").unpack("P5").should == ["hello"] end - it "taints the input string" do - input_string = "hello" - [input_string].pack("P") - input_string.tainted?.should be_true - end - - it "does not taint the output string in normal cases" do - ["hello"].pack("P").tainted?.should be_false - end - it "with nil gives a null pointer" do [nil].pack("P").unpack("J").should == [0] end @@ -42,16 +32,6 @@ describe "Array#pack with format 'p'" do ["hello"].pack("p").unpack("p").should == ["hello"] end - it "taints the input string" do - input_string = "hello" - [input_string].pack("p") - input_string.tainted?.should be_true - end - - it "does not taint the output string in normal cases" do - ["hello"].pack("p").tainted?.should be_false - end - it "with nil gives a null pointer" do [nil].pack("p").unpack("J").should == [0] end diff --git a/spec/ruby/core/array/pack/percent_spec.rb b/spec/ruby/core/array/pack/percent_spec.rb index 3c0e7eca0f..5d56dea5fe 100644 --- a/spec/ruby/core/array/pack/percent_spec.rb +++ b/spec/ruby/core/array/pack/percent_spec.rb @@ -2,6 +2,6 @@ require_relative '../../../spec_helper' describe "Array#pack with format '%'" do it "raises an Argument Error" do - lambda { [1].pack("%") }.should raise_error(ArgumentError) + -> { [1].pack("%") }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb index 39ab15308d..a63f64d296 100644 --- a/spec/ruby/core/array/pack/shared/basic.rb +++ b/spec/ruby/core/array/pack/shared/basic.rb @@ -1,6 +1,6 @@ describe :array_pack_arguments, shared: true do it "raises an ArgumentError if there are fewer elements than the format requires" do - lambda { [].pack(pack_format(1)) }.should raise_error(ArgumentError) + -> { [].pack(pack_format(1)) }.should raise_error(ArgumentError) end end @@ -10,11 +10,11 @@ describe :array_pack_basic, shared: true do end it "raises a TypeError when passed nil" do - lambda { [@obj].pack(nil) }.should raise_error(TypeError) + -> { [@obj].pack(nil) }.should raise_error(TypeError) end it "raises a TypeError when passed an Integer" do - lambda { [@obj].pack(1) }.should raise_error(TypeError) + -> { [@obj].pack(1) }.should raise_error(TypeError) end end @@ -27,15 +27,34 @@ describe :array_pack_basic_non_float, shared: true do [@obj, @obj].pack("a \t\n\v\f\r"+pack_format).should be_an_instance_of(String) end + it "ignores comments in the format string" do + # 2 additional directives ('a') are required for the X directive + [@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should be_an_instance_of(String) + end + + ruby_version_is ""..."3.3" do + it "warns that a directive is unknown" do + # additional directive ('a') is required for the X directive + -> { [@obj, @obj].pack("a K" + pack_format) }.should complain(/unknown pack directive 'K' in 'a K#{pack_format}'/) + -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0' in 'a 0#{pack_format}'/) + -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':' in 'a :#{pack_format}'/) + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError when a directive is unknown" do + # additional directive ('a') is required for the X directive + -> { [@obj, @obj].pack("a R" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive 'R'/) + -> { [@obj, @obj].pack("a 0" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive '0'/) + -> { [@obj, @obj].pack("a :" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive ':'/) + end + end + it "calls #to_str to coerce the directives string" do d = mock("pack directive") d.should_receive(:to_str).and_return("x"+pack_format) [@obj, @obj].pack(d).should be_an_instance_of(String) end - - it "taints the output string if the format string is tainted" do - [@obj, @obj].pack("x"+pack_format.taint).tainted?.should be_true - end end describe :array_pack_basic_float, shared: true do @@ -43,23 +62,23 @@ describe :array_pack_basic_float, shared: true do [9.3, 4.7].pack(" \t\n\v\f\r"+pack_format).should be_an_instance_of(String) end + it "ignores comments in the format string" do + [9.3, 4.7].pack(pack_format + "# some comment \n" + pack_format).should be_an_instance_of(String) + end + it "calls #to_str to coerce the directives string" do d = mock("pack directive") d.should_receive(:to_str).and_return("x"+pack_format) [1.2, 4.7].pack(d).should be_an_instance_of(String) end - - it "taints the output string if the format string is tainted" do - [3.2, 2.8].pack("x"+pack_format.taint).tainted?.should be_true - end end describe :array_pack_no_platform, shared: true do it "raises ArgumentError when the format modifier is '_'" do - lambda{ [1].pack(pack_format("_")) }.should raise_error(ArgumentError) + ->{ [1].pack(pack_format("_")) }.should raise_error(ArgumentError) end it "raises ArgumentError when the format modifier is '!'" do - lambda{ [1].pack(pack_format("!")) }.should raise_error(ArgumentError) + ->{ [1].pack(pack_format("!")) }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/core/array/pack/shared/encodings.rb b/spec/ruby/core/array/pack/shared/encodings.rb index 3724a5d859..6b7ffac764 100644 --- a/spec/ruby/core/array/pack/shared/encodings.rb +++ b/spec/ruby/core/array/pack/shared/encodings.rb @@ -5,12 +5,12 @@ describe :array_pack_hex, shared: true do it "raises a TypeError if the object does not respond to #to_str" do obj = mock("pack hex non-string") - lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + -> { [obj].pack(pack_format) }.should raise_error(TypeError) end it "raises a TypeError if #to_str does not return a String" do obj = mock("pack hex non-string") obj.should_receive(:to_str).and_return(1) - lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + -> { [obj].pack(pack_format) }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb index 6cd326ce9c..76c800b74d 100644 --- a/spec/ruby/core/array/pack/shared/float.rb +++ b/spec/ruby/core/array/pack/shared/float.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary describe :array_pack_float_le, shared: true do it "encodes a positive Float" do @@ -14,7 +14,7 @@ describe :array_pack_float_le, shared: true do end it "raises a TypeError if passed a String representation of a floating point number" do - lambda { ["13"].pack(pack_format) }.should raise_error(TypeError) + -> { ["13"].pack(pack_format) }.should raise_error(TypeError) end it "encodes the number of array elements specified by the count modifier" do @@ -25,8 +25,20 @@ describe :array_pack_float_le, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "\x9a\x999@33\xb3?33\x03A" end - it "ignores NULL bytes between directives" do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [5.3, 9.2].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -53,6 +65,14 @@ describe :array_pack_float_le, shared: true do it "encodes a negative Float outside the range of a single precision float" do [-1e150].pack(pack_format).should == "\x00\x00\x80\xff" end + + it "encodes a bignum as a float" do + [2 ** 65].pack(pack_format).should == [(2 ** 65).to_f].pack(pack_format) + end + + it "encodes a rational as a float" do + [Rational(3, 4)].pack(pack_format).should == [Rational(3, 4).to_f].pack(pack_format) + end end describe :array_pack_float_be, shared: true do @@ -66,10 +86,15 @@ describe :array_pack_float_be, shared: true do it "converts an Integer to a Float" do [8].pack(pack_format).should == "A\x00\x00\x00" + [bignum_value].pack(pack_format).should == "_\x80\x00\x00" + end + + it "converts a Rational to a Float" do + [Rational(8)].pack(pack_format).should == "A\x00\x00\x00" end it "raises a TypeError if passed a String representation of a floating point number" do - lambda { ["13"].pack(pack_format) }.should raise_error(TypeError) + -> { ["13"].pack(pack_format) }.should raise_error(TypeError) end it "encodes the number of array elements specified by the count modifier" do @@ -80,8 +105,20 @@ describe :array_pack_float_be, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "@9\x99\x9a?\xb333A\x0333" end - it "ignores NULL bytes between directives" do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [5.3, 9.2].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -121,10 +158,15 @@ describe :array_pack_double_le, shared: true do it "converts an Integer to a Float" do [8].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\x20@" + [bignum_value].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\xF0C" + end + + it "converts a Rational to a Float" do + [Rational(8)].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00 @" end it "raises a TypeError if passed a String representation of a floating point number" do - lambda { ["13"].pack(pack_format) }.should raise_error(TypeError) + -> { ["13"].pack(pack_format) }.should raise_error(TypeError) end it "encodes the number of array elements specified by the count modifier" do @@ -135,8 +177,20 @@ describe :array_pack_double_le, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "333333\x07@ffffff\xf6?ffffff\x20@" end - it "ignores NULL bytes between directives" do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [5.3, 9.2].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -183,7 +237,7 @@ describe :array_pack_double_be, shared: true do end it "raises a TypeError if passed a String representation of a floating point number" do - lambda { ["13"].pack(pack_format) }.should raise_error(TypeError) + -> { ["13"].pack(pack_format) }.should raise_error(TypeError) end it "encodes the number of array elements specified by the count modifier" do @@ -194,8 +248,20 @@ describe :array_pack_double_be, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "@\x07333333?\xf6ffffff@\x20ffffff" end - it "ignores NULL bytes between directives" do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [5.3, 9.2].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb index 6592f85022..61f7cca184 100644 --- a/spec/ruby/core/array/pack/shared/integer.rb +++ b/spec/ruby/core/array/pack/shared/integer.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary describe :array_pack_16bit_le, shared: true do it "encodes the least significant 16 bits of a positive number" do @@ -41,9 +41,21 @@ describe :array_pack_16bit_le, shared: true do str.should == "\x78\x65\xcd\xab\x21\x43" end - it "ignores NULL bytes between directives" do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x78\x65\xcd\xab" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x78\x65\xcd\xab" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -93,9 +105,21 @@ describe :array_pack_16bit_be, shared: true do str.should == "\x65\x78\xab\xcd\x43\x21" end - it "ignores NULL bytes between directives" do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x65\x78\xab\xcd" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x65\x78\xab\xcd" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -145,9 +169,21 @@ describe :array_pack_32bit_le, shared: true do str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78" end - it "ignores NULL bytes between directives" do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -197,9 +233,21 @@ describe :array_pack_32bit_be, shared: true do str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21" end - it "ignores NULL bytes between directives" do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -225,7 +273,7 @@ describe :array_pack_32bit_le_platform, shared: true do str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78" end - platform_is wordsize: 64 do + platform_is c_long_size: 64 do it "encodes the least significant 32 bits of a number that is greater than 32 bits" do [ [[0xff_7865_4321], "\x21\x43\x65\x78"], [[-0xff_7865_4321], "\xdf\xbc\x9a\x87"] @@ -251,7 +299,7 @@ describe :array_pack_32bit_be_platform, shared: true do str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21" end - platform_is wordsize: 64 do + platform_is c_long_size: 64 do it "encodes the least significant 32 bits of a number that is greater than 32 bits" do [ [[0xff_7865_4321], "\x78\x65\x43\x21"], [[-0xff_7865_4321], "\x87\x9a\xbc\xdf"] @@ -309,9 +357,21 @@ describe :array_pack_64bit_le, shared: true do str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" end - it "ignores NULL bytes between directives" do - str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -369,9 +429,21 @@ describe :array_pack_64bit_be, shared: true do str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" end - it "ignores NULL bytes between directives" do - str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/shared/numeric_basic.rb b/spec/ruby/core/array/pack/shared/numeric_basic.rb index 3ebdbc4c1a..545e215e64 100644 --- a/spec/ruby/core/array/pack/shared/numeric_basic.rb +++ b/spec/ruby/core/array/pack/shared/numeric_basic.rb @@ -4,15 +4,15 @@ describe :array_pack_numeric_basic, shared: true do end it "raises a TypeError when passed nil" do - lambda { [nil].pack(pack_format) }.should raise_error(TypeError) + -> { [nil].pack(pack_format) }.should raise_error(TypeError) end it "raises a TypeError when passed true" do - lambda { [true].pack(pack_format) }.should raise_error(TypeError) + -> { [true].pack(pack_format) }.should raise_error(TypeError) end it "raises a TypeError when passed false" do - lambda { [false].pack(pack_format) }.should raise_error(TypeError) + -> { [false].pack(pack_format) }.should raise_error(TypeError) end it "returns a binary string" do @@ -24,21 +24,27 @@ end describe :array_pack_integer, shared: true do it "raises a TypeError when the object does not respond to #to_int" do obj = mock('not an integer') - lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + -> { [obj].pack(pack_format) }.should raise_error(TypeError) end it "raises a TypeError when passed a String" do - lambda { ["5"].pack(pack_format) }.should raise_error(TypeError) + -> { ["5"].pack(pack_format) }.should raise_error(TypeError) end end describe :array_pack_float, shared: true do it "raises a TypeError if a String does not represent a floating point number" do - lambda { ["a"].pack(pack_format) }.should raise_error(TypeError) + -> { ["a"].pack(pack_format) }.should raise_error(TypeError) end - it "raises a TypeError when the object does not respond to #to_f" do - obj = mock('not an float') - lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + it "raises a TypeError when the object is not Numeric" do + obj = Object.new + -> { [obj].pack(pack_format) }.should raise_error(TypeError, /can't convert Object into Float/) + end + + it "raises a TypeError when the Numeric object does not respond to #to_f" do + klass = Class.new(Numeric) + obj = klass.new + -> { [obj].pack(pack_format) }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/array/pack/shared/string.rb b/spec/ruby/core/array/pack/shared/string.rb index 98e8c4d562..805f78b53b 100644 --- a/spec/ruby/core/array/pack/shared/string.rb +++ b/spec/ruby/core/array/pack/shared/string.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary describe :array_pack_string, shared: true do it "adds count bytes of a String to the output" do ["abc"].pack(pack_format(2)).should == "ab" @@ -17,11 +17,11 @@ describe :array_pack_string, shared: true do end it "raises an ArgumentError when the Array is empty" do - lambda { [].pack(pack_format) }.should raise_error(ArgumentError) + -> { [].pack(pack_format) }.should raise_error(ArgumentError) end it "raises an ArgumentError when the Array has too few elements" do - lambda { ["a"].pack(pack_format(nil, 2)) }.should raise_error(ArgumentError) + -> { ["a"].pack(pack_format(nil, 2)) }.should raise_error(ArgumentError) end it "calls #to_str to convert the element to a String" do @@ -33,14 +33,14 @@ describe :array_pack_string, shared: true do it "raises a TypeError when the object does not respond to #to_str" do obj = mock("not a string") - lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + -> { [obj].pack(pack_format) }.should raise_error(TypeError) end it "returns a string in encoding of common to the concatenated results" do f = pack_format("*") [ [["\u{3042 3044 3046 3048}", 0x2000B].pack(f+"U"), Encoding::BINARY], [["abcde\xd1", "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::BINARY], - [["a".force_encoding("ascii"), "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::BINARY], + [["a".dup.force_encoding("ascii"), "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::BINARY], # under discussion [ruby-dev:37294] [["\u{3042 3044 3046 3048}", 1].pack(f+"N"), Encoding::BINARY] ].should be_computed_by(:encoding) diff --git a/spec/ruby/core/array/pack/shared/taint.rb b/spec/ruby/core/array/pack/shared/taint.rb index 88f349cb24..2c2b011c34 100644 --- a/spec/ruby/core/array/pack/shared/taint.rb +++ b/spec/ruby/core/array/pack/shared/taint.rb @@ -1,33 +1,2 @@ describe :array_pack_taint, shared: true do - it "returns a tainted string when a pack argument is tainted" do - ["abcd".taint, 0x20].pack(pack_format("3C")).tainted?.should be_true - end - - it "does not return a tainted string when the array is tainted" do - ["abcd", 0x20].taint.pack(pack_format("3C")).tainted?.should be_false - end - - it "returns a tainted string when the format is tainted" do - ["abcd", 0x20].pack(pack_format("3C").taint).tainted?.should be_true - end - - it "returns a tainted string when an empty format is tainted" do - ["abcd", 0x20].pack("".taint).tainted?.should be_true - end - - it "returns a untrusted string when the format is untrusted" do - ["abcd", 0x20].pack(pack_format("3C").untrust).untrusted?.should be_true - end - - it "returns a untrusted string when the empty format is untrusted" do - ["abcd", 0x20].pack("".untrust).untrusted?.should be_true - end - - it "returns a untrusted string when a pack argument is untrusted" do - ["abcd".untrust, 0x20].pack(pack_format("3C")).untrusted?.should be_true - end - - it "returns a trusted string when the array is untrusted" do - ["abcd", 0x20].untrust.pack(pack_format("3C")).untrusted?.should be_false - end end diff --git a/spec/ruby/core/array/pack/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb index e16110c491..4d8eaef323 100644 --- a/spec/ruby/core/array/pack/shared/unicode.rb +++ b/spec/ruby/core/array/pack/shared/unicode.rb @@ -64,11 +64,23 @@ describe :array_pack_unicode, shared: true do it "raises a TypeError if #to_int does not return an Integer" do obj = mock('to_int') obj.should_receive(:to_int).and_return("5") - lambda { [obj].pack("U") }.should raise_error(TypeError) + -> { [obj].pack("U") }.should raise_error(TypeError) end - it "ignores NULL bytes between directives" do - [1, 2, 3].pack("U\x00U").should == "\x01\x02" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + [1, 2, 3].pack("U\x00U").should == "\x01\x02" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [1, 2, 3].pack("U\x00U") + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -76,11 +88,11 @@ describe :array_pack_unicode, shared: true do end it "raises a RangeError if passed a negative number" do - lambda { [-1].pack("U") }.should raise_error(RangeError) + -> { [-1].pack("U") }.should raise_error(RangeError) end it "raises a RangeError if passed a number larger than an unsigned 32-bit integer" do - lambda { [2**32].pack("U") }.should raise_error(RangeError) + -> { [2**32].pack("U") }.should raise_error(RangeError) end it "sets the output string to UTF-8 encoding" do diff --git a/spec/ruby/core/array/pack/u_spec.rb b/spec/ruby/core/array/pack/u_spec.rb index 8c3eb3a177..1f84095ac4 100644 --- a/spec/ruby/core/array/pack/u_spec.rb +++ b/spec/ruby/core/array/pack/u_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/basic' @@ -18,6 +18,16 @@ describe "Array#pack with format 'u'" do it_behaves_like :array_pack_arguments, 'u' it_behaves_like :array_pack_taint, 'u' + it "calls #to_str to convert an Object to a String" do + obj = mock("pack u string") + obj.should_receive(:to_str).and_return("``abcdef") + [obj].pack("u*").should == "(8&!A8F-D968`\n" + end + + it "will not implicitly convert a number to a string" do + -> { [0].pack('u') }.should raise_error(TypeError) + end + it "encodes an empty string as an empty string" do [""].pack("u").should == "" end @@ -112,16 +122,16 @@ describe "Array#pack with format 'u'" do it "raises a TypeError if #to_str does not return a String" do obj = mock("pack m non-string") - lambda { [obj].pack("u") }.should raise_error(TypeError) + -> { [obj].pack("u") }.should raise_error(TypeError) end it "raises a TypeError if passed nil" do - lambda { [nil].pack("u") }.should raise_error(TypeError) + -> { [nil].pack("u") }.should raise_error(TypeError) end it "raises a TypeError if passed an Integer" do - lambda { [0].pack("u") }.should raise_error(TypeError) - lambda { [bignum_value].pack("u") }.should raise_error(TypeError) + -> { [0].pack("u") }.should raise_error(TypeError) + -> { [bignum_value].pack("u") }.should raise_error(TypeError) end it "sets the output string to US-ASCII encoding" do diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb index 889f42bdf7..e770288d67 100644 --- a/spec/ruby/core/array/pack/w_spec.rb +++ b/spec/ruby/core/array/pack/w_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/basic' @@ -24,8 +24,20 @@ describe "Array#pack with format 'w'" do [obj].pack("w").should == "\x05" end - it "ignores NULL bytes between directives" do - [1, 2, 3].pack("w\x00w").should == "\x01\x02" + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + [1, 2, 3].pack("w\x00w").should == "\x01\x02" + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + [1, 2, 3].pack("w\x00w") + }.should raise_error(ArgumentError, /unknown pack directive/) + end end it "ignores spaces between directives" do @@ -33,7 +45,7 @@ describe "Array#pack with format 'w'" do end it "raises an ArgumentError when passed a negative value" do - lambda { [-1].pack("w") }.should raise_error(ArgumentError) + -> { [-1].pack("w") }.should raise_error(ArgumentError) end it "returns a binary string" do diff --git a/spec/ruby/core/array/pack/x_spec.rb b/spec/ruby/core/array/pack/x_spec.rb index 2662873d03..012fe4567f 100644 --- a/spec/ruby/core/array/pack/x_spec.rb +++ b/spec/ruby/core/array/pack/x_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/basic' @@ -30,6 +30,7 @@ describe "Array#pack with format 'x'" do it "does not add a NULL byte when passed the '*' modifier" do [].pack("x*").should == "" + [1, 2].pack("Cx*C").should == "\x01\x02" end end @@ -55,10 +56,10 @@ describe "Array#pack with format 'X'" do end it "raises an ArgumentError if the output string is empty" do - lambda { [1, 2, 3].pack("XC") }.should raise_error(ArgumentError) + -> { [1, 2, 3].pack("XC") }.should raise_error(ArgumentError) end it "raises an ArgumentError if the count modifier is greater than the bytes in the string" do - lambda { [1, 2, 3].pack("C2X3") }.should raise_error(ArgumentError) + -> { [1, 2, 3].pack("C2X3") }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/core/array/pack/z_spec.rb b/spec/ruby/core/array/pack/z_spec.rb index 82ce7b4a1c..60f8f7bf10 100644 --- a/spec/ruby/core/array/pack/z_spec.rb +++ b/spec/ruby/core/array/pack/z_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: binary -*- +# encoding: binary require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/basic' @@ -12,11 +12,21 @@ describe "Array#pack with format 'Z'" do it_behaves_like :array_pack_string, 'Z' it_behaves_like :array_pack_taint, 'Z' + it "calls #to_str to convert an Object to a String" do + obj = mock("pack Z string") + obj.should_receive(:to_str).and_return("``abcdef") + [obj].pack("Z*").should == "``abcdef\x00" + end + + it "will not implicitly convert a number to a string" do + -> { [0].pack('Z') }.should raise_error(TypeError) + end + it "adds all the bytes and appends a NULL byte when passed the '*' modifier" do ["abc"].pack("Z*").should == "abc\x00" end - it "padds the output with NULL bytes when the count exceeds the size of the String" do + it "pads the output with NULL bytes when the count exceeds the size of the String" do ["abc"].pack("Z6").should == "abc\x00\x00\x00" end diff --git a/spec/ruby/core/array/plus_spec.rb b/spec/ruby/core/array/plus_spec.rb index 7692163980..b7153fd3ef 100644 --- a/spec/ruby/core/array/plus_spec.rb +++ b/spec/ruby/core/array/plus_spec.rb @@ -14,10 +14,23 @@ describe "Array#+" do (ary + ary).should == [1, 2, 3, 1, 2, 3] end - it "tries to convert the passed argument to an Array using #to_ary" do - obj = mock('["x", "y"]') - obj.should_receive(:to_ary).and_return(["x", "y"]) - ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"] + describe "converts the passed argument to an Array using #to_ary" do + it "successfully concatenates the resulting array from the #to_ary call" do + obj = mock('["x", "y"]') + obj.should_receive(:to_ary).and_return(["x", "y"]) + ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"] + end + + it "raises a TypeError if the given argument can't be converted to an array" do + -> { [1, 2, 3] + nil }.should raise_error(TypeError) + -> { [1, 2, 3] + "abc" }.should raise_error(TypeError) + end + + it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do + obj = mock("hello") + obj.should_receive(:to_ary).and_raise(NoMethodError) + -> { [1, 2, 3] + obj }.should raise_error(NoMethodError) + end end it "properly handles recursive arrays" do @@ -40,18 +53,4 @@ describe "Array#+" do it "does not call to_ary on array subclasses" do ([5, 6] + ArraySpecs::ToAryArray[1, 2]).should == [5, 6, 1, 2] end - - it "does not get infected even if an original array is tainted" do - ([1, 2] + [3, 4]).tainted?.should be_false - ([1, 2].taint + [3, 4]).tainted?.should be_false - ([1, 2] + [3, 4].taint).tainted?.should be_false - ([1, 2].taint + [3, 4].taint).tainted?.should be_false - end - - it "does not infected even if an original array is untrusted" do - ([1, 2] + [3, 4]).untrusted?.should be_false - ([1, 2].untrust + [3, 4]).untrusted?.should be_false - ([1, 2] + [3, 4].untrust).untrusted?.should be_false - ([1, 2].untrust + [3, 4].untrust).untrusted?.should be_false - end end diff --git a/spec/ruby/core/array/pop_spec.rb b/spec/ruby/core/array/pop_spec.rb index 335a0f2b60..2a19408660 100644 --- a/spec/ruby/core/array/pop_spec.rb +++ b/spec/ruby/core/array/pop_spec.rb @@ -30,28 +30,12 @@ describe "Array#pop" do array.pop.should == [1, 'two', 3.0, array, array, array, array] end - it "keeps taint status" do - a = [1, 2].taint - a.pop - a.tainted?.should be_true - a.pop - a.tainted?.should be_true + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.pop }.should raise_error(FrozenError) end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.pop }.should raise_error(frozen_error_class) - end - - it "raises a #{frozen_error_class} on an empty frozen array" do - lambda { ArraySpecs.empty_frozen_array.pop }.should raise_error(frozen_error_class) - end - - it "keeps untrusted status" do - a = [1, 2].untrust - a.pop - a.untrusted?.should be_true - a.pop - a.untrusted?.should be_true + it "raises a FrozenError on an empty frozen array" do + -> { ArraySpecs.empty_frozen_array.pop }.should raise_error(FrozenError) end describe "passed a number n as an argument" do @@ -105,7 +89,7 @@ describe "Array#pop" do end it "raises an ArgumentError if n is negative" do - lambda{ [1, 2, 3].pop(-1) }.should raise_error(ArgumentError) + ->{ [1, 2, 3].pop(-1) }.should raise_error(ArgumentError) end it "tries to convert n to an Integer using #to_int" do @@ -120,49 +104,21 @@ describe "Array#pop" do end it "raises a TypeError when the passed n cannot be coerced to Integer" do - lambda{ [1, 2].pop("cat") }.should raise_error(TypeError) - lambda{ [1, 2].pop(nil) }.should raise_error(TypeError) + ->{ [1, 2].pop("cat") }.should raise_error(TypeError) + ->{ [1, 2].pop(nil) }.should raise_error(TypeError) end it "raises an ArgumentError if more arguments are passed" do - lambda{ [1, 2].pop(1, 2) }.should raise_error(ArgumentError) + ->{ [1, 2].pop(1, 2) }.should raise_error(ArgumentError) end it "does not return subclass instances with Array subclass" do ArraySpecs::MyArray[1, 2, 3].pop(2).should be_an_instance_of(Array) end - it "returns an untainted array even if the array is tainted" do - ary = [1, 2].taint - ary.pop(2).tainted?.should be_false - ary.pop(0).tainted?.should be_false - end - - it "keeps taint status" do - a = [1, 2].taint - a.pop(2) - a.tainted?.should be_true - a.pop(2) - a.tainted?.should be_true - end - - it "returns a trusted array even if the array is untrusted" do - ary = [1, 2].untrust - ary.pop(2).untrusted?.should be_false - ary.pop(0).untrusted?.should be_false - end - - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.pop(2) }.should raise_error(frozen_error_class) - lambda { ArraySpecs.frozen_array.pop(0) }.should raise_error(frozen_error_class) - end - - it "keeps untrusted status" do - a = [1, 2].untrust - a.pop(2) - a.untrusted?.should be_true - a.pop(2) - a.untrusted?.should be_true + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.pop(2) }.should raise_error(FrozenError) + -> { ArraySpecs.frozen_array.pop(0) }.should raise_error(FrozenError) end end end diff --git a/spec/ruby/core/array/prepend_spec.rb b/spec/ruby/core/array/prepend_spec.rb index 22230ec300..368b8dcfcd 100644 --- a/spec/ruby/core/array/prepend_spec.rb +++ b/spec/ruby/core/array/prepend_spec.rb @@ -2,8 +2,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/unshift' -ruby_version_is "2.5" do - describe "Array#prepend" do - it_behaves_like :array_unshift, :prepend - end +describe "Array#prepend" do + it_behaves_like :array_unshift, :prepend end diff --git a/spec/ruby/core/array/product_spec.rb b/spec/ruby/core/array/product_spec.rb index 7d810b6196..6fb3818508 100644 --- a/spec/ruby/core/array/product_spec.rb +++ b/spec/ruby/core/array/product_spec.rb @@ -3,12 +3,17 @@ require_relative 'fixtures/classes' describe "Array#product" do it "returns converted arguments using :to_ary" do - lambda{ [1].product(2..3) }.should raise_error(TypeError) + ->{ [1].product(2..3) }.should raise_error(TypeError) ar = ArraySpecs::ArrayConvertible.new(2,3) [1].product(ar).should == [[1,2],[1,3]] ar.called.should == :to_ary end + it "returns converted arguments using :method_missing" do + ar = ArraySpecs::ArrayMethodMissing.new(2,3) + [1].product(ar).should == [[1,2],[1,3]] + end + it "returns the expected result" do [1,2].product([3,4,5],[6,8]).should == [[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8], [2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]] @@ -24,7 +29,7 @@ describe "Array#product" do it "does not attempt to produce an unreasonable number of products" do a = (0..100).to_a - lambda do + -> do a.product(a, a, a, a, a, a, a, a, a, a) end.should raise_error(RangeError) end @@ -49,7 +54,7 @@ describe "Array#product" do it "will ignore unreasonable numbers of products and yield anyway" do a = (0..100).to_a - lambda do + -> do a.product(a, a, a, a, a, a, a, a, a, a) end.should raise_error(RangeError) end diff --git a/spec/ruby/core/array/rassoc_spec.rb b/spec/ruby/core/array/rassoc_spec.rb index 62fbd40611..632a05e8b3 100644 --- a/spec/ruby/core/array/rassoc_spec.rb +++ b/spec/ruby/core/array/rassoc_spec.rb @@ -35,4 +35,18 @@ describe "Array#rassoc" do [[1, :foobar, o], [2, o, 1], [3, mock('foo')]].rassoc(key).should == [2, o, 1] end + + ruby_version_is "3.3" do + it "calls to_ary on non-array elements" do + s1 = [1, 2] + s2 = ArraySpecs::ArrayConvertible.new(2, 3) + a = [s1, s2] + + s1.should_not_receive(:to_ary) + a.rassoc(2).should equal(s1) + + a.rassoc(3).should == [2, 3] + s2.called.should equal(:to_ary) + end + end end diff --git a/spec/ruby/core/array/reject_spec.rb b/spec/ruby/core/array/reject_spec.rb index 6ae2581ff5..81a467e364 100644 --- a/spec/ruby/core/array/reject_spec.rb +++ b/spec/ruby/core/array/reject_spec.rb @@ -2,6 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/enumeratorize' require_relative 'shared/delete_if' +require_relative 'shared/iterable_and_tolerating_size_increasing' require_relative '../enumerable/shared/enumeratorized' describe "Array#reject" do @@ -47,6 +48,10 @@ describe "Array#reject" do it_behaves_like :enumeratorized_with_origin_size, :reject, [1,2,3] end +describe "Array#reject" do + it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject +end + describe "Array#reject!" do it "removes elements for which block is true" do a = [3, 4, 5, 6, 7, 8, 9, 10, 11] @@ -103,12 +108,17 @@ describe "Array#reject!" do ArraySpecs.frozen_array.reject!.should be_an_instance_of(Enumerator) end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.reject! {} }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.reject! {} }.should raise_error(FrozenError) + end + + it "raises a FrozenError on an empty frozen array" do + -> { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(FrozenError) end - it "raises a #{frozen_error_class} on an empty frozen array" do - lambda { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array only during iteration if called without a block" do + enum = ArraySpecs.frozen_array.reject! + -> { enum.each {} }.should raise_error(FrozenError) end it "does not truncate the array is the block raises an exception" do @@ -141,3 +151,8 @@ describe "Array#reject!" do it_behaves_like :enumeratorized_with_origin_size, :reject!, [1,2,3] it_behaves_like :delete_if, :reject! end + +describe "Array#reject!" do + @value_to_return = -> _ { false } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject! +end diff --git a/spec/ruby/core/array/reverse_each_spec.rb b/spec/ruby/core/array/reverse_each_spec.rb index 28b8bfcb34..59dabcd33d 100644 --- a/spec/ruby/core/array/reverse_each_spec.rb +++ b/spec/ruby/core/array/reverse_each_spec.rb @@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized' # Modifying a collection while the contents are being iterated # gives undefined behavior. See -# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633 +# https://blade.ruby-lang.org/ruby-core/23633 describe "Array#reverse_each" do before :each do @@ -38,6 +38,20 @@ describe "Array#reverse_each" do [1, 2, 3].reverse_each.size.should == 3 end + it "tolerates increasing an array size during iteration" do + array = [:a, :b, :c] + ScratchPad.record [] + i = 0 + + array.reverse_each do |e| + ScratchPad << e + array.prepend i if i < 100 + i += 1 + end + + ScratchPad.recorded.should == [:c, :a, 1] + end + it_behaves_like :enumeratorize, :reverse_each it_behaves_like :enumeratorized_with_origin_size, :reverse_each, [1,2,3] end diff --git a/spec/ruby/core/array/reverse_spec.rb b/spec/ruby/core/array/reverse_spec.rb index d8ff26639d..05dbd2efcf 100644 --- a/spec/ruby/core/array/reverse_spec.rb +++ b/spec/ruby/core/array/reverse_spec.rb @@ -36,7 +36,7 @@ describe "Array#reverse!" do array.reverse!.should == [array, array, array, array, array, 3.0, 'two', 1] end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.reverse! }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.reverse! }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/rindex_spec.rb b/spec/ruby/core/array/rindex_spec.rb index 175c7bcfe2..13de88818c 100644 --- a/spec/ruby/core/array/rindex_spec.rb +++ b/spec/ruby/core/array/rindex_spec.rb @@ -4,7 +4,7 @@ require_relative '../enumerable/shared/enumeratorized' # Modifying a collection while the contents are being iterated # gives undefined behavior. See -# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633 +# https://blade.ruby-lang.org/ruby-core/23633 describe "Array#rindex" do it "returns the first index backwards from the end where element == to object" do @@ -68,6 +68,21 @@ describe "Array#rindex" do seen.should == [3] end + it "tolerates increasing an array size during iteration" do + array = [:a, :b, :c] + ScratchPad.record [] + i = 0 + + array.rindex do |e| + ScratchPad << e + array.prepend i if i < 100 + i += 1 + false + end + + ScratchPad.recorded.should == [:c, :a, 1] + end + describe "given no argument and no block" do it "produces an Enumerator" do enum = [4, 2, 1, 5, 1, 3].rindex diff --git a/spec/ruby/core/array/rotate_spec.rb b/spec/ruby/core/array/rotate_spec.rb index 6450d3892b..60dcc8b113 100644 --- a/spec/ruby/core/array/rotate_spec.rb +++ b/spec/ruby/core/array/rotate_spec.rb @@ -27,10 +27,10 @@ describe "Array#rotate" do end it "raises a TypeError if not passed an integer-like argument" do - lambda { + -> { [1, 2].rotate(nil) }.should raise_error(TypeError) - lambda { + -> { [1, 2].rotate("4") }.should raise_error(TypeError) end @@ -46,7 +46,7 @@ describe "Array#rotate" do end it "does not mutate the receiver" do - lambda { + -> { [].freeze.rotate [2].freeze.rotate(2) [1,2,3].freeze.rotate(-3) @@ -94,10 +94,10 @@ describe "Array#rotate!" do end it "raises a TypeError if not passed an integer-like argument" do - lambda { + -> { [1, 2].rotate!(nil) }.should raise_error(TypeError) - lambda { + -> { [1, 2].rotate!("4") }.should raise_error(TypeError) end @@ -121,9 +121,9 @@ describe "Array#rotate!" do a.should == [] end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { [1, 2, 3].freeze.rotate!(0) }.should raise_error(frozen_error_class) - lambda { [1].freeze.rotate!(42) }.should raise_error(frozen_error_class) - lambda { [].freeze.rotate! }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { [1, 2, 3].freeze.rotate!(0) }.should raise_error(FrozenError) + -> { [1].freeze.rotate!(42) }.should raise_error(FrozenError) + -> { [].freeze.rotate! }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb index 3bd5d046cc..d4e945152d 100644 --- a/spec/ruby/core/array/sample_spec.rb +++ b/spec/ruby/core/array/sample_spec.rb @@ -3,26 +3,36 @@ require_relative 'fixtures/classes' describe "Array#sample" do it "samples evenly" do - ary = [0, 1, 2, 3] - 3.times do |i| - counts = [0, 0, 0, 0] - 4000.times do - counts[ary.sample(3)[i]] += 1 - end - counts.each do |count| - (800..1200).should include(count) - end - end + ArraySpecs.measure_sample_fairness(4, 1, 400) + ArraySpecs.measure_sample_fairness(4, 2, 400) + ArraySpecs.measure_sample_fairness(4, 3, 400) + ArraySpecs.measure_sample_fairness(40, 3, 400) + ArraySpecs.measure_sample_fairness(40, 4, 400) + ArraySpecs.measure_sample_fairness(40, 8, 400) + ArraySpecs.measure_sample_fairness(40, 16, 400) + ArraySpecs.measure_sample_fairness_large_sample_size(100, 80, 4000) end it "returns nil for an empty Array" do [].sample.should be_nil end + it "returns nil for an empty array when called without n and a Random is given" do + [].sample(random: Random.new(42)).should be_nil + end + it "returns a single value when not passed a count" do [4].sample.should equal(4) end + it "returns a single value when not passed a count and a Random is given" do + [4].sample(random: Random.new(42)).should equal(4) + end + + it "returns a single value when not passed a count and a Random class is given" do + [4].sample(random: Random).should equal(4) + end + it "returns an empty Array when passed zero" do [4].sample(0).should == [] end @@ -57,7 +67,7 @@ describe "Array#sample" do end it "raises ArgumentError when passed a negative count" do - lambda { [1, 2].sample(-1) }.should raise_error(ArgumentError) + -> { [1, 2].sample(-1) }.should raise_error(ArgumentError) end it "does not return subclass instances with Array subclass" do @@ -65,38 +75,21 @@ describe "Array#sample" do end describe "with options" do - it "calls #to_hash to convert the passed Object" do - obj = mock("array_sample") - obj.should_receive(:to_hash).and_return({}) - obj.should_not_receive(:to_int) - - [1, 2].sample(obj).should be_an_instance_of(Fixnum) - end - - it "calls #to_int on the first argument and #to_hash on the second when passed Objects" do - count = mock("array_sample_count") - count.should_receive(:to_int).and_return(2) - options = mock("array_sample_options") - options.should_receive(:to_hash).and_return({}) - - [1, 2].sample(count, options).size.should == 2 - end - it "calls #rand on the Object passed by the :random key in the arguments Hash" do obj = mock("array_sample_random") obj.should_receive(:rand).and_return(0.5) - [1, 2].sample(random: obj).should be_an_instance_of(Fixnum) + [1, 2].sample(random: obj).should be_an_instance_of(Integer) end it "raises a NoMethodError if an object passed for the RNG does not define #rand" do obj = BasicObject.new - lambda { [1, 2].sample(random: obj) }.should raise_error(NoMethodError) + -> { [1, 2].sample(random: obj) }.should raise_error(NoMethodError) end - describe "when the object returned by #rand is a Fixnum" do - it "uses the fixnum as index" do + describe "when the object returned by #rand is an Integer" do + it "uses the integer as index" do random = mock("array_sample_random_ret") random.should_receive(:rand).and_return(0) @@ -112,19 +105,26 @@ describe "Array#sample" do random = mock("array_sample_random") random.should_receive(:rand).and_return(-1) - lambda { [1, 2].sample(random: random) }.should raise_error(RangeError) + -> { [1, 2].sample(random: random) }.should raise_error(RangeError) end it "raises a RangeError if the value is equal to the Array size" do random = mock("array_sample_random") random.should_receive(:rand).and_return(2) - lambda { [1, 2].sample(random: random) }.should raise_error(RangeError) + -> { [1, 2].sample(random: random) }.should raise_error(RangeError) + end + + it "raises a RangeError if the value is greater than the Array size" do + random = mock("array_sample_random") + random.should_receive(:rand).and_return(3) + + -> { [1, 2].sample(random: random) }.should raise_error(RangeError) end end end - describe "when the object returned by #rand is not a Fixnum but responds to #to_int" do + describe "when the object returned by #rand is not an Integer but responds to #to_int" do it "calls #to_int on the Object" do value = mock("array_sample_random_value") value.should_receive(:to_int).and_return(1) @@ -140,7 +140,7 @@ describe "Array#sample" do random = mock("array_sample_random") random.should_receive(:rand).and_return(value) - lambda { [1, 2].sample(random: random) }.should raise_error(RangeError) + -> { [1, 2].sample(random: random) }.should raise_error(RangeError) end it "raises a RangeError if the value is equal to the Array size" do @@ -149,7 +149,7 @@ describe "Array#sample" do random = mock("array_sample_random") random.should_receive(:rand).and_return(value) - lambda { [1, 2].sample(random: random) }.should raise_error(RangeError) + -> { [1, 2].sample(random: random) }.should raise_error(RangeError) end end end diff --git a/spec/ruby/core/array/shared/clone.rb b/spec/ruby/core/array/shared/clone.rb index 95d0d0a3d5..035b45ec99 100644 --- a/spec/ruby/core/array/shared/clone.rb +++ b/spec/ruby/core/array/shared/clone.rb @@ -17,26 +17,4 @@ describe :array_clone, shared: true do b.should == a b.__id__.should_not == a.__id__ end - - it "copies taint status from the original" do - a = [1, 2, 3, 4] - b = [1, 2, 3, 4] - a.taint - aa = a.send @method - bb = b.send @method - - aa.tainted?.should == true - bb.tainted?.should == false - end - - it "copies untrusted status from the original" do - a = [1, 2, 3, 4] - b = [1, 2, 3, 4] - a.untrust - aa = a.send @method - bb = b.send @method - - aa.untrusted?.should == true - bb.untrusted?.should == false - end end diff --git a/spec/ruby/core/array/shared/collect.rb b/spec/ruby/core/array/shared/collect.rb index 8ad6e61855..030302ced6 100644 --- a/spec/ruby/core/array/shared/collect.rb +++ b/spec/ruby/core/array/shared/collect.rb @@ -1,4 +1,5 @@ require_relative '../../enumerable/shared/enumeratorized' +require_relative '../shared/iterable_and_tolerating_size_increasing' describe :array_collect, shared: true do it "returns a copy of array with each element replaced by the value returned by block" do @@ -37,27 +38,17 @@ describe :array_collect, shared: true do it "raises an ArgumentError when no block and with arguments" do a = [1, 2, 3] - lambda { + -> { a.send(@method, :foo) }.should raise_error(ArgumentError) end - it "does not copy tainted status" do - a = [1, 2, 3] - a.taint - a.send(@method){|x| x}.tainted?.should be_false - end - - it "does not copy untrusted status" do - a = [1, 2, 3] - a.untrust - a.send(@method){|x| x}.untrusted?.should be_false - end - before :all do @object = [1, 2, 3, 4] end it_should_behave_like :enumeratorized_with_origin_size + + it_should_behave_like :array_iterable_and_tolerating_size_increasing end describe :array_collect_b, shared: true do @@ -94,43 +85,57 @@ describe :array_collect_b, shared: true do a.should == ["1!", "2!", "3!"] end - it "keeps tainted status" do - a = [1, 2, 3] - a.taint - a.tainted?.should be_true - a.send(@method){|x| x} - a.tainted?.should be_true - end - - it "keeps untrusted status" do - a = [1, 2, 3] - a.untrust - a.send(@method){|x| x} - a.untrusted?.should be_true - end - describe "when frozen" do - it "raises a #{frozen_error_class}" do - lambda { ArraySpecs.frozen_array.send(@method) {} }.should raise_error(frozen_error_class) + it "raises a FrozenError" do + -> { ArraySpecs.frozen_array.send(@method) {} }.should raise_error(FrozenError) end - it "raises a #{frozen_error_class} when empty" do - lambda { ArraySpecs.empty_frozen_array.send(@method) {} }.should raise_error(frozen_error_class) + it "raises a FrozenError when empty" do + -> { ArraySpecs.empty_frozen_array.send(@method) {} }.should raise_error(FrozenError) end - it "raises a #{frozen_error_class} when calling #each on the returned Enumerator" do + it "raises a FrozenError when calling #each on the returned Enumerator" do enumerator = ArraySpecs.frozen_array.send(@method) - lambda { enumerator.each {|x| x } }.should raise_error(frozen_error_class) + -> { enumerator.each {|x| x } }.should raise_error(FrozenError) end - it "raises a #{frozen_error_class} when calling #each on the returned Enumerator when empty" do + it "raises a FrozenError when calling #each on the returned Enumerator when empty" do enumerator = ArraySpecs.empty_frozen_array.send(@method) - lambda { enumerator.each {|x| x } }.should raise_error(frozen_error_class) + -> { enumerator.each {|x| x } }.should raise_error(FrozenError) + end + end + + it "does not truncate the array is the block raises an exception" do + a = [1, 2, 3] + begin + a.send(@method) { raise StandardError, 'Oops' } + rescue + end + + a.should == [1, 2, 3] + end + + it "only changes elements before error is raised, keeping the element which raised an error." do + a = [1, 2, 3, 4] + begin + a.send(@method) do |e| + case e + when 1 then -1 + when 2 then -2 + when 3 then raise StandardError, 'Oops' + else 0 + end + end + rescue StandardError end + + a.should == [-1, -2, 3, 4] end before :all do @object = [1, 2, 3, 4] end it_should_behave_like :enumeratorized_with_origin_size + + it_should_behave_like :array_iterable_and_tolerating_size_increasing end diff --git a/spec/ruby/core/array/shared/difference.rb b/spec/ruby/core/array/shared/difference.rb index c43a6375e0..3e69050d82 100644 --- a/spec/ruby/core/array/shared/difference.rb +++ b/spec/ruby/core/array/shared/difference.rb @@ -27,7 +27,7 @@ describe :array_binary_difference, shared: true do it "raises a TypeError if the argument cannot be coerced to an Array by calling #to_ary" do obj = mock('not an array') - lambda { [1, 2, 3].send(@method, obj) }.should raise_error(TypeError) + -> { [1, 2, 3].send(@method, obj) }.should raise_error(TypeError) end it "does not return subclass instance for Array subclasses" do diff --git a/spec/ruby/core/array/shared/index.rb b/spec/ruby/core/array/shared/index.rb index a9896554f2..a4a0adbab6 100644 --- a/spec/ruby/core/array/shared/index.rb +++ b/spec/ruby/core/array/shared/index.rb @@ -1,3 +1,5 @@ +require_relative '../shared/iterable_and_tolerating_size_increasing' + describe :array_index, shared: true do it "returns the index of the first element == to object" do x = mock('3') @@ -34,4 +36,6 @@ describe :array_index, shared: true do [].send(@method).should be_an_instance_of(Enumerator) end end + + it_should_behave_like :array_iterable_and_tolerating_size_increasing end diff --git a/spec/ruby/core/array/shared/inspect.rb b/spec/ruby/core/array/shared/inspect.rb index 1bcc9f9ca8..af5128c645 100644 --- a/spec/ruby/core/array/shared/inspect.rb +++ b/spec/ruby/core/array/shared/inspect.rb @@ -19,7 +19,7 @@ describe :array_inspect, shared: true do end it "does not call #to_s on a String returned from #inspect" do - str = "abc" + str = +"abc" str.should_not_receive(:to_s) [str].send(@method).should == '["abc"]' @@ -55,7 +55,7 @@ describe :array_inspect, shared: true do obj.should_receive(:inspect).and_return(obj) obj.should_receive(:to_s).and_raise(Exception) - lambda { [obj].send(@method) }.should raise_error(Exception) + -> { [obj].send(@method) }.should raise_error(Exception) end it "represents a recursive element with '[...]'" do @@ -64,30 +64,6 @@ describe :array_inspect, shared: true do ArraySpecs.empty_recursive_array.send(@method).should == "[[...]]" end - it "taints the result if the Array is non-empty and tainted" do - [1, 2].taint.send(@method).tainted?.should be_true - end - - it "does not taint the result if the Array is tainted but empty" do - [].taint.send(@method).tainted?.should be_false - end - - it "taints the result if an element is tainted" do - ["str".taint].send(@method).tainted?.should be_true - end - - it "untrusts the result if the Array is untrusted" do - [1, 2].untrust.send(@method).untrusted?.should be_true - end - - it "does not untrust the result if the Array is untrusted but empty" do - [].untrust.send(@method).untrusted?.should be_false - end - - it "untrusts the result if an element is untrusted" do - ["str".untrust].send(@method).untrusted?.should be_true - end - describe "with encoding" do before :each do @default_external_encoding = Encoding.default_external @@ -122,8 +98,8 @@ describe :array_inspect, shared: true do end it "does not raise if inspected result is not default external encoding" do - utf_16be = mock("utf_16be") - utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode!(Encoding::UTF_16BE)) + utf_16be = mock(+"utf_16be") + utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE)) [utf_16be].send(@method).should == '["utf_16be \u3042"]' end diff --git a/spec/ruby/core/array/shared/intersection.rb b/spec/ruby/core/array/shared/intersection.rb new file mode 100644 index 0000000000..0b4166ab63 --- /dev/null +++ b/spec/ruby/core/array/shared/intersection.rb @@ -0,0 +1,85 @@ +describe :array_intersection, shared: true do + it "creates an array with elements common to both arrays (intersection)" do + [].send(@method, []).should == [] + [1, 2].send(@method, []).should == [] + [].send(@method, [1, 2]).should == [] + [ 1, 3, 5 ].send(@method, [ 1, 2, 3 ]).should == [1, 3] + end + + it "creates an array with no duplicates" do + [ 1, 1, 3, 5 ].send(@method, [ 1, 2, 3 ]).uniq!.should == nil + end + + it "creates an array with elements in order they are first encountered" do + [ 1, 2, 3, 2, 5, 6, 7, 8 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5] # array > other + [ 5, 2, 3, 4 ].send(@method, [ 1, 2, 3, 2, 5, 6, 7, 8 ]).should == [5, 2, 3] # array < other + end + + it "does not modify the original Array" do + a = [1, 1, 3, 5] + a.send(@method, [1, 2, 3]).should == [1, 3] + a.should == [1, 1, 3, 5] + end + + it "properly handles recursive arrays" do + empty = ArraySpecs.empty_recursive_array + empty.send(@method, empty).should == empty + + ArraySpecs.recursive_array.send(@method, []).should == [] + [].send(@method, ArraySpecs.recursive_array).should == [] + + ArraySpecs.recursive_array.send(@method, ArraySpecs.recursive_array).should == [1, 'two', 3.0, ArraySpecs.recursive_array] + end + + it "tries to convert the passed argument to an Array using #to_ary" do + obj = mock('[1,2,3]') + obj.should_receive(:to_ary).and_return([1, 2, 3]) + [1, 2].send(@method, obj).should == ([1, 2]) + end + + it "determines equivalence between elements in the sense of eql?" do + not_supported_on :opal do + [5.0, 4.0].send(@method, [5, 4]).should == [] + end + + str = "x" + [str].send(@method, [str.dup]).should == [str] + + obj1 = mock('1') + obj2 = mock('2') + obj1.stub!(:hash).and_return(0) + obj2.stub!(:hash).and_return(0) + obj1.should_receive(:eql?).at_least(1).and_return(true) + obj2.stub!(:eql?).and_return(true) + + [obj1].send(@method, [obj2]).should == [obj1] + [obj1, obj1, obj2, obj2].send(@method, [obj2]).should == [obj1] + + obj1 = mock('3') + obj2 = mock('4') + obj1.stub!(:hash).and_return(0) + obj2.stub!(:hash).and_return(0) + obj1.should_receive(:eql?).at_least(1).and_return(false) + + [obj1].send(@method, [obj2]).should == [] + [obj1, obj1, obj2, obj2].send(@method, [obj2]).should == [obj2] + end + + it "does return subclass instances for Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].send(@method, []).should be_an_instance_of(Array) + ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array) + [].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array) + end + + it "does not call to_ary on array subclasses" do + [5, 6].send(@method, ArraySpecs::ToAryArray[1, 2, 5, 6]).should == [5, 6] + end + + it "properly handles an identical item even when its #eql? isn't reflexive" do + x = mock('x') + x.stub!(:hash).and_return(42) + x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI. + + [x].send(@method, [x]).should == [x] + end +end diff --git a/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb b/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb new file mode 100644 index 0000000000..3e73bad44b --- /dev/null +++ b/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb @@ -0,0 +1,25 @@ +describe :array_iterable_and_tolerating_size_increasing, shared: true do + before do + @value_to_return ||= -> _ { nil } + end + + it "tolerates increasing an array size during iteration" do + # The goal is to trigger potential reallocation of internal array storage, so we: + # - use elements of different types, starting with the less generic (Integer) + # - add reasonably big number of new elements (~ 100) + array = [1, 2, 3] # to test some methods we need several uniq elements + array_to_join = [:a, :b, :c] + (4..100).to_a + + ScratchPad.record [] + i = 0 + + array.send(@method) do |e| + ScratchPad << e + array << array_to_join[i] if i < array_to_join.size + i += 1 + @value_to_return.call(e) + end + + ScratchPad.recorded.should == [1, 2, 3] + array_to_join + end +end diff --git a/spec/ruby/core/array/shared/join.rb b/spec/ruby/core/array/shared/join.rb index 0d07e93b2c..507b13e3c8 100644 --- a/spec/ruby/core/array/shared/join.rb +++ b/spec/ruby/core/array/shared/join.rb @@ -49,41 +49,13 @@ describe :array_join_with_default_separator, shared: true do it "raises a NoMethodError if an element does not respond to #to_str, #to_ary, or #to_s" do obj = mock('o') class << obj; undef :to_s; end - lambda { [1, obj].send(@method) }.should raise_error(NoMethodError) + -> { [1, obj].send(@method) }.should raise_error(NoMethodError) end it "raises an ArgumentError when the Array is recursive" do - lambda { ArraySpecs.recursive_array.send(@method) }.should raise_error(ArgumentError) - lambda { ArraySpecs.head_recursive_array.send(@method) }.should raise_error(ArgumentError) - lambda { ArraySpecs.empty_recursive_array.send(@method) }.should raise_error(ArgumentError) - end - - it "taints the result if the Array is tainted and non-empty" do - [1, 2].taint.send(@method).tainted?.should be_true - end - - it "does not taint the result if the Array is tainted but empty" do - [].taint.send(@method).tainted?.should be_false - end - - it "taints the result if the result of coercing an element is tainted" do - s = mock("taint") - s.should_receive(:to_s).and_return("str".taint) - [s].send(@method).tainted?.should be_true - end - - it "untrusts the result if the Array is untrusted and non-empty" do - [1, 2].untrust.send(@method).untrusted?.should be_true - end - - it "does not untrust the result if the Array is untrusted but empty" do - [].untrust.send(@method).untrusted?.should be_false - end - - it "untrusts the result if the result of coercing an element is untrusted" do - s = mock("untrust") - s.should_receive(:to_s).and_return("str".untrust) - [s].send(@method).untrusted?.should be_true + -> { ArraySpecs.recursive_array.send(@method) }.should raise_error(ArgumentError) + -> { ArraySpecs.head_recursive_array.send(@method) }.should raise_error(ArgumentError) + -> { ArraySpecs.empty_recursive_array.send(@method) }.should raise_error(ArgumentError) end it "uses the first encoding when other strings are compatible" do @@ -109,7 +81,20 @@ describe :array_join_with_default_separator, shared: true do it "fails for arrays with incompatibly-encoded strings" do ary_utf8_bad_binary = ArraySpecs.array_with_utf8_and_binary_strings - lambda { ary_utf8_bad_binary.send(@method) }.should raise_error(EncodingError) + -> { ary_utf8_bad_binary.send(@method) }.should raise_error(EncodingError) + end + + context "when $, is not nil" do + before do + suppress_warning do + $, = '*' + end + end + + it "warns" do + -> { [].join }.should complain(/warning: \$, is set to non-nil value/) + -> { [].join(nil) }.should complain(/warning: \$, is set to non-nil value/) + end end end @@ -124,40 +109,4 @@ describe :array_join_with_string_separator, shared: true do [1, [2, [3, 4], 5], 6].send(@method, ":").should == "1:2:3:4:5:6" [1, [2, ArraySpecs::MyArray[3, 4], 5], 6].send(@method, ":").should == "1:2:3:4:5:6" end - - describe "with a tainted separator" do - before :each do - @sep = ":".taint - end - - it "does not taint the result if the array is empty" do - [].send(@method, @sep).tainted?.should be_false - end - - it "does not taint the result if the array has only one element" do - [1].send(@method, @sep).tainted?.should be_false - end - - it "taints the result if the array has two or more elements" do - [1, 2].send(@method, @sep).tainted?.should be_true - end - end - - describe "with an untrusted separator" do - before :each do - @sep = ":".untrust - end - - it "does not untrust the result if the array is empty" do - [].send(@method, @sep).untrusted?.should be_false - end - - it "does not untrust the result if the array has only one element" do - [1].send(@method, @sep).untrusted?.should be_false - end - - it "untrusts the result if the array has two or more elements" do - [1, 2].send(@method, @sep).untrusted?.should be_true - end - end end diff --git a/spec/ruby/core/array/shared/keep_if.rb b/spec/ruby/core/array/shared/keep_if.rb index 906ad9b9e2..43a047c0a7 100644 --- a/spec/ruby/core/array/shared/keep_if.rb +++ b/spec/ruby/core/array/shared/keep_if.rb @@ -1,4 +1,5 @@ require_relative '../../enumerable/shared/enumeratorized' +require_relative '../shared/iterable_and_tolerating_size_increasing' describe :keep_if, shared: true do it "deletes elements for which the block returns a false value" do @@ -37,24 +38,58 @@ describe :keep_if, shared: true do describe "with truthy block" do it "keeps elements after any exception" do - lambda { @frozen.send(@method) { true } }.should raise_error(Exception) + -> { @frozen.send(@method) { true } }.should raise_error(Exception) @frozen.should == @origin end - it "raises a #{frozen_error_class}" do - lambda { @frozen.send(@method) { true } }.should raise_error(frozen_error_class) + it "raises a FrozenError" do + -> { @frozen.send(@method) { true } }.should raise_error(FrozenError) end end describe "with falsy block" do it "keeps elements after any exception" do - lambda { @frozen.send(@method) { false } }.should raise_error(Exception) + -> { @frozen.send(@method) { false } }.should raise_error(Exception) @frozen.should == @origin end - it "raises a #{frozen_error_class}" do - lambda { @frozen.send(@method) { false } }.should raise_error(frozen_error_class) + it "raises a FrozenError" do + -> { @frozen.send(@method) { false } }.should raise_error(FrozenError) end end + + it "raises a FrozenError on a frozen array only during iteration if called without a block" do + enum = @frozen.send(@method) + -> { enum.each {} }.should raise_error(FrozenError) + end + end + + it "does not truncate the array is the block raises an exception" do + a = [1, 2, 3] + begin + a.send(@method) { raise StandardError, 'Oops' } + rescue + end + + a.should == [1, 2, 3] end + + it "only changes elements before error is raised, keeping the element which raised an error." do + a = [1, 2, 3, 4] + begin + a.send(@method) do |e| + case e + when 2 then false + when 3 then raise StandardError, 'Oops' + else true + end + end + rescue StandardError + end + + a.should == [1, 3, 4] + end + + @value_to_return = -> _ { true } + it_should_behave_like :array_iterable_and_tolerating_size_increasing end diff --git a/spec/ruby/core/array/shared/push.rb b/spec/ruby/core/array/shared/push.rb index effa632890..ac790fb6a4 100644 --- a/spec/ruby/core/array/shared/push.rb +++ b/spec/ruby/core/array/shared/push.rb @@ -26,8 +26,8 @@ describe :array_push, shared: true do array.send(@method, :last).should == [1, 'two', 3.0, array, array, array, array, array, :last] end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.send(@method, 1) }.should raise_error(frozen_error_class) - lambda { ArraySpecs.frozen_array.send(@method) }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.send(@method, 1) }.should raise_error(FrozenError) + -> { ArraySpecs.frozen_array.send(@method) }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/shared/replace.rb b/spec/ruby/core/array/shared/replace.rb index b8dae8d33e..9a6e60c1b0 100644 --- a/spec/ruby/core/array/shared/replace.rb +++ b/spec/ruby/core/array/shared/replace.rb @@ -52,9 +52,9 @@ describe :array_replace, shared: true do [].send(@method, ArraySpecs::ToAryArray[5, 6, 7]).should == [5, 6, 7] end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.send(@method, ArraySpecs.frozen_array) - }.should raise_error(frozen_error_class) + }.should raise_error(FrozenError) end end diff --git a/spec/ruby/core/array/shared/select.rb b/spec/ruby/core/array/shared/select.rb index 09101e8ab5..9c2cbf76c4 100644 --- a/spec/ruby/core/array/shared/select.rb +++ b/spec/ruby/core/array/shared/select.rb @@ -2,11 +2,14 @@ require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/enumeratorize' require_relative '../shared/keep_if' +require_relative '../shared/iterable_and_tolerating_size_increasing' require_relative '../../enumerable/shared/enumeratorized' describe :array_select, shared: true do it_should_behave_like :enumeratorize + it_should_behave_like :array_iterable_and_tolerating_size_increasing + before :each do @object = [1,2,3] end diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb index b3f4ccb9a6..b80261d32f 100644 --- a/spec/ruby/core/array/shared/slice.rb +++ b/spec/ruby/core/array/shared/slice.rb @@ -117,6 +117,27 @@ describe :array_slice, shared: true do a.send(@method, 0, obj).should == [1, 2] end + it "raises TypeError if to_int returns non-integer" do + from = mock('from') + to = mock('to') + + # So we can construct a range out of them... + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + a = [1, 2, 3, 4, 5] + + def from.to_int() 'cat' end + def to.to_int() -2 end + + -> { a.send(@method, from..to) }.should raise_error(TypeError) + + def from.to_int() 1 end + def to.to_int() 'cat' end + + -> { a.send(@method, from..to) }.should raise_error(TypeError) + end + it "returns the elements specified by Range indexes with [m..n]" do [ "a", "b", "c", "d", "e" ].send(@method, 1..3).should == ["b", "c", "d"] [ "a", "b", "c", "d", "e" ].send(@method, 4..-1).should == ['e'] @@ -266,10 +287,10 @@ describe :array_slice, shared: true do a.send(@method, 1..0).should == [] a.send(@method, 1...0).should == [] - lambda { a.send(@method, "a" .. "b") }.should raise_error(TypeError) - lambda { a.send(@method, "a" ... "b") }.should raise_error(TypeError) - lambda { a.send(@method, from .. "b") }.should raise_error(TypeError) - lambda { a.send(@method, from ... "b") }.should raise_error(TypeError) + -> { a.send(@method, "a" .. "b") }.should raise_error(TypeError) + -> { a.send(@method, "a" ... "b") }.should raise_error(TypeError) + -> { a.send(@method, from .. "b") }.should raise_error(TypeError) + -> { a.send(@method, from ... "b") }.should raise_error(TypeError) end it "returns the same elements as [m..n] and [m...n] with Range subclasses" do @@ -376,28 +397,28 @@ describe :array_slice, shared: true do @array = ArraySpecs::MyArray[1, 2, 3, 4, 5] end - it "returns a subclass instance with [n, m]" do - @array.send(@method, 0, 2).should be_an_instance_of(ArraySpecs::MyArray) + it "returns a Array instance with [n, m]" do + @array.send(@method, 0, 2).should be_an_instance_of(Array) end - it "returns a subclass instance with [-n, m]" do - @array.send(@method, -3, 2).should be_an_instance_of(ArraySpecs::MyArray) + it "returns a Array instance with [-n, m]" do + @array.send(@method, -3, 2).should be_an_instance_of(Array) end - it "returns a subclass instance with [n..m]" do - @array.send(@method, 1..3).should be_an_instance_of(ArraySpecs::MyArray) + it "returns a Array instance with [n..m]" do + @array.send(@method, 1..3).should be_an_instance_of(Array) end - it "returns a subclass instance with [n...m]" do - @array.send(@method, 1...3).should be_an_instance_of(ArraySpecs::MyArray) + it "returns a Array instance with [n...m]" do + @array.send(@method, 1...3).should be_an_instance_of(Array) end - it "returns a subclass instance with [-n..-m]" do - @array.send(@method, -3..-1).should be_an_instance_of(ArraySpecs::MyArray) + it "returns a Array instance with [-n..-m]" do + @array.send(@method, -3..-1).should be_an_instance_of(Array) end - it "returns a subclass instance with [-n...-m]" do - @array.send(@method, -3...-1).should be_an_instance_of(ArraySpecs::MyArray) + it "returns a Array instance with [-n...-m]" do + @array.send(@method, -3...-1).should be_an_instance_of(Array) end it "returns an empty array when m == n with [m...n]" do @@ -440,20 +461,397 @@ describe :array_slice, shared: true do it "raises a RangeError when the start index is out of range of Fixnum" do array = [1, 2, 3, 4, 5, 6] obj = mock('large value') - obj.should_receive(:to_int).and_return(0x8000_0000_0000_0000_0000) - lambda { array.send(@method, obj) }.should raise_error(RangeError) + obj.should_receive(:to_int).and_return(bignum_value) + -> { array.send(@method, obj) }.should raise_error(RangeError) obj = 8e19 - lambda { array.send(@method, obj) }.should raise_error(RangeError) + -> { array.send(@method, obj) }.should raise_error(RangeError) + + # boundary value when longs are 64 bits + -> { array.send(@method, 2.0**63) }.should raise_error(RangeError) + + # just under the boundary value when longs are 64 bits + array.send(@method, max_long.to_f.prev_float).should == nil end it "raises a RangeError when the length is out of range of Fixnum" do array = [1, 2, 3, 4, 5, 6] obj = mock('large value') - obj.should_receive(:to_int).and_return(0x8000_0000_0000_0000_0000) - lambda { array.send(@method, 1, obj) }.should raise_error(RangeError) + obj.should_receive(:to_int).and_return(bignum_value) + -> { array.send(@method, 1, obj) }.should raise_error(RangeError) obj = 8e19 - lambda { array.send(@method, 1, obj) }.should raise_error(RangeError) + -> { array.send(@method, 1, obj) }.should raise_error(RangeError) + end + + it "raises a type error if a range is passed with a length" do + ->{ [1, 2, 3].send(@method, 1..2, 1) }.should raise_error(TypeError) + end + + it "raises a RangeError if passed a range with a bound that is too large" do + array = [1, 2, 3, 4, 5, 6] + -> { array.send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError) + -> { array.send(@method, 0..bignum_value) }.should raise_error(RangeError) + end + + it "can accept endless ranges" do + a = [0, 1, 2, 3, 4, 5] + a.send(@method, eval("(2..)")).should == [2, 3, 4, 5] + a.send(@method, eval("(2...)")).should == [2, 3, 4, 5] + a.send(@method, eval("(-2..)")).should == [4, 5] + a.send(@method, eval("(-2...)")).should == [4, 5] + a.send(@method, eval("(9..)")).should == nil + a.send(@method, eval("(9...)")).should == nil + a.send(@method, eval("(-9..)")).should == nil + a.send(@method, eval("(-9...)")).should == nil + end + + describe "can be sliced with Enumerator::ArithmeticSequence" do + before :each do + @array = [0, 1, 2, 3, 4, 5] + end + + it "has endless range and positive steps" do + @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5] + @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4] + @array.send(@method, eval("(0..).step(10)")).should == [0] + + @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5] + @array.send(@method, eval("(2..).step(2)")).should == [2, 4] + @array.send(@method, eval("(2..).step(10)")).should == [2] + + @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5] + @array.send(@method, eval("(-3..).step(2)")).should == [3, 5] + @array.send(@method, eval("(-3..).step(10)")).should == [3] + end + + it "has beginless range and positive steps" do + # end with zero index + @array.send(@method, (..0).step(1)).should == [0] + @array.send(@method, (...0).step(1)).should == [] + + @array.send(@method, (..0).step(2)).should == [0] + @array.send(@method, (...0).step(2)).should == [] + + @array.send(@method, (..0).step(10)).should == [0] + @array.send(@method, (...0).step(10)).should == [] + + # end with positive index + @array.send(@method, (..3).step(1)).should == [0, 1, 2, 3] + @array.send(@method, (...3).step(1)).should == [0, 1, 2] + + @array.send(@method, (..3).step(2)).should == [0, 2] + @array.send(@method, (...3).step(2)).should == [0, 2] + + @array.send(@method, (..3).step(10)).should == [0] + @array.send(@method, (...3).step(10)).should == [0] + + # end with negative index + @array.send(@method, (..-2).step(1)).should == [0, 1, 2, 3, 4,] + @array.send(@method, (...-2).step(1)).should == [0, 1, 2, 3] + + @array.send(@method, (..-2).step(2)).should == [0, 2, 4] + @array.send(@method, (...-2).step(2)).should == [0, 2] + + @array.send(@method, (..-2).step(10)).should == [0] + @array.send(@method, (...-2).step(10)).should == [0] + end + + it "has endless range and negative steps" do + @array.send(@method, eval("(0..).step(-1)")).should == [0] + @array.send(@method, eval("(0..).step(-2)")).should == [0] + @array.send(@method, eval("(0..).step(-10)")).should == [0] + + @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0] + @array.send(@method, eval("(2..).step(-2)")).should == [2, 0] + + @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0] + @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1] + end + + it "has closed range and positive steps" do + # start and end with 0 + @array.send(@method, eval("(0..0).step(1)")).should == [0] + @array.send(@method, eval("(0...0).step(1)")).should == [] + + @array.send(@method, eval("(0..0).step(2)")).should == [0] + @array.send(@method, eval("(0...0).step(2)")).should == [] + + @array.send(@method, eval("(0..0).step(10)")).should == [0] + @array.send(@method, eval("(0...0).step(10)")).should == [] + + # start and end with positive index + @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3] + @array.send(@method, eval("(1...3).step(1)")).should == [1, 2] + + @array.send(@method, eval("(1..3).step(2)")).should == [1, 3] + @array.send(@method, eval("(1...3).step(2)")).should == [1] + + @array.send(@method, eval("(1..3).step(10)")).should == [1] + @array.send(@method, eval("(1...3).step(10)")).should == [1] + + # start with positive index, end with negative index + @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4] + @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3] + + @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3] + @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3] + + @array.send(@method, eval("(1..-2).step(10)")).should == [1] + @array.send(@method, eval("(1...-2).step(10)")).should == [1] + + # start with negative index, end with positive index + @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4] + @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3] + + @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4] + @array.send(@method, eval("(-4...4).step(2)")).should == [2] + + @array.send(@method, eval("(-4..4).step(10)")).should == [2] + @array.send(@method, eval("(-4...4).step(10)")).should == [2] + + # start with negative index, end with negative index + @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4] + @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3] + + @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4] + @array.send(@method, eval("(-4...-2).step(2)")).should == [2] + + @array.send(@method, eval("(-4..-2).step(10)")).should == [2] + @array.send(@method, eval("(-4...-2).step(10)")).should == [2] + end + + it "has closed range and negative steps" do + # start and end with 0 + @array.send(@method, eval("(0..0).step(-1)")).should == [0] + @array.send(@method, eval("(0...0).step(-1)")).should == [] + + @array.send(@method, eval("(0..0).step(-2)")).should == [0] + @array.send(@method, eval("(0...0).step(-2)")).should == [] + + @array.send(@method, eval("(0..0).step(-10)")).should == [0] + @array.send(@method, eval("(0...0).step(-10)")).should == [] + + # start and end with positive index + @array.send(@method, eval("(1..3).step(-1)")).should == [] + @array.send(@method, eval("(1...3).step(-1)")).should == [] + + @array.send(@method, eval("(1..3).step(-2)")).should == [] + @array.send(@method, eval("(1...3).step(-2)")).should == [] + + @array.send(@method, eval("(1..3).step(-10)")).should == [] + @array.send(@method, eval("(1...3).step(-10)")).should == [] + + # start with positive index, end with negative index + @array.send(@method, eval("(1..-2).step(-1)")).should == [] + @array.send(@method, eval("(1...-2).step(-1)")).should == [] + + @array.send(@method, eval("(1..-2).step(-2)")).should == [] + @array.send(@method, eval("(1...-2).step(-2)")).should == [] + + @array.send(@method, eval("(1..-2).step(-10)")).should == [] + @array.send(@method, eval("(1...-2).step(-10)")).should == [] + + # start with negative index, end with positive index + @array.send(@method, eval("(-4..4).step(-1)")).should == [] + @array.send(@method, eval("(-4...4).step(-1)")).should == [] + + @array.send(@method, eval("(-4..4).step(-2)")).should == [] + @array.send(@method, eval("(-4...4).step(-2)")).should == [] + + @array.send(@method, eval("(-4..4).step(-10)")).should == [] + @array.send(@method, eval("(-4...4).step(-10)")).should == [] + + # start with negative index, end with negative index + @array.send(@method, eval("(-4..-2).step(-1)")).should == [] + @array.send(@method, eval("(-4...-2).step(-1)")).should == [] + + @array.send(@method, eval("(-4..-2).step(-2)")).should == [] + @array.send(@method, eval("(-4...-2).step(-2)")).should == [] + + @array.send(@method, eval("(-4..-2).step(-10)")).should == [] + @array.send(@method, eval("(-4...-2).step(-10)")).should == [] + end + + it "has inverted closed range and positive steps" do + # start and end with positive index + @array.send(@method, eval("(3..1).step(1)")).should == [] + @array.send(@method, eval("(3...1).step(1)")).should == [] + + @array.send(@method, eval("(3..1).step(2)")).should == [] + @array.send(@method, eval("(3...1).step(2)")).should == [] + + @array.send(@method, eval("(3..1).step(10)")).should == [] + @array.send(@method, eval("(3...1).step(10)")).should == [] + + # start with negative index, end with positive index + @array.send(@method, eval("(-2..1).step(1)")).should == [] + @array.send(@method, eval("(-2...1).step(1)")).should == [] + + @array.send(@method, eval("(-2..1).step(2)")).should == [] + @array.send(@method, eval("(-2...1).step(2)")).should == [] + + @array.send(@method, eval("(-2..1).step(10)")).should == [] + @array.send(@method, eval("(-2...1).step(10)")).should == [] + + # start with positive index, end with negative index + @array.send(@method, eval("(4..-4).step(1)")).should == [] + @array.send(@method, eval("(4...-4).step(1)")).should == [] + + @array.send(@method, eval("(4..-4).step(2)")).should == [] + @array.send(@method, eval("(4...-4).step(2)")).should == [] + + @array.send(@method, eval("(4..-4).step(10)")).should == [] + @array.send(@method, eval("(4...-4).step(10)")).should == [] + + # start with negative index, end with negative index + @array.send(@method, eval("(-2..-4).step(1)")).should == [] + @array.send(@method, eval("(-2...-4).step(1)")).should == [] + + @array.send(@method, eval("(-2..-4).step(2)")).should == [] + @array.send(@method, eval("(-2...-4).step(2)")).should == [] + + @array.send(@method, eval("(-2..-4).step(10)")).should == [] + @array.send(@method, eval("(-2...-4).step(10)")).should == [] + end + + it "has range with bounds outside of array" do + # end is equal to array's length + @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5] + -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError) + + # end is greater than length with positive steps + @array.send(@method, (1..6).step(2)).should == [1, 3, 5] + @array.send(@method, (2..7).step(2)).should == [2, 4] + -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError) + + # begin is greater than length with negative steps + @array.send(@method, (6..1).step(-2)).should == [5, 3, 1] + @array.send(@method, (7..2).step(-2)).should == [5, 3] + -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError) + end + + it "has endless range with start outside of array's bounds" do + @array.send(@method, eval("(6..).step(1)")).should == [] + @array.send(@method, eval("(7..).step(1)")).should == nil + + @array.send(@method, eval("(6..).step(2)")).should == [] + -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError) + end + end + + it "can accept beginless ranges" do + a = [0, 1, 2, 3, 4, 5] + a.send(@method, (..3)).should == [0, 1, 2, 3] + a.send(@method, (...3)).should == [0, 1, 2] + a.send(@method, (..-3)).should == [0, 1, 2, 3] + a.send(@method, (...-3)).should == [0, 1, 2] + a.send(@method, (..0)).should == [0] + a.send(@method, (...0)).should == [] + a.send(@method, (..9)).should == [0, 1, 2, 3, 4, 5] + a.send(@method, (...9)).should == [0, 1, 2, 3, 4, 5] + a.send(@method, (..-9)).should == [] + a.send(@method, (...-9)).should == [] + end + + describe "can be sliced with Enumerator::ArithmeticSequence" do + it "with infinite/inverted ranges and negative steps" do + @array = [0, 1, 2, 3, 4, 5] + @array.send(@method, (2..).step(-1)).should == [2, 1, 0] + @array.send(@method, (2..).step(-2)).should == [2, 0] + @array.send(@method, (2..).step(-3)).should == [2] + @array.send(@method, (2..).step(-4)).should == [2] + + @array.send(@method, (-3..).step(-1)).should == [3, 2, 1, 0] + @array.send(@method, (-3..).step(-2)).should == [3, 1] + @array.send(@method, (-3..).step(-3)).should == [3, 0] + @array.send(@method, (-3..).step(-4)).should == [3] + @array.send(@method, (-3..).step(-5)).should == [3] + + @array.send(@method, (..0).step(-1)).should == [5, 4, 3, 2, 1, 0] + @array.send(@method, (..0).step(-2)).should == [5, 3, 1] + @array.send(@method, (..0).step(-3)).should == [5, 2] + @array.send(@method, (..0).step(-4)).should == [5, 1] + @array.send(@method, (..0).step(-5)).should == [5, 0] + @array.send(@method, (..0).step(-6)).should == [5] + @array.send(@method, (..0).step(-7)).should == [5] + + @array.send(@method, (...0).step(-1)).should == [5, 4, 3, 2, 1] + @array.send(@method, (...0).step(-2)).should == [5, 3, 1] + @array.send(@method, (...0).step(-3)).should == [5, 2] + @array.send(@method, (...0).step(-4)).should == [5, 1] + @array.send(@method, (...0).step(-5)).should == [5] + @array.send(@method, (...0).step(-6)).should == [5] + + @array.send(@method, (...1).step(-1)).should == [5, 4, 3, 2] + @array.send(@method, (...1).step(-2)).should == [5, 3] + @array.send(@method, (...1).step(-3)).should == [5, 2] + @array.send(@method, (...1).step(-4)).should == [5] + @array.send(@method, (...1).step(-5)).should == [5] + + @array.send(@method, (..-5).step(-1)).should == [5, 4, 3, 2, 1] + @array.send(@method, (..-5).step(-2)).should == [5, 3, 1] + @array.send(@method, (..-5).step(-3)).should == [5, 2] + @array.send(@method, (..-5).step(-4)).should == [5, 1] + @array.send(@method, (..-5).step(-5)).should == [5] + @array.send(@method, (..-5).step(-6)).should == [5] + + @array.send(@method, (...-5).step(-1)).should == [5, 4, 3, 2] + @array.send(@method, (...-5).step(-2)).should == [5, 3] + @array.send(@method, (...-5).step(-3)).should == [5, 2] + @array.send(@method, (...-5).step(-4)).should == [5] + @array.send(@method, (...-5).step(-5)).should == [5] + + @array.send(@method, (4..1).step(-1)).should == [4, 3, 2, 1] + @array.send(@method, (4..1).step(-2)).should == [4, 2] + @array.send(@method, (4..1).step(-3)).should == [4, 1] + @array.send(@method, (4..1).step(-4)).should == [4] + @array.send(@method, (4..1).step(-5)).should == [4] + + @array.send(@method, (4...1).step(-1)).should == [4, 3, 2] + @array.send(@method, (4...1).step(-2)).should == [4, 2] + @array.send(@method, (4...1).step(-3)).should == [4] + @array.send(@method, (4...1).step(-4)).should == [4] + + @array.send(@method, (-2..1).step(-1)).should == [4, 3, 2, 1] + @array.send(@method, (-2..1).step(-2)).should == [4, 2] + @array.send(@method, (-2..1).step(-3)).should == [4, 1] + @array.send(@method, (-2..1).step(-4)).should == [4] + @array.send(@method, (-2..1).step(-5)).should == [4] + + @array.send(@method, (-2...1).step(-1)).should == [4, 3, 2] + @array.send(@method, (-2...1).step(-2)).should == [4, 2] + @array.send(@method, (-2...1).step(-3)).should == [4] + @array.send(@method, (-2...1).step(-4)).should == [4] + + @array.send(@method, (4..-5).step(-1)).should == [4, 3, 2, 1] + @array.send(@method, (4..-5).step(-2)).should == [4, 2] + @array.send(@method, (4..-5).step(-3)).should == [4, 1] + @array.send(@method, (4..-5).step(-4)).should == [4] + @array.send(@method, (4..-5).step(-5)).should == [4] + + @array.send(@method, (4...-5).step(-1)).should == [4, 3, 2] + @array.send(@method, (4...-5).step(-2)).should == [4, 2] + @array.send(@method, (4...-5).step(-3)).should == [4] + @array.send(@method, (4...-5).step(-4)).should == [4] + + @array.send(@method, (-2..-5).step(-1)).should == [4, 3, 2, 1] + @array.send(@method, (-2..-5).step(-2)).should == [4, 2] + @array.send(@method, (-2..-5).step(-3)).should == [4, 1] + @array.send(@method, (-2..-5).step(-4)).should == [4] + @array.send(@method, (-2..-5).step(-5)).should == [4] + + @array.send(@method, (-2...-5).step(-1)).should == [4, 3, 2] + @array.send(@method, (-2...-5).step(-2)).should == [4, 2] + @array.send(@method, (-2...-5).step(-3)).should == [4] + @array.send(@method, (-2...-5).step(-4)).should == [4] + end + end + + it "can accept nil...nil ranges" do + a = [0, 1, 2, 3, 4, 5] + a.send(@method, eval("(nil...nil)")).should == a + a.send(@method, (...nil)).should == a + a.send(@method, eval("(nil..)")).should == a end end diff --git a/spec/ruby/core/array/shared/union.rb b/spec/ruby/core/array/shared/union.rb index 12a98cc9fe..0b60df9ca4 100644 --- a/spec/ruby/core/array/shared/union.rb +++ b/spec/ruby/core/array/shared/union.rb @@ -31,7 +31,7 @@ describe :array_binary_union, shared: true do [0].send(@method, obj).should == ([0] | [1, 2, 3]) end - # MRI follows hashing semantics here, so doesn't actually call eql?/hash for Fixnum/Symbol + # MRI follows hashing semantics here, so doesn't actually call eql?/hash for Integer/Symbol it "acts as if using an intermediate hash to collect values" do not_supported_on :opal do [5.0, 4.0].send(@method, [5, 4]).should == [5.0, 4.0, 5, 4] diff --git a/spec/ruby/core/array/shared/unshift.rb b/spec/ruby/core/array/shared/unshift.rb index d7464cdaca..9e0fe7556a 100644 --- a/spec/ruby/core/array/shared/unshift.rb +++ b/spec/ruby/core/array/shared/unshift.rb @@ -22,6 +22,11 @@ describe :array_unshift, shared: true do a.should == [3, 4] end + it "returns self" do + a = [1, 2, 3] + a.send(@method, "a").should.equal?(a) + end + it "quietly ignores unshifting nothing" do [].send(@method).should == [] end @@ -35,12 +40,25 @@ describe :array_unshift, shared: true do array[0..5].should == [:new, 1, 'two', 3.0, array, array] end - it "raises a #{frozen_error_class} on a frozen array when the array is modified" do - lambda { ArraySpecs.frozen_array.send(@method, 1) }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array when the array is modified" do + -> { ArraySpecs.frozen_array.send(@method, 1) }.should raise_error(FrozenError) end # see [ruby-core:23666] - it "raises a #{frozen_error_class} on a frozen array when the array would not be modified" do - lambda { ArraySpecs.frozen_array.send(@method) }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array when the array would not be modified" do + -> { ArraySpecs.frozen_array.send(@method) }.should raise_error(FrozenError) + end + + # https://github.com/truffleruby/truffleruby/issues/2772 + it "doesn't rely on Array#[]= so it can be overridden" do + subclass = Class.new(Array) do + def []=(*) + raise "[]= is called" + end + end + + array = subclass.new + array.send(@method, 1) + array.should == [1] end end diff --git a/spec/ruby/core/array/shift_spec.rb b/spec/ruby/core/array/shift_spec.rb index 26bce8aeb3..6b4ef39f77 100644 --- a/spec/ruby/core/array/shift_spec.rb +++ b/spec/ruby/core/array/shift_spec.rb @@ -30,11 +30,11 @@ describe "Array#shift" do array[0..2].should == ['two', 3.0, array] end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.shift }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.shift }.should raise_error(FrozenError) end - it "raises a #{frozen_error_class} on an empty frozen array" do - lambda { ArraySpecs.empty_frozen_array.shift }.should raise_error(frozen_error_class) + it "raises a FrozenError on an empty frozen array" do + -> { ArraySpecs.empty_frozen_array.shift }.should raise_error(FrozenError) end describe "passed a number n as an argument" do @@ -90,7 +90,7 @@ describe "Array#shift" do end it "raises an ArgumentError if n is negative" do - lambda{ [1, 2, 3].shift(-1) }.should raise_error(ArgumentError) + ->{ [1, 2, 3].shift(-1) }.should raise_error(ArgumentError) end it "tries to convert n to an Integer using #to_int" do @@ -105,30 +105,16 @@ describe "Array#shift" do end it "raises a TypeError when the passed n cannot be coerced to Integer" do - lambda{ [1, 2].shift("cat") }.should raise_error(TypeError) - lambda{ [1, 2].shift(nil) }.should raise_error(TypeError) + ->{ [1, 2].shift("cat") }.should raise_error(TypeError) + ->{ [1, 2].shift(nil) }.should raise_error(TypeError) end it "raises an ArgumentError if more arguments are passed" do - lambda{ [1, 2].shift(1, 2) }.should raise_error(ArgumentError) + ->{ [1, 2].shift(1, 2) }.should raise_error(ArgumentError) end it "does not return subclass instances with Array subclass" do ArraySpecs::MyArray[1, 2, 3].shift(2).should be_an_instance_of(Array) end - - it "returns an untainted array even if the array is tainted" do - ary = [1, 2].taint - ary.shift(2).tainted?.should be_false - ary.shift(0).tainted?.should be_false - end - - it "keeps taint status" do - a = [1, 2].taint - a.shift(2) - a.tainted?.should be_true - a.shift(2) - a.tainted?.should be_true - end end end diff --git a/spec/ruby/core/array/shuffle_spec.rb b/spec/ruby/core/array/shuffle_spec.rb index 4f793acf19..b84394bcb5 100644 --- a/spec/ruby/core/array/shuffle_spec.rb +++ b/spec/ruby/core/array/shuffle_spec.rb @@ -25,12 +25,6 @@ describe "Array#shuffle" do ArraySpecs::MyArray[1, 2, 3].shuffle.should be_an_instance_of(Array) end - it "attempts coercion via #to_hash" do - obj = mock('hash') - obj.should_receive(:to_hash).once.and_return({}) - [2, 3].shuffle(obj) - end - it "calls #rand on the Object passed by the :random key in the arguments Hash" do obj = mock("array_shuffle_random") obj.should_receive(:rand).at_least(1).times.and_return(0.5) @@ -43,7 +37,7 @@ describe "Array#shuffle" do it "raises a NoMethodError if an object passed for the RNG does not define #rand" do obj = BasicObject.new - lambda { [1, 2].shuffle(random: obj) }.should raise_error(NoMethodError) + -> { [1, 2].shuffle(random: obj) }.should raise_error(NoMethodError) end it "accepts a Float for the value returned by #rand" do @@ -53,6 +47,10 @@ describe "Array#shuffle" do [1, 2].shuffle(random: random).should be_an_instance_of(Array) end + it "accepts a Random class for the value for random: argument" do + [1, 2].shuffle(random: Random).should be_an_instance_of(Array) + end + it "calls #to_int on the Object returned by #rand" do value = mock("array_shuffle_random_value") value.should_receive(:to_int).at_least(1).times.and_return(0) @@ -68,16 +66,25 @@ describe "Array#shuffle" do random = mock("array_shuffle_random") random.should_receive(:rand).and_return(value) - lambda { [1, 2].shuffle(random: random) }.should raise_error(RangeError) + -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError) + end + + it "raises a RangeError if the value is equal to the Array size" do + value = mock("array_shuffle_random_value") + value.should_receive(:to_int).at_least(1).times.and_return(2) + random = mock("array_shuffle_random") + random.should_receive(:rand).at_least(1).times.and_return(value) + + -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError) end - it "raises a RangeError if the value is equal to one" do + it "raises a RangeError if the value is greater than the Array size" do value = mock("array_shuffle_random_value") - value.should_receive(:to_int).at_least(1).times.and_return(1) + value.should_receive(:to_int).at_least(1).times.and_return(3) random = mock("array_shuffle_random") random.should_receive(:rand).at_least(1).times.and_return(value) - lambda { [1, 2].shuffle(random: random) }.should raise_error(RangeError) + -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError) end end @@ -95,8 +102,18 @@ describe "Array#shuffle!" do a.should equal(original) end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.shuffle! }.should raise_error(frozen_error_class) - lambda { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.shuffle! }.should raise_error(FrozenError) + -> { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(FrozenError) + end + + it "matches CRuby with random:" do + %w[a b c].shuffle(random: Random.new(1)).should == %w[a c b] + (0..10).to_a.shuffle(random: Random.new(10)).should == [2, 6, 8, 5, 7, 10, 3, 1, 0, 4, 9] + end + + it "matches CRuby with srand" do + srand(123) + %w[a b c d e f g h i j k].shuffle.should == %w[a e f h i j d b g k c] end end diff --git a/spec/ruby/core/array/slice_spec.rb b/spec/ruby/core/array/slice_spec.rb index cd16b3892c..731c129251 100644 --- a/spec/ruby/core/array/slice_spec.rb +++ b/spec/ruby/core/array/slice_spec.rb @@ -116,8 +116,8 @@ describe "Array#slice!" do a.slice!(from .. to).should == [2, 3, 4] a.should == [1, 5] - lambda { a.slice!("a" .. "b") }.should raise_error(TypeError) - lambda { a.slice!(from .. "b") }.should raise_error(TypeError) + -> { a.slice!("a" .. "b") }.should raise_error(TypeError) + -> { a.slice!(from .. "b") }.should raise_error(TypeError) end it "returns last element for consecutive calls at zero index" do @@ -150,8 +150,66 @@ describe "Array#slice!" do a.should == [1, 2] end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.slice!(0, 0) }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.slice!(0, 0) }.should raise_error(FrozenError) + end + + it "works with endless ranges" do + a = [1, 2, 3] + a.slice!(eval("(1..)")).should == [2, 3] + a.should == [1] + + a = [1, 2, 3] + a.slice!(eval("(2...)")).should == [3] + a.should == [1, 2] + + a = [1, 2, 3] + a.slice!(eval("(-2..)")).should == [2, 3] + a.should == [1] + + a = [1, 2, 3] + a.slice!(eval("(-1...)")).should == [3] + a.should == [1, 2] + end + + it "works with beginless ranges" do + a = [0,1,2,3,4] + a.slice!((..3)).should == [0, 1, 2, 3] + a.should == [4] + + a = [0,1,2,3,4] + a.slice!((...-2)).should == [0, 1, 2] + a.should == [3, 4] + end + + describe "with a subclass of Array" do + before :each do + @array = ArraySpecs::MyArray[1, 2, 3, 4, 5] + end + + it "returns a Array instance with [n, m]" do + @array.slice!(0, 2).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n, m]" do + @array.slice!(-3, 2).should be_an_instance_of(Array) + end + + it "returns a Array instance with [n..m]" do + @array.slice!(1..3).should be_an_instance_of(Array) + end + + it "returns a Array instance with [n...m]" do + @array.slice!(1...3).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n..-m]" do + @array.slice!(-3..-1).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n...-m]" do + @array.slice!(-3...-1).should be_an_instance_of(Array) + end end end diff --git a/spec/ruby/core/array/sort_by_spec.rb b/spec/ruby/core/array/sort_by_spec.rb index 6428194dfb..0334f953f6 100644 --- a/spec/ruby/core/array/sort_by_spec.rb +++ b/spec/ruby/core/array/sort_by_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'shared/iterable_and_tolerating_size_increasing' require_relative '../enumerable/shared/enumeratorized' describe "Array#sort_by!" do @@ -23,12 +24,17 @@ describe "Array#sort_by!" do a.should be_an_instance_of(Array) end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.sort_by! {}}.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.sort_by! {}}.should raise_error(FrozenError) end - it "raises a #{frozen_error_class} on an empty frozen array" do - lambda { ArraySpecs.empty_frozen_array.sort_by! {}}.should raise_error(frozen_error_class) + it "raises a FrozenError on an empty frozen array" do + -> { ArraySpecs.empty_frozen_array.sort_by! {}}.should raise_error(FrozenError) + end + + it "raises a FrozenError on a frozen array only during iteration if called without a block" do + enum = ArraySpecs.frozen_array.sort_by! + -> { enum.each {} }.should raise_error(FrozenError) end it "returns the specified value when it would break in the given block" do @@ -48,5 +54,32 @@ describe "Array#sort_by!" do [1].sort_by!(&:to_s).should == [1] end + it "does not truncate the array is the block raises an exception" do + a = [1, 2, 3] + begin + a.sort_by! { raise StandardError, 'Oops' } + rescue + end + + a.should == [1, 2, 3] + end + + it "doesn't change array if error is raised" do + a = [4, 3, 2, 1] + begin + a.sort_by! do |e| + raise StandardError, 'Oops' if e == 1 + e + end + rescue StandardError + end + + a.should == [4, 3, 2, 1] + end + it_behaves_like :enumeratorized_with_origin_size, :sort_by!, [1,2,3] end + +describe "Array#sort_by!" do + it_behaves_like :array_iterable_and_tolerating_size_increasing, :sort_by! +end diff --git a/spec/ruby/core/array/sort_spec.rb b/spec/ruby/core/array/sort_spec.rb index c0d6628549..e20b650516 100644 --- a/spec/ruby/core/array/sort_spec.rb +++ b/spec/ruby/core/array/sort_spec.rb @@ -58,15 +58,15 @@ describe "Array#sort" do b = ArraySpecs::MockForCompared.new c = ArraySpecs::MockForCompared.new - ArraySpecs::MockForCompared.compared?.should == false + ArraySpecs::MockForCompared.should_not.compared? [a, b, c].sort.should == [c, b, a] - ArraySpecs::MockForCompared.compared?.should == true + ArraySpecs::MockForCompared.should.compared? end it "does not deal with exceptions raised by unimplemented or incorrect #<=>" do o = Object.new - lambda { + -> { [o, 1].sort }.should raise_error(ArgumentError) end @@ -78,7 +78,7 @@ describe "Array#sort" do end it "raises an error when a given block returns nil" do - lambda { [1, 2].sort {} }.should raise_error(ArgumentError) + -> { [1, 2].sort {} }.should raise_error(ArgumentError) end it "does not call #<=> on contained objects when invoked with a block" do @@ -104,17 +104,17 @@ describe "Array#sort" do it "does not freezes self during being sorted" do a = [1, 2, 3] - a.sort { |x,y| a.frozen?.should == false; x <=> y } + a.sort { |x,y| a.should_not.frozen?; x <=> y } end it "returns the specified value when it would break in the given block" do [1, 2, 3].sort{ break :a }.should == :a end - it "uses the sign of Bignum block results as the sort result" do + it "uses the sign of Integer block results as the sort result" do a = [1, 2, 5, 10, 7, -4, 12] begin - class Bignum; + class Integer alias old_spaceship <=> def <=>(other) raise @@ -122,7 +122,7 @@ describe "Array#sort" do end a.sort {|n, m| (n - m) * (2 ** 200)}.should == [-4, 1, 2, 5, 7, 10, 12] ensure - class Bignum + class Integer alias <=> old_spaceship end end @@ -132,9 +132,9 @@ describe "Array#sort" do a = [1, 2, 5, 10, 7, -4, 12] a.sort { |n, m| n - m }.should == [-4, 1, 2, 5, 7, 10, 12] a.sort { |n, m| - ArraySpecs::ComparableWithFixnum.new(n-m) + ArraySpecs::ComparableWithInteger.new(n-m) }.should == [-4, 1, 2, 5, 7, 10, 12] - lambda { + -> { a.sort { |n, m| (n - m).to_s } }.should raise_error(ArgumentError) end @@ -155,7 +155,7 @@ describe "Array#sort" do it "raises an error if objects can't be compared" do a=[ArraySpecs::Uncomparable.new, ArraySpecs::Uncomparable.new] - lambda {a.sort}.should raise_error(ArgumentError) + -> {a.sort}.should raise_error(ArgumentError) end # From a strange Rubinius bug @@ -207,9 +207,9 @@ describe "Array#sort!" do b = ArraySpecs::MockForCompared.new c = ArraySpecs::MockForCompared.new - ArraySpecs::MockForCompared.compared?.should == false + ArraySpecs::MockForCompared.should_not.compared? [a, b, c].sort!.should == [c, b, a] - ArraySpecs::MockForCompared.compared?.should == true + ArraySpecs::MockForCompared.should.compared? end it "does not call #<=> on contained objects when invoked with a block" do @@ -233,8 +233,8 @@ describe "Array#sort!" do a.sort!{ -1 }.should be_an_instance_of(Array) end - it "raises a #{frozen_error_class} on a frozen array" do - lambda { ArraySpecs.frozen_array.sort! }.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array" do + -> { ArraySpecs.frozen_array.sort! }.should raise_error(FrozenError) end it "returns the specified value when it would break in the given block" do diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb index a7e77d8c2e..06abe06135 100644 --- a/spec/ruby/core/array/sum_spec.rb +++ b/spec/ruby/core/array/sum_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#sum" do it "returns the sum of elements" do @@ -9,6 +10,39 @@ describe "Array#sum" do [1, 2, 3].sum { |i| i * 10 }.should == 60 end + it "doesn't apply the block init" do + [1, 2, 3].sum(1) { |i| i * 10 }.should == 61 + end + + # https://bugs.ruby-lang.org/issues/12217 + # https://github.com/ruby/ruby/blob/master/doc/ChangeLog/ChangeLog-2.4.0#L6208-L6214 + it "uses Kahan's compensated summation algorithm for precise sum of float numbers" do + floats = [2.7800000000000002, 5.0, 2.5, 4.44, 3.89, 3.89, 4.44, 7.78, 5.0, 2.7800000000000002, 5.0, 2.5] + naive_sum = floats.reduce { |sum, e| sum + e } + naive_sum.should == 50.00000000000001 + floats.sum.should == 50.0 + end + + it "handles infinite values and NaN" do + [1.0, Float::INFINITY].sum.should == Float::INFINITY + [1.0, -Float::INFINITY].sum.should == -Float::INFINITY + [1.0, Float::NAN].sum.should.nan? + + [Float::INFINITY, 1.0].sum.should == Float::INFINITY + [-Float::INFINITY, 1.0].sum.should == -Float::INFINITY + [Float::NAN, 1.0].sum.should.nan? + + [Float::NAN, Float::INFINITY].sum.should.nan? + [Float::INFINITY, Float::NAN].sum.should.nan? + + [Float::INFINITY, -Float::INFINITY].sum.should.nan? + [-Float::INFINITY, Float::INFINITY].sum.should.nan? + + [Float::INFINITY, Float::INFINITY].sum.should == Float::INFINITY + [-Float::INFINITY, -Float::INFINITY].sum.should == -Float::INFINITY + [Float::NAN, Float::NAN].sum.should.nan? + end + it "returns init value if array is empty" do [].sum(-1).should == -1 end @@ -26,11 +60,11 @@ describe "Array#sum" do end it 'raises TypeError if any element are not numeric' do - lambda { ["a"].sum }.should raise_error(TypeError) + -> { ["a"].sum }.should raise_error(TypeError) end it 'raises TypeError if any element cannot be added to init value' do - lambda { [1].sum([]) }.should raise_error(TypeError) + -> { [1].sum([]) }.should raise_error(TypeError) end it "calls + to sum the elements" do @@ -39,4 +73,18 @@ describe "Array#sum" do a.should_receive(:+).with(b).and_return(42) [b].sum(a).should == 42 end + + ruby_bug '#19530', ''...'3.3' do + it "calls + on the init value" do + a = mock("a") + b = mock("b") + a.should_receive(:+).with(42).and_return(b) + [42].sum(a).should == b + end + end +end + +describe "Array#sum" do + @value_to_return = -> _ { 1 } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :sum end diff --git a/spec/ruby/core/array/take_spec.rb b/spec/ruby/core/array/take_spec.rb index 2c9e3f5cfe..c4f0ac9aa4 100644 --- a/spec/ruby/core/array/take_spec.rb +++ b/spec/ruby/core/array/take_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe "Array#take" do it "returns the first specified number of elements" do @@ -22,6 +23,10 @@ describe "Array#take" do end it "raises an ArgumentError when the argument is negative" do - lambda{ [1].take(-3) }.should raise_error(ArgumentError) + ->{ [1].take(-3) }.should raise_error(ArgumentError) + end + + it 'returns a Array instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array) end end diff --git a/spec/ruby/core/array/take_while_spec.rb b/spec/ruby/core/array/take_while_spec.rb index f159e6f251..8f50260b42 100644 --- a/spec/ruby/core/array/take_while_spec.rb +++ b/spec/ruby/core/array/take_while_spec.rb @@ -1,4 +1,6 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#take_while" do it "returns all elements until the block returns false" do @@ -12,4 +14,13 @@ describe "Array#take_while" do it "returns all elements until the block returns false" do [1, 2, false, 4].take_while{ |element| element }.should == [1, 2] end + + it 'returns a Array instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array) + end +end + +describe "Array#take_while" do + @value_to_return = -> _ { true } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :take_while end diff --git a/spec/ruby/core/array/to_h_spec.rb b/spec/ruby/core/array/to_h_spec.rb index 4431430216..1c814f3d01 100644 --- a/spec/ruby/core/array/to_h_spec.rb +++ b/spec/ruby/core/array/to_h_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#to_h" do it "converts empty array to empty hash" do @@ -24,58 +25,67 @@ describe "Array#to_h" do end it "raises TypeError if an element is not an array" do - lambda { [:x].to_h }.should raise_error(TypeError) + -> { [:x].to_h }.should raise_error(TypeError) end it "raises ArgumentError if an element is not a [key, value] pair" do - lambda { [[:x]].to_h }.should raise_error(ArgumentError) + -> { [[:x]].to_h }.should raise_error(ArgumentError) end it "does not accept arguments" do - lambda { [].to_h(:a, :b) }.should raise_error(ArgumentError) + -> { [].to_h(:a, :b) }.should raise_error(ArgumentError) end it "produces a hash that returns nil for a missing element" do [[:a, 1], [:b, 2]].to_h[:c].should be_nil end - ruby_version_is "2.6" do - context "with block" do - it "converts [key, value] pairs returned by the block to a Hash" do - [:a, :b].to_h { |k| [k, k.to_s] }.should == { a: 'a', b: 'b' } - end - - it "raises ArgumentError if block returns longer or shorter array" do - -> do - [:a, :b].to_h { |k| [k, k.to_s, 1] } - end.should raise_error(ArgumentError, /wrong array length at 0/) - - -> do - [:a, :b].to_h { |k| [k] } - end.should raise_error(ArgumentError, /wrong array length at 0/) - end - - it "raises TypeError if block returns something other than Array" do - -> do - [:a, :b].to_h { |k| "not-array" } - end.should raise_error(TypeError, /wrong element type String at 0/) - end - - it "coerces returned pair to Array with #to_ary" do - x = mock('x') - x.stub!(:to_ary).and_return([:b, 'b']) - - [:a].to_h { |k| x }.should == { :b => 'b' } - end - - it "does not coerce returned pair to Array with #to_a" do - x = mock('x') - x.stub!(:to_a).and_return([:b, 'b']) - - -> do - [:a].to_h { |k| x } - end.should raise_error(TypeError, /wrong element type MockObject at 0/) - end + context "with block" do + it "converts [key, value] pairs returned by the block to a Hash" do + [:a, :b].to_h { |k| [k, k.to_s] }.should == { a: 'a', b: 'b' } + end + + it "passes to a block each element as a single argument" do + ScratchPad.record [] + [[:a, 1], [:b, 2]].to_h { |*args| ScratchPad << args; [args[0], args[1]] } + ScratchPad.recorded.sort.should == [[[:a, 1]], [[:b, 2]]] + end + + it "raises ArgumentError if block returns longer or shorter array" do + -> do + [:a, :b].to_h { |k| [k, k.to_s, 1] } + end.should raise_error(ArgumentError, /wrong array length at 0/) + + -> do + [:a, :b].to_h { |k| [k] } + end.should raise_error(ArgumentError, /wrong array length at 0/) + end + + it "raises TypeError if block returns something other than Array" do + -> do + [:a, :b].to_h { |k| "not-array" } + end.should raise_error(TypeError, /wrong element type String at 0/) + end + + it "coerces returned pair to Array with #to_ary" do + x = mock('x') + x.stub!(:to_ary).and_return([:b, 'b']) + + [:a].to_h { |k| x }.should == { :b => 'b' } + end + + it "does not coerce returned pair to Array with #to_a" do + x = mock('x') + x.stub!(:to_a).and_return([:b, 'b']) + + -> do + [:a].to_h { |k| x } + end.should raise_error(TypeError, /wrong element type MockObject at 0/) end end end + +describe "Array#to_h" do + @value_to_return = -> e { [e, e.to_s] } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :to_h +end diff --git a/spec/ruby/core/array/transpose_spec.rb b/spec/ruby/core/array/transpose_spec.rb index c7bd7e7338..b39077f4c9 100644 --- a/spec/ruby/core/array/transpose_spec.rb +++ b/spec/ruby/core/array/transpose_spec.rb @@ -32,7 +32,7 @@ describe "Array#transpose" do end it "raises a TypeError if the passed Argument does not respond to #to_ary" do - lambda { [Object.new, [:a, :b]].transpose }.should raise_error(TypeError) + -> { [Object.new, [:a, :b]].transpose }.should raise_error(TypeError) end it "does not call to_ary on array subclass elements" do @@ -41,7 +41,7 @@ describe "Array#transpose" do end it "raises an IndexError if the arrays are not of the same length" do - lambda { [[1, 2], [:a]].transpose }.should raise_error(IndexError) + -> { [[1, 2], [:a]].transpose }.should raise_error(IndexError) end it "does not return subclass instance on Array subclasses" do diff --git a/spec/ruby/core/array/try_convert_spec.rb b/spec/ruby/core/array/try_convert_spec.rb index 5f653b6807..bea8815006 100644 --- a/spec/ruby/core/array/try_convert_spec.rb +++ b/spec/ruby/core/array/try_convert_spec.rb @@ -39,12 +39,12 @@ describe "Array.try_convert" do it "sends #to_ary to the argument and raises TypeError if it's not a kind of Array" do obj = mock("to_ary") obj.should_receive(:to_ary).and_return(Object.new) - lambda { Array.try_convert obj }.should raise_error(TypeError) + -> { Array.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_ary gives Object)") end it "does not rescue exceptions raised by #to_ary" do obj = mock("to_ary") obj.should_receive(:to_ary).and_raise(RuntimeError) - lambda { Array.try_convert obj }.should raise_error(RuntimeError) + -> { Array.try_convert obj }.should raise_error(RuntimeError) end end diff --git a/spec/ruby/core/array/union_spec.rb b/spec/ruby/core/array/union_spec.rb index 1dca47696d..ba2cc0d6b7 100644 --- a/spec/ruby/core/array/union_spec.rb +++ b/spec/ruby/core/array/union_spec.rb @@ -6,22 +6,20 @@ describe "Array#|" do it_behaves_like :array_binary_union, :| end -ruby_version_is "2.6" do - describe "Array#union" do - it_behaves_like :array_binary_union, :union +describe "Array#union" do + it_behaves_like :array_binary_union, :union - it "returns unique elements when given no argument" do - x = [1, 2, 3, 2] - x.union.should == [1, 2, 3] - end + it "returns unique elements when given no argument" do + x = [1, 2, 3, 2] + x.union.should == [1, 2, 3] + end - it "does not return subclass instances for Array subclasses" do - ArraySpecs::MyArray[1, 2, 3].union.should be_an_instance_of(Array) - end + it "does not return subclass instances for Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].union.should be_an_instance_of(Array) + end - it "accepts multiple arguments" do - x = [1, 2, 3] - x.union(x, x, x, x, [3, 4], x).should == [1, 2, 3, 4] - end + it "accepts multiple arguments" do + x = [1, 2, 3] + x.union(x, x, x, x, [3, 4], x).should == [1, 2, 3, 4] end end diff --git a/spec/ruby/core/array/uniq_spec.rb b/spec/ruby/core/array/uniq_spec.rb index 471717b8e2..d5d826db15 100644 --- a/spec/ruby/core/array/uniq_spec.rb +++ b/spec/ruby/core/array/uniq_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#uniq" do it "returns an array with no duplicates" do @@ -45,10 +46,6 @@ describe "Array#uniq" do obj.should_receive(:hash).at_least(1).and_return(0) def obj.eql?(o) - # It's undefined whether the impl does a[0].eql?(a[1]) or - # a[1].eql?(a[0]) so we taint both. - taint - o.taint false end @@ -56,18 +53,12 @@ describe "Array#uniq" do end a.uniq.should == a - a[0].tainted?.should == true - a[1].tainted?.should == true a = Array.new(2) do obj = mock('0') obj.should_receive(:hash).at_least(1).and_return(0) def obj.eql?(o) - # It's undefined whether the impl does a[0].eql?(a[1]) or - # a[1].eql?(a[0]) so we taint both. - taint - o.taint true end @@ -75,8 +66,6 @@ describe "Array#uniq" do end a.uniq.size.should == 1 - a[0].tainted?.should == true - a[1].tainted?.should == true end it "compares elements based on the value returned from the block" do @@ -96,8 +85,8 @@ describe "Array#uniq" do [false, nil, 42].uniq { :bar }.should == [false] end - it "returns subclass instance on Array subclasses" do - ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(ArraySpecs::MyArray) + it "returns Array instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array) end it "properly handles an identical item even when its #eql? isn't reflexive" do @@ -135,6 +124,11 @@ describe "Array#uniq" do end end +describe "Array#uniq" do + @value_to_return = -> e { e } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq +end + describe "Array#uniq!" do it "modifies the array in place" do a = [ "a", "a", "b", "b", "c" ] @@ -188,20 +182,20 @@ describe "Array#uniq!" do [ "a", "b", "c" ].uniq!.should == nil end - it "raises a #{frozen_error_class} on a frozen array when the array is modified" do + it "raises a FrozenError on a frozen array when the array is modified" do dup_ary = [1, 1, 2] dup_ary.freeze - lambda { dup_ary.uniq! }.should raise_error(frozen_error_class) + -> { dup_ary.uniq! }.should raise_error(FrozenError) end # see [ruby-core:23666] - it "raises a #{frozen_error_class} on a frozen array when the array would not be modified" do - lambda { ArraySpecs.frozen_array.uniq!}.should raise_error(frozen_error_class) - lambda { ArraySpecs.empty_frozen_array.uniq!}.should raise_error(frozen_error_class) + it "raises a FrozenError on a frozen array when the array would not be modified" do + -> { ArraySpecs.frozen_array.uniq!}.should raise_error(FrozenError) + -> { ArraySpecs.empty_frozen_array.uniq!}.should raise_error(FrozenError) end it "doesn't yield to the block on a frozen array" do - lambda { ArraySpecs.frozen_array.uniq!{ raise RangeError, "shouldn't yield"}}.should raise_error(frozen_error_class) + -> { ArraySpecs.frozen_array.uniq!{ raise RangeError, "shouldn't yield"}}.should raise_error(FrozenError) end it "compares elements based on the value returned from the block" do @@ -218,4 +212,32 @@ describe "Array#uniq!" do a.uniq! a.should == [x] end + + it "does not truncate the array is the block raises an exception" do + a = [1, 2, 3] + begin + a.send(@method) { raise StandardError, 'Oops' } + rescue + end + + a.should == [1, 2, 3] + end + + it "doesn't change array if error is raised" do + a = [1, 1, 2, 2, 3, 3, 4, 4] + begin + a.send(@method) do |e| + raise StandardError, 'Oops' if e == 3 + e + end + rescue StandardError + end + + a.should == [1, 1, 2, 2, 3, 3, 4, 4] + end +end + +describe "Array#uniq!" do + @value_to_return = -> e { e } + it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq! end diff --git a/spec/ruby/core/array/values_at_spec.rb b/spec/ruby/core/array/values_at_spec.rb index 13860150bb..e85bbee400 100644 --- a/spec/ruby/core/array/values_at_spec.rb +++ b/spec/ruby/core/array/values_at_spec.rb @@ -1,6 +1,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +# Should be synchronized with core/struct/values_at_spec.rb describe "Array#values_at" do it "returns an array of elements at the indexes when passed indexes" do [1, 2, 3, 4, 5].values_at().should == [] @@ -60,4 +61,14 @@ describe "Array#values_at" do it "does not return subclass instance on Array subclasses" do ArraySpecs::MyArray[1, 2, 3].values_at(0, 1..2, 1).should be_an_instance_of(Array) end + + it "works when given endless ranges" do + [1, 2, 3, 4].values_at(eval("(1..)")).should == [2, 3, 4] + [1, 2, 3, 4].values_at(eval("(3...)")).should == [4] + end + + it "works when given beginless ranges" do + [1, 2, 3, 4].values_at((..2)).should == [1, 2, 3] + [1, 2, 3, 4].values_at((...2)).should == [1, 2] + end end diff --git a/spec/ruby/core/array/zip_spec.rb b/spec/ruby/core/array/zip_spec.rb index af4013debe..2a0f64cb49 100644 --- a/spec/ruby/core/array/zip_spec.rb +++ b/spec/ruby/core/array/zip_spec.rb @@ -62,4 +62,10 @@ describe "Array#zip" do it "does not return subclass instance on Array subclasses" do ArraySpecs::MyArray[1, 2, 3].zip(["a", "b"]).should be_an_instance_of(Array) end + + it "raises TypeError when some argument isn't Array and doesn't respond to #to_ary and #to_enum" do + -> { [1, 2, 3].zip(Object.new) }.should raise_error(TypeError, "wrong argument type Object (must respond to :each)") + -> { [1, 2, 3].zip(1) }.should raise_error(TypeError, "wrong argument type Integer (must respond to :each)") + -> { [1, 2, 3].zip(true) }.should raise_error(TypeError, "wrong argument type TrueClass (must respond to :each)") + end end |
