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

Mark any_instance proxy methods as private if they were private #1596

Merged
merged 3 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading