rspec-mocks 2.8.0.rc1 → 2.8.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  module RSpec
2
2
  module Mocks
3
+ # @api private
3
4
  class ArgumentExpectation
4
5
  attr_reader :args
5
6
 
@@ -1,12 +1,12 @@
1
1
  module RSpec
2
2
  module Mocks
3
3
 
4
- # ArgumentMatchers are messages that you can include in message
4
+ # ArgumentMatchers are placeholders that you can include in message
5
5
  # expectations to match arguments against a broader check than simple
6
6
  # equality.
7
7
  #
8
- # With the exception of any_args() and no_args(), the matchers
9
- # are all positional - they match against the arg in the given position.
8
+ # With the exception of `any_args` and `no_args`, they all match against
9
+ # the arg in same position in the argument list.
10
10
  module ArgumentMatchers
11
11
 
12
12
  class AnyArgsMatcher
@@ -36,8 +36,7 @@ module RSpec
36
36
  end
37
37
 
38
38
  def ==(value)
39
- return value =~ @regexp unless value.is_a?(Regexp)
40
- value == @regexp
39
+ Regexp === value ? value == @regexp : value =~ @regexp
41
40
  end
42
41
  end
43
42
 
@@ -46,7 +45,7 @@ module RSpec
46
45
  end
47
46
 
48
47
  def ==(value)
49
- TrueClass === value || FalseClass === value
48
+ [true,false].include?(value)
50
49
  end
51
50
  end
52
51
 
@@ -56,12 +55,9 @@ module RSpec
56
55
  end
57
56
 
58
57
  def ==(actual)
59
- @expected.each do | key, value |
60
- return false unless actual.has_key?(key) && value == actual[key]
61
- end
62
- true
58
+ @expected.all? {|k,v| actual.has_key?(k) && v == actual[k]}
63
59
  rescue NoMethodError
64
- return false
60
+ false
65
61
  end
66
62
 
67
63
  def description
@@ -69,18 +65,15 @@ module RSpec
69
65
  end
70
66
  end
71
67
 
72
- class HashNotIncludingMatcher
68
+ class HashExcludingMatcher
73
69
  def initialize(expected)
74
70
  @expected = expected
75
71
  end
76
72
 
77
73
  def ==(actual)
78
- @expected.each do | key, value |
79
- return false if actual.has_key?(key) && value == actual[key]
80
- end
81
- true
74
+ @expected.none? {|k,v| actual.has_key?(k) && v == actual[k]}
82
75
  rescue NoMethodError
83
- return false
76
+ false
84
77
  end
85
78
 
86
79
  def description
@@ -94,7 +87,7 @@ module RSpec
94
87
  end
95
88
 
96
89
  def ==(value)
97
- @methods_to_respond_to.all? { |sym| value.respond_to?(sym) }
90
+ @methods_to_respond_to.all? {|sym| value.respond_to?(sym)}
98
91
  end
99
92
  end
100
93
 
@@ -138,10 +131,11 @@ module RSpec
138
131
  end
139
132
  end
140
133
 
141
- # Passes if object receives :message with any args at all. This is
142
- # really a more explicit variation of object.should_receive(:message)
134
+ # Passes if object receives `:message` with any args at all. This is
135
+ # really a more explicit variation of `object.should_receive(:message)`
136
+ #
137
+ # @example
143
138
  #
144
- # == Examples
145
139
  # object.should_receive(:message).with(any_args())
146
140
  def any_args
147
141
  AnyArgsMatcher.new
@@ -149,7 +143,8 @@ module RSpec
149
143
 
150
144
  # Passes as long as there is an argument.
151
145
  #
152
- # == Examples
146
+ # @example
147
+ #
153
148
  # object.should_receive(:message).with(anything())
154
149
  def anything
155
150
  AnyArgMatcher.new(nil)
@@ -157,7 +152,8 @@ module RSpec
157
152
 
158
153
  # Passes if no arguments are passed along with the message
159
154
  #
160
- # == Examples
155
+ # @example
156
+ #
161
157
  # object.should_receive(:message).with(no_args)
162
158
  def no_args
163
159
  NoArgsMatcher.new
@@ -165,25 +161,28 @@ module RSpec
165
161
 
166
162
  # Passes if the argument responds to the specified messages.
