Skip to content

Commit

Permalink
Only fulfill any_instance expectations when args match.
Browse files Browse the repository at this point in the history
  • Loading branch information
myronmarston committed Apr 30, 2014
1 parent 9cafc85 commit 30a1751
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 4 deletions.
11 changes: 11 additions & 0 deletions lib/rspec/mocks/any_instance/chain.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def initialize(recorder, *args, &block)
@recorder = recorder
@expectation_args = args
@expectation_block = block
@argument_list_matcher = ArgumentListMatcher::MATCH_ALL
end

# @private
Expand Down Expand Up @@ -63,6 +64,11 @@ def constrained_to_any_of?(*constraints)
end
end

# @private
def matches_args?(*args)
@argument_list_matcher.args_match?(*args)
end

# @private
def expectation_fulfilled!
@expectation_fulfilled = true
Expand All @@ -73,6 +79,11 @@ def never
super
end

def with(*args, &block)
@argument_list_matcher = ArgumentListMatcher.new(*args)
super
end

private

def negated?
Expand Down
9 changes: 9 additions & 0 deletions lib/rspec/mocks/any_instance/message_chains.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ def has_expectation?(method_name)
end
end

# @private
def each_unfulfilled_expectation_matching(method_name, *args)
@chains_by_method_name[method_name].each do |chain|
if !chain.expectation_fulfilled? && chain.matches_args?(*args)
yield chain
end
end
end

# @private
def all_expectations_fulfilled?
@chains_by_method_name.all? do |method_name, chains|
Expand Down
4 changes: 3 additions & 1 deletion lib/rspec/mocks/any_instance/recorder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ def already_observing?(method_name)

# @private
def notify_received_message(object, message, args, blk)
received_expected_message!(message) if message_chains.has_expectation?(message)
message_chains.each_unfulfilled_expectation_matching(message, *args) do |expectation|
expectation.expectation_fulfilled!
end
end

protected
Expand Down
20 changes: 20 additions & 0 deletions spec/rspec/mocks/any_instance_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,26 @@ def inspect
expect(object.foo).to eq(3)
end

context "when argument matching is used and an instance has stubbed the message" do
it "fails on verify if the arguments do not match" do
expect_any_instance_of(klass).to receive(:foo).with(3)
instance = klass.new
allow(instance).to receive(:foo).and_return(2)

expect(instance.foo(4)).to eq(2)
expect { verify_all }.to fail
end

it "passes on verify if the arguments do match" do
expect_any_instance_of(klass).to receive(:foo).with(3)
instance = klass.new
allow(instance).to receive(:foo).and_return(2)

expect(instance.foo(3)).to eq(2)
expect { verify_all }.not_to raise_error
end
end

context "with an expectation is set on a method which does not exist" do
it "returns the expected value" do
expect_any_instance_of(klass).to receive(:foo).and_return(1)
Expand Down
3 changes: 0 additions & 3 deletions spec/rspec/mocks/matchers/receive_message_chain_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,6 @@ module RSpec::Mocks::Matchers

expect_any_instance_of(Object).to receive_message_chain(:foo, :bar => 3)
expect(o.foo.bar).to eq(3)

# TODO: this shouldn't be necessary to satisfy the expectation, but is.
Object.new.foo.bar
end

it "passes when with expect_any_instance_of is used and the entire chain is called" do
Expand Down

0 comments on commit 30a1751

Please sign in to comment.