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

Commit

Permalink
Merge pull request #1596 from rspec/fix-any-instance-private-method-v…
Browse files Browse the repository at this point in the history
…isibility

Mark any_instance proxy methods as private if they were private
  • Loading branch information
JonRowe authored Oct 19, 2024
2 parents 1ae5c4e + b9a7c04 commit 73eb4f5
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 9 deletions.
6 changes: 6 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
### Development
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.13.2...main)

Bug Fixes:

* When stubbing methods using the `expect_any_instance_of` or `allow_any_instance_of`
ensure the stubbed method has the same visibility as the real method.
(Jon Rowe, #1596)

### 3.13.2 / 2024-10-02
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.13.1...v3.13.2)

Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/mocks/any_instance/recorder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,12 @@ def observe!(method_name)
@observed_methods << method_name
backup_method!(method_name)
recorder = self
method_was_private = @klass.private_method_defined?(method_name)
@klass.__send__(:define_method, method_name) do |*args, &blk|
recorder.playback!(self, method_name)
__send__(method_name, *args, &blk)
end
@klass.__send__(:private, method_name) if method_was_private
@klass.__send__(:ruby2_keywords, method_name) if @klass.respond_to?(:ruby2_keywords, true)
end

Expand Down
40 changes: 31 additions & 9 deletions spec/rspec/mocks/any_instance_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1074,22 +1074,43 @@ def foo; end
end

context "private methods" do
before :each do
allow_any_instance_of(klass).to receive(:private_method).and_return(:something)
before(:example) { allow_any_instance_of(klass).to receive(:private_method).and_return(:something) }

verify_all
let(:object) { klass.new }

# The map(&:to_sym) is for legacy Ruby compatability and can be dropped in RSpec 4
it "maintains the method in the list of private_methods" do
expect {
verify_all
}.to_not change { object.private_methods.map(&:to_sym).include?(:private_method) }.from(true)
end

it "cleans up the backed up method" do
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
it "maintains the methods exclusion from the list of public_methods" do
expect {
verify_all
}.to_not change { object.public_methods.map(&:to_sym).include?(:private_method) }.from(false)
end

it "restores a stubbed private method after the spec is run" do
it "maintains the methods visibility" do
expect { klass.new.private_method }.to raise_error(NoMethodError)
expect(klass.new.send(:private_method)).to eq(:something)
expect(klass.private_method_defined?(:private_method)).to be_truthy
end

it "ensures that the restored method behaves as it originally did" do
expect(klass.new.send(:private_method)).to eq(:private_method_return_value)
context "after the spec has run" do
before(:example) { verify_all }

it "cleans up the backed up method" do
expect(klass.method_defined?(:__existing_method_without_any_instance__)).to be_falsey
end

it "restores a stubbed private method after the spec is run" do
expect(klass.private_method_defined?(:private_method)).to be_truthy
end

it "ensures that the restored method behaves as it originally did" do
expect(klass.new.send(:private_method)).to eq(:private_method_return_value)
end
end
end
end
Expand All @@ -1098,7 +1119,7 @@ def foo; end
context "private methods" do
before :each do
expect_any_instance_of(klass).to receive(:private_method).and_return(:something)
klass.new.private_method
klass.new.send(:private_method)

verify_all
end
Expand All @@ -1109,6 +1130,7 @@ def foo; end

it "restores a stubbed private method after the spec is run" do
expect(klass.private_method_defined?(:private_method)).to be_truthy
expect(klass.new.private_methods.map(&:to_sym)).to include :private_method
end

it "ensures that the restored method behaves as it originally did" do
Expand Down

0 comments on commit 73eb4f5

Please sign in to comment.