167
163
  #
168
- # == Examples
164
+ # @example
165
+ #
169
166
  # object.should_receive(:message).with(duck_type(:hello))
170
167
  # object.should_receive(:message).with(duck_type(:hello, :goodbye))
171
168
  def duck_type(*args)
172
169
  DuckTypeMatcher.new(*args)
173
170
  end
174
171
 
175
- # == Examples
176
- # object.should_receive(:message).with(boolean())
177
- #
178
172
  # Passes if the argument is boolean.
173
+ #
174
+ # @example
175
+ #
176
+ # object.should_receive(:message).with(boolean())
179
177
  def boolean
180
178
  BooleanMatcher.new(nil)
181
179
  end
182
180
 
183
- # Passes if the argument is a hash that includes the specified key(s) or key/value
184
- # pairs. If the hash includes other keys, it will still pass.
181
+ # Passes if the argument is a hash that includes the specified key(s) or
182
+ # key/value pairs. If the hash includes other keys, it will still pass.
183
+ #
184
+ # @example
185
185
  #
186
- # == Examples
187
186
  # object.should_receive(:message).with(hash_including(:key => val))
188
187
  # object.should_receive(:message).with(hash_including(:key))
189
188
  # object.should_receive(:message).with(hash_including(:key, :key2 => val2))
@@ -191,24 +190,28 @@ module RSpec
191
190
  HashIncludingMatcher.new(anythingize_lonely_keys(*args))
192
191
  end
193
192
 
194
- # Passes if the argument is a hash that doesn't include the specified key(s) or key/value
193
+ # Passes if the argument is a hash that doesn't include the specified
194
+ # key(s) or key/value
195
+ #
196
+ # @example
195
197
  #
196
- # == Examples
197
- # object.should_receive(:message).with(hash_not_including(:key => val))
198
- # object.should_receive(:message).with(hash_not_including(:key))
199
- # object.should_receive(:message).with(hash_not_including(:key, :key2 => :val2))
200
- def hash_not_including(*args)
201
- HashNotIncludingMatcher.new(anythingize_lonely_keys(*args))
198
+ # object.should_receive(:message).with(hash_excluding(:key => val))
199
+ # object.should_receive(:message).with(hash_excluding(:key))
200
+ # object.should_receive(:message).with(hash_excluding(:key, :key2 => :val2))
201
+ def hash_excluding(*args)
202
+ HashExcludingMatcher.new(anythingize_lonely_keys(*args))
202
203
  end
204
+
205
+ alias_method :hash_not_including, :hash_excluding
203
206
 
204
- # Passes if arg.instance_of?(klass)
207
+ # Passes if `arg.instance_of?(klass)`
205
208
  def instance_of(klass)
206
209
  InstanceOf.new(klass)
207
210
  end
208
211
 
209
212
  alias_method :an_instance_of, :instance_of
210
213
 
211
- # Passes if arg.kind_of?(klass)
214
+ # Passes if `arg.kind_of?(klass)`
212
215
  def kind_of(klass)
213
216
  KindOf.new(klass)
214
217
  end
@@ -1,55 +1,65 @@
1
1
  module RSpec
2
2
  module Mocks
3
+ # @private
3
4
  class ErrorGenerator
4
5
  attr_writer :opts
5
-
6
+
6
7
  def initialize(target, name, options={})
7
8
  @declared_as = options[:__declared_as] || 'Mock'
8
9
  @target = target
9
10
  @name = name
10
11
  end
11
-
12
+
13
+ # @private
12
14
  def opts
13
15
  @opts ||= {}
14
16
  end
15
17
 
18
+ # @private
16
19
  def raise_unexpected_message_error(sym, *args)
17
20
  __raise "#{intro} received unexpected message :#{sym}#{arg_message(*args)}"
18
21
  end
19
-
22
+
23
+ # @private
20
24
  def raise_unexpected_message_args_error(expectation, *args)
21
25
  expected_args = format_args(*expectation.expected_args)
22
26
  actual_args = format_args(*args)
23
27
  __raise "#{intro} received #{expectation.sym.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}"
24
28
  end
25
-
29
+
30
+ # @private
26
31
  def raise_similar_message_args_error(expectation, *args)
27
32
  expected_args = format_args(*expectation.expected_args)
