Skip to content
This repository has been archived by the owner on Nov 30, 2024. It is now read-only.

Commit

Permalink
Add more specs for kwargs forwarding and matching
Browse files Browse the repository at this point in the history
  • Loading branch information
pirj authored and JonRowe committed Jan 7, 2023
1 parent 1c4c7f8 commit c65ff0a
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
4 changes: 3 additions & 1 deletion lib/rspec/mocks/argument_list_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ def args_match?(*actual_args)
return false if expected_args.size != actual_args.size

if RUBY_VERSION >= "3"
# if both arguments end with Hashes, and if one is a keyword hash and the other is not, they don't match
# If the expectation was set with keywords, while the actual method was called with a positional hash argument, they don't match.
# If the expectation was set without keywords, e.g., with({a: 1}), then it fine to call it with either foo(a: 1) or foo({a: 1}).
# This corresponds to Ruby semantics, as if the method was def foo(options).
if Hash === expected_args.last && Hash === actual_args.last
if !Hash.ruby2_keywords_hash?(actual_args.last) && Hash.ruby2_keywords_hash?(expected_args.last)
return false
Expand Down
2 changes: 1 addition & 1 deletion spec/rspec/mocks/argument_matchers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ def ==(other)
end

if RUBY_VERSION >= "3"
it "fails to matches against a hash submitted as a positional argument and received as keyword arguments in Ruby 3.0 or later", :reset => true do
it "fails to match against a hash submitted as a positional argument and received as keyword arguments in Ruby 3.0 or later", :reset => true do
opts = {:a => "a", :b => "b"}
expect(a_double).to receive(:random_call).with(:a => "a", :b => "b")
expect do
Expand Down
53 changes: 53 additions & 0 deletions spec/rspec/mocks/matchers/receive_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ module Mocks
end
end

# FIXME: this is defined here to prevent
# "warning: method redefined; discarding old kw_args_method"
# because shared examples are evaluated several times.
# When we flatten those shared examples in RSpec 4 because
# of no "should" syntax, it will become possible to put this
# class definition closer to examples that use it.
if RSpec::Support::RubyFeatures.required_kw_args_supported?
binding.eval(<<-RUBY, __FILE__, __LINE__)
class TestObject
def kw_args_method(a:, b:); end
end
RUBY
end

shared_examples "a receive matcher" do |*options|
it 'allows the caller to configure how the subject responds' do
wrapped.to receive(:foo).and_return(5)
Expand Down Expand Up @@ -109,6 +123,45 @@ module Mocks
expect(receiver.foo(kw: :arg)).to eq(:arg)
end
it "expects to receive keyword args" do
dbl = instance_double(TestObject)
expect(dbl).to receive(:kw_args_method).with(a: 1, b: 2)
dbl.kw_args_method(a: 1, b: 2)
end
if RUBY_VERSION >= '3.0'
it "fails to expect to receive hash with keyword args" do
expect {
dbl = instance_double(TestObject)
expect(dbl).to receive(:kw_args_method).with(a: 1, b: 2)
dbl.kw_args_method({a: 1, b: 2})
}.to fail_with do |failure|
reset_all
expect(failure.message)
.to include('expected: ({:a=>1, :b=>2}) (keyword arguments)')
.and include('got: ({:a=>1, :b=>2}) (options hash)')
end
end
else
it "expects to receive hash with keyword args" do
dbl = instance_double(TestObject)
expect(dbl).to receive(:kw_args_method).with(a: 1, b: 2)
dbl.kw_args_method({a: 1, b: 2})
end
end
it "expects to receive hash with a hash" do
dbl = instance_double(TestObject)
expect(dbl).to receive(:kw_args_method).with({a: 1, b: 2})
dbl.kw_args_method({a: 1, b: 2})
end
it "expects to receive keyword args with a hash" do
dbl = instance_double(TestObject)
expect(dbl).to receive(:kw_args_method).with({a: 1, b: 2})
dbl.kw_args_method(a: 1, b: 2)
end
RUBY
end
end
Expand Down
14 changes: 14 additions & 0 deletions spec/rspec/mocks/stub_implementation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ def obj.foo; :original; end
include_context "with isolated configuration"
before { RSpec::Mocks.configuration.verify_partial_doubles = true }
include_examples "stubbing `new` on class objects"

if RSpec::Support::RubyFeatures.required_kw_args_supported?
binding.eval(<<-RUBY, __FILE__, __LINE__)
it "handles keyword arguments correctly" do
klass = Class.new do
def initialize(kw:)
end
end
allow(klass).to receive(:new).and_call_original
klass.new(kw: 42)
end
RUBY
end
end
end
end
Expand Down

0 comments on commit c65ff0a

Please sign in to comment.