Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stub attempts to call method on Class'es superclass when method accepts keyword arguments on Ruby 2.7 #1472

Open
postmodern opened this issue May 7, 2022 · 1 comment

Comments

@postmodern
Copy link

postmodern commented May 7, 2022

Subject of the issue

If you rspec stubs to test whether a class method, which accepts both positional and keyword arguments, is called with a positional argument, then RSpec::Mocks::Proxy will attempt to call the superclass's method. This will result in a confusing error (undefined method 'start' for Object:Class) if the Class in question does not inherit from another Class. This bug occurs under ruby-2.7, but not ruby-3.x. However, the bug does not occur if I remove **kwargs from the method definitions.

Your environment

  • Ruby version: ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [x86_64-linux]
  • rspec-mocks version: 3.11.1

Steps to reproduce

require 'rspec'

class Shell
  def self.start(io,**kwargs)
  end
end

class IO
  def shell(**kwargs)
    Shell.start(self,**kwargs)
  end
end

describe IO do
  subject { File.new(__FILE__) }

  describe "#shell" do
    it do
      expect(Shell).to receive(:start).with(subject)

      subject.shell
    end
  end
end

Rescuing NoMethodError in the test points us to RSpec::Mocks::Proxy line 228.

/home/postmodern/.gem/ruby/2.7.5/gems/rspec-mocks-3.11.1/lib/rspec/mocks/proxy.rb:228:in `message_received'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-mocks-3.11.1/lib/rspec/mocks/proxy.rb:366:in `message_received'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-mocks-3.11.1/lib/rspec/mocks/method_double.rb:80:in `proxy_method_invoked'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-mocks-3.11.1/lib/rspec/mocks/method_double.rb:64:in `block (2 levels) in define_proxy_method'
/home/postmodern/test/ruby/rspec/spec/test_spec.rb:10:in `shell'
/home/postmodern/test/ruby/rspec/spec/test_spec.rb:22:in `block (3 levels) in <top (required)>'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example.rb:263:in `instance_exec'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example.rb:263:in `block in run'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example.rb:511:in `block in with_around_and_singleton_context_hooks'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example.rb:468:in `block in with_around_example_hooks'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/hooks.rb:486:in `block in run'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/hooks.rb:624:in `run_around_example_hooks_for'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/hooks.rb:486:in `run'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example.rb:468:in `with_around_example_hooks'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example.rb:511:in `with_around_and_singleton_context_hooks'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example.rb:259:in `run'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example_group.rb:646:in `block in run_examples'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example_group.rb:642:in `map'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example_group.rb:642:in `run_examples'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example_group.rb:607:in `run'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example_group.rb:608:in `block in run'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example_group.rb:608:in `map'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/example_group.rb:608:in `run'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/runner.rb:121:in `block (3 levels) in run_specs'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/runner.rb:121:in `map'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/runner.rb:121:in `block (2 levels) in run_specs'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/configuration.rb:2068:in `with_suite_hooks'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/runner.rb:116:in `block in run_specs'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/reporter.rb:74:in `report'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/runner.rb:115:in `run_specs'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/runner.rb:89:in `run'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/runner.rb:71:in `run'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/lib/rspec/core/runner.rb:45:in `invoke'
/home/postmodern/.gem/ruby/2.7.5/gems/rspec-core-3.11.0/exe/rspec:4:in `<top (required)>'
/home/postmodern/.gem/ruby/2.7.5/bin/rspec:23:in `load'
/home/postmodern/.gem/ruby/2.7.5/bin/rspec:23:in `<main>'

Expected behavior

IO
  #shell
    is expected to receive start(#<File:/home/postmodern/test/ruby/rspec/spec/test_spec.rb>) 1 time

Finished in 0.00547 seconds (files took 0.08959 seconds to load)
1 example, 0 failures

Actual behavior

IO
  #shell
    is expected to receive start(#<File:/home/postmodern/test/ruby/rspec/spec/test_spec.rb>) 1 time (FAILED - 1)

Failures:

  1) IO#shell is expected to receive start(#<File:/home/postmodern/test/ruby/rspec/spec/test_spec.rb>) 1 time
     Failure/Error: Shell.start(self,**kwargs)
     
     NoMethodError:
       undefined method `start' for Object:Class
     # ./spec/test_spec.rb:10:in `shell'
     # ./spec/test_spec.rb:21:in `block (3 levels) in <top (required)>'

Finished in 0.00563 seconds (files took 0.09395 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/test_spec.rb:18 # IO#shell is expected to receive start(#<File:/home/postmodern/test/ruby/rspec/spec/test_spec.rb>) 1 time
@DylanEtris
Copy link

This issue looks like it relates to #1466.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants