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

Log a warning when methods are reset on a frozen object #496

Closed
wants to merge 1 commit into from
Closed
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
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Breaking Changes for 3.0.0:

Bug Fixes:

* Instead of crashing when cleaning up stub methods on a frozen object, it now
issues a warning explaining that it's impossible to clean up the stubs.
(Justin Coyne)
* Fix regression in 3.0.0.beta1 that caused `double("string_name" => :value)`
to stop working. (Xavier Shay)
* Fix the way rspec-mocks and rspec-core interact so that if users
Expand Down
10 changes: 10 additions & 0 deletions lib/rspec/mocks/method_double.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def initialize(object, method_name, proxy)
@method_is_proxied = false
@expectations = []
@stubs = []
@show_frozen_warnings = []
end

def original_method
Expand Down Expand Up @@ -85,6 +86,15 @@ def restore_original_method
restore_original_visibility

@method_is_proxied = false
rescue RuntimeError => e
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, this needs to be TypeError on 1.8.7...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm now wondering if it would be better to rescue StandardError and inspect the message for the word frozen... Thoughts @myronmarston, am I being too picky?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think checking frozen? on the singleton class (as it is now) is a less brittle approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just drop back to a bare rescue?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that sounds fine.

One thing thats unclear to me: what purpose does @show_frozen_warnings serve? I don't see any spec showing what it does...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prevents the message appearing twice for the same method. We're still reseting mocks twice.

frozen = object_singleton_class.frozen?
if frozen && !@show_frozen_warnings.include?(@method_name)
RSpec.warn_with "Unable to remove stub method #{@method_name} because the object was frozen.",
:call_site => nil
@show_frozen_warnings << @method_name
elsif !frozen
raise e
end
end

# @private
Expand Down
11 changes: 11 additions & 0 deletions spec/rspec/mocks/matchers/receive_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,17 @@ def receiver.method_missing(*a); end # a poor man's stub...
target.to receive(:foo).and_return(:baz)
expect { reset object }.to change { object.foo }.from(:baz).to(:bar)
end

context "on a frozen object" do
it "removes the method double" do
with_isolated_stderr do
target.to receive(:foo).and_return(:baz)
expect_warning_without_call_site(/Unable to remove stub method foo because the object was frozen./)
object.freeze
reset object
end
end
end
end

shared_examples_for "resets partial mocks of any instance cleanly" do
Expand Down