Skip to content

Commit

Permalink
Merge cf5ef39 into 638d3ff
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Phippen committed Jul 14, 2013
2 parents 638d3ff + cf5ef39 commit 58cce58
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 2 deletions.
7 changes: 6 additions & 1 deletion lib/rspec/mocks/any_instance/expectation_chain.rb
Expand Up @@ -25,7 +25,12 @@ class PositiveExpectationChain < ExpectationChain
def create_message_expectation_on(instance)
proxy = ::RSpec::Mocks.proxy_for(instance)
expected_from = IGNORED_BACKTRACE_LINE
proxy.add_message_expectation(expected_from, *@expectation_args, &@expectation_block)
me = proxy.add_message_expectation(expected_from, *@expectation_args, &@expectation_block)
if RSpec::Mocks.configuration.yield_instance_from_any_instance_implementation_blocks
me.and_yield_receiver_to_implementation
end

me
end

def invocation_order
Expand Down
8 changes: 7 additions & 1 deletion lib/rspec/mocks/any_instance/stub_chain.rb
Expand Up @@ -14,7 +14,13 @@ def expectation_fulfilled?
def create_message_expectation_on(instance)
proxy = ::RSpec::Mocks.proxy_for(instance)
expected_from = IGNORED_BACKTRACE_LINE
proxy.add_stub(expected_from, *@expectation_args, &@expectation_block)
stub = proxy.add_stub(expected_from, *@expectation_args, &@expectation_block)

if RSpec::Mocks.configuration.yield_instance_from_any_instance_implementation_blocks
stub.and_yield_receiver_to_implementation
end

stub
end

def invocation_order
Expand Down
8 changes: 8 additions & 0 deletions lib/rspec/mocks/configuration.rb
Expand Up @@ -23,6 +23,14 @@ def add_stub_and_should_receive_to(*modules)
end
end

def yield_instance_from_any_instance_implementation_blocks
@yield_instance_from_any_instance_implementation_blocks ||= false
end

def yield_instance_from_any_instance_implementation_blocks=(arg)
@yield_instance_from_any_instance_implementation_blocks = arg
end

def syntax=(values)
if Array(values).include?(:expect)
Syntax.enable_expect
Expand Down
10 changes: 10 additions & 0 deletions lib/rspec/mocks/message_expectation.rb
Expand Up @@ -5,6 +5,8 @@ class MessageExpectation
# @private
attr_accessor :error_generator, :implementation
attr_reader :message
attr_reader :orig_object
attr_reader :yield_receiver_to_implementation
attr_writer :expected_received_count, :expected_from, :argument_list_matcher
protected :expected_received_count=, :expected_from=, :error_generator, :error_generator=, :implementation=

Expand All @@ -15,6 +17,7 @@ def initialize(error_generator, expectation_ordering, expected_from, method_doub
@error_generator.opts = opts
@expected_from = expected_from
@method_double = method_double
@orig_object = @method_double.object
@message = @method_double.method_name
@actual_received_count = 0
@expected_received_count = expected_received_count
Expand All @@ -24,6 +27,8 @@ def initialize(error_generator, expectation_ordering, expected_from, method_doub
@args_to_yield = []
@failed_fast = nil
@eval_context = nil
@yield_receiver_to_implementation = false
@is_any_instance_expectation = opts[:is_any_instance_expectation]

@implementation = Implementation.new
self.inner_implementation_action = implementation_block
Expand Down Expand Up @@ -89,6 +94,11 @@ def and_return(*values, &implementation)
end
end

def and_yield_receiver_to_implementation
@yield_receiver_to_implementation = true
self
end

# Tells the object to delegate to the original unmodified method
# when it receives the message.
#
Expand Down
6 changes: 6 additions & 0 deletions lib/rspec/mocks/proxy.rb
Expand Up @@ -139,8 +139,14 @@ def message_received(message, *args, &block)
if expectation = find_almost_matching_expectation(message, *args)
expectation.advise(*args) unless expectation.expected_messages_received?
end
if stub.yield_receiver_to_implementation
args.unshift(stub.orig_object)
end
stub.invoke(nil, *args, &block)
elsif expectation
if expectation.yield_receiver_to_implementation
args.unshift(expectation.orig_object)
end
expectation.invoke(stub, *args, &block)
elsif expectation = find_almost_matching_expectation(message, *args)
expectation.advise(*args) if null_object? unless expectation.expected_messages_received?
Expand Down
61 changes: 61 additions & 0 deletions spec/rspec/mocks/any_instance_spec.rb
Expand Up @@ -830,6 +830,67 @@ def foo; end
end
end

context "passing the receiver to the implementation block" do
context "when configured to pass the instance" do
include_context 'with isolated configuration'
before(:each) do
RSpec::Mocks.configuration.yield_instance_from_any_instance_implementation_blocks = true
end

describe "an any instance stub" do
it "passes the instance as the first arg of the implementation block" do
instance = klass.new

expect { |b|
klass.any_instance.should_receive(:bees).with(:sup, &b)
instance.bees(:sup)
}.to yield_with_args(instance, :sup)
end
end

describe "an any instance expectation" do
it "doesn't effect with" do
instance = klass.new
klass.any_instance.should_receive(:bees).with(:sup)
instance.bees(:sup)
end

it "passes the instance as the first arg of the implementation block" do
instance = klass.new

expect { |b|
klass.any_instance.should_receive(:bees).with(:sup, &b)
instance.bees(:sup)
}.to yield_with_args(instance, :sup)
end
end
end

context "when configured not to pass the instance" do
include_context 'with isolated configuration'
before(:each) do
RSpec::Mocks.configuration.yield_instance_from_any_instance_implementation_blocks = false
end

describe "an any instance stub" do
it "does not pass the instance to the implementation block" do
instance = klass.new

expect { |b|
klass.any_instance.should_receive(:bees).with(:sup, &b)
instance.bees(:sup)
}.to yield_with_args(:sup)
end

it "does not cause with to fail when the instance is passed" do
instance = klass.new
klass.any_instance.should_receive(:bees).with(:faces)
instance.bees(:faces)
end
end
end
end

context 'when used in conjunction with a `dup`' do
it "doesn't cause an infinite loop" do
pending "This intermittently fails on JRuby" if RUBY_PLATFORM == 'java'
Expand Down
22 changes: 22 additions & 0 deletions spec/rspec/mocks/with_isolated_configuration_spec.rb
@@ -0,0 +1,22 @@
require 'spec_helper'
require 'pry'

module RSpec
module Mocks
describe 'the with isolated configuration shared example group' do
@@c = describe '' do
include_context 'with isolated configuration'
end
it 'resets the configuration' do
@@c.before.first.block.call
RSpec::Mocks.configuration.instance_eval do
def this_method_wont_be_here
end
end

@@c.after.last.block.call
expect(RSpec::Mocks.configuration.respond_to? :this_method_wont_be_here).to be false
end
end
end
end
12 changes: 12 additions & 0 deletions spec/spec_helper.rb
Expand Up @@ -68,3 +68,15 @@ def reset(object)
end
end


shared_context "with isolated configuration" do
orig_configuration = nil
before do
orig_configuration = RSpec::Mocks.configuration
RSpec::Mocks.instance_variable_set(:@configuration, RSpec::Mocks::Configuration.new)
end

after do
RSpec::Mocks.instance_variable_set(:@configuration, orig_configuration)
end
end

0 comments on commit 58cce58

Please sign in to comment.