28
33
  actual_args = args.collect {|a| format_args(*a)}.join(", ")
29
34
  __raise "#{intro} received #{expectation.sym.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}"
30
35
  end
31
-
36
+
37
+ # @private
32
38
  def raise_expectation_error(sym, expected_received_count, actual_received_count, *args)
33
39
  __raise "(#{intro}).#{sym}#{format_args(*args)}\n expected: #{count_message(expected_received_count)}\n received: #{count_message(actual_received_count)}"
34
40
  end
35
-
41
+
42
+ # @private
36
43
  def raise_out_of_order_error(sym)
37
44
  __raise "#{intro} received :#{sym} out of order"
38
45
  end
39
-
46
+
47
+ # @private
40
48
  def raise_block_failed_error(sym, detail)
41
49
  __raise "#{intro} received :#{sym} but passed block failed with: #{detail}"
42
50
  end
43
-
51
+
52
+ # @private
44
53
  def raise_missing_block_error(args_to_yield)
45
54
  __raise "#{intro} asked to yield |#{arg_list(*args_to_yield)}| but no block was passed"
46
55
  end
47
-
56
+
57
+ # @private
48
58
  def raise_wrong_arity_error(args_to_yield, arity)
49
59
  __raise "#{intro} yielded |#{arg_list(*args_to_yield)}| to block with arity of #{arity}"
50
60
  end
51
-
52
- private
61
+
62
+ private
53
63
 
54
64
  def intro
55
65
  if @name
@@ -64,16 +74,16 @@ module RSpec
64
74
  "nil"
65
75
  end
66
76
  end
67
-
77
+
68
78
  def __raise(message)
69
79
  message = opts[:message] unless opts[:message].nil?
70
80
  Kernel::raise(RSpec::Mocks::MockExpectationError, message)
71
81
  end
72
-
82
+
73
83
  def arg_message(*args)
74
84
  " with " + format_args(*args)
75
85
  end
76
-
86
+
77
87
  def format_args(*args)
78
88
  args.empty? ? "(no args)" : "(" + arg_list(*args) + ")"
79
89
  end
@@ -81,7 +91,7 @@ module RSpec
81
91
  def arg_list(*args)
82
92
  args.collect {|arg| arg.respond_to?(:description) ? arg.description : arg.inspect}.join(", ")
83
93
  end
84
-
94
+
85
95
  def count_message(count)
86
96
  return "at least #{pretty_print(count.abs)}" if count < 0
87
97
  return pretty_print(count)
@@ -1,8 +1,10 @@
1
1
  module RSpec
2
2
  module Mocks
3
+ # @private
3
4
  class MockExpectationError < Exception
4
5
  end
5
6
 
7
+ # @private
6
8
  class AmbiguousReturnError < StandardError
7
9
  end
8
10
  end
@@ -5,37 +5,38 @@ module RSpec
5
5
 
6
6
  # Creates an instance of RSpec::Mocks::Mock.
7
7
  #
8
- # +name+ is used for failure reporting, so you should use the role that
8
+ # `name` is used for failure reporting, so you should use the role that
9
9
  # the mock is playing in the example.
10
10
  #
11
- # Use +stubs+ to declare one or more method stubs in one statement.
11
+ # Use `stubs` to declare one or more method stubs in one statement.
12
12
  #
13
- # == Examples
13
+ # @example
14
14
  #
15
15
  # book = double("book", :title => "The RSpec Book")
16
- # book.title => "The RSpec Book"
16
+ # book.title #=> "The RSpec Book"
17
17
  #
18
- # card = double("card", :suit => "Spades", :rank => "A"
19
- # card.suit => "Spades"
20
- # card.rank => "A"
18
+ # card = double("card", :suit => "Spades", :rank => "A")
19
+ # card.suit #=> "Spades"
20
+ # card.rank #=> "A"
21
21
  def double(*args)
22
22
  declare_double('Double', *args)
23
23
  end
24
24
 
25
- # Just like double, but use double
25
+ # Just like double
26
26
  def mock(*args)
27
27
  declare_double('Mock', *args)
28
28
  end
29
29
 
30
- # Just like double, but use double
30
+ # Just like double
31
31
  def stub(*args)
32
32
  declare_double('Stub', *args)
33
33
  end
34
34
 
