summaryrefslogtreecommitdiff
path: root/spec/ruby/core/hash/shared/equal.rb
blob: 43606437feb99a4a577adc2f90093e69dc4073d7 (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
describe :hash_equal, shared: true do
  it "does not compare values when keys don't match" do
    value = mock('x')
    value.should_not_receive(:==)
    value.should_not_receive(:eql?)
    { 1 => value }.send(@method, { 2 => value }).should be_false
  end

  it "returns false when the numbers of keys differ without comparing any elements" do
    obj = mock('x')
    h = { obj => obj }

    obj.should_not_receive(:==)
    obj.should_not_receive(:eql?)

    {}.send(@method, h).should be_false
    h.send(@method, {}).should be_false
  end

  it "first compares keys via hash" do
    x = mock('x')
    x.should_receive(:hash).and_return(0)
    y = mock('y')
    y.should_receive(:hash).and_return(0)

    { x => 1 }.send(@method, { y => 1 }).should be_false
  end

  it "does not compare keys with different hash codes via eql?" do
    x = mock('x')
    y = mock('y')
    x.should_not_receive(:eql?)
    y.should_not_receive(:eql?)

    x.should_receive(:hash).and_return(0)
    y.should_receive(:hash).and_return(1)

    def x.hash() 0 end
    def y.hash() 1 end

    { x => 1 }.send(@method, { y => 1 }).should be_false
  end

  it "computes equality for recursive hashes" do
    h = {}
    h[:a] = h
    h.send(@method, h[:a]).should be_true
    (h == h[:a]).should be_true
  end

  it "computes equality for complex recursive hashes" do
    a, b = {}, {}
    a.merge! self: a, other: b
    b.merge! self: b, other: a
    a.send(@method, b).should be_true # they both have the same structure!

    c = {}
    c.merge! other: c, self: c
    c.send(@method, a).should be_true # subtle, but they both have the same structure!
    a[:delta] = c[:delta] = a
    c.send(@method, a).should be_false # not quite the same structure, as a[:other][:delta] = nil
    c[:delta] = 42
    c.send(@method, a).should be_false
    a[:delta] = 42
    c.send(@method, a).should be_false
    b[:delta] = 42
    c.send(@method, a).should be_true
  end

  it "computes equality for recursive hashes & arrays" do
    x, y, z = [], [], []
    a, b, c = {foo: x, bar: 42}, {foo: y, bar: 42}, {foo: z, bar: 42}
    x << a
    y << c
    z << b
    b.send(@method, c).should be_true # they clearly have the same structure!
    y.send(@method, z).should be_true
    a.send(@method, b).should be_true # subtle, but they both have the same structure!
    x.send(@method, y).should be_true
    y << x
    y.send(@method, z).should be_false
    z << x
    y.send(@method, z).should be_true

    a[:foo], a[:bar] = a[:bar], a[:foo]
    a.send(@method, b).should be_false
    b[:bar] = b[:foo]
    b.send(@method, c).should be_false
  end
end