1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
module RSpec
module Mocks
module Matchers
class Receive
def initialize(message, block)
@message = message
@block = block
@recorded_customizations = []
# MRI, JRuby and RBX report the caller inconsistently; MRI
# reports an extra "in `new'" line in the backtrace that the
# others do not include. The safest way to find the right
# line is to search for the first line BEFORE rspec/mocks/syntax.rb.
@backtrace_line = caller.find do |line|
!line.split(':').first.end_with?('rspec/mocks/syntax.rb')
end
end
def setup_expectation(subject, &block)
setup_mock_proxy_method_substitute(subject, :add_message_expectation, block)
end
alias matches? setup_expectation
def setup_negative_expectation(subject, &block)
# ensure `never` goes first for cases like `never.and_return(5)`,
# where `and_return` is meant to raise an error
@recorded_customizations.unshift Customization.new(:never, [], nil)
setup_expectation(subject, &block)
end
alias does_not_match? setup_negative_expectation
def setup_allowance(subject, &block)
setup_mock_proxy_method_substitute(subject, :add_stub, block)
end
def setup_any_instance_expectation(subject, &block)
setup_any_instance_method_substitute(subject, :should_receive, block)
end
def setup_any_instance_negative_expectation(subject, &block)
setup_any_instance_method_substitute(subject, :should_not_receive, block)
end
def setup_any_instance_allowance(subject, &block)
setup_any_instance_method_substitute(subject, :stub, block)
end
MessageExpectation.public_instance_methods(false).each do |method|
next if method_defined?(method)
class_eval(<<-RUBY)
def #{method}(*args, &block)
@recorded_customizations << Customization.new(#{method.inspect}, args, block)
self
end
RUBY
end
private
def setup_mock_proxy_method_substitute(subject, method, block)
proxy = ::RSpec::Mocks.proxy_for(subject)
setup_method_substitute(proxy, method, block, @backtrace_line)
end
def setup_any_instance_method_substitute(subject, method, block)
any_instance_recorder = ::RSpec::Mocks.any_instance_recorder_for(subject)
setup_method_substitute(any_instance_recorder, method, block)
end
def setup_method_substitute(host, method, block, *args)
args << @message.to_sym
expectation = host.__send__(method, *args, &(@block || block))
@recorded_customizations.each do |customization|
customization.playback_onto(expectation)
end
expectation
end
class Customization
def initialize(method_name, args, block)
@method_name = method_name
@args = args
@block = block
end
def playback_onto(expectation)
expectation.__send__(@method_name, *@args, &@block)
end
end
end
end
end
end
|