35
35
  # Disables warning messages about expectations being set on nil.
36
36
  #
37
- # By default warning messages are issued when expectations are set on nil. This is to
38
- # prevent false-positives and to catch potential bugs early on.
37
+ # By default warning messages are issued when expectations are set on
38
+ # nil. This is to prevent false-positives and to catch potential bugs
39
+ # early on.
39
40
  def allow_message_expectations_on_nil
40
41
  Proxy.allow_message_expectations_on_nil
41
42
  end
@@ -1,7 +1,10 @@
1
1
  module RSpec
2
2
  module Mocks
3
+ # @private
3
4
  module InstanceExec
4
5
  unless respond_to?(:instance_exec)
6
+ # @private
7
+ #
5
8
  # based on Bounded Spec InstanceExec (Mauricio Fernandez)
6
9
  # http://eigenclass.org/hiki/bounded+space+instance_exec
7
10
  # - uses singleton_class of matcher instead of global
@@ -1,13 +1,15 @@
1
1
  module RSpec
2
2
  module Mocks
3
3
 
4
- class BaseExpectation
4
+ class MessageExpectation
5
+ # @private
5
6
  attr_reader :sym
6
7
  attr_writer :expected_received_count, :method_block, :expected_from
7
8
  protected :expected_received_count=, :method_block=, :expected_from=
8
9
  attr_accessor :error_generator
9
10
  protected :error_generator, :error_generator=
10
-
11
+
12
+ # @private
11
13
  def initialize(error_generator, expectation_ordering, expected_from, sym, method_block, expected_received_count=1, opts={}, &implementation)
12
14
  @error_generator = error_generator
13
15
  @error_generator.opts = opts
@@ -20,7 +22,7 @@ module RSpec
20
22
  @args_expectation = ArgumentExpectation.new(ArgumentMatchers::AnyArgsMatcher.new)
21
23
  @consecutive = false
22
24
  @exception_to_raise = nil
23
- @symbol_to_throw = nil
25
+ @args_to_throw = []
24
26
  @order_group = expectation_ordering
25
27
  @at_least = nil
26
28
  @at_most = nil
@@ -31,7 +33,8 @@ module RSpec
31
33
  @return_block = implementation
32
34
  @eval_context = nil
33
35
  end
34
-
36
+
37
+ # @private
35
38
  def build_child(expected_from, method_block, expected_received_count, opts={})
36
39
  child = clone
37
40
  child.expected_from = expected_from
@@ -44,80 +47,140 @@ module RSpec
44
47
  child.clone_args_to_yield(*@args_to_yield)
45
48
  child
46
49
  end
47
-
50
+
51
+ # @private
48
52
  def expected_args
49
53
  @args_expectation.args
50
54
  end
51
55
 
56
+ # @overload and_return(value)
57
+ # @overload and_return(first_value, second_value)
58
+ # @overload and_return(&block)
59
+ #
60
+ # Tells the object to return a value when it receives the message. Given
61
+ # more than one value, the first value is returned the first time the
62
+ # message is received, the second value is returned the next time, etc,
63
+ # etc.
64
+ #
65
+ # If the message is received more times than there are values, the last
66
+ # value is received for every subsequent call.
67
+ #
68
+ # The block format is still supported, but is unofficially deprecated in
69
+ # favor of just passing a block to the stub method.
70
+ #
71
+ # @example
72
+ #
73
+ # counter.stub(:count).and_return(1)
74
+ # counter.count # => 1
75
+ # counter.count # => 1
76
+ #
77
+ # counter.stub(:count).and_return(1,2,3)
78
+ # counter.count # => 1
79
+ # counter.count # => 2
80
+ # counter.count # => 3
81
+ # counter.count # => 3
82
+ # counter.count # => 3
83
+ # # etc
84
+ #
85
+ # # Supported, but ...
86
+ # counter.stub(:count).and_return { 1 }
87
+ # counter.count # => 1
88
+ #
89
+ # # ... this is prefered
90
+ # counter.stub(:count) { 1 }
91
+ # counter.count # => 1
52
92
  def and_return(*values, &return_block)
53
93
  Kernel::raise AmbiguousReturnError unless @method_block.nil?
54
94
  case values.size
