diff options
Diffstat (limited to 'spec/ruby/core/hash')
79 files changed, 1138 insertions, 1018 deletions
diff --git a/spec/ruby/core/hash/allocate_spec.rb b/spec/ruby/core/hash/allocate_spec.rb index 93420de866..a92accc161 100644 --- a/spec/ruby/core/hash/allocate_spec.rb +++ b/spec/ruby/core/hash/allocate_spec.rb @@ -3,7 +3,7 @@ require_relative '../../spec_helper' describe "Hash.allocate" do it "returns an instance of Hash" do hsh = Hash.allocate - hsh.should be_an_instance_of(Hash) + hsh.should.instance_of?(Hash) end it "returns a fully-formed instance of Hash" do diff --git a/spec/ruby/core/hash/assoc_spec.rb b/spec/ruby/core/hash/assoc_spec.rb index 62b2a11b30..51af51a20f 100644 --- a/spec/ruby/core/hash/assoc_spec.rb +++ b/spec/ruby/core/hash/assoc_spec.rb @@ -6,7 +6,7 @@ describe "Hash#assoc" do end it "returns an Array if the argument is == to a key of the Hash" do - @h.assoc(:apple).should be_an_instance_of(Array) + @h.assoc(:apple).should.instance_of?(Array) end it "returns a 2-element Array if the argument is == to a key of the Hash" do @@ -40,11 +40,11 @@ describe "Hash#assoc" do end it "returns nil if the argument is not a key of the Hash" do - @h.assoc(:green).should be_nil + @h.assoc(:green).should == nil end it "returns nil if the argument is not a key of the Hash even when there is a default" do - Hash.new(42).merge!( foo: :bar ).assoc(42).should be_nil - Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).assoc(42).should be_nil + Hash.new(42).merge!( foo: :bar ).assoc(42).should == nil + Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).assoc(42).should == nil end end diff --git a/spec/ruby/core/hash/clear_spec.rb b/spec/ruby/core/hash/clear_spec.rb index cf05e36ac9..beff925a63 100644 --- a/spec/ruby/core/hash/clear_spec.rb +++ b/spec/ruby/core/hash/clear_spec.rb @@ -4,7 +4,7 @@ require_relative 'fixtures/classes' describe "Hash#clear" do it "removes all key, value pairs" do h = { 1 => 2, 3 => 4 } - h.clear.should equal(h) + h.clear.should.equal?(h) h.should == {} end @@ -26,7 +26,7 @@ describe "Hash#clear" do end it "raises a FrozenError if called on a frozen instance" do - -> { HashSpecs.frozen_hash.clear }.should raise_error(FrozenError) - -> { HashSpecs.empty_frozen_hash.clear }.should raise_error(FrozenError) + -> { HashSpecs.frozen_hash.clear }.should.raise(FrozenError) + -> { HashSpecs.empty_frozen_hash.clear }.should.raise(FrozenError) end end diff --git a/spec/ruby/core/hash/clone_spec.rb b/spec/ruby/core/hash/clone_spec.rb index 6c96fc0c67..d135a84453 100644 --- a/spec/ruby/core/hash/clone_spec.rb +++ b/spec/ruby/core/hash/clone_spec.rb @@ -7,6 +7,6 @@ describe "Hash#clone" do clone = hash.clone clone.should == hash - clone.should_not equal hash + clone.should_not.equal? hash end end diff --git a/spec/ruby/core/hash/compact_spec.rb b/spec/ruby/core/hash/compact_spec.rb index 76aa43949d..de83dabed3 100644 --- a/spec/ruby/core/hash/compact_spec.rb +++ b/spec/ruby/core/hash/compact_spec.rb @@ -10,7 +10,7 @@ describe "Hash#compact" do it "returns new object that rejects pair has nil value" do ret = @hash.compact - ret.should_not equal(@hash) + ret.should_not.equal?(@hash) ret.should == @compact end @@ -19,28 +19,26 @@ describe "Hash#compact" do @hash.should == @initial_pairs end - ruby_version_is '3.3' do - it "retains the default value" do - hash = Hash.new(1) - hash.compact.default.should == 1 - hash[:a] = 1 - hash.compact.default.should == 1 - end + it "retains the default value" do + hash = Hash.new(1) + hash.compact.default.should == 1 + hash[:a] = 1 + hash.compact.default.should == 1 + end - it "retains the default_proc" do - pr = proc { |h, k| h[k] = [] } - hash = Hash.new(&pr) - hash.compact.default_proc.should == pr - hash[:a] = 1 - hash.compact.default_proc.should == pr - end + it "retains the default_proc" do + pr = proc { |h, k| h[k] = [] } + hash = Hash.new(&pr) + hash.compact.default_proc.should == pr + hash[:a] = 1 + hash.compact.default_proc.should == pr + end - it "retains compare_by_identity_flag" do - hash = {}.compare_by_identity - hash.compact.compare_by_identity?.should == true - hash[:a] = 1 - hash.compact.compare_by_identity?.should == true - end + it "retains compare_by_identity flag" do + hash = {}.compare_by_identity + hash.compact.compare_by_identity?.should == true + hash[:a] = 1 + hash.compact.compare_by_identity?.should == true end end @@ -52,7 +50,7 @@ describe "Hash#compact!" do end it "returns self" do - @hash.compact!.should equal(@hash) + @hash.compact!.should.equal?(@hash) end it "rejects own pair has nil value" do @@ -66,7 +64,7 @@ describe "Hash#compact!" do end it "returns nil" do - @hash.compact!.should be_nil + @hash.compact!.should == nil end end @@ -76,7 +74,7 @@ describe "Hash#compact!" do end it "keeps pairs and raises a FrozenError" do - ->{ @hash.compact! }.should raise_error(FrozenError) + ->{ @hash.compact! }.should.raise(FrozenError) @hash.should == @initial_pairs end end diff --git a/spec/ruby/core/hash/compare_by_identity_spec.rb b/spec/ruby/core/hash/compare_by_identity_spec.rb index 2975526a97..1abf9d5666 100644 --- a/spec/ruby/core/hash/compare_by_identity_spec.rb +++ b/spec/ruby/core/hash/compare_by_identity_spec.rb @@ -11,7 +11,7 @@ describe "Hash#compare_by_identity" do @h[[1]] = :a @h[[1]].should == :a @h.compare_by_identity - @h[[1].dup].should be_nil + @h[[1].dup].should == nil end it "rehashes internally so that old keys can be looked up" do @@ -27,21 +27,21 @@ describe "Hash#compare_by_identity" do it "returns self" do h = {} h[:foo] = :bar - h.compare_by_identity.should equal h + h.compare_by_identity.should.equal? h end it "has no effect on an already compare_by_identity hash" do @idh[:foo] = :bar - @idh.compare_by_identity.should equal @idh + @idh.compare_by_identity.should.equal? @idh @idh.should.compare_by_identity? @idh[:foo].should == :bar end it "uses the semantics of BasicObject#equal? to determine key identity" do - [1].should_not equal([1]) + [1].should_not.equal?([1]) @idh[[1]] = :c @idh[[1]] = :d - :bar.should equal(:bar) + :bar.should.equal?(:bar) @idh[:bar] = :e @idh[:bar] = :f @idh.values.should == [:c, :d, :f] @@ -64,13 +64,13 @@ describe "Hash#compare_by_identity" do it "regards #dup'd objects as having different identities" do key = ['foo'] @idh[key.dup] = :str - @idh[key].should be_nil + @idh[key].should == nil end it "regards #clone'd objects as having different identities" do key = ['foo'] @idh[key.clone] = :str - @idh[key].should be_nil + @idh[key].should == nil end it "regards references to the same object as having the same identity" do @@ -82,7 +82,7 @@ describe "Hash#compare_by_identity" do it "raises a FrozenError on frozen hashes" do @h = @h.freeze - -> { @h.compare_by_identity }.should raise_error(FrozenError) + -> { @h.compare_by_identity }.should.raise(FrozenError) end # Behaviour confirmed in https://bugs.ruby-lang.org/issues/1871 @@ -107,7 +107,7 @@ describe "Hash#compare_by_identity" do @idh[foo] = true @idh[foo] = true @idh.size.should == 1 - @idh.keys.first.should equal foo + @idh.keys.first.should.equal? foo end # Check `#[]=` call with a String literal. @@ -128,20 +128,20 @@ end describe "Hash#compare_by_identity?" do it "returns false by default" do h = {} - h.compare_by_identity?.should be_false + h.compare_by_identity?.should == false end it "returns true once #compare_by_identity has been invoked on self" do h = {} h.compare_by_identity - h.compare_by_identity?.should be_true + h.compare_by_identity?.should == true end it "returns true when called multiple times on the same ident hash" do h = {} h.compare_by_identity - h.compare_by_identity?.should be_true - h.compare_by_identity?.should be_true - h.compare_by_identity?.should be_true + h.compare_by_identity?.should == true + h.compare_by_identity?.should == true + h.compare_by_identity?.should == true end end diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb index 8d29773909..c16f373160 100644 --- a/spec/ruby/core/hash/constructor_spec.rb +++ b/spec/ruby/core/hash/constructor_spec.rb @@ -44,23 +44,23 @@ describe "Hash.[]" do it "raises for elements that are not arrays" do -> { - Hash[[:a]].should == {} - }.should raise_error(ArgumentError) + Hash[[:a]] + }.should.raise(ArgumentError, "wrong element type Symbol at 0 (expected array)") -> { - Hash[[:nil]].should == {} - }.should raise_error(ArgumentError) + Hash[[nil]] + }.should.raise(ArgumentError, "wrong element type nil at 0 (expected array)") end it "raises an ArgumentError for arrays of more than 2 elements" do - ->{ Hash[[[:a, :b, :c]]].should == {} }.should raise_error(ArgumentError) + ->{ + Hash[[[:a, :b, :c]]] + }.should.raise(ArgumentError, "invalid number of elements (3 for 1..2)") 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) + Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]] + }.should.raise(ArgumentError, "wrong element type Integer at 2 (expected array)") end describe "passed a single argument which responds to #to_hash" do @@ -71,13 +71,13 @@ describe "Hash.[]" do result = Hash[to_hash] result.should == h - result.should_not equal(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) + -> { Hash[1, 2, 3] }.should.raise(ArgumentError) + -> { Hash[1, 2, { 3 => 4 }] }.should.raise(ArgumentError) end it "calls to_hash" do @@ -87,42 +87,41 @@ describe "Hash.[]" do 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) + HashSpecs::MyHash[1,2,3,4].should.instance_of?(HashSpecs::MyHash) end it "returns instances of subclasses" do - HashSpecs::MyHash[].should be_an_instance_of(HashSpecs::MyHash) + HashSpecs::MyHash[].should.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) + HashSpecs::MyHash[Hash[1, 2]].should.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) + HashSpecs::MyInitializerHash[Hash[1, 2]].should.instance_of?(HashSpecs::MyInitializerHash) end - it "removes the default value" do + it "does not retain the default value" do hash = Hash.new(1) - Hash[hash].default.should be_nil + Hash[hash].default.should == nil hash[:a] = 1 - Hash[hash].default.should be_nil + Hash[hash].default.should == nil end - it "removes the default_proc" do + it "does not retain the default_proc" do hash = Hash.new { |h, k| h[k] = [] } - Hash[hash].default_proc.should be_nil + Hash[hash].default_proc.should == nil hash[:a] = 1 - Hash[hash].default_proc.should be_nil + Hash[hash].default_proc.should == nil end - ruby_version_is '3.3' do - it "does not retain compare_by_identity_flag" do - hash = {}.compare_by_identity - Hash[hash].compare_by_identity?.should == false - hash[:a] = 1 - Hash[hash].compare_by_identity?.should == false - end + 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 diff --git a/spec/ruby/core/hash/deconstruct_keys_spec.rb b/spec/ruby/core/hash/deconstruct_keys_spec.rb index bbcd8932e5..f6ff3a2818 100644 --- a/spec/ruby/core/hash/deconstruct_keys_spec.rb +++ b/spec/ruby/core/hash/deconstruct_keys_spec.rb @@ -4,13 +4,13 @@ describe "Hash#deconstruct_keys" do it "returns self" do hash = {a: 1, b: 2} - hash.deconstruct_keys([:a, :b]).should equal hash + hash.deconstruct_keys([:a, :b]).should.equal? hash end it "requires one argument" do -> { {a: 1}.deconstruct_keys - }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/) + }.should.raise(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/) end it "ignores argument" do diff --git a/spec/ruby/core/hash/default_proc_spec.rb b/spec/ruby/core/hash/default_proc_spec.rb index f4e4803632..4830e02acd 100644 --- a/spec/ruby/core/hash/default_proc_spec.rb +++ b/spec/ruby/core/hash/default_proc_spec.rb @@ -25,24 +25,24 @@ describe "Hash#default_proc=" do h = Hash.new { 'Paris' } obj = mock('to_proc') obj.should_receive(:to_proc).and_return(Proc.new { 'Montreal' }) - (h.default_proc = obj).should equal(obj) + (h.default_proc = obj).should.equal?(obj) h[:cool_city].should == 'Montreal' end it "overrides the static default" do h = Hash.new(42) h.default_proc = Proc.new { 6 } - h.default.should be_nil + h.default.should == nil h.default_proc.call.should == 6 end it "raises an error if passed stuff not convertible to procs" do - ->{{}.default_proc = 42}.should raise_error(TypeError) + ->{{}.default_proc = 42}.should.raise(TypeError) end it "returns the passed Proc" do new_proc = Proc.new {} - ({}.default_proc = new_proc).should equal(new_proc) + ({}.default_proc = new_proc).should.equal?(new_proc) end it "clears the default proc if passed nil" do @@ -53,28 +53,28 @@ describe "Hash#default_proc=" do end it "returns nil if passed nil" do - ({}.default_proc = nil).should be_nil + ({}.default_proc = nil).should == nil end it "accepts a lambda with an arity of 2" do h = {} -> do h.default_proc = -> a, b { } - end.should_not raise_error(TypeError) + end.should_not.raise(TypeError) end it "raises a TypeError if passed a lambda with an arity other than 2" do h = {} -> do h.default_proc = -> a { } - end.should raise_error(TypeError) + end.should.raise(TypeError) -> do h.default_proc = -> a, b, c { } - end.should raise_error(TypeError) + end.should.raise(TypeError) end it "raises a FrozenError if self is frozen" do - -> { {}.freeze.default_proc = Proc.new {} }.should raise_error(FrozenError) - -> { {}.freeze.default_proc = nil }.should raise_error(FrozenError) + -> { {}.freeze.default_proc = Proc.new {} }.should.raise(FrozenError) + -> { {}.freeze.default_proc = nil }.should.raise(FrozenError) end end diff --git a/spec/ruby/core/hash/default_spec.rb b/spec/ruby/core/hash/default_spec.rb index d8b62ea196..17ee032e2b 100644 --- a/spec/ruby/core/hash/default_spec.rb +++ b/spec/ruby/core/hash/default_spec.rb @@ -40,7 +40,7 @@ describe "Hash#default=" do end it "raises a FrozenError if called on a frozen instance" do - -> { HashSpecs.frozen_hash.default = nil }.should raise_error(FrozenError) - -> { HashSpecs.empty_frozen_hash.default = nil }.should raise_error(FrozenError) + -> { HashSpecs.frozen_hash.default = nil }.should.raise(FrozenError) + -> { HashSpecs.empty_frozen_hash.default = nil }.should.raise(FrozenError) end end diff --git a/spec/ruby/core/hash/delete_if_spec.rb b/spec/ruby/core/hash/delete_if_spec.rb index c9e670ffc3..3090633d88 100644 --- a/spec/ruby/core/hash/delete_if_spec.rb +++ b/spec/ruby/core/hash/delete_if_spec.rb @@ -12,13 +12,13 @@ describe "Hash#delete_if" do it "removes every entry for which block is true and returns self" do h = { a: 1, b: 2, c: 3, d: 4 } - h.delete_if { |k,v| v % 2 == 1 }.should equal(h) + h.delete_if { |k,v| v % 2 == 1 }.should.equal?(h) h.should == { b: 2, d: 4 } end it "removes all entries if the block is true" do h = { a: 1, b: 2, c: 3 } - h.delete_if { |k,v| true }.should equal(h) + h.delete_if { |k,v| true }.should.equal?(h) h.should == {} end @@ -35,8 +35,8 @@ describe "Hash#delete_if" do end it "raises a FrozenError if called on a frozen instance" do - -> { HashSpecs.frozen_hash.delete_if { false } }.should raise_error(FrozenError) - -> { HashSpecs.empty_frozen_hash.delete_if { true } }.should raise_error(FrozenError) + -> { HashSpecs.frozen_hash.delete_if { false } }.should.raise(FrozenError) + -> { HashSpecs.empty_frozen_hash.delete_if { true } }.should.raise(FrozenError) end it_behaves_like :hash_iteration_no_block, :delete_if diff --git a/spec/ruby/core/hash/delete_spec.rb b/spec/ruby/core/hash/delete_spec.rb index 3e3479c69c..33ff01bf36 100644 --- a/spec/ruby/core/hash/delete_spec.rb +++ b/spec/ruby/core/hash/delete_spec.rb @@ -52,7 +52,7 @@ describe "Hash#delete" do end it "raises a FrozenError if called on a frozen instance" do - -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError) - -> { HashSpecs.empty_frozen_hash.delete("foo") }.should raise_error(FrozenError) + -> { HashSpecs.frozen_hash.delete("foo") }.should.raise(FrozenError) + -> { HashSpecs.empty_frozen_hash.delete("foo") }.should.raise(FrozenError) end end diff --git a/spec/ruby/core/hash/dig_spec.rb b/spec/ruby/core/hash/dig_spec.rb index aa0ecadd2f..94ac94e850 100644 --- a/spec/ruby/core/hash/dig_spec.rb +++ b/spec/ruby/core/hash/dig_spec.rb @@ -5,16 +5,16 @@ describe "Hash#dig" do it "returns #[] with one arg" do h = { 0 => false, a: 1 } h.dig(:a).should == 1 - h.dig(0).should be_false - h.dig(1).should be_nil + h.dig(0).should == false + h.dig(1).should == nil end it "returns the nested value specified by the sequence of keys" do h = { foo: { bar: { baz: 1 } } } h.dig(:foo, :bar, :baz).should == 1 - h.dig(:foo, :bar, :nope).should be_nil - h.dig(:foo, :baz).should be_nil - h.dig(:bar, :baz, :foo).should be_nil + h.dig(:foo, :bar, :nope).should == nil + h.dig(:foo, :baz).should == nil + h.dig(:bar, :baz, :foo).should == nil end it "returns the nested value specified if the sequence includes an index" do @@ -28,7 +28,7 @@ describe "Hash#dig" do end it "raises an ArgumentError if no arguments provided" do - -> { { the: 'borg' }.dig() }.should raise_error(ArgumentError) + -> { { the: 'borg' }.dig() }.should.raise(ArgumentError) end it "handles type-mixed deep digging" do @@ -47,8 +47,8 @@ describe "Hash#dig" do it "raises TypeError if an intermediate element does not respond to #dig" do h = {} h[:foo] = [ { bar: [ 1 ] }, [ nil, 'str' ] ] - -> { h.dig(:foo, 0, :bar, 0, 0) }.should raise_error(TypeError) - -> { h.dig(:foo, 1, 1, 0) }.should raise_error(TypeError) + -> { h.dig(:foo, 0, :bar, 0, 0) }.should.raise(TypeError) + -> { h.dig(:foo, 1, 1, 0) }.should.raise(TypeError) end it "calls #dig on the result of #[] with the remaining arguments" do @@ -60,7 +60,7 @@ describe "Hash#dig" do it "respects Hash's default" do default = {bar: 42} h = Hash.new(default) - h.dig(:foo).should equal default + h.dig(:foo).should.equal? default h.dig(:foo, :bar).should == 42 end end diff --git a/spec/ruby/core/hash/each_key_spec.rb b/spec/ruby/core/hash/each_key_spec.rb index c84dd696d5..5b2e9deb63 100644 --- a/spec/ruby/core/hash/each_key_spec.rb +++ b/spec/ruby/core/hash/each_key_spec.rb @@ -7,7 +7,7 @@ describe "Hash#each_key" do it "calls block once for each key, passing key" do r = {} h = { 1 => -1, 2 => -2, 3 => -3, 4 => -4 } - h.each_key { |k| r[k] = k }.should equal(h) + h.each_key { |k| r[k] = k }.should.equal?(h) r.should == { 1 => 1, 2 => 2, 3 => 3, 4 => 4 } end diff --git a/spec/ruby/core/hash/each_pair_spec.rb b/spec/ruby/core/hash/each_pair_spec.rb index eb6656681d..01810c130c 100644 --- a/spec/ruby/core/hash/each_pair_spec.rb +++ b/spec/ruby/core/hash/each_pair_spec.rb @@ -1,11 +1,111 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' require_relative 'shared/iteration' -require_relative 'shared/each' require_relative '../enumerable/shared/enumeratorized' describe "Hash#each_pair" do - it_behaves_like :hash_each, :each_pair it_behaves_like :hash_iteration_no_block, :each_pair it_behaves_like :enumeratorized_with_origin_size, :each_pair, { 1 => 2, 3 => 4, 5 => 6 } + + # This is inconsistent with below, MRI checks the block arity in rb_hash_each_pair() + it "yields a [[key, value]] Array for each pair to a block expecting |*args|" do + all_args = [] + { 1 => 2, 3 => 4 }.each_pair { |*args| all_args << args } + all_args.sort.should == [[[1, 2]], [[3, 4]]] + end + + it "yields the key and value of each pair to a block expecting |key, value|" do + r = {} + h = { a: 1, b: 2, c: 3, d: 5 } + h.each_pair { |k,v| r[k.to_s] = v.to_s }.should.equal?(h) + r.should == { "a" => "1", "b" => "2", "c" => "3", "d" => "5" } + end + + it "yields the key only to a block expecting |key,|" do + ary = [] + h = { "a" => 1, "b" => 2, "c" => 3 } + h.each_pair { |k,| ary << k } + ary.sort.should == ["a", "b", "c"] + end + + it "always yields an Array of 2 elements, even when given a callable of arity 2" do + obj = Object.new + def obj.foo(key, value) + end + + -> { + { "a" => 1 }.each_pair(&obj.method(:foo)) + }.should.raise(ArgumentError) + + -> { + { "a" => 1 }.each_pair(&-> key, value { }) + }.should.raise(ArgumentError) + end + + it "yields an Array of 2 elements when given a callable of arity 1" do + obj = Object.new + def obj.foo(key_value) + ScratchPad << key_value + end + + ScratchPad.record([]) + { "a" => 1 }.each_pair(&obj.method(:foo)) + ScratchPad.recorded.should == [["a", 1]] + end + + it "raises an error for a Hash when an arity enforcing callable of arity >2 is passed in" do + obj = Object.new + def obj.foo(key, value, extra) + end + + -> { + { "a" => 1 }.each_pair(&obj.method(:foo)) + }.should.raise(ArgumentError) + end + + it "uses the same order as keys() and values()" do + h = { a: 1, b: 2, c: 3, d: 5 } + keys = [] + values = [] + + h.each_pair do |k, v| + keys << k + values << v + end + + keys.should == h.keys + values.should == h.values + end + + # Confirming the argument-splatting works from child class for both k, v and [k, v] + it "properly expands (or not) child class's 'each'-yielded args" do + cls1 = Class.new(Hash) do + attr_accessor :k_v + def each + super do |k, v| + @k_v = [k, v] + yield k, v + end + end + end + + cls2 = Class.new(Hash) do + attr_accessor :k_v + def each + super do |k, v| + @k_v = [k, v] + yield([k, v]) + end + end + end + + obj1 = cls1.new + obj1['a'] = 'b' + obj1.map {|k, v| [k, v]}.should == [['a', 'b']] + obj1.k_v.should == ['a', 'b'] + + obj2 = cls2.new + obj2['a'] = 'b' + obj2.map {|k, v| [k, v]}.should == [['a', 'b']] + obj2.k_v.should == ['a', 'b'] + end end diff --git a/spec/ruby/core/hash/each_spec.rb b/spec/ruby/core/hash/each_spec.rb index f0de0bdee5..1644b63216 100644 --- a/spec/ruby/core/hash/each_spec.rb +++ b/spec/ruby/core/hash/each_spec.rb @@ -1,11 +1,7 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/iteration' -require_relative 'shared/each' -require_relative '../enumerable/shared/enumeratorized' describe "Hash#each" do - it_behaves_like :hash_each, :each - it_behaves_like :hash_iteration_no_block, :each - it_behaves_like :enumeratorized_with_origin_size, :each, { 1 => 2, 3 => 4, 5 => 6 } + it "is an alias of Hash#each_pair" do + Hash.instance_method(:each).should == Hash.instance_method(:each_pair) + end end diff --git a/spec/ruby/core/hash/each_value_spec.rb b/spec/ruby/core/hash/each_value_spec.rb index 19b076730d..2df95a8789 100644 --- a/spec/ruby/core/hash/each_value_spec.rb +++ b/spec/ruby/core/hash/each_value_spec.rb @@ -7,7 +7,7 @@ describe "Hash#each_value" do it "calls block once for each key, passing value" do r = [] h = { a: -5, b: -3, c: -2, d: -1, e: -1 } - h.each_value { |v| r << v }.should equal(h) + h.each_value { |v| r << v }.should.equal?(h) r.sort.should == [-5, -3, -2, -1, -1] end diff --git a/spec/ruby/core/hash/element_reference_spec.rb b/spec/ruby/core/hash/element_reference_spec.rb index 94e8237839..3d074b346d 100644 --- a/spec/ruby/core/hash/element_reference_spec.rb +++ b/spec/ruby/core/hash/element_reference_spec.rb @@ -12,7 +12,7 @@ describe "Hash#[]" do h[[]].should == "baz" end - it "returns nil as default default value" do + it "returns nil as default value" do { 0 => 0 }[5].should == nil end @@ -36,7 +36,7 @@ describe "Hash#[]" do b = h[:b] a << "bar" - a.should equal(b) + a.should.equal?(b) a.should == "foobar" b.should == "foobar" end diff --git a/spec/ruby/core/hash/element_set_spec.rb b/spec/ruby/core/hash/element_set_spec.rb index 67c5a04d73..bb805477ca 100644 --- a/spec/ruby/core/hash/element_set_spec.rb +++ b/spec/ruby/core/hash/element_set_spec.rb @@ -1,7 +1,121 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative 'shared/store' describe "Hash#[]=" do - it_behaves_like :hash_store, :[]= + it "associates the key with the value" do + h = { a: 1 } + h[:b] = 2 + h.should == { b:2, a:1 } + end + + it "returns the assigned value" do + h = {} + h.send(:[]=, 1, 2).should == 2 + end + + it "duplicates string keys using dup semantics" do + # dup doesn't copy singleton methods + key = +"foo" + def key.reverse() "bar" end + h = {} + h[key] = 0 + h.keys[0].reverse.should == "oof" + end + + it "stores unequal keys that hash to the same value" do + h = {} + k1 = ["x"] + k2 = ["y"] + # So they end up in the same bucket + k1.should_receive(:hash).and_return(0) + k2.should_receive(:hash).and_return(0) + + h[k1] = 1 + h[k2] = 2 + h.size.should == 2 + end + + it "accepts keys with private #hash method" do + key = HashSpecs::KeyWithPrivateHash.new + h = {} + h[key] = "foo" + h[key].should == "foo" + end + + it " accepts keys with an Integer hash" do + o = mock(hash: 1 << 100) + h = {} + h[o] = 1 + h[o].should == 1 + end + + it "duplicates and freezes string keys" do + key = +"foo" + h = {} + h[key] = 0 + key << "bar" + + h.should == { "foo" => 0 } + h.keys[0].should.frozen? + end + + it "doesn't duplicate and freeze already frozen string keys" do + key = "foo".freeze + h = {} + h[key] = 0 + h.keys[0].should.equal?(key) + end + + it "keeps the existing key in the hash if there is a matching one" do + h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 } + key1 = HashSpecs::ByValueKey.new(13) + key2 = HashSpecs::ByValueKey.new(13) + h[key1] = 41 + key_in_hash = h.keys.last + key_in_hash.should.equal?(key1) + h[key2] = 42 + last_key = h.keys.last + last_key.should.equal?(key_in_hash) + last_key.should_not.equal?(key2) + end + + it "keeps the existing String key in the hash if there is a matching one" do + h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 } + key1 = "foo".dup + key2 = "foo".dup + key1.should_not.equal?(key2) + h[key1] = 41 + frozen_key = h.keys.last + frozen_key.should_not.equal?(key1) + h[key2] = 42 + h.keys.last.should.equal?(frozen_key) + h.keys.last.should_not.equal?(key2) + end + + it "raises a FrozenError if called on a frozen instance" do + -> { HashSpecs.frozen_hash[1] = 2 }.should.raise(FrozenError) + end + + it "does not raise an exception if changing the value of an existing key during iteration" do + hash = {1 => 2, 3 => 4, 5 => 6} + hash.each { hash[1] = :foo } + hash.should == {1 => :foo, 3 => 4, 5 => 6} + end + + it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do + code = <<-EOC + load '#{fixture __FILE__, "name.rb"}' + hash = {} + [true, false, 1, 2.0, "hello", :ok].each do |value| + hash[value] = 42 + raise "incorrect value" unless hash[value] == 42 + hash[value] = 43 + raise "incorrect value" unless hash[value] == 43 + end + puts "OK" + puts hash.size + EOC + result = ruby_exe(code, args: "2>&1") + result.should == "OK\n6\n" + end end diff --git a/spec/ruby/core/hash/equal_value_spec.rb b/spec/ruby/core/hash/equal_value_spec.rb index ae13a42679..ab14f81489 100644 --- a/spec/ruby/core/hash/equal_value_spec.rb +++ b/spec/ruby/core/hash/equal_value_spec.rb @@ -13,6 +13,6 @@ describe "Hash#==" do l_val.should_receive(:==).with(r_val).and_return(true) - ({ 1 => l_val } == { 1 => r_val }).should be_true + ({ 1 => l_val } == { 1 => r_val }).should == true end end diff --git a/spec/ruby/core/hash/except_spec.rb b/spec/ruby/core/hash/except_spec.rb index ac84f9975c..77a020e9b7 100644 --- a/spec/ruby/core/hash/except_spec.rb +++ b/spec/ruby/core/hash/except_spec.rb @@ -7,7 +7,7 @@ describe "Hash#except" do it "returns a new duplicate hash without arguments" do ret = @hash.except - ret.should_not equal(@hash) + ret.should_not.equal?(@hash) ret.should == @hash end @@ -19,14 +19,24 @@ describe "Hash#except" do @hash.except(:a, :chunky_bacon).should == { b: 2, c: 3 } end - it "always returns a Hash without a default" do - klass = Class.new(Hash) - h = klass.new(:default) - h[:bar] = 12 - h[:foo] = 42 - r = h.except(:foo) - r.should == {bar: 12} - r.class.should == Hash - r.default.should == nil + it "does not retain the default value" do + h = Hash.new(1) + h.except(:a).default.should == nil + h[:a] = 1 + h.except(:a).default.should == nil + end + + it "does not retain the default_proc" do + pr = proc { |h, k| h[k] = [] } + h = Hash.new(&pr) + h.except(:a).default_proc.should == nil + h[:a] = 1 + h.except(:a).default_proc.should == nil + end + + it "retains compare_by_identity flag" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = h.except(:a) + h2.compare_by_identity?.should == true end end diff --git a/spec/ruby/core/hash/fetch_spec.rb b/spec/ruby/core/hash/fetch_spec.rb index 6e0d207224..f9b80b6c49 100644 --- a/spec/ruby/core/hash/fetch_spec.rb +++ b/spec/ruby/core/hash/fetch_spec.rb @@ -12,7 +12,7 @@ describe "Hash#fetch" do it "formats the object with #inspect in the KeyError message" do -> { {}.fetch('foo') - }.should raise_error(KeyError, 'key not found: "foo"') + }.should.raise(KeyError, 'key not found: "foo"') end end @@ -38,7 +38,7 @@ describe "Hash#fetch" do end it "raises an ArgumentError when not passed one or two arguments" do - -> { {}.fetch() }.should raise_error(ArgumentError) - -> { {}.fetch(1, 2, 3) }.should raise_error(ArgumentError) + -> { {}.fetch() }.should.raise(ArgumentError) + -> { {}.fetch(1, 2, 3) }.should.raise(ArgumentError) end end diff --git a/spec/ruby/core/hash/filter_spec.rb b/spec/ruby/core/hash/filter_spec.rb index 7dabe44984..625a7feb90 100644 --- a/spec/ruby/core/hash/filter_spec.rb +++ b/spec/ruby/core/hash/filter_spec.rb @@ -1,10 +1,13 @@ require_relative '../../spec_helper' -require_relative 'shared/select' describe "Hash#filter" do - it_behaves_like :hash_select, :filter + it "is an alias of Hash#select" do + Hash.instance_method(:filter).should == Hash.instance_method(:select) + end end describe "Hash#filter!" do - it_behaves_like :hash_select!, :filter! + it "is an alias of Hash#select!" do + Hash.instance_method(:filter!).should == Hash.instance_method(:select!) + end end diff --git a/spec/ruby/core/hash/flatten_spec.rb b/spec/ruby/core/hash/flatten_spec.rb index 825da15bfc..18e9a7b56a 100644 --- a/spec/ruby/core/hash/flatten_spec.rb +++ b/spec/ruby/core/hash/flatten_spec.rb @@ -9,7 +9,7 @@ describe "Hash#flatten" do end it "returns an Array" do - {}.flatten.should be_an_instance_of(Array) + {}.flatten.should.instance_of?(Array) end it "returns an empty Array for an empty Hash" do @@ -57,6 +57,6 @@ describe "Hash#flatten" do it "raises a TypeError if given a non-Integer argument" do -> do @h.flatten(Object.new) - end.should raise_error(TypeError) + end.should.raise(TypeError) end end diff --git a/spec/ruby/core/hash/gt_spec.rb b/spec/ruby/core/hash/gt_spec.rb index cd541d4d83..69d23b7d29 100644 --- a/spec/ruby/core/hash/gt_spec.rb +++ b/spec/ruby/core/hash/gt_spec.rb @@ -8,7 +8,7 @@ describe "Hash#>" do it "returns false if both hashes are identical" do h = { a: 1, b: 2 } - (h > h).should be_false + (h > h).should == false end end diff --git a/spec/ruby/core/hash/gte_spec.rb b/spec/ruby/core/hash/gte_spec.rb index 99b89e7217..be5060ea4f 100644 --- a/spec/ruby/core/hash/gte_spec.rb +++ b/spec/ruby/core/hash/gte_spec.rb @@ -8,7 +8,7 @@ describe "Hash#>=" do it "returns true if both hashes are identical" do h = { a: 1, b: 2 } - (h >= h).should be_true + (h >= h).should == true end end diff --git a/spec/ruby/core/hash/has_key_spec.rb b/spec/ruby/core/hash/has_key_spec.rb index 4af53579e5..9a6244c6f6 100644 --- a/spec/ruby/core/hash/has_key_spec.rb +++ b/spec/ruby/core/hash/has_key_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/key' describe "Hash#has_key?" do - it_behaves_like :hash_key_p, :has_key? + it "is an alias of Hash#include?" do + Hash.instance_method(:has_key?).should == Hash.instance_method(:include?) + end end diff --git a/spec/ruby/core/hash/has_value_spec.rb b/spec/ruby/core/hash/has_value_spec.rb index 39f1627fd3..d40e52ebfd 100644 --- a/spec/ruby/core/hash/has_value_spec.rb +++ b/spec/ruby/core/hash/has_value_spec.rb @@ -1,7 +1,16 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/value' describe "Hash#has_value?" do - it_behaves_like :hash_value_p, :has_value? + it "returns true if the value exists in the hash" do + { a: :b }.has_value?(:a).should == false + { 1 => 2 }.has_value?(2).should == true + h = Hash.new(5) + h.has_value?(5).should == false + h = Hash.new { 5 } + h.has_value?(5).should == false + end + + it "uses == semantics for comparing values" do + { 5 => 2.0 }.has_value?(2).should == true + end end diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb index 19eb806dc4..cd67f7a652 100644 --- a/spec/ruby/core/hash/hash_spec.rb +++ b/spec/ruby/core/hash/hash_spec.rb @@ -42,12 +42,10 @@ describe "Hash#hash" do # Like above, because h.eql?(x: [h]) end - ruby_version_is "3.1" do - it "allows omitting values" do - a = 1 - b = 2 + it "allows omitting values" do + a = 1 + b = 2 - eval('{a:, b:}.should == { a: 1, b: 2 }') - end + {a:, b:}.should == { a: 1, b: 2 } end end diff --git a/spec/ruby/core/hash/include_spec.rb b/spec/ruby/core/hash/include_spec.rb index f3959dc589..1c32e9fb23 100644 --- a/spec/ruby/core/hash/include_spec.rb +++ b/spec/ruby/core/hash/include_spec.rb @@ -1,7 +1,40 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/key' describe "Hash#include?" do - it_behaves_like :hash_key_p, :include? + it "returns true if argument is a key" do + h = { a: 1, b: 2, c: 3, 4 => 0 } + h.include?(:a).should == true + h.include?(:b).should == true + h.include?(2).should == false + h.include?(4).should == true + + not_supported_on :opal do + h.include?('b').should == false + h.include?(4.0).should == false + end + end + + it "returns true if the key's matching value was nil" do + { xyz: nil }.include?(:xyz).should == true + end + + it "returns true if the key's matching value was false" do + { xyz: false }.include?(:xyz).should == true + end + + it "returns true if the key is nil" do + { nil => 'b' }.include?(nil).should == true + { nil => nil }.include?(nil).should == true + end + + it "compares keys with the same #hash value via #eql?" do + x = mock('x') + x.stub!(:hash).and_return(42) + + y = mock('y') + y.stub!(:hash).and_return(42) + y.should_receive(:eql?).and_return(false) + + { x => nil }.include?(y).should == false + end end diff --git a/spec/ruby/core/hash/initialize_spec.rb b/spec/ruby/core/hash/initialize_spec.rb index d13496ba3b..cdba598813 100644 --- a/spec/ruby/core/hash/initialize_spec.rb +++ b/spec/ruby/core/hash/initialize_spec.rb @@ -3,7 +3,7 @@ require_relative 'fixtures/classes' describe "Hash#initialize" do it "is private" do - Hash.should have_private_instance_method("initialize") + Hash.private_instance_methods(false).should.include?(:initialize) end it "can be used to reset default_proc" do @@ -42,20 +42,20 @@ describe "Hash#initialize" do it "returns self" do h = Hash.new - h.send(:initialize).should equal(h) + h.send(:initialize).should.equal?(h) end it "raises a FrozenError if called on a frozen instance" do block = -> { HashSpecs.frozen_hash.instance_eval { initialize() }} - block.should raise_error(FrozenError) + block.should.raise(FrozenError) block = -> { HashSpecs.frozen_hash.instance_eval { initialize(nil) } } - block.should raise_error(FrozenError) + block.should.raise(FrozenError) block = -> { HashSpecs.frozen_hash.instance_eval { initialize(5) } } - block.should raise_error(FrozenError) + block.should.raise(FrozenError) block = -> { HashSpecs.frozen_hash.instance_eval { initialize { 5 } } } - block.should raise_error(FrozenError) + block.should.raise(FrozenError) end end diff --git a/spec/ruby/core/hash/inspect_spec.rb b/spec/ruby/core/hash/inspect_spec.rb index f41ebb70a6..359b13360f 100644 --- a/spec/ruby/core/hash/inspect_spec.rb +++ b/spec/ruby/core/hash/inspect_spec.rb @@ -1,7 +1,123 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/to_s' describe "Hash#inspect" do - it_behaves_like :hash_to_s, :inspect + it "returns a string representation with same order as each()" do + h = { a: [1, 2], b: -2, d: -6, nil => nil } + expected = ruby_version_is("3.4") ? "{a: [1, 2], b: -2, d: -6, nil => nil}" : "{:a=>[1, 2], :b=>-2, :d=>-6, nil=>nil}" + h.inspect.should == expected + end + + it "calls #inspect on keys and values" do + key = mock('key') + val = mock('val') + key.should_receive(:inspect).and_return('key') + val.should_receive(:inspect).and_return('val') + expected = ruby_version_is("3.4") ? "{key => val}" : "{key=>val}" + { key => val }.inspect.should == expected + end + + it "does not call #to_s on a String returned from #inspect" do + str = +"abc" + str.should_not_receive(:to_s) + expected = ruby_version_is("3.4") ? '{a: "abc"}' : '{:a=>"abc"}' + { a: str }.inspect.should == expected + end + + it "calls #to_s on the object returned from #inspect if the Object isn't a String" do + obj = mock("Hash#inspect/to_s calls #to_s") + obj.should_receive(:inspect).and_return(obj) + obj.should_receive(:to_s).and_return("abc") + expected = ruby_version_is("3.4") ? "{a: abc}" : "{:a=>abc}" + { a: obj }.inspect.should == expected + end + + it "does not call #to_str on the object returned from #inspect when it is not a String" do + obj = mock("Hash#inspect/to_s does not call #to_str") + obj.should_receive(:inspect).and_return(obj) + obj.should_not_receive(:to_str) + expected_pattern = ruby_version_is("3.4") ? /^\{a: #<MockObject:0x[0-9a-f]+>\}$/ : /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/ + { a: obj }.inspect.should =~ expected_pattern + end + + it "does not call #to_str on the object returned from #to_s when it is not a String" do + obj = mock("Hash#inspect/to_s does not call #to_str on #to_s result") + obj.should_receive(:inspect).and_return(obj) + obj.should_receive(:to_s).and_return(obj) + obj.should_not_receive(:to_str) + expected_pattern = ruby_version_is("3.4") ? /^\{a: #<MockObject:0x[0-9a-f]+>\}$/ : /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/ + { a: obj }.inspect.should =~ expected_pattern + end + + it "does not swallow exceptions raised by #to_s" do + obj = mock("Hash#inspect/to_s does not swallow #to_s exceptions") + obj.should_receive(:inspect).and_return(obj) + obj.should_receive(:to_s).and_raise(Exception) + + -> { { a: obj }.inspect }.should.raise(Exception) + end + + it "handles hashes with recursive values" do + x = {} + x[0] = x + expected = ruby_version_is("3.4") ? '{0 => {...}}' : '{0=>{...}}' + x.inspect.should == expected + + x = {} + y = {} + x[0] = y + y[1] = x + expected_x = ruby_version_is("3.4") ? '{0 => {1 => {...}}}' : '{0=>{1=>{...}}}' + expected_y = ruby_version_is("3.4") ? '{1 => {0 => {...}}}' : '{1=>{0=>{...}}}' + x.inspect.should == expected_x + y.inspect.should == expected_y + end + + it "does not raise if inspected result is not default external encoding" do + utf_16be = mock("utf_16be") + utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE)) + expected = ruby_version_is("3.4") ? '{a: "utf_16be \u3042"}' : '{:a=>"utf_16be \u3042"}' + {a: utf_16be}.inspect.should == expected + end + + it "works for keys and values whose #inspect return a frozen String" do + expected = ruby_version_is("3.4") ? "{true => false}" : "{true=>false}" + { true => false }.inspect.should == expected + end + + ruby_version_is "3.4" do + it "adds quotes to symbol keys that are not valid symbol literals" do + { "needs-quotes": 1 }.inspect.should == '{"needs-quotes": 1}' + end + + it "can be evaled" do + no_quote = '{a: 1, a!: 1, a?: 1}' + eval(no_quote).inspect.should == no_quote + [ + '{"": 1}', + '{"0": 1, "!": 1, "%": 1, "&": 1, "*": 1, "+": 1, "-": 1, "/": 1, "<": 1, ">": 1, "^": 1, "`": 1, "|": 1, "~": 1}', + '{"@a": 1, "$a": 1, "+@": 1, "a=": 1, "[]": 1}', + '{"a\"b": 1, "@@a": 1, "<=>": 1, "===": 1, "[]=": 1}', + ].each do |quote| + eval(quote).inspect.should == quote + end + end + + it "can be evaled when Encoding.default_external is changed" do + external = Encoding.default_external + + Encoding.default_external = Encoding::ASCII + utf8_ascii_hash = '{"\\u3042": 1}' + eval(utf8_ascii_hash).inspect.should == utf8_ascii_hash + + Encoding.default_external = Encoding::UTF_8 + utf8_hash = "{\u3042: 1}" + eval(utf8_hash).inspect.should == utf8_hash + + Encoding.default_external = Encoding::Windows_31J + sjis_hash = "{\x87]: 1}".dup.force_encoding('sjis') + eval(sjis_hash).inspect.should == sjis_hash + ensure + Encoding.default_external = external + end + end end diff --git a/spec/ruby/core/hash/invert_spec.rb b/spec/ruby/core/hash/invert_spec.rb index 73377a9e97..ea441751f2 100644 --- a/spec/ruby/core/hash/invert_spec.rb +++ b/spec/ruby/core/hash/invert_spec.rb @@ -24,4 +24,25 @@ describe "Hash#invert" do HashSpecs::MyHash[1 => 2, 3 => 4].invert.class.should == Hash HashSpecs::MyHash[].invert.class.should == Hash end + + it "does not retain the default value" do + h = Hash.new(1) + h.invert.default.should == nil + h[:a] = 1 + h.invert.default.should == nil + end + + it "does not retain the default_proc" do + pr = proc { |h, k| h[k] = [] } + h = Hash.new(&pr) + h.invert.default_proc.should == nil + h[:a] = 1 + h.invert.default_proc.should == nil + end + + it "does not retain compare_by_identity flag" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = h.invert + h2.compare_by_identity?.should == false + end end diff --git a/spec/ruby/core/hash/keep_if_spec.rb b/spec/ruby/core/hash/keep_if_spec.rb index d50d969467..c975efc5f8 100644 --- a/spec/ruby/core/hash/keep_if_spec.rb +++ b/spec/ruby/core/hash/keep_if_spec.rb @@ -12,24 +12,24 @@ describe "Hash#keep_if" do it "keeps every entry for which block is true and returns self" do h = { a: 1, b: 2, c: 3, d: 4 } - h.keep_if { |k,v| v % 2 == 0 }.should equal(h) + h.keep_if { |k,v| v % 2 == 0 }.should.equal?(h) h.should == { b: 2, d: 4 } end it "removes all entries if the block is false" do h = { a: 1, b: 2, c: 3 } - h.keep_if { |k,v| false }.should equal(h) + h.keep_if { |k,v| false }.should.equal?(h) h.should == {} end it "returns self even if unmodified" do h = { 1 => 2, 3 => 4 } - h.keep_if { true }.should equal(h) + h.keep_if { true }.should.equal?(h) end it "raises a FrozenError if called on a frozen instance" do - -> { HashSpecs.frozen_hash.keep_if { true } }.should raise_error(FrozenError) - -> { HashSpecs.empty_frozen_hash.keep_if { false } }.should raise_error(FrozenError) + -> { HashSpecs.frozen_hash.keep_if { true } }.should.raise(FrozenError) + -> { HashSpecs.empty_frozen_hash.keep_if { false } }.should.raise(FrozenError) end it_behaves_like :hash_iteration_no_block, :keep_if diff --git a/spec/ruby/core/hash/key_spec.rb b/spec/ruby/core/hash/key_spec.rb index 73eecbc98e..c2d7049aed 100644 --- a/spec/ruby/core/hash/key_spec.rb +++ b/spec/ruby/core/hash/key_spec.rb @@ -1,12 +1,32 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/key' -require_relative 'shared/index' describe "Hash#key?" do - it_behaves_like :hash_key_p, :key? + it "is an alias of Hash#include?" do + Hash.instance_method(:key?).should == Hash.instance_method(:include?) + end end describe "Hash#key" do - it_behaves_like :hash_index, :key + it "returns the corresponding key for value" do + { 2 => 'a', 1 => 'b' }.key('b').should == 1 + end + + it "returns nil if the value is not found" do + { a: -1, b: 3.14, c: 2.718 }.key(1).should == nil + end + + it "doesn't return default value if the value is not found" do + Hash.new(5).key(5).should == nil + end + + it "compares values using ==" do + { 1 => 0 }.key(0.0).should == 1 + { 1 => 0.0 }.key(0).should == 1 + + needle = mock('needle') + inhash = mock('inhash') + inhash.should_receive(:==).with(needle).and_return(true) + + { 1 => inhash }.key(needle).should == 1 + end end diff --git a/spec/ruby/core/hash/keys_spec.rb b/spec/ruby/core/hash/keys_spec.rb index 9a067085e5..789c413bee 100644 --- a/spec/ruby/core/hash/keys_spec.rb +++ b/spec/ruby/core/hash/keys_spec.rb @@ -5,11 +5,11 @@ describe "Hash#keys" do it "returns an array with the keys in the order they were inserted" do {}.keys.should == [] - {}.keys.should be_kind_of(Array) + {}.keys.should.is_a?(Array) Hash.new(5).keys.should == [] Hash.new { 5 }.keys.should == [] { 1 => 2, 4 => 8, 2 => 4 }.keys.should == [1, 4, 2] - { 1 => 2, 2 => 4, 4 => 8 }.keys.should be_kind_of(Array) + { 1 => 2, 2 => 4, 4 => 8 }.keys.should.is_a?(Array) { nil => nil }.keys.should == [nil] end diff --git a/spec/ruby/core/hash/length_spec.rb b/spec/ruby/core/hash/length_spec.rb index d0af0945df..325973306f 100644 --- a/spec/ruby/core/hash/length_spec.rb +++ b/spec/ruby/core/hash/length_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/length' describe "Hash#length" do - it_behaves_like :hash_length, :length + it "is an alias of Hash#size" do + Hash.instance_method(:size).should == Hash.instance_method(:length) + end end diff --git a/spec/ruby/core/hash/lt_spec.rb b/spec/ruby/core/hash/lt_spec.rb index 2219615880..4ca326d077 100644 --- a/spec/ruby/core/hash/lt_spec.rb +++ b/spec/ruby/core/hash/lt_spec.rb @@ -8,7 +8,7 @@ describe "Hash#<" do it "returns false if both hashes are identical" do h = { a: 1, b: 2 } - (h < h).should be_false + (h < h).should == false end end diff --git a/spec/ruby/core/hash/lte_spec.rb b/spec/ruby/core/hash/lte_spec.rb index a166e5bca4..29e60273d1 100644 --- a/spec/ruby/core/hash/lte_spec.rb +++ b/spec/ruby/core/hash/lte_spec.rb @@ -8,7 +8,7 @@ describe "Hash#<=" do it "returns true if both hashes are identical" do h = { a: 1, b: 2 } - (h <= h).should be_true + (h <= h).should == true end end diff --git a/spec/ruby/core/hash/member_spec.rb b/spec/ruby/core/hash/member_spec.rb index 37c0414559..e7309c3f7d 100644 --- a/spec/ruby/core/hash/member_spec.rb +++ b/spec/ruby/core/hash/member_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/key' describe "Hash#member?" do - it_behaves_like :hash_key_p, :member? + it "is an alias of Hash#include?" do + Hash.instance_method(:member?).should == Hash.instance_method(:include?) + end end diff --git a/spec/ruby/core/hash/merge_spec.rb b/spec/ruby/core/hash/merge_spec.rb index 5521864297..9e566fcee9 100644 --- a/spec/ruby/core/hash/merge_spec.rb +++ b/spec/ruby/core/hash/merge_spec.rb @@ -1,7 +1,5 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative 'shared/iteration' -require_relative 'shared/update' describe "Hash#merge" do it "returns a new hash by combining self with the contents of other" do @@ -30,7 +28,7 @@ describe "Hash#merge" do -> { h1.merge(h2) { |k, x, y| raise(IndexError) } - }.should raise_error(IndexError) + }.should.raise(IndexError) r = h1.merge(h1) { |k,x,y| :x } r.should == { a: :x, b: :x, d: :x } @@ -47,8 +45,8 @@ describe "Hash#merge" do end it "returns subclass instance for subclasses" do - HashSpecs::MyHash[1 => 2, 3 => 4].merge({ 1 => 2 }).should be_an_instance_of(HashSpecs::MyHash) - HashSpecs::MyHash[].merge({ 1 => 2 }).should be_an_instance_of(HashSpecs::MyHash) + HashSpecs::MyHash[1 => 2, 3 => 4].merge({ 1 => 2 }).should.instance_of?(HashSpecs::MyHash) + HashSpecs::MyHash[].merge({ 1 => 2 }).should.instance_of?(HashSpecs::MyHash) { 1 => 2, 3 => 4 }.merge(HashSpecs::MyHash[1 => 2]).class.should == Hash {}.merge(HashSpecs::MyHash[1 => 2]).class.should == Hash @@ -90,11 +88,36 @@ describe "Hash#merge" do hash = { a: 1 } merged = hash.merge - merged.should eql(hash) - merged.should_not equal(hash) + merged.should.eql?(hash) + merged.should_not.equal?(hash) + end + + it "retains the default value" do + h = Hash.new(1) + h.merge(b: 1, d: 2).default.should == 1 + end + + it "retains the default_proc" do + pr = proc { |h, k| h[k] = [] } + h = Hash.new(&pr) + h.merge(b: 1, d: 2).default_proc.should == pr + end + + it "retains compare_by_identity flag" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = h.merge(b: 1, d: 2) + h2.compare_by_identity?.should == true + end + + it "ignores compare_by_identity flag of an argument" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = { b: 1, d: 2 }.merge(h) + h2.compare_by_identity?.should == false end end describe "Hash#merge!" do - it_behaves_like :hash_update, :merge! + it "is an alias of Hash#update" do + Hash.instance_method(:merge!).should == Hash.instance_method(:update) + end end diff --git a/spec/ruby/core/hash/new_spec.rb b/spec/ruby/core/hash/new_spec.rb index 5ae3e1f98d..207fc2931f 100644 --- a/spec/ruby/core/hash/new_spec.rb +++ b/spec/ruby/core/hash/new_spec.rb @@ -1,6 +1,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +# Actually these are specs of Hash#initialize, there is no Hash.new it's just Class.new. describe "Hash.new" do it "creates an empty Hash if passed no arguments" do Hash.new.should == {} @@ -14,7 +15,7 @@ describe "Hash.new" do it "does not create a copy of the default argument" do str = "foo" - Hash.new(str).default.should equal(str) + Hash.new(str).default.should.equal?(str) end it "creates a Hash with a default_proc if passed a block" do @@ -26,22 +27,22 @@ describe "Hash.new" do end it "raises an ArgumentError if more than one argument is passed" do - -> { Hash.new(5,6) }.should raise_error(ArgumentError) + -> { Hash.new(5,6) }.should.raise(ArgumentError) end it "raises an ArgumentError if passed both default argument and default block" do - -> { Hash.new(5) { 0 } }.should raise_error(ArgumentError) - -> { Hash.new(nil) { 0 } }.should raise_error(ArgumentError) + -> { Hash.new(5) { 0 } }.should.raise(ArgumentError) + -> { Hash.new(nil) { 0 } }.should.raise(ArgumentError) end - ruby_version_is "3.3"..."3.4" do + ruby_version_is ""..."3.4" do it "emits a deprecation warning if keyword arguments are passed" do -> { Hash.new(unknown: true) }.should complain( Regexp.new(Regexp.escape("Calling Hash.new with keyword arguments is deprecated and will be removed in Ruby 3.4; use Hash.new({ key: value }) instead")) ) - -> { Hash.new(1, unknown: true) }.should raise_error(ArgumentError) - -> { Hash.new(unknown: true) { 0 } }.should raise_error(ArgumentError) + -> { Hash.new(1, unknown: true) }.should.raise(ArgumentError) + -> { Hash.new(unknown: true) { 0 } }.should.raise(ArgumentError) Hash.new({ unknown: true }).default.should == { unknown: true } end @@ -55,13 +56,13 @@ describe "Hash.new" do end it "ignores negative capacity" do - -> { Hash.new(capacity: -42) }.should_not raise_error + -> { Hash.new(capacity: -42) }.should_not.raise end it "raises an error if unknown keyword arguments are passed" do - -> { Hash.new(unknown: true) }.should raise_error(ArgumentError) - -> { Hash.new(1, unknown: true) }.should raise_error(ArgumentError) - -> { Hash.new(unknown: true) { 0 } }.should raise_error(ArgumentError) + -> { Hash.new(unknown: true) }.should.raise(ArgumentError) + -> { Hash.new(1, unknown: true) }.should.raise(ArgumentError) + -> { Hash.new(unknown: true) { 0 } }.should.raise(ArgumentError) end end end diff --git a/spec/ruby/core/hash/rassoc_spec.rb b/spec/ruby/core/hash/rassoc_spec.rb index f3b2a6de20..73379f6867 100644 --- a/spec/ruby/core/hash/rassoc_spec.rb +++ b/spec/ruby/core/hash/rassoc_spec.rb @@ -6,7 +6,7 @@ describe "Hash#rassoc" do end it "returns an Array if the argument is a value of the Hash" do - @h.rassoc(:green).should be_an_instance_of(Array) + @h.rassoc(:green).should.instance_of?(Array) end it "returns a 2-element Array if the argument is a value of the Hash" do @@ -28,15 +28,15 @@ describe "Hash#rassoc" do it "uses #== to compare the argument to the values" do @h[:key] = 1.0 1.should == 1.0 - @h.rassoc(1).should eql [:key, 1.0] + @h.rassoc(1).should.eql? [:key, 1.0] end it "returns nil if the argument is not a value of the Hash" do - @h.rassoc(:banana).should be_nil + @h.rassoc(:banana).should == nil end it "returns nil if the argument is not a value of the Hash even when there is a default" do - Hash.new(42).merge!( foo: :bar ).rassoc(42).should be_nil - Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).rassoc(42).should be_nil + Hash.new(42).merge!( foo: :bar ).rassoc(42).should == nil + Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).rassoc(42).should == nil end end diff --git a/spec/ruby/core/hash/rehash_spec.rb b/spec/ruby/core/hash/rehash_spec.rb index db3e91b166..fcd5a037bd 100644 --- a/spec/ruby/core/hash/rehash_spec.rb +++ b/spec/ruby/core/hash/rehash_spec.rb @@ -20,7 +20,7 @@ describe "Hash#rehash" do h.keys.include?(k1).should == true - h.rehash.should equal(h) + h.rehash.should.equal?(h) h.key?(k1).should == true h[k1].should == :v1 end @@ -108,7 +108,7 @@ describe "Hash#rehash" do end it "raises a FrozenError if called on a frozen instance" do - -> { HashSpecs.frozen_hash.rehash }.should raise_error(FrozenError) - -> { HashSpecs.empty_frozen_hash.rehash }.should raise_error(FrozenError) + -> { HashSpecs.frozen_hash.rehash }.should.raise(FrozenError) + -> { HashSpecs.empty_frozen_hash.rehash }.should.raise(FrozenError) end end diff --git a/spec/ruby/core/hash/reject_spec.rb b/spec/ruby/core/hash/reject_spec.rb index dd8e817237..aa1a074897 100644 --- a/spec/ruby/core/hash/reject_spec.rb +++ b/spec/ruby/core/hash/reject_spec.rb @@ -28,8 +28,8 @@ describe "Hash#reject" do context "with extra state" do it "returns Hash instance for subclasses" do - HashSpecs::MyHash[1 => 2, 3 => 4].reject { false }.should be_kind_of(Hash) - HashSpecs::MyHash[1 => 2, 3 => 4].reject { true }.should be_kind_of(Hash) + HashSpecs::MyHash[1 => 2, 3 => 4].reject { false }.should.is_a?(Hash) + HashSpecs::MyHash[1 => 2, 3 => 4].reject { true }.should.is_a?(Hash) end end @@ -44,6 +44,27 @@ describe "Hash#reject" do reject_pairs.should == reject_bang_pairs end + it "does not retain the default value" do + h = Hash.new(1) + h.reject { false }.default.should == nil + h[:a] = 1 + h.reject { false }.default.should == nil + end + + it "does not retain the default_proc" do + pr = proc { |h, k| h[k] = [] } + h = Hash.new(&pr) + h.reject { false }.default_proc.should == nil + h[:a] = 1 + h.reject { false }.default_proc.should == nil + end + + it "retains compare_by_identity flag" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = h.reject { |k, _| k == :a } + h2.compare_by_identity?.should == true + end + it_behaves_like :hash_iteration_no_block, :reject it_behaves_like :enumeratorized_with_origin_size, :reject, { 1 => 2, 3 => 4, 5 => 6 } end @@ -58,7 +79,7 @@ describe "Hash#reject!" do it "removes all entries if the block is true" do h = { a: 1, b: 2, c: 3 } - h.reject! { |k,v| true }.should equal(h) + h.reject! { |k,v| true }.should.equal?(h) h.should == {} end @@ -83,11 +104,11 @@ describe "Hash#reject!" do end it "raises a FrozenError if called on a frozen instance that is modified" do - -> { HashSpecs.empty_frozen_hash.reject! { true } }.should raise_error(FrozenError) + -> { HashSpecs.empty_frozen_hash.reject! { true } }.should.raise(FrozenError) end it "raises a FrozenError if called on a frozen instance that would not be modified" do - -> { HashSpecs.frozen_hash.reject! { false } }.should raise_error(FrozenError) + -> { HashSpecs.frozen_hash.reject! { false } }.should.raise(FrozenError) end it_behaves_like :hash_iteration_no_block, :reject! diff --git a/spec/ruby/core/hash/replace_spec.rb b/spec/ruby/core/hash/replace_spec.rb index a26a31f5f9..4dacbf9779 100644 --- a/spec/ruby/core/hash/replace_spec.rb +++ b/spec/ruby/core/hash/replace_spec.rb @@ -4,7 +4,7 @@ require_relative 'fixtures/classes' describe "Hash#replace" do it "replaces the contents of self with other" do h = { a: 1, b: 2 } - h.replace(c: -1, d: -2).should equal(h) + h.replace(c: -1, d: -2).should.equal?(h) h.should == { c: -1, d: -2 } end @@ -23,48 +23,57 @@ describe "Hash#replace" do h.should == { 1 => 2 } end - it "transfers the compare_by_identity flag" do - hash_a = { a: 1 } - hash_b = { b: 2 } - hash_b.compare_by_identity - hash_a.should_not.compare_by_identity? - hash_a.replace(hash_b) - hash_a.should.compare_by_identity? + it "does not retain the default value" do + hash = Hash.new(1) + hash.replace(b: 2).default.should == nil + end - hash_a = { a: 1 } - hash_b = { b: 2 } - hash_a.compare_by_identity - hash_a.should.compare_by_identity? - hash_a.replace(hash_b) - hash_a.should_not.compare_by_identity? + it "transfers the default value of an argument" do + hash = Hash.new(1) + { a: 1 }.replace(hash).default.should == 1 end - it "does not transfer default values" do - hash_a = {} - hash_b = Hash.new(5) - hash_a.replace(hash_b) - hash_a.default.should == 5 + it "does not retain the default_proc" do + pr = proc { |h, k| h[k] = [] } + hash = Hash.new(&pr) + hash.replace(b: 2).default_proc.should == nil + end - hash_a = {} - hash_b = Hash.new { |h, k| k * 2 } - hash_a.replace(hash_b) - hash_a.default(5).should == 10 + it "transfers the default_proc of an argument" do + pr = proc { |h, k| h[k] = [] } + hash = Hash.new(&pr) + { a: 1 }.replace(hash).default_proc.should == pr + end + it "does not call the default_proc of an argument" do hash_a = Hash.new { |h, k| k * 5 } hash_b = Hash.new(-> { raise "Should not invoke lambda" }) hash_a.replace(hash_b) hash_a.default.should == hash_b.default end + it "transfers compare_by_identity flag of an argument" do + h = { a: 1, c: 3 } + h2 = { b: 2, d: 4 }.compare_by_identity + h.replace(h2) + h.compare_by_identity?.should == true + end + + it "does not retain compare_by_identity flag" do + h = { a: 1, c: 3 }.compare_by_identity + h.replace(b: 2, d: 4) + h.compare_by_identity?.should == false + end + it "raises a FrozenError if called on a frozen instance that would not be modified" do -> do HashSpecs.frozen_hash.replace(HashSpecs.frozen_hash) - end.should raise_error(FrozenError) + end.should.raise(FrozenError) end it "raises a FrozenError if called on a frozen instance that is modified" do -> do HashSpecs.frozen_hash.replace(HashSpecs.empty_frozen_hash) - end.should raise_error(FrozenError) + end.should.raise(FrozenError) end end diff --git a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb index 7dbb9c0a98..609a53f81f 100644 --- a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb +++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb @@ -16,7 +16,7 @@ describe "Hash.ruby2_keywords_hash?" do end it "raises TypeError for non-Hash" do - -> { Hash.ruby2_keywords_hash?(nil) }.should raise_error(TypeError) + -> { Hash.ruby2_keywords_hash?(nil) }.should.raise(TypeError) end end @@ -54,7 +54,7 @@ describe "Hash.ruby2_keywords_hash" do end it "raises TypeError for non-Hash" do - -> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError) + -> { Hash.ruby2_keywords_hash(nil) }.should.raise(TypeError) end it "retains the default value" do @@ -72,12 +72,10 @@ describe "Hash.ruby2_keywords_hash" do Hash.ruby2_keywords_hash(hash).default_proc.should == pr end - ruby_version_is '3.3' do - it "retains compare_by_identity_flag" do - hash = {}.compare_by_identity - Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true - hash[:a] = 1 - Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true - end + it "retains compare_by_identity_flag" do + hash = {}.compare_by_identity + Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true + hash[:a] = 1 + Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true end end diff --git a/spec/ruby/core/hash/select_spec.rb b/spec/ruby/core/hash/select_spec.rb index 38b0180b0e..60b2ce67c1 100644 --- a/spec/ruby/core/hash/select_spec.rb +++ b/spec/ruby/core/hash/select_spec.rb @@ -1,10 +1,112 @@ require_relative '../../spec_helper' -require_relative 'shared/select' +require_relative '../enumerable/shared/enumeratorized' +require_relative 'fixtures/classes' +require_relative 'shared/iteration' describe "Hash#select" do - it_behaves_like :hash_select, :select + before :each do + @hsh = { 1 => 2, 3 => 4, 5 => 6 } + @empty = {} + end + + it "yields two arguments: key and value" do + all_args = [] + { 1 => 2, 3 => 4 }.select { |*args| all_args << args } + all_args.sort.should == [[1, 2], [3, 4]] + end + + it "returns a Hash of entries for which block is true" do + a_pairs = { 'a' => 9, 'c' => 4, 'b' => 5, 'd' => 2 }.select { |k,v| v % 2 == 0 } + a_pairs.should.instance_of?(Hash) + a_pairs.sort.should == [['c', 4], ['d', 2]] + end + + it "processes entries with the same order as reject" do + h = { a: 9, c: 4, b: 5, d: 2 } + + select_pairs = [] + reject_pairs = [] + h.dup.select{ |*pair| select_pairs << pair } + h.reject { |*pair| reject_pairs << pair } + + select_pairs.should == reject_pairs + end + + it "returns an Enumerator when called on a non-empty hash without a block" do + @hsh.select.should.instance_of?(Enumerator) + end + + it "returns an Enumerator when called on an empty hash without a block" do + @empty.select.should.instance_of?(Enumerator) + end + + it "does not retain the default value" do + h = Hash.new(1) + h.select { true }.default.should == nil + h[:a] = 1 + h.select { true }.default.should == nil + end + + it "does not retain the default_proc" do + pr = proc { |h, k| h[k] = [] } + h = Hash.new(&pr) + h.select { true }.default_proc.should == nil + h[:a] = 1 + h.select { true }.default_proc.should == nil + end + + it "retains compare_by_identity flag" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = h.select { |k, _| k == :a } + h2.compare_by_identity?.should == true + end + + it_behaves_like :hash_iteration_no_block, :select + + before :each do + @object = { 1 => 2, 3 => 4, 5 => 6 } + end + it_behaves_like :enumeratorized_with_origin_size, :select end describe "Hash#select!" do - it_behaves_like :hash_select!, :select! + before :each do + @hsh = { 1 => 2, 3 => 4, 5 => 6 } + @empty = {} + end + + it "is equivalent to keep_if if changes are made" do + h = { a: 2 } + h.select! { |k,v| v <= 1 }.should.equal? h + + h = { 1 => 2, 3 => 4 } + all_args_select = [] + h.dup.select! { |*args| all_args_select << args } + all_args_select.should == [[1, 2], [3, 4]] + end + + it "removes all entries if the block is false" do + h = { a: 1, b: 2, c: 3 } + h.select! { |k,v| false }.should.equal?(h) + h.should == {} + end + + it "returns nil if no changes were made" do + { a: 1 }.select! { |k,v| v <= 1 }.should == nil + end + + it "raises a FrozenError if called on an empty frozen instance" do + -> { HashSpecs.empty_frozen_hash.select! { false } }.should.raise(FrozenError) + end + + it "raises a FrozenError if called on a frozen instance that would not be modified" do + -> { HashSpecs.frozen_hash.select! { true } }.should.raise(FrozenError) + end + + it_behaves_like :hash_iteration_no_block, :select! + + before :each do + @object = { 1 => 2, 3 => 4, 5 => 6 } + end + it_behaves_like :enumeratorized_with_origin_size, :select! end diff --git a/spec/ruby/core/hash/shared/comparison.rb b/spec/ruby/core/hash/shared/comparison.rb index 07564e4cec..2b62837232 100644 --- a/spec/ruby/core/hash/shared/comparison.rb +++ b/spec/ruby/core/hash/shared/comparison.rb @@ -1,15 +1,15 @@ describe :hash_comparison, shared: true do it "raises a TypeError if the right operand is not a hash" do - -> { { a: 1 }.send(@method, 1) }.should raise_error(TypeError) - -> { { a: 1 }.send(@method, nil) }.should raise_error(TypeError) - -> { { a: 1 }.send(@method, []) }.should raise_error(TypeError) + -> { { a: 1 }.send(@method, 1) }.should.raise(TypeError) + -> { { a: 1 }.send(@method, nil) }.should.raise(TypeError) + -> { { a: 1 }.send(@method, []) }.should.raise(TypeError) end it "returns false if both hashes have the same keys but different values" do h1 = { a: 1 } h2 = { a: 2 } - h1.send(@method, h2).should be_false - h2.send(@method, h1).should be_false + h1.send(@method, h2).should == false + h2.send(@method, h1).should == false end end diff --git a/spec/ruby/core/hash/shared/each.rb b/spec/ruby/core/hash/shared/each.rb deleted file mode 100644 index f9839ff58f..0000000000 --- a/spec/ruby/core/hash/shared/each.rb +++ /dev/null @@ -1,105 +0,0 @@ -describe :hash_each, shared: true do - - # This is inconsistent with below, MRI checks the block arity in rb_hash_each_pair() - it "yields a [[key, value]] Array for each pair to a block expecting |*args|" do - all_args = [] - { 1 => 2, 3 => 4 }.send(@method) { |*args| all_args << args } - all_args.sort.should == [[[1, 2]], [[3, 4]]] - end - - it "yields the key and value of each pair to a block expecting |key, value|" do - r = {} - h = { a: 1, b: 2, c: 3, d: 5 } - h.send(@method) { |k,v| r[k.to_s] = v.to_s }.should equal(h) - r.should == { "a" => "1", "b" => "2", "c" => "3", "d" => "5" } - end - - it "yields the key only to a block expecting |key,|" do - ary = [] - h = { "a" => 1, "b" => 2, "c" => 3 } - h.send(@method) { |k,| ary << k } - ary.sort.should == ["a", "b", "c"] - end - - it "always yields an Array of 2 elements, even when given a callable of arity 2" do - obj = Object.new - def obj.foo(key, value) - end - - -> { - { "a" => 1 }.send(@method, &obj.method(:foo)) - }.should raise_error(ArgumentError) - - -> { - { "a" => 1 }.send(@method, &-> key, value { }) - }.should raise_error(ArgumentError) - end - - it "yields an Array of 2 elements when given a callable of arity 1" do - obj = Object.new - def obj.foo(key_value) - ScratchPad << key_value - end - - ScratchPad.record([]) - { "a" => 1 }.send(@method, &obj.method(:foo)) - ScratchPad.recorded.should == [["a", 1]] - end - - it "raises an error for a Hash when an arity enforcing callable of arity >2 is passed in" do - obj = Object.new - def obj.foo(key, value, extra) - end - - -> { - { "a" => 1 }.send(@method, &obj.method(:foo)) - }.should raise_error(ArgumentError) - end - - it "uses the same order as keys() and values()" do - h = { a: 1, b: 2, c: 3, d: 5 } - keys = [] - values = [] - - h.send(@method) do |k, v| - keys << k - values << v - end - - keys.should == h.keys - values.should == h.values - end - - # Confirming the argument-splatting works from child class for both k, v and [k, v] - it "properly expands (or not) child class's 'each'-yielded args" do - cls1 = Class.new(Hash) do - attr_accessor :k_v - def each - super do |k, v| - @k_v = [k, v] - yield k, v - end - end - end - - cls2 = Class.new(Hash) do - attr_accessor :k_v - def each - super do |k, v| - @k_v = [k, v] - yield([k, v]) - end - end - end - - obj1 = cls1.new - obj1['a'] = 'b' - obj1.map {|k, v| [k, v]}.should == [['a', 'b']] - obj1.k_v.should == ['a', 'b'] - - obj2 = cls2.new - obj2['a'] = 'b' - obj2.map {|k, v| [k, v]}.should == [['a', 'b']] - obj2.k_v.should == ['a', 'b'] - end -end diff --git a/spec/ruby/core/hash/shared/eql.rb b/spec/ruby/core/hash/shared/eql.rb index 68db49f76d..512e1ad016 100644 --- a/spec/ruby/core/hash/shared/eql.rb +++ b/spec/ruby/core/hash/shared/eql.rb @@ -3,7 +3,7 @@ describe :hash_eql, shared: true do value = mock('x') value.should_not_receive(:==) value.should_not_receive(:eql?) - { 1 => value }.send(@method, { 2 => value }).should be_false + { 1 => value }.send(@method, { 2 => value }).should == false end it "returns false when the numbers of keys differ without comparing any elements" do @@ -13,8 +13,8 @@ describe :hash_eql, shared: true do obj.should_not_receive(:==) obj.should_not_receive(:eql?) - {}.send(@method, h).should be_false - h.send(@method, {}).should be_false + {}.send(@method, h).should == false + h.send(@method, {}).should == false end it "first compares keys via hash" do @@ -23,7 +23,7 @@ describe :hash_eql, shared: true do y = mock('y') y.should_receive(:hash).any_number_of_times.and_return(0) - { x => 1 }.send(@method, { y => 1 }).should be_false + { x => 1 }.send(@method, { y => 1 }).should == false end it "does not compare keys with different hash codes via eql?" do @@ -35,39 +35,39 @@ describe :hash_eql, shared: true do x.should_receive(:hash).any_number_of_times.and_return(0) y.should_receive(:hash).any_number_of_times.and_return(1) - { x => 1 }.send(@method, { y => 1 }).should be_false + { x => 1 }.send(@method, { y => 1 }).should == 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 + h.send(@method, h[:a]).should == true + (h == h[:a]).should == true end it "doesn't call to_hash on objects" do mock_hash = mock("fake hash") def mock_hash.to_hash() {} end - {}.send(@method, mock_hash).should be_false + {}.send(@method, mock_hash).should == false 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! + a.send(@method, b).should == 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! + c.send(@method, a).should == 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.send(@method, a).should == false # not quite the same structure, as a[:other][:delta] = nil c[:delta] = 42 - c.send(@method, a).should be_false + c.send(@method, a).should == false a[:delta] = 42 - c.send(@method, a).should be_false + c.send(@method, a).should == false b[:delta] = 42 - c.send(@method, a).should be_true + c.send(@method, a).should == true end it "computes equality for recursive hashes & arrays" do @@ -76,19 +76,19 @@ describe :hash_eql, shared: true do 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 + b.send(@method, c).should == true # they clearly have the same structure! + y.send(@method, z).should == true + a.send(@method, b).should == true # subtle, but they both have the same structure! + x.send(@method, y).should == true y << x - y.send(@method, z).should be_false + y.send(@method, z).should == false z << x - y.send(@method, z).should be_true + y.send(@method, z).should == true a[:foo], a[:bar] = a[:bar], a[:foo] - a.send(@method, b).should be_false + a.send(@method, b).should == false b[:bar] = b[:foo] - b.send(@method, c).should be_false + b.send(@method, c).should == false end end @@ -100,7 +100,7 @@ describe :hash_eql_additional, shared: true do def y.==(o) false end def x.eql?(o) false end def y.eql?(o) false end - { 1 => x }.send(@method, { 1 => y }).should be_false + { 1 => x }.send(@method, { 1 => y }).should == false x = mock('x') y = mock('y') @@ -108,45 +108,45 @@ describe :hash_eql_additional, shared: true do def y.==(o) true end def x.eql?(o) true end def y.eql?(o) true end - { 1 => x }.send(@method, { 1 => y }).should be_true + { 1 => x }.send(@method, { 1 => y }).should == true end it "compares keys with eql? semantics" do - { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should be_true - { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should be_true - { 1 => "x" }.send(@method, { 1.0 => "x" }).should be_false - { 1.0 => "x" }.send(@method, { 1 => "x" }).should be_false + { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should == true + { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should == true + { 1 => "x" }.send(@method, { 1.0 => "x" }).should == false + { 1.0 => "x" }.send(@method, { 1 => "x" }).should == false end it "returns true if and only if other Hash has the same number of keys and each key-value pair matches" do a = { a: 5 } b = {} - a.send(@method, b).should be_false + a.send(@method, b).should == false b[:a] = 5 - a.send(@method, b).should be_true + a.send(@method, b).should == true not_supported_on :opal do c = { "a" => 5 } - a.send(@method, c).should be_false + a.send(@method, c).should == false end c = { "A" => 5 } - a.send(@method, c).should be_false + a.send(@method, c).should == false c = { a: 6 } - a.send(@method, c).should be_false + a.send(@method, c).should == false end it "does not call to_hash on hash subclasses" do - { 5 => 6 }.send(@method, HashSpecs::ToHashHash[5 => 6]).should be_true + { 5 => 6 }.send(@method, HashSpecs::ToHashHash[5 => 6]).should == true end it "ignores hash class differences" do h = { 1 => 2, 3 => 4 } - HashSpecs::MyHash[h].send(@method, h).should be_true - HashSpecs::MyHash[h].send(@method, HashSpecs::MyHash[h]).should be_true - h.send(@method, HashSpecs::MyHash[h]).should be_true + HashSpecs::MyHash[h].send(@method, h).should == true + HashSpecs::MyHash[h].send(@method, HashSpecs::MyHash[h]).should == true + h.send(@method, HashSpecs::MyHash[h]).should == true end # Why isn't this true of eql? too ? @@ -163,7 +163,7 @@ describe :hash_eql_additional, shared: true do obj end - { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false + { a[0] => 1 }.send(@method, { a[1] => 1 }).should == false a = Array.new(2) do obj = mock('0') @@ -176,7 +176,7 @@ describe :hash_eql_additional, shared: true do obj end - { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true + { a[0] => 1 }.send(@method, { a[1] => 1 }).should == true end it "compares the values in self to values in other hash" do @@ -185,20 +185,20 @@ describe :hash_eql_additional, shared: true do l_val.should_receive(:eql?).with(r_val).and_return(true) - { 1 => l_val }.eql?({ 1 => r_val }).should be_true + { 1 => l_val }.eql?({ 1 => r_val }).should == true end end describe :hash_eql_additional_more, shared: true do it "returns true if other Hash has the same number of keys and each key-value pair matches, even though the default-value are not same" do - Hash.new(5).send(@method, Hash.new(1)).should be_true - Hash.new {|h, k| 1}.send(@method, Hash.new {}).should be_true - Hash.new {|h, k| 1}.send(@method, Hash.new(2)).should be_true + Hash.new(5).send(@method, Hash.new(1)).should == true + Hash.new {|h, k| 1}.send(@method, Hash.new {}).should == true + Hash.new {|h, k| 1}.send(@method, Hash.new(2)).should == true d = Hash.new {|h, k| 1} e = Hash.new {} d[1] = 2 e[1] = 2 - d.send(@method, e).should be_true + d.send(@method, e).should == true end end diff --git a/spec/ruby/core/hash/shared/greater_than.rb b/spec/ruby/core/hash/shared/greater_than.rb index 1f8b9fcfb7..dfe0b80250 100644 --- a/spec/ruby/core/hash/shared/greater_than.rb +++ b/spec/ruby/core/hash/shared/greater_than.rb @@ -5,11 +5,11 @@ describe :hash_greater_than, shared: true do end it "returns true if the other hash is a subset of self" do - @h1.send(@method, @h2).should be_true + @h1.send(@method, @h2).should == true end it "returns false if the other hash is not a subset of self" do - @h2.send(@method, @h1).should be_false + @h2.send(@method, @h1).should == false end it "converts the right operand to a hash before comparing" do @@ -18,6 +18,6 @@ describe :hash_greater_than, shared: true do { a: 1, b: 2 } end - @h1.send(@method, o).should be_true + @h1.send(@method, o).should == true end end diff --git a/spec/ruby/core/hash/shared/index.rb b/spec/ruby/core/hash/shared/index.rb deleted file mode 100644 index 7f6a186464..0000000000 --- a/spec/ruby/core/hash/shared/index.rb +++ /dev/null @@ -1,37 +0,0 @@ -require_relative '../../../spec_helper' -require_relative '../fixtures/classes' - -describe :hash_index, shared: true do - it "returns the corresponding key for value" do - suppress_warning do # for Hash#index - { 2 => 'a', 1 => 'b' }.send(@method, 'b').should == 1 - end - end - - it "returns nil if the value is not found" do - suppress_warning do # for Hash#index - { a: -1, b: 3.14, c: 2.718 }.send(@method, 1).should be_nil - end - end - - it "doesn't return default value if the value is not found" do - suppress_warning do # for Hash#index - Hash.new(5).send(@method, 5).should be_nil - end - end - - it "compares values using ==" do - suppress_warning do # for Hash#index - { 1 => 0 }.send(@method, 0.0).should == 1 - { 1 => 0.0 }.send(@method, 0).should == 1 - end - - needle = mock('needle') - inhash = mock('inhash') - inhash.should_receive(:==).with(needle).and_return(true) - - suppress_warning do # for Hash#index - { 1 => inhash }.send(@method, needle).should == 1 - end - end -end diff --git a/spec/ruby/core/hash/shared/iteration.rb b/spec/ruby/core/hash/shared/iteration.rb index d27c2443f8..322e4b9a2f 100644 --- a/spec/ruby/core/hash/shared/iteration.rb +++ b/spec/ruby/core/hash/shared/iteration.rb @@ -5,15 +5,15 @@ describe :hash_iteration_no_block, shared: true do end it "returns an Enumerator if called on a non-empty hash without a block" do - @hsh.send(@method).should be_an_instance_of(Enumerator) + @hsh.send(@method).should.instance_of?(Enumerator) end it "returns an Enumerator if called on an empty hash without a block" do - @empty.send(@method).should be_an_instance_of(Enumerator) + @empty.send(@method).should.instance_of?(Enumerator) end it "returns an Enumerator if called on a frozen instance" do @hsh.freeze - @hsh.send(@method).should be_an_instance_of(Enumerator) + @hsh.send(@method).should.instance_of?(Enumerator) end end diff --git a/spec/ruby/core/hash/shared/key.rb b/spec/ruby/core/hash/shared/key.rb deleted file mode 100644 index 17f9f81457..0000000000 --- a/spec/ruby/core/hash/shared/key.rb +++ /dev/null @@ -1,38 +0,0 @@ -describe :hash_key_p, shared: true do - it "returns true if argument is a key" do - h = { a: 1, b: 2, c: 3, 4 => 0 } - h.send(@method, :a).should == true - h.send(@method, :b).should == true - h.send(@method, 2).should == false - h.send(@method, 4).should == true - - not_supported_on :opal do - h.send(@method, 'b').should == false - h.send(@method, 4.0).should == false - end - end - - it "returns true if the key's matching value was nil" do - { xyz: nil }.send(@method, :xyz).should == true - end - - it "returns true if the key's matching value was false" do - { xyz: false }.send(@method, :xyz).should == true - end - - it "returns true if the key is nil" do - { nil => 'b' }.send(@method, nil).should == true - { nil => nil }.send(@method, nil).should == true - end - - it "compares keys with the same #hash value via #eql?" do - x = mock('x') - x.stub!(:hash).and_return(42) - - y = mock('y') - y.stub!(:hash).and_return(42) - y.should_receive(:eql?).and_return(false) - - { x => nil }.send(@method, y).should == false - end -end diff --git a/spec/ruby/core/hash/shared/length.rb b/spec/ruby/core/hash/shared/length.rb deleted file mode 100644 index 24f5563759..0000000000 --- a/spec/ruby/core/hash/shared/length.rb +++ /dev/null @@ -1,12 +0,0 @@ -describe :hash_length, shared: true do - it "returns the number of entries" do - { a: 1, b: 'c' }.send(@method).should == 2 - h = { a: 1, b: 2 } - h[:a] = 2 - h.send(@method).should == 2 - { a: 1, b: 1, c: 1 }.send(@method).should == 3 - {}.send(@method).should == 0 - Hash.new(5).send(@method).should == 0 - Hash.new { 5 }.send(@method).should == 0 - end -end diff --git a/spec/ruby/core/hash/shared/less_than.rb b/spec/ruby/core/hash/shared/less_than.rb index cdc6f14546..071b3e97bb 100644 --- a/spec/ruby/core/hash/shared/less_than.rb +++ b/spec/ruby/core/hash/shared/less_than.rb @@ -5,11 +5,11 @@ describe :hash_less_than, shared: true do end it "returns true if self is a subset of the other hash" do - @h1.send(@method, @h2).should be_true + @h1.send(@method, @h2).should == true end it "returns false if self is not a subset of the other hash" do - @h2.send(@method, @h1).should be_false + @h2.send(@method, @h1).should == false end it "converts the right operand to a hash before comparing" do @@ -18,6 +18,6 @@ describe :hash_less_than, shared: true do { a: 1, b: 2, c: 3 } end - @h1.send(@method, o).should be_true + @h1.send(@method, o).should == true end end diff --git a/spec/ruby/core/hash/shared/select.rb b/spec/ruby/core/hash/shared/select.rb deleted file mode 100644 index 5170af50d6..0000000000 --- a/spec/ruby/core/hash/shared/select.rb +++ /dev/null @@ -1,91 +0,0 @@ -require_relative '../../../spec_helper' -require_relative '../fixtures/classes' -require_relative '../shared/iteration' -require_relative '../../enumerable/shared/enumeratorized' - -describe :hash_select, shared: true do - before :each do - @hsh = { 1 => 2, 3 => 4, 5 => 6 } - @empty = {} - end - - it "yields two arguments: key and value" do - all_args = [] - { 1 => 2, 3 => 4 }.send(@method) { |*args| all_args << args } - all_args.sort.should == [[1, 2], [3, 4]] - end - - it "returns a Hash of entries for which block is true" do - a_pairs = { 'a' => 9, 'c' => 4, 'b' => 5, 'd' => 2 }.send(@method) { |k,v| v % 2 == 0 } - a_pairs.should be_an_instance_of(Hash) - a_pairs.sort.should == [['c', 4], ['d', 2]] - end - - it "processes entries with the same order as reject" do - h = { a: 9, c: 4, b: 5, d: 2 } - - select_pairs = [] - reject_pairs = [] - h.dup.send(@method) { |*pair| select_pairs << pair } - h.reject { |*pair| reject_pairs << pair } - - select_pairs.should == reject_pairs - end - - it "returns an Enumerator when called on a non-empty hash without a block" do - @hsh.send(@method).should be_an_instance_of(Enumerator) - end - - it "returns an Enumerator when called on an empty hash without a block" do - @empty.send(@method).should be_an_instance_of(Enumerator) - end - - it_should_behave_like :hash_iteration_no_block - - before :each do - @object = { 1 => 2, 3 => 4, 5 => 6 } - end - it_should_behave_like :enumeratorized_with_origin_size -end - -describe :hash_select!, shared: true do - before :each do - @hsh = { 1 => 2, 3 => 4, 5 => 6 } - @empty = {} - end - - it "is equivalent to keep_if if changes are made" do - h = { a: 2 } - h.send(@method) { |k,v| v <= 1 }.should equal h - - h = { 1 => 2, 3 => 4 } - all_args_select = [] - h.dup.send(@method) { |*args| all_args_select << args } - all_args_select.should == [[1, 2], [3, 4]] - end - - it "removes all entries if the block is false" do - h = { a: 1, b: 2, c: 3 } - h.send(@method) { |k,v| false }.should equal(h) - h.should == {} - end - - it "returns nil if no changes were made" do - { a: 1 }.send(@method) { |k,v| v <= 1 }.should == nil - end - - it "raises a FrozenError if called on an empty frozen instance" do - -> { HashSpecs.empty_frozen_hash.send(@method) { false } }.should raise_error(FrozenError) - end - - it "raises a FrozenError if called on a frozen instance that would not be modified" do - -> { HashSpecs.frozen_hash.send(@method) { true } }.should raise_error(FrozenError) - end - - it_should_behave_like :hash_iteration_no_block - - before :each do - @object = { 1 => 2, 3 => 4, 5 => 6 } - end - it_should_behave_like :enumeratorized_with_origin_size -end diff --git a/spec/ruby/core/hash/shared/store.rb b/spec/ruby/core/hash/shared/store.rb deleted file mode 100644 index dd1bb52bac..0000000000 --- a/spec/ruby/core/hash/shared/store.rb +++ /dev/null @@ -1,115 +0,0 @@ -require_relative '../fixtures/classes' - -describe :hash_store, shared: true do - it "associates the key with the value and return the value" do - h = { a: 1 } - h.send(@method, :b, 2).should == 2 - h.should == { b:2, a:1 } - end - - it "duplicates string keys using dup semantics" do - # dup doesn't copy singleton methods - key = +"foo" - def key.reverse() "bar" end - h = {} - h.send(@method, key, 0) - h.keys[0].reverse.should == "oof" - end - - it "stores unequal keys that hash to the same value" do - h = {} - k1 = ["x"] - k2 = ["y"] - # So they end up in the same bucket - k1.should_receive(:hash).and_return(0) - k2.should_receive(:hash).and_return(0) - - h.send(@method, k1, 1) - h.send(@method, k2, 2) - h.size.should == 2 - end - - it "accepts keys with private #hash method" do - key = HashSpecs::KeyWithPrivateHash.new - h = {} - h.send(@method, key, "foo") - h[key].should == "foo" - end - - it " accepts keys with an Integer hash" do - o = mock(hash: 1 << 100) - h = {} - h[o] = 1 - h[o].should == 1 - end - - it "duplicates and freezes string keys" do - key = +"foo" - h = {} - h.send(@method, key, 0) - key << "bar" - - h.should == { "foo" => 0 } - h.keys[0].should.frozen? - end - - it "doesn't duplicate and freeze already frozen string keys" do - key = "foo".freeze - h = {} - h.send(@method, key, 0) - h.keys[0].should equal(key) - end - - it "keeps the existing key in the hash if there is a matching one" do - h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 } - key1 = HashSpecs::ByValueKey.new(13) - key2 = HashSpecs::ByValueKey.new(13) - h[key1] = 41 - key_in_hash = h.keys.last - key_in_hash.should equal(key1) - h[key2] = 42 - last_key = h.keys.last - last_key.should equal(key_in_hash) - last_key.should_not equal(key2) - end - - it "keeps the existing String key in the hash if there is a matching one" do - h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 } - key1 = "foo".dup - key2 = "foo".dup - key1.should_not equal(key2) - h[key1] = 41 - frozen_key = h.keys.last - frozen_key.should_not equal(key1) - h[key2] = 42 - h.keys.last.should equal(frozen_key) - h.keys.last.should_not equal(key2) - end - - it "raises a FrozenError if called on a frozen instance" do - -> { HashSpecs.frozen_hash.send(@method, 1, 2) }.should raise_error(FrozenError) - end - - it "does not raise an exception if changing the value of an existing key during iteration" do - hash = {1 => 2, 3 => 4, 5 => 6} - hash.each { hash.send(@method, 1, :foo) } - hash.should == {1 => :foo, 3 => 4, 5 => 6} - end - - it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do - code = <<-EOC - load '#{fixture __FILE__, "name.rb"}' - hash = {} - [true, false, 1, 2.0, "hello", :ok].each do |value| - hash[value] = 42 - raise "incorrect value" unless hash[value] == 42 - hash[value] = 43 - raise "incorrect value" unless hash[value] == 43 - end - puts "OK" - puts hash.size - EOC - result = ruby_exe(code, args: "2>&1") - result.should == "OK\n6\n" - end -end diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb deleted file mode 100644 index 7864d7cd4c..0000000000 --- a/spec/ruby/core/hash/shared/to_s.rb +++ /dev/null @@ -1,89 +0,0 @@ -require_relative '../../../spec_helper' -require_relative '../fixtures/classes' - -describe :hash_to_s, shared: true do - it "returns a string representation with same order as each()" do - h = { a: [1, 2], b: -2, d: -6, nil => nil } - - pairs = [] - h.each do |key, value| - pairs << key.inspect + '=>' + value.inspect - end - - str = '{' + pairs.join(', ') + '}' - h.send(@method).should == str - end - - it "calls #inspect on keys and values" do - key = mock('key') - val = mock('val') - key.should_receive(:inspect).and_return('key') - val.should_receive(:inspect).and_return('val') - - { key => val }.send(@method).should == '{key=>val}' - end - - it "does not call #to_s on a String returned from #inspect" do - str = +"abc" - str.should_not_receive(:to_s) - - { a: str }.send(@method).should == '{:a=>"abc"}' - end - - it "calls #to_s on the object returned from #inspect if the Object isn't a String" do - obj = mock("Hash#inspect/to_s calls #to_s") - obj.should_receive(:inspect).and_return(obj) - obj.should_receive(:to_s).and_return("abc") - - { a: obj }.send(@method).should == "{:a=>abc}" - end - - it "does not call #to_str on the object returned from #inspect when it is not a String" do - obj = mock("Hash#inspect/to_s does not call #to_str") - obj.should_receive(:inspect).and_return(obj) - obj.should_not_receive(:to_str) - - { a: obj }.send(@method).should =~ /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/ - end - - it "does not call #to_str on the object returned from #to_s when it is not a String" do - obj = mock("Hash#inspect/to_s does not call #to_str on #to_s result") - obj.should_receive(:inspect).and_return(obj) - obj.should_receive(:to_s).and_return(obj) - obj.should_not_receive(:to_str) - - { a: obj }.send(@method).should =~ /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/ - end - - it "does not swallow exceptions raised by #to_s" do - obj = mock("Hash#inspect/to_s does not swallow #to_s exceptions") - obj.should_receive(:inspect).and_return(obj) - obj.should_receive(:to_s).and_raise(Exception) - - -> { { a: obj }.send(@method) }.should raise_error(Exception) - end - - it "handles hashes with recursive values" do - x = {} - x[0] = x - x.send(@method).should == '{0=>{...}}' - - x = {} - y = {} - x[0] = y - y[1] = x - x.send(@method).should == "{0=>{1=>{...}}}" - y.send(@method).should == "{1=>{0=>{...}}}" - end - - it "does not raise if inspected result is not default external encoding" do - utf_16be = mock("utf_16be") - utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE)) - - {a: utf_16be}.send(@method).should == '{:a=>"utf_16be \u3042"}' - end - - it "works for keys and values whose #inspect return a frozen String" do - { true => false }.to_s.should == "{true=>false}" - end -end diff --git a/spec/ruby/core/hash/shared/update.rb b/spec/ruby/core/hash/shared/update.rb deleted file mode 100644 index 1b0eb809bf..0000000000 --- a/spec/ruby/core/hash/shared/update.rb +++ /dev/null @@ -1,76 +0,0 @@ -describe :hash_update, shared: true do - it "adds the entries from other, overwriting duplicate keys. Returns self" do - h = { _1: 'a', _2: '3' } - h.send(@method, _1: '9', _9: 2).should equal(h) - h.should == { _1: "9", _2: "3", _9: 2 } - end - - it "sets any duplicate key to the value of block if passed a block" do - h1 = { a: 2, b: -1 } - h2 = { a: -2, c: 1 } - h1.send(@method, h2) { |k,x,y| 3.14 }.should equal(h1) - h1.should == { c: 1, b: -1, a: 3.14 } - - h1.send(@method, h1) { nil } - h1.should == { a: nil, b: nil, c: nil } - end - - it "tries to convert the passed argument to a hash using #to_hash" do - obj = mock('{1=>2}') - obj.should_receive(:to_hash).and_return({ 1 => 2 }) - { 3 => 4 }.send(@method, obj).should == { 1 => 2, 3 => 4 } - end - - it "does not call to_hash on hash subclasses" do - { 3 => 4 }.send(@method, HashSpecs::ToHashHash[1 => 2]).should == { 1 => 2, 3 => 4 } - end - - it "processes entries with same order as merge()" do - h = { 1 => 2, 3 => 4, 5 => 6, "x" => nil, nil => 5, [] => [] } - merge_bang_pairs = [] - merge_pairs = [] - h.merge(h) { |*arg| merge_pairs << arg } - h.send(@method, h) { |*arg| merge_bang_pairs << arg } - merge_bang_pairs.should == merge_pairs - end - - it "raises a FrozenError on a frozen instance that is modified" do - -> do - HashSpecs.frozen_hash.send(@method, 1 => 2) - end.should raise_error(FrozenError) - end - - it "checks frozen status before coercing an object with #to_hash" do - obj = mock("to_hash frozen") - # This is necessary because mock cleanup code cannot run on the frozen - # object. - def obj.to_hash() raise Exception, "should not receive #to_hash" end - obj.freeze - - -> { HashSpecs.frozen_hash.send(@method, obj) }.should raise_error(FrozenError) - end - - # see redmine #1571 - it "raises a FrozenError on a frozen instance that would not be modified" do - -> do - HashSpecs.frozen_hash.send(@method, HashSpecs.empty_frozen_hash) - end.should raise_error(FrozenError) - end - - it "does not raise an exception if changing the value of an existing key during iteration" do - hash = {1 => 2, 3 => 4, 5 => 6} - hash2 = {1 => :foo, 3 => :bar} - hash.each { hash.send(@method, hash2) } - hash.should == {1 => :foo, 3 => :bar, 5 => 6} - end - - it "accepts multiple hashes" do - result = { a: 1 }.send(@method, { b: 2 }, { c: 3 }, { d: 4 }) - result.should == { a: 1, b: 2, c: 3, d: 4 } - end - - it "accepts zero arguments" do - hash = { a: 1 } - hash.send(@method).should eql(hash) - end -end diff --git a/spec/ruby/core/hash/shared/value.rb b/spec/ruby/core/hash/shared/value.rb deleted file mode 100644 index aac76c253e..0000000000 --- a/spec/ruby/core/hash/shared/value.rb +++ /dev/null @@ -1,14 +0,0 @@ -describe :hash_value_p, shared: true do - it "returns true if the value exists in the hash" do - { a: :b }.send(@method, :a).should == false - { 1 => 2 }.send(@method, 2).should == true - h = Hash.new(5) - h.send(@method, 5).should == false - h = Hash.new { 5 } - h.send(@method, 5).should == false - end - - it "uses == semantics for comparing values" do - { 5 => 2.0 }.send(@method, 2).should == true - end -end diff --git a/spec/ruby/core/hash/shared/values_at.rb b/spec/ruby/core/hash/shared/values_at.rb deleted file mode 100644 index ef3b0e8ba0..0000000000 --- a/spec/ruby/core/hash/shared/values_at.rb +++ /dev/null @@ -1,9 +0,0 @@ -describe :hash_values_at, shared: true do - it "returns an array of values for the given keys" do - h = { a: 9, b: 'a', c: -10, d: nil } - h.send(@method).should be_kind_of(Array) - h.send(@method).should == [] - h.send(@method, :a, :d, :b).should be_kind_of(Array) - h.send(@method, :a, :d, :b).should == [9, nil, 'a'] - end -end diff --git a/spec/ruby/core/hash/shift_spec.rb b/spec/ruby/core/hash/shift_spec.rb index ea36488a04..6095d2e55f 100644 --- a/spec/ruby/core/hash/shift_spec.rb +++ b/spec/ruby/core/hash/shift_spec.rb @@ -8,7 +8,7 @@ describe "Hash#shift" do h.size.times do |i| r = h.shift - r.should be_kind_of(Array) + r.should.is_a?(Array) h2[r.first].should == r.last h.size.should == h2.size - i - 1 end @@ -30,45 +30,22 @@ describe "Hash#shift" do h.should == {} end - ruby_version_is '3.2' do - it "returns nil if the Hash is empty" do - h = {} - def h.default(key) - raise - end - h.shift.should == nil - end - end - - ruby_version_is ''...'3.2' do - it "calls #default with nil if the Hash is empty" do - h = {} - def h.default(key) - key.should == nil - :foo - end - h.shift.should == :foo + it "returns nil if the Hash is empty" do + h = {} + def h.default(key) + raise end + h.shift.should == nil end it "returns nil from an empty hash" do {}.shift.should == nil end - ruby_version_is '3.2' do - it "returns nil for empty hashes with defaults and default procs" do - Hash.new(5).shift.should == nil - h = Hash.new { |*args| args } - h.shift.should == nil - end - end - - ruby_version_is ''...'3.2' do - it "returns (computed) default for empty hashes" do - Hash.new(5).shift.should == 5 - h = Hash.new { |*args| args } - h.shift.should == [h, nil] - end + it "returns nil for empty hashes with defaults and default procs" do + Hash.new(5).shift.should == nil + h = Hash.new { |*args| args } + h.shift.should == nil end it "preserves Hash invariants when removing the last item" do @@ -80,8 +57,8 @@ describe "Hash#shift" do end it "raises a FrozenError if called on a frozen instance" do - -> { HashSpecs.frozen_hash.shift }.should raise_error(FrozenError) - -> { HashSpecs.empty_frozen_hash.shift }.should raise_error(FrozenError) + -> { HashSpecs.frozen_hash.shift }.should.raise(FrozenError) + -> { HashSpecs.empty_frozen_hash.shift }.should.raise(FrozenError) end it "works when the hash is at capacity" do diff --git a/spec/ruby/core/hash/size_spec.rb b/spec/ruby/core/hash/size_spec.rb index 1e8abd8d97..5e5008a5dc 100644 --- a/spec/ruby/core/hash/size_spec.rb +++ b/spec/ruby/core/hash/size_spec.rb @@ -1,7 +1,14 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/length' describe "Hash#size" do - it_behaves_like :hash_length, :size + it "returns the number of entries" do + { a: 1, b: 'c' }.size.should == 2 + h = { a: 1, b: 2 } + h[:a] = 2 + h.size.should == 2 + { a: 1, b: 1, c: 1 }.size.should == 3 + {}.size.should == 0 + Hash.new(5).size.should == 0 + Hash.new { 5 }.size.should == 0 + end end diff --git a/spec/ruby/core/hash/slice_spec.rb b/spec/ruby/core/hash/slice_spec.rb index e3046d83d7..fd93254517 100644 --- a/spec/ruby/core/hash/slice_spec.rb +++ b/spec/ruby/core/hash/slice_spec.rb @@ -7,8 +7,8 @@ describe "Hash#slice" do it "returns a new empty hash without arguments" do ret = @hash.slice - ret.should_not equal(@hash) - ret.should be_an_instance_of(Hash) + ret.should_not.equal?(@hash) + ret.should.instance_of?(Hash) ret.should == {} end @@ -50,4 +50,25 @@ describe "Hash#slice" do ScratchPad.recorded.should == [] end + + it "does not retain the default value" do + h = Hash.new(1) + h.slice(:a).default.should == nil + h[:a] = 1 + h.slice(:a).default.should == nil + end + + it "does not retain the default_proc" do + pr = proc { |h, k| h[k] = [] } + h = Hash.new(&pr) + h.slice(:a).default_proc.should == nil + h[:a] = 1 + h.slice(:a).default_proc.should == nil + end + + it "retains compare_by_identity flag" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = h.slice(:a) + h2.compare_by_identity?.should == true + end end diff --git a/spec/ruby/core/hash/store_spec.rb b/spec/ruby/core/hash/store_spec.rb index 7e975380ec..7017d8ba2b 100644 --- a/spec/ruby/core/hash/store_spec.rb +++ b/spec/ruby/core/hash/store_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/store' describe "Hash#store" do - it_behaves_like :hash_store, :store + it "is an alias of Hash#[]=" do + Hash.instance_method(:store).should == Hash.instance_method(:[]=) + end end diff --git a/spec/ruby/core/hash/to_a_spec.rb b/spec/ruby/core/hash/to_a_spec.rb index 5baf677929..8c638db6c3 100644 --- a/spec/ruby/core/hash/to_a_spec.rb +++ b/spec/ruby/core/hash/to_a_spec.rb @@ -10,7 +10,7 @@ describe "Hash#to_a" do pairs << [key, value] end - h.to_a.should be_kind_of(Array) + h.to_a.should.is_a?(Array) h.to_a.should == pairs end @@ -23,7 +23,7 @@ describe "Hash#to_a" do end ent = h.entries - ent.should be_kind_of(Array) + ent.should.is_a?(Array) ent.should == pairs end end diff --git a/spec/ruby/core/hash/to_h_spec.rb b/spec/ruby/core/hash/to_h_spec.rb index e17ca7e671..5d5a280dac 100644 --- a/spec/ruby/core/hash/to_h_spec.rb +++ b/spec/ruby/core/hash/to_h_spec.rb @@ -4,7 +4,7 @@ require_relative 'fixtures/classes' describe "Hash#to_h" do it "returns self for Hash instances" do h = {} - h.to_h.should equal(h) + h.to_h.should.equal?(h) end describe "when called on a subclass of Hash" do @@ -14,22 +14,27 @@ describe "Hash#to_h" do end it "returns a new Hash instance" do - @h.to_h.should be_an_instance_of(Hash) + @h.to_h.should.instance_of?(Hash) @h.to_h.should == @h @h[:foo].should == :bar end - it "copies the default" do + it "retains the default" do @h.default = 42 @h.to_h.default.should == 42 @h[:hello].should == 42 end - it "copies the default_proc" do + it "retains the default_proc" do @h.default_proc = prc = Proc.new{ |h, k| h[k] = 2 * k } @h.to_h.default_proc.should == prc @h[42].should == 84 end + + it "retains compare_by_identity flag" do + @h.compare_by_identity + @h.to_h.compare_by_identity?.should == true + end end context "with block" do @@ -50,17 +55,17 @@ describe "Hash#to_h" do it "raises ArgumentError if block returns longer or shorter array" do -> do { a: 1, b: 2 }.to_h { |k, v| [k.to_s, v*v, 1] } - end.should raise_error(ArgumentError, /element has wrong array length/) + end.should.raise(ArgumentError, /element has wrong array length/) -> do { a: 1, b: 2 }.to_h { |k, v| [k] } - end.should raise_error(ArgumentError, /element has wrong array length/) + end.should.raise(ArgumentError, /element has wrong array length/) end it "raises TypeError if block returns something other than Array" do -> do { a: 1, b: 2 }.to_h { |k, v| "not-array" } - end.should raise_error(TypeError, /wrong element type String/) + end.should.raise(TypeError, /wrong element type String/) end it "coerces returned pair to Array with #to_ary" do @@ -76,7 +81,26 @@ describe "Hash#to_h" do -> do { a: 1 }.to_h { |k| x } - end.should raise_error(TypeError, /wrong element type MockObject/) + end.should.raise(TypeError, /wrong element type MockObject/) + end + + it "does not retain the default value" do + h = Hash.new(1) + h2 = h.to_h { |k, v| [k.to_s, v*v]} + h2.default.should == nil + end + + it "does not retain the default_proc" do + pr = proc { |h, k| h[k] = [] } + h = Hash.new(&pr) + h2 = h.to_h { |k, v| [k.to_s, v*v]} + h2.default_proc.should == nil + end + + it "does not retain compare_by_identity flag" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = h.to_h { |k, v| [k.to_s, v*v]} + h2.compare_by_identity?.should == false end end end diff --git a/spec/ruby/core/hash/to_hash_spec.rb b/spec/ruby/core/hash/to_hash_spec.rb index f479fa1fb2..f5622b3d9c 100644 --- a/spec/ruby/core/hash/to_hash_spec.rb +++ b/spec/ruby/core/hash/to_hash_spec.rb @@ -4,11 +4,11 @@ require_relative 'fixtures/classes' describe "Hash#to_hash" do it "returns self for Hash instances" do h = {} - h.to_hash.should equal(h) + h.to_hash.should.equal?(h) end it "returns self for instances of subclasses of Hash" do h = HashSpecs::MyHash.new - h.to_hash.should equal(h) + h.to_hash.should.equal?(h) end end diff --git a/spec/ruby/core/hash/to_proc_spec.rb b/spec/ruby/core/hash/to_proc_spec.rb index 9dbc79e5eb..bc4756600d 100644 --- a/spec/ruby/core/hash/to_proc_spec.rb +++ b/spec/ruby/core/hash/to_proc_spec.rb @@ -11,7 +11,7 @@ describe "Hash#to_proc" do end it "returns an instance of Proc" do - @hash.to_proc.should be_an_instance_of Proc + @hash.to_proc.should.instance_of? Proc end describe "the returned proc" do @@ -30,22 +30,22 @@ describe "Hash#to_proc" do it "raises ArgumentError if not passed exactly one argument" do -> { @proc.call - }.should raise_error(ArgumentError) + }.should.raise(ArgumentError) -> { @proc.call 1, 2 - }.should raise_error(ArgumentError) + }.should.raise(ArgumentError) end context "with a stored key" do it "returns the paired value" do - @proc.call(@key).should equal(@value) + @proc.call(@key).should.equal?(@value) end end context "passed as a block" do it "retrieves the hash's values" do - [@key].map(&@proc)[0].should equal(@value) + [@key].map(&@proc)[0].should.equal?(@value) end context "to instance_exec" do @@ -63,7 +63,7 @@ describe "Hash#to_proc" do context "with no stored key" do it "returns nil" do - @proc.call(@unstored).should be_nil + @proc.call(@unstored).should == nil end context "when the hash has a default value" do @@ -72,7 +72,7 @@ describe "Hash#to_proc" do end it "returns the default value" do - @proc.call(@unstored).should equal(@default) + @proc.call(@unstored).should.equal?(@default) end end @@ -85,7 +85,7 @@ describe "Hash#to_proc" do end it "raises an ArgumentError when calling #call on the Proc with no arguments" do - -> { @hash.to_proc.call }.should raise_error(ArgumentError) + -> { @hash.to_proc.call }.should.raise(ArgumentError) end end end diff --git a/spec/ruby/core/hash/to_s_spec.rb b/spec/ruby/core/hash/to_s_spec.rb index e52b09962e..2915db6ef8 100644 --- a/spec/ruby/core/hash/to_s_spec.rb +++ b/spec/ruby/core/hash/to_s_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/to_s' describe "Hash#to_s" do - it_behaves_like :hash_to_s, :to_s + it "is an alias of Hash#inspect" do + Hash.instance_method(:to_s).should == Hash.instance_method(:inspect) + end end diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb index 2fbb17a8e2..d37a2b8616 100644 --- a/spec/ruby/core/hash/transform_keys_spec.rb +++ b/spec/ruby/core/hash/transform_keys_spec.rb @@ -7,8 +7,8 @@ describe "Hash#transform_keys" do it "returns new hash" do ret = @hash.transform_keys(&:succ) - ret.should_not equal(@hash) - ret.should be_an_instance_of(Hash) + ret.should_not.equal?(@hash) + ret.should.instance_of?(Hash) end it "sets the result as transformed keys with the given block" do @@ -22,13 +22,13 @@ describe "Hash#transform_keys" do it "makes both hashes to share values" do value = [1, 2, 3] new_hash = { a: value }.transform_keys(&:upcase) - new_hash[:A].should equal(value) + new_hash[:A].should.equal?(value) end context "when no block is given" do it "returns a sized Enumerator" do enumerator = @hash.transform_keys - enumerator.should be_an_instance_of(Enumerator) + enumerator.should.instance_of?(Enumerator) enumerator.size.should == @hash.size enumerator.each(&:succ).should == { b: 1, c: 2, d: 3 } end @@ -54,6 +54,27 @@ describe "Hash#transform_keys" do it "allows a combination of hash and block argument" do @hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 } end + + it "does not retain the default value" do + h = Hash.new(1) + h.transform_keys(&:succ).default.should == nil + h[:a] = 1 + h.transform_keys(&:succ).default.should == nil + end + + it "does not retain the default_proc" do + pr = proc { |h, k| h[k] = [] } + h = Hash.new(&pr) + h.transform_values(&:succ).default_proc.should == nil + h[:a] = 1 + h.transform_values(&:succ).default_proc.should == nil + end + + it "does not retain compare_by_identity flag" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = h.transform_keys(&:succ) + h2.compare_by_identity?.should == false + end end describe "Hash#transform_keys!" do @@ -63,7 +84,7 @@ describe "Hash#transform_keys!" do end it "returns self" do - @hash.transform_keys!(&:succ).should equal(@hash) + @hash.transform_keys!(&:succ).should.equal?(@hash) end it "updates self as transformed values with the given block" do @@ -76,24 +97,12 @@ describe "Hash#transform_keys!" do @hash.should == { b: 1, c: 2, d: 3, e: 4 } end - ruby_version_is ""..."3.0.2" do # https://bugs.ruby-lang.org/issues/17735 - it "returns the processed keys if we break from the block" do - @hash.transform_keys! do |v| - break if v == :c - v.succ - end - @hash.should == { b: 1, c: 2 } - end - end - - ruby_version_is "3.0.2" do - it "returns the processed keys and non evaluated keys if we break from the block" do - @hash.transform_keys! do |v| - break if v == :c - v.succ - end - @hash.should == { b: 1, c: 2, d: 4 } + it "returns the processed keys and non evaluated keys if we break from the block" do + @hash.transform_keys! do |v| + break if v == :c + v.succ end + @hash.should == { b: 1, c: 2, d: 4 } end it "keeps later pair if new keys conflict" do @@ -103,7 +112,7 @@ describe "Hash#transform_keys!" do context "when no block is given" do it "returns a sized Enumerator" do enumerator = @hash.transform_keys! - enumerator.should be_an_instance_of(Enumerator) + enumerator.should.instance_of?(Enumerator) enumerator.size.should == @hash.size enumerator.each(&:upcase).should == { A: 1, B: 2, C: 3, D: 4 } end @@ -120,21 +129,21 @@ describe "Hash#transform_keys!" do end it "raises a FrozenError on an empty hash" do - ->{ {}.freeze.transform_keys!(&:upcase) }.should raise_error(FrozenError) + ->{ {}.freeze.transform_keys!(&:upcase) }.should.raise(FrozenError) end it "keeps pairs and raises a FrozenError" do - ->{ @hash.transform_keys!(&:upcase) }.should raise_error(FrozenError) + ->{ @hash.transform_keys!(&:upcase) }.should.raise(FrozenError) @hash.should == @initial_pairs end it "raises a FrozenError on hash argument" do - ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError) + ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should.raise(FrozenError) end context "when no block is given" do it "does not raise an exception" do - @hash.transform_keys!.should be_an_instance_of(Enumerator) + @hash.transform_keys!.should.instance_of?(Enumerator) end end end diff --git a/spec/ruby/core/hash/transform_values_spec.rb b/spec/ruby/core/hash/transform_values_spec.rb index acb469416a..b19543a9f4 100644 --- a/spec/ruby/core/hash/transform_values_spec.rb +++ b/spec/ruby/core/hash/transform_values_spec.rb @@ -7,8 +7,8 @@ describe "Hash#transform_values" do it "returns new hash" do ret = @hash.transform_values(&:succ) - ret.should_not equal(@hash) - ret.should be_an_instance_of(Hash) + ret.should_not.equal?(@hash) + ret.should.instance_of?(Hash) end it "sets the result as transformed values with the given block" do @@ -19,13 +19,13 @@ describe "Hash#transform_values" do key = [1, 2, 3] new_hash = { key => 1 }.transform_values(&:succ) new_hash[key].should == 2 - new_hash.keys[0].should equal(key) + new_hash.keys[0].should.equal?(key) end context "when no block is given" do it "returns a sized Enumerator" do enumerator = @hash.transform_values - enumerator.should be_an_instance_of(Enumerator) + enumerator.should.instance_of?(Enumerator) enumerator.size.should == @hash.size enumerator.each(&:succ).should == { a: 2, b: 3, c: 4 } end @@ -39,6 +39,27 @@ describe "Hash#transform_values" do r[:foo].should == 84 r.class.should == Hash end + + it "does not retain the default value" do + h = Hash.new(1) + h.transform_values(&:succ).default.should == nil + h[:a] = 1 + h.transform_values(&:succ).default.should == nil + end + + it "does not retain the default_proc" do + pr = proc { |h, k| h[k] = [] } + h = Hash.new(&pr) + h.transform_values(&:succ).default_proc.should == nil + h[:a] = 1 + h.transform_values(&:succ).default_proc.should == nil + end + + it "retains compare_by_identity flag" do + h = { a: 9, c: 4 }.compare_by_identity + h2 = h.transform_values(&:succ) + h2.compare_by_identity?.should == true + end end describe "Hash#transform_values!" do @@ -48,7 +69,7 @@ describe "Hash#transform_values!" do end it "returns self" do - @hash.transform_values!(&:succ).should equal(@hash) + @hash.transform_values!(&:succ).should.equal?(@hash) end it "updates self as transformed values with the given block" do @@ -67,7 +88,7 @@ describe "Hash#transform_values!" do context "when no block is given" do it "returns a sized Enumerator" do enumerator = @hash.transform_values! - enumerator.should be_an_instance_of(Enumerator) + enumerator.should.instance_of?(Enumerator) enumerator.size.should == @hash.size enumerator.each(&:succ) @hash.should == { a: 2, b: 3, c: 4 } @@ -80,17 +101,17 @@ describe "Hash#transform_values!" do end it "raises a FrozenError on an empty hash" do - ->{ {}.freeze.transform_values!(&:succ) }.should raise_error(FrozenError) + ->{ {}.freeze.transform_values!(&:succ) }.should.raise(FrozenError) end it "keeps pairs and raises a FrozenError" do - ->{ @hash.transform_values!(&:succ) }.should raise_error(FrozenError) + ->{ @hash.transform_values!(&:succ) }.should.raise(FrozenError) @hash.should == @initial_pairs end context "when no block is given" do it "does not raise an exception" do - @hash.transform_values!.should be_an_instance_of(Enumerator) + @hash.transform_values!.should.instance_of?(Enumerator) end end end diff --git a/spec/ruby/core/hash/try_convert_spec.rb b/spec/ruby/core/hash/try_convert_spec.rb index d359ae49d8..c321183356 100644 --- a/spec/ruby/core/hash/try_convert_spec.rb +++ b/spec/ruby/core/hash/try_convert_spec.rb @@ -4,47 +4,47 @@ require_relative 'fixtures/classes' describe "Hash.try_convert" do it "returns the argument if it's a Hash" do x = Hash.new - Hash.try_convert(x).should equal(x) + Hash.try_convert(x).should.equal?(x) end it "returns the argument if it's a kind of Hash" do x = HashSpecs::MyHash.new - Hash.try_convert(x).should equal(x) + Hash.try_convert(x).should.equal?(x) end it "returns nil when the argument does not respond to #to_hash" do - Hash.try_convert(Object.new).should be_nil + Hash.try_convert(Object.new).should == nil end it "sends #to_hash to the argument and returns the result if it's nil" do obj = mock("to_hash") obj.should_receive(:to_hash).and_return(nil) - Hash.try_convert(obj).should be_nil + Hash.try_convert(obj).should == nil end it "sends #to_hash to the argument and returns the result if it's a Hash" do x = Hash.new obj = mock("to_hash") obj.should_receive(:to_hash).and_return(x) - Hash.try_convert(obj).should equal(x) + Hash.try_convert(obj).should.equal?(x) end it "sends #to_hash to the argument and returns the result if it's a kind of Hash" do x = HashSpecs::MyHash.new obj = mock("to_hash") obj.should_receive(:to_hash).and_return(x) - Hash.try_convert(obj).should equal(x) + Hash.try_convert(obj).should.equal?(x) end it "sends #to_hash to the argument and raises TypeError if it's not a kind of Hash" do obj = mock("to_hash") obj.should_receive(:to_hash).and_return(Object.new) - -> { Hash.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Hash (MockObject#to_hash gives Object)") + -> { Hash.try_convert obj }.should raise_consistent_error(TypeError, "can't convert MockObject into Hash (MockObject#to_hash gives Object)") end it "does not rescue exceptions raised by #to_hash" do obj = mock("to_hash") obj.should_receive(:to_hash).and_raise(RuntimeError) - -> { Hash.try_convert obj }.should raise_error(RuntimeError) + -> { Hash.try_convert obj }.should.raise(RuntimeError) end end diff --git a/spec/ruby/core/hash/update_spec.rb b/spec/ruby/core/hash/update_spec.rb index 0975045ad1..f3a3e6b4db 100644 --- a/spec/ruby/core/hash/update_spec.rb +++ b/spec/ruby/core/hash/update_spec.rb @@ -1,7 +1,79 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative 'shared/update' describe "Hash#update" do - it_behaves_like :hash_update, :update + it "adds the entries from other, overwriting duplicate keys. Returns self" do + h = { _1: 'a', _2: '3' } + h.update(_1: '9', _9: 2).should.equal?(h) + h.should == { _1: "9", _2: "3", _9: 2 } + end + + it "sets any duplicate key to the value of block if passed a block" do + h1 = { a: 2, b: -1 } + h2 = { a: -2, c: 1 } + h1.update(h2) { |k,x,y| 3.14 }.should.equal?(h1) + h1.should == { c: 1, b: -1, a: 3.14 } + + h1.update(h1) { nil } + h1.should == { a: nil, b: nil, c: nil } + end + + it "tries to convert the passed argument to a hash using #to_hash" do + obj = mock('{1=>2}') + obj.should_receive(:to_hash).and_return({ 1 => 2 }) + { 3 => 4 }.update(obj).should == { 1 => 2, 3 => 4 } + end + + it "does not call to_hash on hash subclasses" do + { 3 => 4 }.update(HashSpecs::ToHashHash[1 => 2]).should == { 1 => 2, 3 => 4 } + end + + it "processes entries with same order as merge()" do + h = { 1 => 2, 3 => 4, 5 => 6, "x" => nil, nil => 5, [] => [] } + merge_bang_pairs = [] + merge_pairs = [] + h.merge(h) { |*arg| merge_pairs << arg } + h.update(h) { |*arg| merge_bang_pairs << arg } + merge_bang_pairs.should == merge_pairs + end + + it "raises a FrozenError on a frozen instance that is modified" do + -> do + HashSpecs.frozen_hash.update(1 => 2) + end.should.raise(FrozenError) + end + + it "checks frozen status before coercing an object with #to_hash" do + obj = mock("to_hash frozen") + # This is necessary because mock cleanup code cannot run on the frozen + # object. + def obj.to_hash() raise Exception, "should not receive #to_hash" end + obj.freeze + + -> { HashSpecs.frozen_hash.update(obj) }.should.raise(FrozenError) + end + + # see redmine #1571 + it "raises a FrozenError on a frozen instance that would not be modified" do + -> do + HashSpecs.frozen_hash.update(HashSpecs.empty_frozen_hash) + end.should.raise(FrozenError) + end + + it "does not raise an exception if changing the value of an existing key during iteration" do + hash = {1 => 2, 3 => 4, 5 => 6} + hash2 = {1 => :foo, 3 => :bar} + hash.each { hash.update(hash2) } + hash.should == {1 => :foo, 3 => :bar, 5 => 6} + end + + it "accepts multiple hashes" do + result = { a: 1 }.update({ b: 2 }, { c: 3 }, { d: 4 }) + result.should == { a: 1, b: 2, c: 3, d: 4 } + end + + it "accepts zero arguments" do + hash = { a: 1 } + hash.update.should.eql?(hash) + end end diff --git a/spec/ruby/core/hash/value_spec.rb b/spec/ruby/core/hash/value_spec.rb index 0ab16a5d1b..9cfbe576d2 100644 --- a/spec/ruby/core/hash/value_spec.rb +++ b/spec/ruby/core/hash/value_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/value' describe "Hash#value?" do - it_behaves_like :hash_value_p, :value? + it "is an alias of Hash#has_value?" do + Hash.instance_method(:value?).should == Hash.instance_method(:has_value?) + end end diff --git a/spec/ruby/core/hash/values_at_spec.rb b/spec/ruby/core/hash/values_at_spec.rb index b620a279ba..78dcd8df6a 100644 --- a/spec/ruby/core/hash/values_at_spec.rb +++ b/spec/ruby/core/hash/values_at_spec.rb @@ -1,7 +1,11 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/values_at' describe "Hash#values_at" do - it_behaves_like :hash_values_at, :values_at + it "returns an array of values for the given keys" do + h = { a: 9, b: 'a', c: -10, d: nil } + h.values_at.should.is_a?(Array) + h.values_at.should == [] + h.values_at(:a, :d, :b).should.is_a?(Array) + h.values_at(:a, :d, :b).should == [9, nil, 'a'] + end end diff --git a/spec/ruby/core/hash/values_spec.rb b/spec/ruby/core/hash/values_spec.rb index 9f2a481a48..1fe5f48ad6 100644 --- a/spec/ruby/core/hash/values_spec.rb +++ b/spec/ruby/core/hash/values_spec.rb @@ -4,7 +4,7 @@ require_relative 'fixtures/classes' describe "Hash#values" do it "returns an array of values" do h = { 1 => :a, 'a' => :a, 'the' => 'lang' } - h.values.should be_kind_of(Array) + h.values.should.is_a?(Array) h.values.sort {|a, b| a.to_s <=> b.to_s}.should == [:a, :a, 'lang'] end end |
