rspec-mocks 2.8.0.rc1 → 2.8.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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