rspec / rspec-mocks

RSpec's 'test double' framework, with support for stubbing and mocking
https://rspec.info
MIT License
1.16k stars 356 forks source link

Add missing ruby2_keywords calls in rspec-mocks #1464

Closed eregon closed 2 years ago

eregon commented 2 years ago

cc @bjfish

This is progress towards https://github.com/rspec/rspec-metagem/issues/68. Before: 25 failures, After: 2 failures left (which seem unrelated):

Failures:

  1) #any_instance when stubbing aliased methods tracks aliased method calls
     Failure/Error: parent_aliased_method

     NameError:
       undefined local variable or method `parent_aliased_method' for #<AnyInstanceSpec::ParentClass:0x2bb88>
     # ./spec/rspec/mocks/any_instance_spec.rb:20:in `caller_of_parent_aliased_method'
     # ./spec/rspec/mocks/any_instance_spec.rb:210:in `block (4 levels) in <module:Mocks>'

  2) Marshal extensions #dump when rspec-mocks has been fully initialized applying and unapplying patch is idempotent
     Failure/Error: expect { Marshal.dump(obj) }.to raise_error(TypeError)
       expected TypeError but nothing was raised
     # ./spec/rspec/mocks/marshal_extension_spec.rb:46:in `block (4 levels) in <top (required)>'

BTW, the reason the code worked before these ruby2_keywords seems accidental and due to a bug/inconsistency in CRuby: https://bugs.ruby-lang.org/issues/18625

eregon commented 2 years ago

This change is also needed for Ruby 3.2 if the fix for https://bugs.ruby-lang.org/issues/18625 gets in. So what I did is build that change locally and run rspec-mocks specs without & with this patch. Without this PR, there are 23 failures. With this PR, no failures.

Since 3.2 needs that fix, it seems we will need a rspec release, so Bundler can get this fix, and Bundler is tested in ruby/ruby's CI. Bundler's specs can't just point to a github branch due to rspec inter-gem version restrictions (and that wouldn't be a good solution longer-term either of course): https://github.com/ruby/ruby/pull/5684/checks

pirj commented 2 years ago

Re-running jobs to see if a weird failure was temporary.

JonRowe commented 2 years ago

I'm fine with this if we can get a passing build, although if there is an easy way to get a spec (or specs) that would fail without these changes on one of the existing MRI builds that'd be a nice to have.

eregon commented 2 years ago

I'm really confused how this PR can cause 2.5/2.6 to fail rspec-rails specs, on Linux but not Windows, when ruby2_keywords doesn't exist in Ruby < 2.7 (and even if it's defined there it would noop). I'll schedule a few runs on my fork to try to debug it.

eregon commented 2 years ago

Looks like I'm running into https://github.com/rspec/rspec-mocks/pull/1385#issuecomment-755340298

eregon commented 2 years ago

CI shall be green now (here is my run), except 2.3 Windows which is already failing on main.

although if there is an easy way to get a spec (or specs) that would fail without these changes on one of the existing MRI builds that'd be a nice to have.

This is not possible, the code before this PR only works "thanks" to a CRuby bug of not resetting the ruby2_keywords flag correctly (https://bugs.ruby-lang.org/issues/18625). So this PR has no effect on CRuby <= 3.1, but it does fix TruffleRuby (which doesn't have that bug) and CRuby 3.2 (if the bug is fixed in CRuby 3.2, let's hope so). I verified this change is required to pass existing specs on a local build of CRuby 3.2-dev with the fix (https://github.com/rspec/rspec-mocks/pull/1464#issuecomment-1074998528).

pirj commented 2 years ago

~I recalled that there was a reason to switch to Module.private_method_defined? in the first place. There's some discussion here https://github.com/rspec/rspec-mocks/pull/1385#issuecomment-755829430~ - PS my apologies, I've just realized you've dug down to this discussion, too.

Just to have some records of what the fix entailed, what is the difference between your original implementation of this PR and the final result, @eregon? I can spot a call of ruby2_keywords on an instance of a Proc (TIL) 🤯

eregon commented 2 years ago

Just to have some records of what the fix entailed, what is the difference between your original implementation of this PR and the final result, @eregon?

You can see it with the Compare button above, it links to this diff. So it's just restoring that check and adding comment why it's done that way (I otherwise used the well-known if respond_to?(:ruby2_keywords, true) check).

eregon commented 2 years ago

Could I ask for a release of rspec-mocks including this fix? I tried various things, but I can't get the Bundler tests in ruby/ruby CI to use rspec-mocks master (https://github.com/ruby/ruby/pull/5684)

JonRowe commented 2 years ago

Released as 3.11.1