55
- when 0 then value = nil
56
- when 1 then value = values[0]
95
+ when 0 then value = nil
96
+ when 1 then value = values[0]
57
97
  else
58
98
  value = values
59
99
  @consecutive = true
60
100
  @expected_received_count = values.size if !ignoring_args? &&
61
- @expected_received_count < values.size
101
+ @expected_received_count < values.size
62
102
  end
63
103
  @return_block = block_given? ? return_block : lambda { value }
64
104
  end
65
-
66
- # Tells the mock or stub to raise an exception when the message
67
- # is received.
105
+
106
+ # @overload and_raise
107
+ # @overload and_raise(ExceptionClass)
108
+ # @overload and_raise(exception_instance)
109
+ #
110
+ # Tells the object to raise an exception when the message is received.
68
111
  #
69
- # == Warning
112
+ # @note
70
113
  #
71
- # When you pass an exception class, the MessageExpectation will
72
- # raise an instance of it, creating it with +new+. If the exception
73
- # class initializer requires any parameters, you must pass in an
74
- # instance and not the class.
114
+ # When you pass an exception class, the MessageExpectation will raise
115
+ # an instance of it, creating it with `new`. If the exception class
116
+ # initializer requires any parameters, you must pass in an instance and
117
+ # not the class.
75
118
  #
76
- # == Examples
77
- # and_raise()
78
- # and_raise(Exception) #any exception class
79
- # and_raise(exception) #any exception object
119
+ # @example
120
+ #
121
+ # car.stub(:go).and_raise
122
+ # car.stub(:go).and_raise(OutOfGas)
123
+ # car.stub(:go).and_raise(OutOfGas.new(2, :oz))
80
124
  def and_raise(exception=Exception)
81
125
  @exception_to_raise = exception
82
126
  end
83
-
84
- def and_throw(symbol)
85
- @symbol_to_throw = symbol
127
+
128
+ # @overload and_throw(symbol)
129
+ # @overload and_throw(symbol, object)
130
+ #
131
+ # Tells the object to throw a symbol (with the object if that form is
132
+ # used) when the message is received.
133
+ #
134
+ # @example
135
+ #
136
+ # car.stub(:go).and_throw(:out_of_gas)
137
+ # car.stub(:go).and_throw(:out_of_gas, :level => 0.1)
138
+ def and_throw(symbol, object = nil)
139
+ @args_to_throw << symbol
140
+ @args_to_throw << object if object
86
141
  end
87
-
142
+
143
+ # Tells the object to yield one or more args to a block when the message
144
+ # is received.
145
+ #
146
+ # @example
147
+ #
148
+ # stream.stub(:open).and_yield(StringIO.new)
88
149
  def and_yield(*args, &block)
89
150
  if @args_to_yield_were_cloned
90
151
  @args_to_yield.clear
91
152
  @args_to_yield_were_cloned = false
92
153
  end
93
-
154
+
94
155
  if block
95
156
  @eval_context = Object.new
96
157
  @eval_context.extend RSpec::Mocks::InstanceExec
97
158
  yield @eval_context
98
159
  end
99
-
160
+
100
161
  @args_to_yield << args
101
162
  self
102
163
  end
103
-
164
+
165
+ # @private
104
166
  def matches?(sym, *args)
105
167
  @sym == sym and @args_expectation.args_match?(*args)
106
168
  end
107
-
169
+
170
+ # @private
108
171
  def invoke(*args, &block)
109
172
  if @expected_received_count == 0
110
173
  @failed_fast = true
111
174
  @actual_received_count += 1
112
175
  @error_generator.raise_expectation_error(@sym, @expected_received_count, @actual_received_count, *args)
113
176
  end
114
-
177
+
115
178
  @order_group.handle_order_constraint self
116
179
 
117
180
  begin
118
- Kernel::raise @exception_to_raise unless @exception_to_raise.nil?
119
- Kernel::throw @symbol_to_throw unless @symbol_to_throw.nil?
120
-
181
+ Kernel::raise(@exception_to_raise) unless @exception_to_raise.nil?
182
+ Kernel::throw(*@args_to_throw) unless @args_to_throw.empty?
183
+
121
184
  default_return_val = if !@method_block.nil?
122
185
  invoke_method_block(*args, &block)
123
186
  elsif !@args_to_yield.empty? || @eval_context
