Skip to content

Commit

Permalink
fix: handling of blocks in pass_thru
Browse files Browse the repository at this point in the history
  • Loading branch information
doudou committed Sep 8, 2024
1 parent 930e794 commit 30d718a
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 13 deletions.
2 changes: 1 addition & 1 deletion lib/flexmock/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def flexmock_calls

# Invocke the original non-mocked functionality for the given
# symbol.
def flexmock_invoke_original(method_name, args)
def flexmock_invoke_original(method_name, args, orig_block)
return FlexMock.undefined
end

Expand Down
4 changes: 2 additions & 2 deletions lib/flexmock/expectation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,9 @@ def and_throw(sym, value=nil)

def pass_thru(&block)
block ||= lambda { |value| value }
and_return { |*args|
and_return { |*args, &orig_block|
begin
block.call(@mock.flexmock_invoke_original(@sym, args))
block.call(@mock.flexmock_invoke_original(@sym, args, orig_block))
rescue NoMethodError => e
if e.name == @sym
raise e, "#{e.message} while performing #pass_thru in expectation object #{self}"
Expand Down
13 changes: 3 additions & 10 deletions lib/flexmock/partial_mock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,7 @@ def should_expect(*args)
#
# Usually called in a #and_return statement
def invoke_original(m, *args, &block)
if block
args << block
end
flexmock_invoke_original(m, args)
flexmock_invoke_original(m, args, block)
end

# Whether the given method's original definition has been stored
Expand Down Expand Up @@ -321,7 +318,7 @@ def initialize_stub_remove
# (3) Apply any recorded expecations
#
def create_new_mocked_object(allocate_method, args, recorder, block)
new_obj = flexmock_invoke_original(allocate_method, args)
new_obj = flexmock_invoke_original(allocate_method, args, nil)
mock = flexmock_container.flexmock(new_obj)
block.call(mock) unless block.nil?
recorder.apply(mock)
Expand All @@ -331,12 +328,8 @@ def create_new_mocked_object(allocate_method, args, recorder, block)

# Invoke the original definition of method on the object supported by
# the stub.
def flexmock_invoke_original(method, args)
def flexmock_invoke_original(method, args, block)
if (original_method = find_original_method(method))
if Proc === args.last
block = args.last
args = args[0..-2]
end
original_method.call(*args, &block)
else
@obj.__send__(:method_missing, method, *args, &block)
Expand Down
14 changes: 14 additions & 0 deletions test/partial_mock_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,20 @@ def test_partial_mocks_leaves_NoMethodError_exceptions_raised_by_the_original_me
assert_equal "undefined method `does_not_exist' for #{obj}", exception.message
end

def test_pass_thru_forwards_a_given_block
obj = Class.new do
attr_reader :block
def mocked_method(&block)
@block = block
end
end.new
flexmock(obj).should_receive(:mocked_method).with_block.pass_thru

block = obj.mocked_method { 42 }
assert_kind_of Proc, block
assert_equal block, obj.block
end

def test_it_checks_whether_mocks_are_forbidden_before_forwarding_the_call
obj = Class.new
flexmock(obj).should_receive(:mocked).never
Expand Down

0 comments on commit 30d718a

Please sign in to comment.