summaryrefslogtreecommitdiff
path: root/spec/ruby/core/hash/constructor_spec.rb
blob: 0f97f7b40e9c2c9b11f375ed049dc007d5d4b7a5 (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
require_relative '../../spec_helper'
require_relative 'fixtures/classes'

describe "Hash.[]" do
  describe "passed zero arguments" do
    it "returns an empty hash" do
      Hash[].should == {}
    end
  end

  it "creates a Hash; values can be provided as the argument list" do
    Hash[:a, 1, :b, 2].should == { a: 1, b: 2 }
    Hash[].should == {}
    Hash[:a, 1, :b, { c: 2 }].should == { a: 1, b: { c: 2 } }
  end

  it "creates a Hash; values can be provided as one single hash" do
    Hash[a: 1, b: 2].should == { a: 1, b: 2 }
    Hash[{1 => 2, 3 => 4}].should == {1 => 2, 3 => 4}
    Hash[{}].should == {}
  end

  describe "passed an array" do
    it "treats elements that are 2 element arrays as key and value" do
      Hash[[[:a, :b], [:c, :d]]].should == { a: :b, c: :d }
    end

    it "treats elements that are 1 element arrays as keys with value nil" do
      Hash[[[:a]]].should == { a: nil }
    end
  end

  # #1000 #1385
  it "creates a Hash; values can be provided as a list of value-pairs in an array" do
    Hash[[[:a, 1], [:b, 2]]].should == { a: 1, b: 2 }
  end

  it "coerces a single argument which responds to #to_ary" do
    ary = mock('to_ary')
    ary.should_receive(:to_ary).and_return([[:a, :b]])

    Hash[ary].should == { a: :b }
  end

  it "raises for elements that are not arrays" do
    -> {
      Hash[[:a]].should == {}
    }.should raise_error(ArgumentError)
    -> {
      Hash[[:nil]].should == {}
    }.should raise_error(ArgumentError)
  end

  it "raises an ArgumentError for arrays of more than 2 elements" do
    ->{ Hash[[[:a, :b, :c]]].should == {} }.should raise_error(ArgumentError)
  end

  it "raises an ArgumentError when passed a list of value-invalid-pairs in an array" do
    -> {
      -> {
        Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]]
      }.should complain(/ignoring wrong elements/)
    }.should raise_error(ArgumentError)
  end

  describe "passed a single argument which responds to #to_hash" do
    it "coerces it and returns a copy" do
      h = { a: :b, c: :d }
      to_hash = mock('to_hash')
      to_hash.should_receive(:to_hash).and_return(h)

      result = Hash[to_hash]
      result.should == h
      result.should_not equal(h)
    end
  end

  it "raises an ArgumentError when passed an odd number of arguments" do
    -> { Hash[1, 2, 3] }.should raise_error(ArgumentError)
    -> { Hash[1, 2, { 3 => 4 }] }.should raise_error(ArgumentError)
  end

  it "calls to_hash" do
    obj = mock('x')
    def obj.to_hash() { 1 => 2, 3 => 4 } end
    Hash[obj].should == { 1 => 2, 3 => 4 }
  end

  it "returns an instance of a subclass when passed an Array" do
    HashSpecs::MyHash[1,2,3,4].should be_an_instance_of(HashSpecs::MyHash)
  end

  it "returns instances of subclasses" do
    HashSpecs::MyHash[].should be_an_instance_of(HashSpecs::MyHash)
  end

  it "returns an instance of the class it's called on" do
    Hash[HashSpecs::MyHash[1, 2]].class.should == Hash
    HashSpecs::MyHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyHash)
  end

  it "does not call #initialize on the subclass instance" do
    HashSpecs::MyInitializerHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyInitializerHash)
  end

  it "does not retain the default value" do
    hash = Hash.new(1)
    Hash[hash].default.should be_nil
    hash[:a] = 1
    Hash[hash].default.should be_nil
  end

  it "does not retain the default_proc" do
    hash = Hash.new { |h, k| h[k] = [] }
    Hash[hash].default_proc.should be_nil
    hash[:a] = 1
    Hash[hash].default_proc.should be_nil
  end

  ruby_version_is '3.3' do
    it "does not retain compare_by_identity flag" do
      hash = { a: 1 }.compare_by_identity
      Hash[hash].compare_by_identity?.should == false

      hash = {}.compare_by_identity
      Hash[hash].compare_by_identity?.should == false
    end
  end
end