@@ -125,7 +188,7 @@ module RSpec
125
188
  else
126
189
  nil
127
190
  end
128
-
191
+
129
192
  if @consecutive
130
193
  invoke_consecutive_return_block(*args, &block)
131
194
  elsif @return_block
@@ -138,111 +201,61 @@ module RSpec
138
201
  end
139
202
  end
140
203
 
204
+ # @private
141
205
  def called_max_times?
142
206
  @expected_received_count != :any && @expected_received_count > 0 &&
143
207
  @actual_received_count >= @expected_received_count
144
208
  end
145
-
146
- protected
147
-
148
- def invoke_method_block(*args, &block)
149
- begin
150
- @method_block.call(*args, &block)
151
- rescue => detail
152
- @error_generator.raise_block_failed_error(@sym, detail.message)
153
- end
154
- end
155
-
156
- def invoke_with_yield(&block)
157
- if block.nil?
158
- @error_generator.raise_missing_block_error @args_to_yield
159
- end
160
- value = nil
161
- @args_to_yield.each do |args_to_yield_this_time|
162
- if block.arity > -1 && args_to_yield_this_time.length != block.arity
163
- @error_generator.raise_wrong_arity_error args_to_yield_this_time, block.arity
164
- end
165
- value = eval_block(*args_to_yield_this_time, &block)
166
- end
167
- value
168
- end
169
-
170
- def eval_block(*args, &block)
171
- if @eval_context
172
- @eval_context.instance_exec(*args, &block)
173
- else
174
- block.call(*args)
175
- end
176
- end
177
209
 
178
- def invoke_consecutive_return_block(*args, &block)
179
- value = invoke_return_block(*args, &block)
180
- index = [@actual_received_count, value.size-1].min
181
- value[index]
182
- end
183
-
184
- def invoke_return_block(*args, &block)
185
- args << block unless block.nil?
186
- # Ruby 1.9 - when we set @return_block to return values
187
- # regardless of arguments, any arguments will result in
188
- # a "wrong number of arguments" error
189
- @return_block.arity == 0 ? @return_block.call : @return_block.call(*args)
190
- end
191
-
192
- def clone_args_to_yield(*args)
193
- @args_to_yield = args.clone
194
- @args_to_yield_were_cloned = true
195
- end
196
-
197
- def failed_fast?
198
- @failed_fast
199
- end
200
- end
201
-
202
- class MessageExpectation < BaseExpectation
203
-
210
+ # @private
204
211
  def matches_name_but_not_args(sym, *args)
205
212
  @sym == sym and not @args_expectation.args_match?(*args)
206
213
  end
207
-
214
+
215
+ # @private
208
216
  def verify_messages_received
209
- return if expected_messages_received? || failed_fast?
210
-
211
- generate_error
217
+ generate_error unless expected_messages_received? || failed_fast?
212
218
  rescue RSpec::Mocks::MockExpectationError => error
213
219
  error.backtrace.insert(0, @expected_from)
214
220
  Kernel::raise error
215
221
  end
216
-
222
+
223
+ # @private
217
224
  def expected_messages_received?
218
- ignoring_args? || matches_exact_count? ||
219
- matches_at_least_count? || matches_at_most_count?
225
+ ignoring_args? || matches_exact_count? || matches_at_least_count? || matches_at_most_count?
220
226
  end
221
-
227
+
228
+ # @private
222
229
  def ignoring_args?
223
230
  @expected_received_count == :any
224
231
  end
225
-
232
+
233
+ # @private
226
234
  def matches_at_least_count?
227
235
  @at_least && @actual_received_count >= @expected_received_count
228
236
  end
229
-
237
+
238
+ # @private
230
239
  def matches_at_most_count?
231
240
  @at_most && @actual_received_count <= @expected_received_count
232
241
  end
233
-
242
+
243
+ # @private
234
244
  def matches_exact_count?
235
245
  @expected_received_count == @actual_received_count
236
246
  end
237
-
247
+
248
+ # @private
238
249
  def similar_messages
239
250
  @similar_messages ||= []
240
251
  end
241
252
 
253
+ # @private
242
254
  def advise(*args)
243
255
  similar_messages << args
244
256
  end
245
-
257
+
258
+ # @private
246
259
  def generate_error
