Keyword argument expectation matching failing in Ruby 2.7
Created by: marcotc
Subject of the issue
When upgrading to 3.10.3 today, I noticed one test failure in our CI matrix that only affected Ruby 2.7.
This issue happens when we provide an empty keyword argument Hash as a keyword splat argument (method(**{})
) to RSpec::Mocks::Matchers::Receive#with
. Example: expect(obj).to receive(:call).with(:foo, **{})
.
When later invoking obj.call(:foo, **{})
I receive the expected: (:foo, {}) got: (:foo)
assertion error.
This does not affect Ruby < 2.7, nor Ruby > 2.7. Nor it affects rspec-mocks 3.10.2.
Preliminary investigation
Looking at the changelog for v3.10.3, I can see changes around ruby2_keywords
, and it looks like the empty keyword argument {}
get dropped in this invocation: https://github.com/rspec/rspec-mocks/blob/97c972be57f2c060a4a7fb8a3c5700a5ede693f0/lib/rspec/mocks/method_double.rb#L64
Another option is to filter out the empty hash before is gets stored in the args
here: https://github.com/rspec/rspec-mocks/blob/97c972be57f2c060a4a7fb8a3c5700a5ede693f0/lib/rspec/mocks/matchers/receive_message_chain.rb#L18
I'm not sure which of these avenues is the correct one, though.
Your environment
- Ruby version: 2.7.3p183
- rspec-mocks version: 3.10.3
Steps to reproduce
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'rspec', '3.10.0'
gem 'rspec-mocks', '3.10.3'
end
require 'rspec/autorun'
RSpec.describe do
it do
obj = Object.new
expect(obj).to receive(:call).with(:foo, **{})
obj.call(:foo, **{})
end
end
Expected behavior
Assertion to match, and test to pass:
Finished in 0.00839 seconds (files took 0.08246 seconds to load)
1 example, 0 failures
Actual behavior
1) is expected to receive call(:foo, {}) 1 time
Failure/Error: obj.call(:foo, **{})
#<Object:0x000055fe45517ba8> received :call with unexpected arguments
expected: (:foo, {})
got: (:foo)
# test.rb:15:in `block (2 levels) in <main>'