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/uniq_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

253 lines
6.3 KiB
Ruby

require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Array#uniq" do
it "returns an array with no duplicates" do
["a", "a", "b", "b", "c"].uniq.should == ["a", "b", "c"]
end
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
empty.uniq.should == [empty]
array = ArraySpecs.recursive_array
array.uniq.should == [1, 'two', 3.0, array]
end
it "uses eql? semantics" do
[1.0, 1].uniq.should == [1.0, 1]
end
it "compares elements first with hash" do
x = mock('0')
x.should_receive(:hash).at_least(1).and_return(0)
y = mock('0')
y.should_receive(:hash).at_least(1).and_return(0)
[x, y].uniq.should == [x, y]
end
it "does not compare elements with different hash codes via eql?" do
x = mock('0')
x.should_not_receive(:eql?)
y = mock('1')
y.should_not_receive(:eql?)
x.should_receive(:hash).at_least(1).and_return(0)
y.should_receive(:hash).at_least(1).and_return(1)
[x, y].uniq.should == [x, y]
end
ruby_version_is '2.7' do
it "compares elements with matching hash codes with #eql?" do
a = Array.new(2) do
obj = mock('0')
obj.should_receive(:hash).at_least(1).and_return(0)
def obj.eql?(o)
false
end
obj
end
a.uniq.should == a
a = Array.new(2) do
obj = mock('0')
obj.should_receive(:hash).at_least(1).and_return(0)
def obj.eql?(o)
true
end
obj
end
a.uniq.size.should == 1
end
end
ruby_version_is ''...'2.7' do
it "compares elements with matching hash codes with #eql?" do
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
false
end
obj
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
obj
end
a.uniq.size.should == 1
a[0].tainted?.should == true
a[1].tainted?.should == true
end
end
it "compares elements based on the value returned from the block" do
a = [1, 2, 3, 4]
a.uniq { |x| x >= 2 ? 1 : 0 }.should == [1, 2]
end
it "yields items in order" do
a = [1, 2, 3]
yielded = []
a.uniq { |v| yielded << v }
yielded.should == a
end
it "handles nil and false like any other values" do
[nil, false, 42].uniq { :foo }.should == [nil]
[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)
end
it "properly handles an identical item even when its #eql? isn't reflexive" do
x = mock('x')
x.should_receive(:hash).at_least(1).and_return(42)
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
[x, x].uniq.should == [x]
end
describe "given an array of BasicObject subclasses that define ==, eql?, and hash" do
# jruby/jruby#3227
it "filters equivalent elements using those definitions" do
basic = Class.new(BasicObject) do
attr_reader :x
def initialize(x)
@x = x
end
def ==(rhs)
@x == rhs.x
end
alias_method :eql?, :==
def hash
@x.hash
end
end
a = [basic.new(3), basic.new(2), basic.new(1), basic.new(4), basic.new(1), basic.new(2), basic.new(3)]
a.uniq.should == [basic.new(3), basic.new(2), basic.new(1), basic.new(4)]
end
end
end
describe "Array#uniq!" do
it "modifies the array in place" do
a = [ "a", "a", "b", "b", "c" ]
a.uniq!
a.should == ["a", "b", "c"]
end
it "returns self" do
a = [ "a", "a", "b", "b", "c" ]
a.should equal(a.uniq!)
end
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
empty_dup = empty.dup
empty.uniq!
empty.should == empty_dup
array = ArraySpecs.recursive_array
expected = array[0..3]
array.uniq!
array.should == expected
end
it "compares elements first with hash" do
x = mock('0')
x.should_receive(:hash).at_least(1).and_return(0)
y = mock('0')
y.should_receive(:hash).at_least(1).and_return(0)
a = [x, y]
a.uniq!
a.should == [x, y]
end
it "does not compare elements with different hash codes via eql?" do
x = mock('0')
x.should_not_receive(:eql?)
y = mock('1')
y.should_not_receive(:eql?)
x.should_receive(:hash).at_least(1).and_return(0)
y.should_receive(:hash).at_least(1).and_return(1)
a = [x, y]
a.uniq!
a.should == [x, y]
end
it "returns nil if no changes are made to the array" do
[ "a", "b", "c" ].uniq!.should == nil
end
it "raises a #{frozen_error_class} on a frozen array when the array is modified" do
dup_ary = [1, 1, 2]
dup_ary.freeze
-> { dup_ary.uniq! }.should raise_error(frozen_error_class)
end
# see [ruby-core:23666]
it "raises a #{frozen_error_class} on a frozen array when the array would not be modified" do
-> { ArraySpecs.frozen_array.uniq!}.should raise_error(frozen_error_class)
-> { ArraySpecs.empty_frozen_array.uniq!}.should raise_error(frozen_error_class)
end
it "doesn't yield to the block on a frozen array" do
-> { ArraySpecs.frozen_array.uniq!{ raise RangeError, "shouldn't yield"}}.should raise_error(frozen_error_class)
end
it "compares elements based on the value returned from the block" do
a = [1, 2, 3, 4]
a.uniq! { |x| x >= 2 ? 1 : 0 }.should == [1, 2]
end
it "properly handles an identical item even when its #eql? isn't reflexive" do
x = mock('x')
x.should_receive(:hash).at_least(1).and_return(42)
x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
a = [x, x]
a.uniq!
a.should == [x]
end
end