247
260
  if similar_messages.empty?
248
261
  @error_generator.raise_expectation_error(@sym, @expected_received_count, @actual_received_count, *@args_expectation.args)
@@ -251,107 +264,238 @@ module RSpec
251
264
  end
252
265
  end
253
266
 
267
+ # Constrains a stub or message expectation to invocations with specific
268
+ # arguments.
269
+ #
270
+ # With a stub, if the message might be received with other args as well,
271
+ # you should stub a default value first, and then stub or mock the same
272
+ # message using `with` to constrain to specific arguments.
273
+ #
274
+ # A message expectation will fail if the message is received with different
275
+ # arguments.
276
+ #
277
+ # @example
278
+ #
279
+ # cart.stub(:add) { :failure }
280
+ # cart.stub(:add).with(Book.new(:isbn => 1934356379)) { :success }
281
+ # cart.add(Book.new(:isbn => 1234567890))
282
+ # # => :failure
283
+ # cart.add(Book.new(:isbn => 1934356379))
284
+ # # => :success
285
+ #
286
+ # cart.should_receive(:add).with(Book.new(:isbn => 1934356379)) { :success }
287
+ # cart.add(Book.new(:isbn => 1234567890))
288
+ # # => failed expectation
289
+ # cart.add(Book.new(:isbn => 1934356379))
290
+ # # => passes
254
291
  def with(*args, &block)
255
292
  @return_block = block if block_given? unless args.empty?
256
293
  @args_expectation = ArgumentExpectation.new(*args, &block)
257
294
  self
258
295
  end
259
-
296
+
297
+ # Constrain a message expectation to be received a specific number of
298
+ # times.
299
+ #
300
+ # @example
301
+ #
302
+ # dealer.should_recieve(:deal_card).exactly(10).times
260
303
  def exactly(n, &block)
261
304
  @method_block = block if block
262
305
  set_expected_received_count :exactly, n
263
306
  self
264
307
  end
265
-
308
+
309
+ # Constrain a message expectation to be received at least a specific
310
+ # number of times.
311
+ #
312
+ # @example
313
+ #
314
+ # dealer.should_recieve(:deal_card).at_least(9).times
266
315
  def at_least(n, &block)
267
316
  @method_block = block if block
268
317
  set_expected_received_count :at_least, n
269
318
  self
270
319
  end
271
-
320
+
321
+ # Constrain a message expectation to be received at most a specific
322
+ # number of times.
323
+ #
324
+ # @example
325
+ #
326
+ # dealer.should_recieve(:deal_card).at_most(10).times
272
327
  def at_most(n, &block)
273
328
  @method_block = block if block
274
329
  set_expected_received_count :at_most, n
275
330
  self
276
331
  end
277
332
 
333
+ # Syntactic sugar for `exactly`, `at_least` and `at_most`
334
+ #
335
+ # @example
336
+ #
337
+ # dealer.should_recieve(:deal_card).exactly(10).times
338
+ # dealer.should_recieve(:deal_card).at_least(10).times
339
+ # dealer.should_recieve(:deal_card).at_most(10).times
278
340
  def times(&block)
279
341
  @method_block = block if block
280
342
  self
281
343
  end
282
-
344
+
345
+
346
+ # Allows an expected message to be received any number of times.
283
347
  def any_number_of_times(&block)
284
348
  @method_block = block if block
285
349
  @expected_received_count = :any
286
350
  self
287
351
  end
288
-
352
+
353
+ # Expect a message not to be received at all.
354
+ #
355
+ # @example
356
+ #
357
+ # car.should_receive(:stop).never
289
358
  def never
290
359
  @expected_received_count = 0
291
360
  self
292
361
  end
293
-
362
+
363
+ # Expect a message to be received exactly one time.
364
+ #
365
+ # @example
366
+ #
367
+ # car.should_receive(:go).once
294
368
  def once(&block)
295
369
  @method_block = block if block
296
370
  set_expected_received_count :exactly, 1
297
371
  self
298
372
  end
299
-
373
+
374
+ # Expect a message to be received exactly two times.
375
+ #
376
+ # @example
377
+ #
378
+ # car.should_receive(:go).twice
300
379
  def twice(&block)
301
380
  @method_block = block if block
302
381
  set_expected_received_count :exactly, 2
