diff --git a/lib/rspec/mocks/message_expectation.rb b/lib/rspec/mocks/message_expectation.rb index cb5a39922..d999dc0f8 100644 --- a/lib/rspec/mocks/message_expectation.rb +++ b/lib/rspec/mocks/message_expectation.rb @@ -98,7 +98,7 @@ def and_return(first_value, *values) # expect(counter.count).to eq(original_count + 1) def and_call_original wrap_original(__method__) do |original, *args, &block| - original.call(*args, &block) + __call_original(original, *args, &block) end end @@ -354,6 +354,25 @@ def to_s end alias inspect to_s + private + + if RSpec::Support::RubyFeatures.kw_args_supported? + def __call_original(original, *args, &block) + if RSpec::Support::MethodSignature.new(original).has_kw_args_in?(args) + binding.eval(<<-CODE, __FILE__, __LINE__) + kwargs = args.pop + original.call(*args, **kwargs, &block) + CODE + else + original.call(*args, &block) + end + end + else + def __call_original(original, *args, &block) + original.call(*args, &block) + end + end + # @private # Contains the parts of `MessageExpectation` that aren't part of # rspec-mocks' public API. The class is very big and could really use diff --git a/spec/rspec/mocks/and_call_original_spec.rb b/spec/rspec/mocks/and_call_original_spec.rb index 8bb20d563..6380d17d4 100644 --- a/spec/rspec/mocks/and_call_original_spec.rb +++ b/spec/rspec/mocks/and_call_original_spec.rb @@ -12,6 +12,12 @@ def meth_2(x) yield x, :additional_yielded_arg end + binding.eval(<<-CODE, __FILE__, __LINE__) + def meth_3(keyword_arg: nil) + keyword_arg + end + CODE + def self.new_instance new end @@ -59,6 +65,15 @@ def self.new_instance expect(value).to eq([:submitted_arg, :additional_yielded_arg]) end + if RSpec::Support::RubyFeatures.kw_args_supported? + it 'works with keyword arguments' do + expect(instance).to receive(:meth_3).and_call_original + binding.eval(<<-CODE, __FILE__, __LINE__) + expect(instance.meth_3(keyword_arg: :original_arg)).to eq :original_arg + CODE + end + end + it 'errors when you pass through the wrong number of args' do expect(instance).to receive(:meth_1).and_call_original expect(instance).to receive(:meth_2).twice.and_call_original