8 def initialize(target, name, options={})
11 @error_generator = ErrorGenerator.new target, name
12 @expectation_ordering = OrderGroup.new @error_generator
14 @messages_received = []
17 @options = options ? DEFAULT_OPTIONS.dup.merge(options) : DEFAULT_OPTIONS
21 @options[:null_object]
24 def add_message_expectation(expected_from, sym, opts={}, &block)
26 @expectations << MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil, 1, opts)
30 def add_negative_message_expectation(expected_from, sym, &block)
32 @expectations << NegativeMessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil)
36 def add_stub(expected_from, sym, opts={})
38 @stubs.unshift MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, nil, :any, opts)
55 def received_message?(sym, *args, &block)
56 @messages_received.any? {|array| array == [sym, args, block]}
59 def has_negative_expectation?(sym)
60 @expectations.detect {|expectation| expectation.negative_expectation_for?(sym)}
63 def message_received(sym, *args, &block)
64 if expectation = find_matching_expectation(sym, *args)
65 expectation.invoke(args, block)
66 elsif stub = find_matching_method_stub(sym, *args)
67 stub.invoke([], block)
68 elsif expectation = find_almost_matching_expectation(sym, *args)
69 raise_unexpected_message_args_error(expectation, *args) unless has_negative_expectation?(sym) unless null_object?
71 @target.send :method_missing, sym, *args, &block
75 def raise_unexpected_message_args_error(expectation, *args)
76 @error_generator.raise_unexpected_message_args_error expectation, *args
79 def raise_unexpected_message_error(sym, *args)
80 @error_generator.raise_unexpected_message_error sym, *args
86 $rspec_mocks.add(@target) unless $rspec_mocks.nil?
87 define_expected_method(sym)
90 def define_expected_method(sym)
91 if target_responds_to?(sym) && !metaclass.method_defined?(munge(sym))
92 munged_sym = munge(sym)
93 metaclass.instance_eval do
94 alias_method munged_sym, sym if method_defined?(sym.to_s)
96 @proxied_methods << sym
99 metaclass_eval(<<-EOF, __FILE__, __LINE__)
100 def #{sym}(*args, &block)
101 __mock_proxy.message_received :#{sym}, *args, &block
106 def target_responds_to?(sym)
107 return @target.send(munge(:respond_to?),sym) if @already_proxied_respond_to
108 return @already_proxied_respond_to = true if sym == :respond_to?
109 return @target.respond_to?(sym)
113 "proxied_by_rspec__#{sym.to_s}".to_sym
116 def clear_expectations
124 def clear_proxied_methods
125 @proxied_methods.clear
128 def metaclass_eval(str, filename, lineno)
129 metaclass.class_eval(str, filename, lineno)
133 (class << @target; self; end)
136 def verify_expectations
137 @expectations.each do |expectation|
138 expectation.verify_messages_received
142 def reset_proxied_methods
143 @proxied_methods.each do |sym|
144 munged_sym = munge(sym)
145 metaclass.instance_eval do
146 if method_defined?(munged_sym.to_s)
147 alias_method sym, munged_sym
148 undef_method munged_sym
156 def find_matching_expectation(sym, *args)
157 @expectations.find {|expectation| expectation.matches(sym, args)}
160 def find_almost_matching_expectation(sym, *args)
161 @expectations.find {|expectation| expectation.matches_name_but_not_args(sym, args)}
164 def find_matching_method_stub(sym, *args)
165 @stubs.find {|stub| stub.matches(sym, args)}