303
382
  self
304
383
  end
305
-
384
+
385
+ # Expect messages to be received in a specific order.
386
+ #
387
+ # @example
388
+ #
389
+ # api.should_receive(:prepare).ordered
390
+ # api.should_receive(:run).ordered
391
+ # api.should_receive(:finish).ordered
306
392
  def ordered(&block)
307
393
  @method_block = block if block
308
394
  @order_group.register(self)
309
395
  @ordered = true
310
396
  self
311
397
  end
312
-
398
+
399
+ # @private
313
400
  def negative_expectation_for?(sym)
314
401
  return false
315
402
  end
316
-
403
+
404
+ # @private
317
405
  def actual_received_count_matters?
318
406
  @at_least || @at_most || @exactly
319
407
  end
320
408
 
409
+ # @private
321
410
  def increase_actual_received_count!
322
411
  @actual_received_count += 1
323
412
  end
324
413
 
325
414
  protected
326
- def set_expected_received_count(relativity, n)
327
- @at_least = (relativity == :at_least)
328
- @at_most = (relativity == :at_most)
329
- @exactly = (relativity == :exactly)
330
- @expected_received_count = case n
331
- when Numeric
332
- n
333
- when :once
334
- 1
335
- when :twice
336
- 2
415
+
416
+ def invoke_method_block(*args, &block)
417
+ begin
418
+ @method_block.call(*args, &block)
419
+ rescue => detail
420
+ @error_generator.raise_block_failed_error(@sym, detail.message)
421
+ end
422
+ end
423
+
424
+ def invoke_with_yield(&block)
425
+ if block.nil?
426
+ @error_generator.raise_missing_block_error @args_to_yield
427
+ end
428
+ value = nil
429
+ @args_to_yield.each do |args_to_yield_this_time|
430
+ if block.arity > -1 && args_to_yield_this_time.length != block.arity
431
+ @error_generator.raise_wrong_arity_error args_to_yield_this_time, block.arity
337
432
  end
433
+ value = eval_block(*args_to_yield_this_time, &block)
338
434
  end
339
-
340
- def clear_actual_received_count!
341
- @actual_received_count = 0
435
+ value
436
+ end
437
+
438
+ def eval_block(*args, &block)
439
+ if @eval_context
440
+ @eval_context.instance_exec(*args, &block)
441
+ else
442
+ block.call(*args)
342
443
  end
444
+ end
445
+
446
+ def invoke_consecutive_return_block(*args, &block)
447
+ value = invoke_return_block(*args, &block)
448
+ index = [@actual_received_count, value.size-1].min
449
+ value[index]
450
+ end
451
+
452
+ def invoke_return_block(*args, &block)
453
+ args << block unless block.nil?
454
+ # Ruby 1.9 - when we set @return_block to return values
455
+ # regardless of arguments, any arguments will result in
456
+ # a "wrong number of arguments" error
457
+ @return_block.arity == 0 ? @return_block.call : @return_block.call(*args)
458
+ end
459
+
460
+ def clone_args_to_yield(*args)
461
+ @args_to_yield = args.clone
462
+ @args_to_yield_were_cloned = true
463
+ end
464
+
465
+ def failed_fast?
466
+ @failed_fast
467
+ end
343
468
 
469
+ def set_expected_received_count(relativity, n)
470
+ @at_least = (relativity == :at_least)
471
+ @at_most = (relativity == :at_most)
472
+ @exactly = (relativity == :exactly)
473
+ @expected_received_count = case n
474
+ when Numeric
475
+ n
476
+ when :once
477
+ 1
478
+ when :twice
479
+ 2
480
+ end
481
+ end
482
+
483
+ def clear_actual_received_count!
484
+ @actual_received_count = 0
485
+ end
344
486
  end
345
-
487
+
488
+ # @private
346
489
  class NegativeMessageExpectation < MessageExpectation
490
+ # @private
347
491
  def initialize(message, expectation_ordering, expected_from, sym, method_block)
348
492
  super(message, expectation_ordering, expected_from, sym, method_block, 0)
349
493
  end
350
-
494
+
495
+ # @private
351
496
  def negative_expectation_for?(sym)
352
497
  return @sym == sym
353
498
  end
354
499
  end
355
-
356
500
  end
357
501
  end