summaryrefslogtreecommitdiff
path: root/spec/ruby/library/set/compare_by_identity_spec.rb
blob: 363a108935c06c9772ef4f7f064a79c04f795226 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
require_relative '../../spec_helper'
require 'set'

ruby_version_is '2.4' do
  describe "Set#compare_by_identity" do
    it "compares its members by identity" do
      a = "a"
      b1 = "b"
      b2 = "b"

      set = Set.new
      set.compare_by_identity
      set.merge([a, a, b1, b2])
      set.to_a.sort.should == [a, b1, b2].sort
    end

    it "causes future comparisons on the receiver to be made by identity" do
      elt = [1]
      set = Set.new
      set << elt
      set.member?(elt.dup).should be_true
      set.compare_by_identity
      set.member?(elt.dup).should be_false
    end

    it "rehashes internally so that old members can be looked up" do
      set = Set.new
      (1..10).each { |k| set << k }
      o = Object.new
      def o.hash; 123; end
      set << o
      set.compare_by_identity
      set.member?(o).should be_true
    end

    it "returns self" do
      set = Set.new
      result = set.compare_by_identity
      result.should equal(set)
    end

    it "is idempotent and has no effect on an already compare_by_identity set" do
      set = Set.new.compare_by_identity
      set << :foo
      set.compare_by_identity.should equal(set)
      set.compare_by_identity?.should == true
      set.to_a.should == [:foo]
    end

    it "uses the semantics of BasicObject#equal? to determine members identity" do
      :a.equal?(:a).should == true
      Set.new.compare_by_identity.merge([:a, :a]).to_a.should == [:a]

      ary1 = [1]
      ary2 = [1]
      ary1.equal?(ary2).should == false
      Set.new.compare_by_identity.merge([ary1, ary2]).to_a.sort.should == [ary1, ary2].sort
    end

    it "uses #equal? semantics, but doesn't actually call #equal? to determine identity" do
      set = Set.new.compare_by_identity
      obj = mock("equal")
      obj.should_not_receive(:equal?)
      set << :foo
      set << obj
      set.to_a.should == [:foo, obj]
    end

    it "does not call #hash on members" do
      elt = mock("element")
      elt.should_not_receive(:hash)
      set = Set.new.compare_by_identity
      set << elt
      set.member?(elt).should be_true
    end

    it "regards #dup'd objects as having different identities" do
      a1 = "a"
      a2 = a1.dup

      set = Set.new.compare_by_identity
      set.merge([a1, a2])
      set.to_a.sort.should == [a1, a2].sort
    end

    it "regards #clone'd objects as having different identities" do
      a1 = "a"
      a2 = a1.clone

      set = Set.new.compare_by_identity
      set.merge([a1, a2])
      set.to_a.sort.should == [a1, a2].sort
    end

    it "raises a #{frozen_error_class} on frozen sets" do
      set = Set.new.freeze
      lambda {
        set.compare_by_identity
      }.should raise_error(frozen_error_class, /frozen Hash/)
    end

    it "persists over #dups" do
      set = Set.new.compare_by_identity
      set << :a
      set_dup = set.dup
      set_dup.should == set
      set_dup << :a
      set_dup.to_a.should == [:a]
    end

    it "persists over #clones" do
      set = Set.new.compare_by_identity
      set << :a
      set_clone = set.clone
      set_clone.should == set
      set_clone << :a
      set_clone.to_a.should == [:a]
    end

    it "is not equal to set what does not compare by identity" do
      Set.new([1, 2]).should == Set.new([1, 2])
      Set.new([1, 2]).should_not == Set.new([1, 2]).compare_by_identity
    end
  end
end

ruby_version_is '2.4' do
  describe "Set#compare_by_identity?" do
    it "returns false by default" do
      Set.new.compare_by_identity?.should == false
    end

    it "returns true once #compare_by_identity has been invoked on self" do
      set = Set.new
      set.compare_by_identity
      set.compare_by_identity?.should == true
    end

    it "returns true when called multiple times on the same set" do
      set = Set.new
      set.compare_by_identity
      set.compare_by_identity?.should == true
      set.compare_by_identity?.should == true
      set.compare_by_identity?.should == true
    end
  end
end