1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/spec/ruby/core/array/flatten_spec.rb
Jeremy Evans ffd0820ab3 Deprecate taint/trust and related methods, and make the methods no-ops
This removes the related tests, and puts the related specs behind
version guards.  This affects all code in lib, including some
libraries that may want to support older versions of Ruby.
2019-11-18 01:00:25 +02:00

286 lines
8.6 KiB
Ruby

require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Array#flatten" do
it "returns a one-dimensional flattening recursively" do
[[[1, [2, 3]],[2, 3, [4, [4, [5, 5]], [1, 2, 3]]], [4]], []].flatten.should == [1, 2, 3, 2, 3, 4, 4, 5, 5, 1, 2, 3, 4]
end
it "takes an optional argument that determines the level of recursion" do
[ 1, 2, [3, [4, 5] ] ].flatten(1).should == [1, 2, 3, [4, 5]]
end
it "returns dup when the level of recursion is 0" do
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten(0).should == a
a.flatten(0).should_not equal(a)
end
it "ignores negative levels" do
[ 1, 2, [ 3, 4, [5, 6] ] ].flatten(-1).should == [1, 2, 3, 4, 5, 6]
[ 1, 2, [ 3, 4, [5, 6] ] ].flatten(-10).should == [1, 2, 3, 4, 5, 6]
end
it "tries to convert passed Objects to Integers using #to_int" do
obj = mock("Converted to Integer")
obj.should_receive(:to_int).and_return(1)
[ 1, 2, [3, [4, 5] ] ].flatten(obj).should == [1, 2, 3, [4, 5]]
end
it "raises a TypeError when the passed Object can't be converted to an Integer" do
obj = mock("Not converted")
-> { [ 1, 2, [3, [4, 5] ] ].flatten(obj) }.should raise_error(TypeError)
end
it "does not call flatten on elements" do
obj = mock('[1,2]')
obj.should_not_receive(:flatten)
[obj, obj].flatten.should == [obj, obj]
obj = [5, 4]
obj.should_not_receive(:flatten)
[obj, obj].flatten.should == [5, 4, 5, 4]
end
it "raises an ArgumentError on recursive arrays" do
x = []
x << x
-> { x.flatten }.should raise_error(ArgumentError)
x = []
y = []
x << y
y << x
-> { x.flatten }.should raise_error(ArgumentError)
end
it "flattens any element which responds to #to_ary, using the return value of said method" do
x = mock("[3,4]")
x.should_receive(:to_ary).at_least(:once).and_return([3, 4])
[1, 2, x, 5].flatten.should == [1, 2, 3, 4, 5]
y = mock("MyArray[]")
y.should_receive(:to_ary).at_least(:once).and_return(ArraySpecs::MyArray[])
[y].flatten.should == []
z = mock("[2,x,y,5]")
z.should_receive(:to_ary).and_return([2, x, y, 5])
[1, z, 6].flatten.should == [1, 2, 3, 4, 5, 6]
end
it "does not call #to_ary on elements beyond the given level" do
obj = mock("1")
obj.should_not_receive(:to_ary)
[[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]
[ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
end
it "is not destructive" do
ary = [1, [2, 3]]
ary.flatten
ary.should == [1, [2, 3]]
end
describe "with a non-Array object in the Array" do
before :each do
@obj = mock("Array#flatten")
ScratchPad.record []
end
it "does not call #to_ary if the method is not defined" do
[@obj].flatten.should == [@obj]
end
it "does not raise an exception if #to_ary returns nil" do
@obj.should_receive(:to_ary).and_return(nil)
[@obj].flatten.should == [@obj]
end
it "raises a TypeError if #to_ary does not return an Array" do
@obj.should_receive(:to_ary).and_return(1)
-> { [@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
end
it "does not call #to_ary if not defined when #respond_to_missing? returns false" do
def @obj.respond_to_missing?(name, priv) ScratchPad << name; false end
[@obj].flatten.should == [@obj]
ScratchPad.recorded.should == [:to_ary]
end
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
-> { [@obj].flatten }.should raise_error(NoMethodError)
ScratchPad.recorded.should == [:to_ary]
end
it "calls #method_missing if defined" do
@obj.should_receive(:method_missing).with(:to_ary).and_return([1, 2, 3])
[@obj].flatten.should == [1, 2, 3]
end
end
ruby_version_is ''...'2.7' do
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
end
it "performs respond_to? and method_missing-aware checks when coercing elements to array" do
bo = BasicObject.new
[bo].flatten.should == [bo]
def bo.method_missing(name, *)
[1,2]
end
[bo].flatten.should == [1,2]
def bo.respond_to?(name, *)
false
end
[bo].flatten.should == [bo]
def bo.respond_to?(name, *)
true
end
[bo].flatten.should == [1,2]
end
end
describe "Array#flatten!" do
it "modifies array to produce a one-dimensional flattening recursively" do
a = [[[1, [2, 3]],[2, 3, [4, [4, [5, 5]], [1, 2, 3]]], [4]], []]
a.flatten!
a.should == [1, 2, 3, 2, 3, 4, 4, 5, 5, 1, 2, 3, 4]
end
it "returns self if made some modifications" do
a = [[[1, [2, 3]],[2, 3, [4, [4, [5, 5]], [1, 2, 3]]], [4]], []]
a.flatten!.should equal(a)
end
it "returns nil if no modifications took place" do
a = [1, 2, 3]
a.flatten!.should == nil
a = [1, [2, 3]]
a.flatten!.should_not == nil
end
it "should not check modification by size" do
a = [1, 2, [3]]
a.flatten!.should_not == nil
a.should == [1, 2, 3]
end
it "takes an optional argument that determines the level of recursion" do
[ 1, 2, [3, [4, 5] ] ].flatten!(1).should == [1, 2, 3, [4, 5]]
end
# redmine #1440
it "returns nil when the level of recursion is 0" do
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten!(0).should == nil
end
it "treats negative levels as no arguments" do
[ 1, 2, [ 3, 4, [5, 6] ] ].flatten!(-1).should == [1, 2, 3, 4, 5, 6]
[ 1, 2, [ 3, 4, [5, 6] ] ].flatten!(-10).should == [1, 2, 3, 4, 5, 6]
end
it "tries to convert passed Objects to Integers using #to_int" do
obj = mock("Converted to Integer")
obj.should_receive(:to_int).and_return(1)
[ 1, 2, [3, [4, 5] ] ].flatten!(obj).should == [1, 2, 3, [4, 5]]
end
it "raises a TypeError when the passed Object can't be converted to an Integer" do
obj = mock("Not converted")
-> { [ 1, 2, [3, [4, 5] ] ].flatten!(obj) }.should raise_error(TypeError)
end
it "does not call flatten! on elements" do
obj = mock('[1,2]')
obj.should_not_receive(:flatten!)
[obj, obj].flatten!.should == nil
obj = [5, 4]
obj.should_not_receive(:flatten!)
[obj, obj].flatten!.should == [5, 4, 5, 4]
end
it "raises an ArgumentError on recursive arrays" do
x = []
x << x
-> { x.flatten! }.should raise_error(ArgumentError)
x = []
y = []
x << y
y << x
-> { x.flatten! }.should raise_error(ArgumentError)
end
it "flattens any elements which responds to #to_ary, using the return value of said method" do
x = mock("[3,4]")
x.should_receive(:to_ary).at_least(:once).and_return([3, 4])
[1, 2, x, 5].flatten!.should == [1, 2, 3, 4, 5]
y = mock("MyArray[]")
y.should_receive(:to_ary).at_least(:once).and_return(ArraySpecs::MyArray[])
[y].flatten!.should == []
z = mock("[2,x,y,5]")
z.should_receive(:to_ary).and_return([2, x, y, 5])
[1, z, 6].flatten!.should == [1, 2, 3, 4, 5, 6]
ary = [ArraySpecs::MyArray[1, 2, 3]]
ary.flatten!
ary.should be_an_instance_of(Array)
ary.should == [1, 2, 3]
end
it "raises a #{frozen_error_class} on frozen arrays when the array is modified" do
nested_ary = [1, 2, []]
nested_ary.freeze
-> { nested_ary.flatten! }.should raise_error(frozen_error_class)
end
# see [ruby-core:23663]
it "raises a #{frozen_error_class} on frozen arrays when the array would not be modified" do
-> { ArraySpecs.frozen_array.flatten! }.should raise_error(frozen_error_class)
-> { ArraySpecs.empty_frozen_array.flatten! }.should raise_error(frozen_error_class)
end
end