]> git.openstreetmap.org Git - rails.git/blob - vendor/gems/rspec-1.1.2/lib/spec/mocks/message_expectation.rb
Show whether a trace is public or private in the trace list, so that a user can easil...
[rails.git] / vendor / gems / rspec-1.1.2 / lib / spec / mocks / message_expectation.rb
1 module Spec
2   module Mocks
3
4     class BaseExpectation
5       attr_reader :sym
6       
7       def initialize(error_generator, expectation_ordering, expected_from, sym, method_block, expected_received_count=1, opts={})
8         @error_generator = error_generator
9         @error_generator.opts = opts
10         @expected_from = expected_from
11         @sym = sym
12         @method_block = method_block
13         @return_block = nil
14         @actual_received_count = 0
15         @expected_received_count = expected_received_count
16         @args_expectation = ArgumentExpectation.new([AnyArgsConstraint.new])
17         @consecutive = false
18         @exception_to_raise = nil
19         @symbol_to_throw = nil
20         @order_group = expectation_ordering
21         @at_least = nil
22         @at_most = nil
23         @args_to_yield = []
24       end
25       
26       def expected_args
27         @args_expectation.args
28       end
29
30       def and_return(*values, &return_block)
31         Kernel::raise AmbiguousReturnError unless @method_block.nil?
32         case values.size
33           when 0 then value = nil
34           when 1 then value = values[0]
35         else
36           value = values
37           @consecutive = true
38           @expected_received_count = values.size if !ignoring_args? &&
39                                                     @expected_received_count < values.size
40         end
41         @return_block = block_given? ? return_block : lambda { value }
42         # Ruby 1.9 - see where this is used below
43         @ignore_args = !block_given?
44       end
45       
46       # :call-seq:
47       #   and_raise()
48       #   and_raise(Exception) #any exception class
49       #   and_raise(exception) #any exception object
50       #
51       # == Warning
52       #
53       # When you pass an exception class, the MessageExpectation will
54       # raise an instance of it, creating it with +new+. If the exception
55       # class initializer requires any parameters, you must pass in an
56       # instance and not the class.
57       def and_raise(exception=Exception)
58         @exception_to_raise = exception
59       end
60       
61       def and_throw(symbol)
62         @symbol_to_throw = symbol
63       end
64       
65       def and_yield(*args)
66         @args_to_yield << args
67         self
68       end
69   
70       def matches(sym, args)
71         @sym == sym and @args_expectation.check_args(args)
72       end
73       
74       def invoke(args, block)
75         @order_group.handle_order_constraint self
76
77         begin
78           Kernel::raise @exception_to_raise unless @exception_to_raise.nil?
79           Kernel::throw @symbol_to_throw unless @symbol_to_throw.nil?
80           
81           if !@method_block.nil?
82             default_return_val = invoke_method_block(args)
83           elsif @args_to_yield.size > 0
84             default_return_val = invoke_with_yield(block)
85           else
86             default_return_val = nil
87           end
88           
89           if @consecutive
90             return invoke_consecutive_return_block(args, block)
91           elsif @return_block
92             return invoke_return_block(args, block)
93           else
94             return default_return_val
95           end
96         ensure
97           @actual_received_count += 1
98         end
99       end
100       
101       protected
102
103       def invoke_method_block(args)
104         begin
105           @method_block.call(*args)
106         rescue => detail
107           @error_generator.raise_block_failed_error @sym, detail.message
108         end
109       end
110       
111       def invoke_with_yield(block)
112         if block.nil?
113           @error_generator.raise_missing_block_error @args_to_yield
114         end
115         @args_to_yield.each do |args_to_yield_this_time|
116           if block.arity > -1 && args_to_yield_this_time.length != block.arity
117             @error_generator.raise_wrong_arity_error args_to_yield_this_time, block.arity
118           end
119           block.call(*args_to_yield_this_time)
120         end
121       end
122       
123       def invoke_consecutive_return_block(args, block)
124         args << block unless block.nil?
125         value = @return_block.call(*args)
126         
127         index = [@actual_received_count, value.size-1].min
128         value[index]
129       end
130       
131       def invoke_return_block(args, block)
132         args << block unless block.nil?
133         # Ruby 1.9 - when we set @return_block to return values
134         # regardless of arguments, any arguments will result in
135         # a "wrong number of arguments" error
136         if @ignore_args
137           @return_block.call()
138         else
139           @return_block.call(*args)
140         end
141       end
142     end
143     
144     class MessageExpectation < BaseExpectation
145       
146       def matches_name_but_not_args(sym, args)
147         @sym == sym and not @args_expectation.check_args(args)
148       end
149        
150       def verify_messages_received        
151         return if ignoring_args? || matches_exact_count? ||
152            matches_at_least_count? || matches_at_most_count?
153     
154         generate_error
155       rescue Spec::Mocks::MockExpectationError => error
156         error.backtrace.insert(0, @expected_from)
157         Kernel::raise error
158       end
159       
160       def ignoring_args?
161         @expected_received_count == :any
162       end
163       
164       def matches_at_least_count?
165         @at_least && @actual_received_count >= @expected_received_count
166       end
167       
168       def matches_at_most_count?
169         @at_most && @actual_received_count <= @expected_received_count
170       end
171       
172       def matches_exact_count?
173         @expected_received_count == @actual_received_count
174       end
175       
176       def generate_error
177         @error_generator.raise_expectation_error(@sym, @expected_received_count, @actual_received_count, *@args_expectation.args)
178       end
179
180       def with(*args, &block)
181         @method_block = block if block
182         @args_expectation = ArgumentExpectation.new(args)
183         self
184       end
185       
186       def exactly(n)
187         set_expected_received_count :exactly, n
188         self
189       end
190       
191       def at_least(n)
192         set_expected_received_count :at_least, n
193         self
194       end
195       
196       def at_most(n)
197         set_expected_received_count :at_most, n
198         self
199       end
200
201       def times(&block)
202         @method_block = block if block
203         self
204       end
205   
206       def any_number_of_times(&block)
207         @method_block = block if block
208         @expected_received_count = :any
209         self
210       end
211   
212       def never
213         @expected_received_count = 0
214         self
215       end
216   
217       def once(&block)
218         @method_block = block if block
219         @expected_received_count = 1
220         self
221       end
222   
223       def twice(&block)
224         @method_block = block if block
225         @expected_received_count = 2
226         self
227       end
228   
229       def ordered(&block)
230         @method_block = block if block
231         @order_group.register(self)
232         @ordered = true
233         self
234       end
235       
236       def negative_expectation_for?(sym)
237         return false
238       end
239       
240       protected
241         def set_expected_received_count(relativity, n)
242           @at_least = (relativity == :at_least)
243           @at_most = (relativity == :at_most)
244           @expected_received_count = case n
245             when Numeric
246               n
247             when :once
248               1
249             when :twice
250               2
251           end
252         end
253       
254     end
255     
256     class NegativeMessageExpectation < MessageExpectation
257       def initialize(message, expectation_ordering, expected_from, sym, method_block)
258         super(message, expectation_ordering, expected_from, sym, method_block, 0)
259       end
260       
261       def negative_expectation_for?(sym)
262         return @sym == sym
263       end
264     end
265     
266   end
267 end