rspec-mocks 2.12.2 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,33 @@
1
+ ### 2.13.0 / 2013-02-23
2
+ [full changelog](http://github.com/rspec/rspec-mocks/compare/v2.12.2...v2.13.0)
3
+
4
+ Bug fixes
5
+
6
+ * Fix bug that caused weird behavior when a method that had
7
+ previously been stubbed with multiple return values (e.g.
8
+ `obj.stub(:foo).and_return(1, 2)`) was later mocked with a
9
+ single return value (e.g. `obj.should_receive(:foo).once.and_return(1)`).
10
+ (Myron Marston)
11
+ * Fix bug related to a mock expectation for a method that already had
12
+ multiple stubs with different `with` constraints. Previously, the
13
+ first stub was used, even though it may not have matched the passed
14
+ args. The fix defers this decision until the message is received so
15
+ that the proper stub response can be chosen based on the passed
16
+ arguments (Myron Marston).
17
+ * Do not call `nil?` extra times on a mocked object, in case `nil?`
18
+ itself is expected a set number of times (Myron Marston).
19
+ * Fix `missing_default_stub_error` message so array args are handled
20
+ properly (Myron Marston).
21
+ * Explicitly disallow `any_instance.unstub!` (Ryan Jones).
22
+ * Fix `any_instance` stubbing so that it works with `Delegator`
23
+ subclasses (Myron Marston).
24
+ * Fix `and_call_original` so that it works with `Delegator` subclasses
25
+ (Myron Marston).
26
+ * Fix `any_instance.should_not_receive` when `any_instance.should_receive`
27
+ is used on the same class in the same example. Previously it would
28
+ wrongly report a failure even when the message was not received
29
+ (Myron Marston).
30
+
1
31
  ### 2.12.2 / 2013-01-27
2
32
  [full changelog](http://github.com/rspec/rspec-mocks/compare/v2.12.1...v.2.12.2)
3
33
 
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # RSpec Mocks [![Build Status](https://secure.travis-ci.org/rspec/rspec-mocks.png?branch=master)](http://travis-ci.org/rspec/rspec-mocks) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/rspec/rspec-mocks)
1
+ # RSpec Mocks [![Build Status](https://secure.travis-ci.org/rspec/rspec-mocks.png?branch=master)](http://travis-ci.org/rspec/rspec-mocks) [![Code Climate](https://codeclimate.com/github/rspec/rspec-mocks.png)](https://codeclimate.com/github/rspec/rspec-mocks)
2
2
 
3
3
  rspec-mocks is a test-double framework for rspec with support for method stubs,
4
4
  fakes, and message expectations on generated test-doubles and real objects
@@ -137,6 +137,13 @@ double.should_receive(:msg).with(*args)
137
137
  double.should_not_receive(:msg).with(*args)
138
138
  ```
139
139
 
140
+ You can set multiple expectations for the same message if you need to:
141
+
142
+ ```ruby
143
+ double.should_receive(:msg).with("A", 1, 3)
144
+ double.should_receive(:msg).with("B", 2, 4)
145
+ ```
146
+
140
147
  ## Argument Matchers
141
148
 
142
149
  Arguments that are passed to `with` are compared with actual arguments
@@ -183,6 +190,13 @@ double.should_receive(:other_msg).ordered
183
190
  #This will fail if the messages are received out of order
184
191
  ```
185
192
 
193
+ This can include the same message with different arguments:
194
+
195
+ ```ruby
196
+ double.should_receive(:msg).with("A", 1, 3).ordered
197
+ double.should_receive(:msg).with("B", 2, 4).ordered
198
+ ```
199
+
186
200
  ## Setting Responses
187
201
 
188
202
  Whether you are setting a message expectation or a method stub, you can
@@ -233,7 +247,7 @@ double.should_receive(:msg) do |arg|
233
247
  end
234
248
  ```
235
249
 
236
- If the method being stubbed itself takes a block, and you need to yield to it
250
+ If the method being stubbed itself takes a block, and you need to yield to it
237
251
  in some special way, you can use this:
238
252
 
239
253
  ```ruby
@@ -35,6 +35,25 @@ module RSpec
35
35
  warn(message)
36
36
  end
37
37
 
38
+ # @api private
39
+ KERNEL_METHOD_METHOD = ::Kernel.instance_method(:method)
40
+
41
+ # @api private
42
+ # Used internally to get a method handle for a particular object
43
+ # and method name.
44
+ #
45
+ # Includes handling for a few special cases:
46
+ #
47
+ # - Objects that redefine #method (e.g. an HTTPRequest struct)
48
+ # - BasicObject subclasses that mixin a Kernel dup (e.g. SimpleDelegator)
49
+ def method_handle_for(object, method_name)
50
+ if ::Kernel === object
51
+ KERNEL_METHOD_METHOD.bind(object).call(method_name)
52
+ else
53
+ object.method(method_name)
54
+ end
55
+ end
56
+
38
57
  private
39
58
 
40
59
  def add_extensions
@@ -41,6 +41,15 @@ module RSpec
41
41
  super(:should_not_receive, *args, &block)
42
42
  end
43
43
 
44
+ # `should_not_receive` causes a failure at the point in time the
45
+ # message is wrongly received, rather than during `rspec_verify`
46
+ # at the end of an example. Thus, we should always consider a
47
+ # negative expectation fulfilled for the purposes of end-of-example
48
+ # verification (which is where this is used).
49
+ def expectation_fulfilled?
50
+ true
51
+ end
52
+
44
53
  private
45
54
 
46
55
  def invocation_order
@@ -91,6 +91,11 @@ module RSpec
91
91
  raise "stub! is not supported on any_instance. Use stub instead."
92
92
  end
93
93
 
94
+ # @private
95
+ def unstub!(*)
96
+ raise "unstub! is not supported on any_instance. Use unstub instead."
97
+ end
98
+
94
99
  # @private
95
100
  def stop_all_observation!
96
101
  @observed_methods.each {|method_name| restore_method!(method_name)}
@@ -175,7 +180,7 @@ module RSpec
175
180
  backup_method!(method_name)
176
181
  @klass.class_eval(<<-EOM, __FILE__, __LINE__ + 1)
177
182
  def #{method_name}(*args, &blk)
178
- klass = ::Object.instance_method(:method).bind(self).call(:#{method_name}).owner
183
+ klass = ::RSpec::Mocks.method_handle_for(self, :#{method_name}).owner
179
184
  klass.__recorder.playback!(self, :#{method_name})
180
185
  self.__send__(:#{method_name}, *args, &blk)
181
186
  end
@@ -187,7 +192,7 @@ module RSpec
187
192
  @klass.class_eval(<<-EOM, __FILE__, __LINE__ + 1)
188
193
  def #{method_name}(*args, &blk)
189
194
  method_name = :#{method_name}
190
- klass = ::Object.instance_method(:method).bind(self).call(:#{method_name}).owner
195
+ klass = ::RSpec::Mocks.method_handle_for(self, :#{method_name}).owner
191
196
  invoked_instance = klass.__recorder.instance_that_received(method_name)
192
197
  raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by \#{self.inspect} but has already been received by \#{invoked_instance}"
193
198
  end
@@ -28,16 +28,16 @@ module RSpec
28
28
  end
29
29
 
30
30
  # @private
31
- def raise_missing_default_stub_error(expectation,*args)
31
+ def raise_missing_default_stub_error(expectation, *args)
32
32
  expected_args = format_args(*expectation.expected_args)
33
- actual_args = args.collect {|a| format_args(*a)}.join(", ")
33
+ actual_args = format_args(*args)
34
34
  __raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}\n Please stub a default value first if message might be received with other args as well. \n"
35
35
  end
36
36
 
37
37
  # @private
38
- def raise_similar_message_args_error(expectation, *args)
38
+ def raise_similar_message_args_error(expectation, *args_for_multiple_calls)
39
39
  expected_args = format_args(*expectation.expected_args)
40
- actual_args = args.collect {|a| format_args(*a)}.join(", ")
40
+ actual_args = args_for_multiple_calls.collect {|a| format_args(*a)}.join(", ")
41
41
  __raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}"
42
42
  end
43
43
 
@@ -3,10 +3,10 @@ module RSpec
3
3
 
4
4
  class MessageExpectation
5
5
  # @private
6
- attr_accessor :error_generator
6
+ attr_accessor :error_generator, :implementation
7
7
  attr_reader :message
8
8
  attr_writer :expected_received_count, :expected_from, :argument_list_matcher
9
- protected :expected_received_count=, :expected_from=, :error_generator, :error_generator=
9
+ protected :expected_received_count=, :expected_from=, :error_generator, :error_generator=, :implementation=
10
10
 
11
11
  # @private
12
12
  def initialize(error_generator, expectation_ordering, expected_from, method_double,
@@ -19,36 +19,16 @@ module RSpec
19
19
  @actual_received_count = 0
20
20
  @expected_received_count = expected_received_count
21
21
  @argument_list_matcher = ArgumentListMatcher.new(ArgumentMatchers::AnyArgsMatcher.new)
22
- @consecutive = false
23
22
  @order_group = expectation_ordering
24
23
  @at_least = @at_most = @exactly = nil
25
24
  @args_to_yield = []
26
25
  @failed_fast = nil
27
- @args_to_yield_were_cloned = false
28
26
  @eval_context = nil
29
27
  @implementation = implementation
28
+ @values_to_return = nil
30
29
  end
31
30
 
32
- def implementation=(implementation)
33
- @consecutive = false
34
- @implementation = implementation
35
- end
36
- protected :implementation=
37
-
38
31
  # @private
39
- def build_child(expected_from, expected_received_count, opts={}, &implementation)
40
- child = clone
41
- child.expected_from = expected_from
42
- child.implementation = implementation if implementation
43
- child.expected_received_count = expected_received_count
44
- child.clear_actual_received_count!
45
- new_gen = error_generator.clone
46
- new_gen.opts = opts
47
- child.error_generator = new_gen
48
- child.clone_args_to_yield(*@args_to_yield)
49
- child.argument_list_matcher = ArgumentListMatcher.new(ArgumentMatchers::AnyArgsMatcher.new)
50
- child
51
- end
52
32
 
53
33
  # @private
54
34
  def expected_args
@@ -93,8 +73,14 @@ module RSpec
93
73
  # counter.count # => 1
94
74
  def and_return(*values, &implementation)
95
75
  @expected_received_count = [@expected_received_count, values.size].max unless ignoring_args? || (@expected_received_count == 0 and @at_least)
96
- @consecutive = true if values.size > 1
97
- @implementation = implementation || build_implementation(values)
76
+
77
+ if implementation
78
+ # TODO: deprecate `and_return { value }`
79
+ @implementation = implementation
80
+ else
81
+ @values_to_return = values
82
+ @implementation = build_implementation
83
+ end
98
84
  end
99
85
 
100
86
  # Tells the object to delegate to the original unmodified method
@@ -112,7 +98,7 @@ module RSpec
112
98
  if @method_double.object.is_a?(RSpec::Mocks::TestDouble)
113
99
  @error_generator.raise_only_valid_on_a_partial_mock(:and_call_original)
114
100
  else
115
- self.implementation = @method_double.original_method
101
+ @implementation = @method_double.original_method
116
102
  end
117
103
  end
118
104
 
@@ -142,7 +128,7 @@ module RSpec
142
128
  exception = message ? exception.exception(message) : exception.exception
143
129
  end
144
130
 
145
- self.implementation = Proc.new { raise exception }
131
+ @implementation = Proc.new { raise exception }
146
132
  end
147
133
 
148
134
  # @overload and_throw(symbol)
@@ -156,7 +142,7 @@ module RSpec
156
142
  # car.stub(:go).and_throw(:out_of_gas)
157
143
  # car.stub(:go).and_throw(:out_of_gas, :level => 0.1)
158
144
  def and_throw(*args)
159
- self.implementation = Proc.new { throw *args }
145
+ @implementation = Proc.new { throw *args }
160
146
  end
161
147
 
162
148
  # Tells the object to yield one or more args to a block when the message
@@ -166,14 +152,9 @@ module RSpec
166
152
  #
167
153
  # stream.stub(:open).and_yield(StringIO.new)
168
154
  def and_yield(*args, &block)
169
- if @args_to_yield_were_cloned
170
- @args_to_yield.clear
171
- @args_to_yield_were_cloned = false
172
- end
173
-
174
155
  yield @eval_context = Object.new.extend(RSpec::Mocks::InstanceExec) if block
175
-
176
156
  @args_to_yield << args
157
+ @implementation = build_implementation
177
158
  self
178
159
  end
179
160
 
@@ -183,7 +164,7 @@ module RSpec
183
164
  end
184
165
 
185
166
  # @private
186
- def invoke(*args, &block)
167
+ def invoke(parent_stub, *args, &block)
187
168
  if (@expected_received_count == 0 && !@at_least) || ((@exactly || @at_most) && (@actual_received_count == @expected_received_count))
188
169
  @actual_received_count += 1
189
170
  @failed_fast = true
@@ -193,14 +174,10 @@ module RSpec
193
174
  @order_group.handle_order_constraint self
194
175
 
195
176
  begin
196
- default_return_val = call_with_yield(&block) if !@args_to_yield.empty? || @eval_context
197
-
198
- if @consecutive
199
- call_implementation_consecutive(*args, &block)
200
- elsif @implementation
177
+ if @implementation
201
178
  call_implementation(*args, &block)
202
- else
203
- default_return_val
179
+ elsif parent_stub
180
+ parent_stub.invoke(nil, *args, &block)
204
181
  end
205
182
  ensure
206
183
  @actual_received_count += 1
@@ -425,30 +402,12 @@ module RSpec
425
402
 
426
403
  protected
427
404
 
428
- def call_with_yield(&block)
429
- @error_generator.raise_missing_block_error @args_to_yield unless block
430
- value = nil
431
- @args_to_yield.each do |args|
432
- if block.arity > -1 && args.length != block.arity
433
- @error_generator.raise_wrong_arity_error args, block.arity
434
- end
435
- value = @eval_context ? @eval_context.instance_exec(*args, &block) : block.call(*args)
436
- end
437
- value
438
- end
439
-
440
- def call_implementation_consecutive(*args, &block)
441
- @value ||= call_implementation(*args, &block)
442
- @value[[@actual_received_count, @value.size-1].min]
443
- end
444
-
445
405
  def call_implementation(*args, &block)
446
- @implementation.arity == 0 ? @implementation.call(&block) : @implementation.call(*args, &block)
447
- end
448
-
449
- def clone_args_to_yield(*args)
450
- @args_to_yield = args.clone
451
- @args_to_yield_were_cloned = true
406
+ if @implementation.arity.zero?
407
+ @implementation.call(&block)
408
+ else
409
+ @implementation.call(*args, &block)
410
+ end
452
411
  end
453
412
 
454
413
  def failed_fast?
@@ -466,15 +425,13 @@ module RSpec
466
425
  end
467
426
  end
468
427
 
469
- def clear_actual_received_count!
470
- @actual_received_count = 0
471
- end
472
-
473
428
  private
474
429
 
475
- def build_implementation(values)
476
- value = values.size == 1 ? values.first : values
477
- lambda { value }
430
+ def build_implementation
431
+ Implementation.new(
432
+ @values_to_return, @args_to_yield,
433
+ @eval_context, @error_generator
434
+ ).method(:call)
478
435
  end
479
436
  end
480
437
 
@@ -499,5 +456,42 @@ MSG
499
456
  return @message == message
500
457
  end
501
458
  end
459
+
460
+ # Represents a configured implementation. Takes into account
461
+ # `and_return` and `and_yield` instructions.
462
+ # @private
463
+ class Implementation
464
+ def initialize(values_to_return, args_to_yield, eval_context, error_generator)
465
+ @values_to_return = values_to_return
466
+ @args_to_yield = args_to_yield
467
+ @eval_context = eval_context
468
+ @error_generator = error_generator
469
+ end
470
+
471
+ def call(&block)
472
+ default_return_value = perform_yield(&block)
473
+ return default_return_value unless @values_to_return
474
+
475
+ if @values_to_return.size > 1
476
+ @values_to_return.shift
477
+ else
478
+ @values_to_return.first
479
+ end
480
+ end
481
+
482
+ def perform_yield(&block)
483
+ return if @args_to_yield.empty? && @eval_context.nil?
484
+
485
+ @error_generator.raise_missing_block_error @args_to_yield unless block
486
+ value = nil
487
+ @args_to_yield.each do |args|
488
+ if block.arity > -1 && args.length != block.arity
489
+ @error_generator.raise_wrong_arity_error args, block.arity
490
+ end
491
+ value = @eval_context ? @eval_context.instance_exec(*args, &block) : block.call(*args)
492
+ end
493
+ value
494
+ end
495
+ end
502
496
  end
503
497
  end
@@ -44,7 +44,7 @@ module RSpec
44
44
  def original_method
45
45
  if @method_stasher.method_is_stashed?
46
46
  # Example: a singleton method defined on @object
47
- method_handle_for(@object, @method_stasher.stashed_method_name)
47
+ ::RSpec::Mocks.method_handle_for(@object, @method_stasher.stashed_method_name)
48
48
  elsif meth = original_unrecorded_any_instance_method
49
49
  # Example: a method that has been mocked through
50
50
  # klass.any_instance.should_receive(:msg).and_call_original
@@ -135,15 +135,6 @@ module RSpec
135
135
  @object.superclass.method(@method_name)
136
136
  end
137
137
  end
138
-
139
- # @private
140
- OBJECT_METHOD_METHOD = ::Object.instance_method(:method)
141
-
142
- # @private
143
- def method_handle_for(object, method_name)
144
- OBJECT_METHOD_METHOD.bind(object).call(method_name)
145
- end
146
-
147
138
  # @private
148
139
  def object_singleton_class
149
140
  class << @object; self; end
@@ -214,12 +205,8 @@ module RSpec
214
205
  # @private
215
206
  def add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation)
216
207
  configure_method
217
- expectation = if existing_stub = stubs.first
218
- existing_stub.build_child(expected_from, 1, opts, &implementation)
219
- else
220
- MessageExpectation.new(error_generator, expectation_ordering,
221
- expected_from, self, 1, opts, &implementation)
222
- end
208
+ expectation = MessageExpectation.new(error_generator, expectation_ordering,
209
+ expected_from, self, 1, opts, &implementation)
223
210
  expectations << expectation
224
211
  expectation
225
212
  end
@@ -256,7 +243,7 @@ module RSpec
256
243
 
257
244
  # @private
258
245
  def proxy_for_nil_class?
259
- @object.nil?
246
+ NilClass === @object
260
247
  end
261
248
 
262
249
  # @private
@@ -82,7 +82,7 @@ module RSpec
82
82
  if chain.length > 1
83
83
  if matching_stub = __mock_proxy.__send__(:find_matching_method_stub, chain[0].to_sym)
84
84
  chain.shift
85
- matching_stub.invoke.stub_chain(*chain, &blk)
85
+ matching_stub.invoke(nil).stub_chain(*chain, &blk)
86
86
  else
87
87
  next_in_chain = Mock.new
88
88
  stub(chain.shift) { next_in_chain }
@@ -128,9 +128,9 @@ module RSpec
128
128
  if expectation = find_almost_matching_expectation(message, *args)
129
129
  expectation.advise(*args) unless expectation.expected_messages_received?
130
130
  end
131
- stub.invoke(*args, &block)
131
+ stub.invoke(nil, *args, &block)
132
132
  elsif expectation
133
- expectation.invoke(*args, &block)
133
+ expectation.invoke(stub, *args, &block)
134
134
  elsif expectation = find_almost_matching_expectation(message, *args)
135
135
  expectation.advise(*args) if null_object? unless expectation.expected_messages_received?
136
136
  raise_unexpected_message_args_error(expectation, *args) unless (has_negative_expectation?(message) or null_object?)
@@ -1,7 +1,7 @@
1
1
  module RSpec
2
2
  module Mocks
3
3
  module Version
4
- STRING = '2.12.2'
4
+ STRING = '2.13.0'
5
5
  end
6
6
  end
7
7
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'delegate'
2
3
 
3
4
  describe "and_call_original" do
4
5
  context "on a partial mock object" do
@@ -31,10 +32,19 @@ describe "and_call_original" do
31
32
  expect(value).to eq([:submitted_arg, :additional_yielded_arg])
32
33
  end
33
34
 
34
- it 'works for singleton methods' do
35
- def instance.foo; :bar; end
36
- instance.should_receive(:foo).and_call_original
37
- expect(instance.foo).to eq(:bar)
35
+ context "for singleton methods" do
36
+ it 'works' do
37
+ def instance.foo; :bar; end
38
+ instance.should_receive(:foo).and_call_original
39
+ expect(instance.foo).to eq(:bar)
40
+ end
41
+
42
+ it 'works for SimpleDelegator subclasses', :if => (RUBY_VERSION.to_f > 1.8) do
43
+ instance = Class.new(SimpleDelegator).new(1)
44
+ def instance.foo; :bar; end
45
+ instance.should_receive(:foo).and_call_original
46
+ expect(instance.foo).to eq(:bar)
47
+ end
38
48
  end
39
49
 
40
50
  it 'works for methods added through an extended module' do
@@ -5,6 +5,19 @@ describe RSpec::Mocks::Mock do
5
5
  let(:obj) { double }
6
6
 
7
7
  describe "#and_yield" do
8
+ context 'when the method double has been constrained by `with`' do
9
+ it 'uses the default stub if the provided args do not match' do
10
+ obj.stub(:foo) { 15 }
11
+ obj.stub(:foo).with(:yield).and_yield
12
+
13
+ # should_receive is required to trigger the bug:
14
+ # https://github.com/rspec/rspec-mocks/issues/127
15
+ obj.should_receive(:foo)
16
+
17
+ expect(obj.foo(:dont_yield)).to eq(15)
18
+ end
19
+ end
20
+
8
21
  context "with eval context as block argument" do
9
22
 
10
23
  it "evaluates the supplied block as it is read" do
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'delegate'
2
3
 
3
4
  module RSpec
4
5
  module Mocks
@@ -245,6 +246,14 @@ module RSpec
245
246
  end
246
247
  end
247
248
 
249
+ context "with #unstub!" do
250
+ it "raises with a message instructing the user to use unstub instead" do
251
+ expect do
252
+ klass.any_instance.unstub!(:foo)
253
+ end.to raise_error(/Use unstub instead/)
254
+ end
255
+ end
256
+
248
257
  context "unstub implementation" do
249
258
  it "replaces the stubbed method with the original method" do
250
259
  klass.any_instance.stub(:existing_method)
@@ -302,6 +311,15 @@ module RSpec
302
311
  expect { klass.new.existing_method_with_arguments(:argument_three, :argument_four) }.to_not raise_error
303
312
  end
304
313
  end
314
+
315
+ context 'when used in combination with should_receive' do
316
+ it 'passes if only the expected message is received' do
317
+ klass.any_instance.should_receive(:foo)
318
+ klass.any_instance.should_not_receive(:bar)
319
+ klass.new.foo
320
+ klass.rspec_verify
321
+ end
322
+ end
305
323
  end
306
324
 
307
325
  context "with #should_receive" do
@@ -436,6 +454,25 @@ module RSpec
436
454
  end
437
455
  end
438
456
 
457
+ it 'works with a BasicObject subclass that mixes in Kernel', :if => defined?(BasicObject) do
458
+ klass = Class.new(BasicObject) do
459
+ include ::Kernel
460
+ def foo; end
461
+ end
462
+
463
+ klass.any_instance.should_receive(:foo)
464
+ klass.new.foo
465
+ end
466
+
467
+ it 'works with a SimpleDelegator subclass', :if => (RUBY_VERSION.to_f > 1.8) do
468
+ klass = Class.new(SimpleDelegator) do
469
+ def foo; end
470
+ end
471
+
472
+ klass.any_instance.should_receive(:foo)
473
+ klass.new(Object.new).foo
474
+ end
475
+
439
476
  context "with argument matching" do
440
477
  before do
441
478
  klass.any_instance.should_receive(:foo).with(:param_one, :param_two).and_return(:result_one)
@@ -539,14 +539,14 @@ module RSpec
539
539
  @double.rspec_verify
540
540
  end
541
541
 
542
- it "yields multiple values after a similar stub" do
543
- File.stub(:open).and_yield(:stub_value)
544
- File.should_receive(:open).and_yield(:first_call).and_yield(:second_call)
545
- yielded_args = []
546
- File.open {|v| yielded_args << v }
547
- expect(yielded_args).to eq [:first_call, :second_call]
548
- File.open {|v| expect(v).to eq :stub_value }
549
- File.rspec_verify
542
+ it "can yield multiple times when told to do so" do
543
+ @double.stub(:foo).and_yield(:stub_value)
544
+ @double.should_receive(:foo).and_yield(:first_yield).and_yield(:second_yield)
545
+
546
+ expect { |b| @double.foo(&b) }.to yield_successive_args(:first_yield, :second_yield)
547
+ expect { |b| @double.foo(&b) }.to yield_with_args(:stub_value)
548
+
549
+ @double.rspec_verify
550
550
  end
551
551
 
552
552
  it "assigns stub return values" do
@@ -2,6 +2,19 @@ require 'spec_helper'
2
2
 
3
3
  module RSpec
4
4
  module Mocks
5
+ describe "a double stubbed with multiple return values" do
6
+ let(:a_double) { double }
7
+
8
+ before do
9
+ a_double.stub(:foo).and_return(:val_1, nil)
10
+ end
11
+
12
+ it 'can still set a message expectation with a single return value' do
13
+ a_double.should_receive(:foo).once.and_return(:val_1)
14
+ expect(a_double.foo).to eq(:val_1)
15
+ end
16
+ end
17
+
5
18
  describe "a message expectation with multiple return values and no specified count" do
6
19
  before(:each) do
7
20
  @double = double
@@ -34,6 +34,12 @@ module RSpec
34
34
  nil.should_not_receive(:bar)
35
35
  nil.foo
36
36
  end
37
+
38
+ it 'does not call #nil? on a double extra times' do
39
+ dbl = double
40
+ dbl.should_receive(:nil?).once.and_return(false)
41
+ dbl.nil?
42
+ end
37
43
  end
38
44
 
39
45
  describe "#allow_message_expectations_on_nil" do
@@ -260,6 +260,19 @@ module RSpec
260
260
  it "supports options" do
261
261
  @stub.stub(:foo, :expected_from => "bar")
262
262
  end
263
+
264
+ it 'uses the correct stubbed response when responding to a mock expectation' do
265
+ @stub.stub(:bar) { 15 }
266
+ @stub.stub(:bar).with(:eighteen) { 18 }
267
+ @stub.stub(:bar).with(:thirteen) { 13 }
268
+
269
+ @stub.should_receive(:bar).exactly(4).times
270
+
271
+ expect(@stub.bar(:blah)).to eq(15)
272
+ expect(@stub.bar(:thirteen)).to eq(13)
273
+ expect(@stub.bar(:eighteen)).to eq(18)
274
+ expect(@stub.bar).to eq(15)
275
+ end
263
276
  end
264
277
 
265
278
  end
@@ -43,5 +43,16 @@ describe "expection set on previously stubbed method" do
43
43
  double.foo(3)
44
44
  expect { double.rspec_verify }.to raise_error(/expected: \(4\)\s+got: \(3\)/)
45
45
  end
46
+
47
+ it 'distinguishes between individual values and arrays properly' do
48
+ dbl = double
49
+ dbl.stub(:foo).with('a', ['b'])
50
+
51
+ expect {
52
+ dbl.foo(['a'], 'b')
53
+ }.to raise_error { |e|
54
+ expect(e.message).to include('expected: ("a", ["b"])', 'got: (["a"], "b")')
55
+ }
56
+ end
46
57
  end
47
58
  end
metadata CHANGED
@@ -1,80 +1,71 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rspec-mocks
3
- version: !ruby/object:Gem::Version
4
- hash: 59
3
+ version: !ruby/object:Gem::Version
5
4
  prerelease:
6
- segments:
7
- - 2
8
- - 12
9
- - 2
10
- version: 2.12.2
5
+ version: 2.13.0
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Steven Baker
14
9
  - David Chelimsky
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2013-01-28 00:00:00 Z
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
22
- version_requirements: &id001 !ruby/object:Gem::Requirement
23
- none: false
24
- requirements:
13
+ date: 2013-02-23 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
25
18
  - - ~>
26
- - !ruby/object:Gem::Version
27
- hash: 79
28
- segments:
29
- - 10
30
- - 0
31
- - 0
19
+ - !ruby/object:Gem::Version
32
20
  version: 10.0.0
21
+ none: false
33
22
  prerelease: false
34
- type: :development
35
23
  name: rake
36
- requirement: *id001
37
- - !ruby/object:Gem::Dependency
38
- version_requirements: &id002 !ruby/object:Gem::Requirement
24
+ requirement: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ version: 10.0.0
39
29
  none: false
40
- requirements:
30
+ type: :development
31
+ - !ruby/object:Gem::Dependency
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
41
34
  - - ~>
42
- - !ruby/object:Gem::Version
43
- hash: 1
44
- segments:
45
- - 1
46
- - 1
47
- - 9
35
+ - !ruby/object:Gem::Version
48
36
  version: 1.1.9
37
+ none: false
49
38
  prerelease: false
50
- type: :development
51
39
  name: cucumber
52
- requirement: *id002
53
- - !ruby/object:Gem::Dependency
54
- version_requirements: &id003 !ruby/object:Gem::Requirement
40
+ requirement: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 1.1.9
55
45
  none: false
56
- requirements:
46
+ type: :development
47
+ - !ruby/object:Gem::Dependency
48
+ version_requirements: !ruby/object:Gem::Requirement
49
+ requirements:
57
50
  - - ~>
58
- - !ruby/object:Gem::Version
59
- hash: 25
60
- segments:
61
- - 0
62
- - 4
63
- - 11
51
+ - !ruby/object:Gem::Version
64
52
  version: 0.4.11
53
+ none: false
65
54
  prerelease: false
66
- type: :development
67
55
  name: aruba
68
- requirement: *id003
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: 0.4.11
61
+ none: false
62
+ type: :development
69
63
  description: RSpec's 'test double' framework, with support for stubbing and mocking
70
64
  email: rspec-users@rubyforge.org
71
65
  executables: []
72
-
73
66
  extensions: []
74
-
75
67
  extra_rdoc_files: []
76
-
77
- files:
68
+ files:
78
69
  - lib/rspec/mocks.rb
79
70
  - lib/rspec/mocks/any_instance.rb
80
71
  - lib/rspec/mocks/any_instance/chain.rb
@@ -191,39 +182,38 @@ files:
191
182
  - spec/rspec/mocks_spec.rb
192
183
  - spec/spec_helper.rb
193
184
  homepage: http://github.com/rspec/rspec-mocks
194
- licenses:
185
+ licenses:
195
186
  - MIT
196
187
  post_install_message:
197
- rdoc_options:
188
+ rdoc_options:
198
189
  - --charset=UTF-8
199
- require_paths:
190
+ require_paths:
200
191
  - lib
201
- required_ruby_version: !ruby/object:Gem::Requirement
202
- none: false
203
- requirements:
204
- - - ">="
205
- - !ruby/object:Gem::Version
206
- hash: 3
207
- segments:
192
+ required_ruby_version: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - ! '>='
195
+ - !ruby/object:Gem::Version
196
+ version: '0'
197
+ segments:
208
198
  - 0
209
- version: "0"
210
- required_rubygems_version: !ruby/object:Gem::Requirement
199
+ hash: 2521574480756142487
211
200
  none: false
212
- requirements:
213
- - - ">="
214
- - !ruby/object:Gem::Version
215
- hash: 3
216
- segments:
201
+ required_rubygems_version: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - ! '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ segments:
217
207
  - 0
218
- version: "0"
208
+ hash: 2521574480756142487
209
+ none: false
219
210
  requirements: []
220
-
221
211
  rubyforge_project: rspec
222
212
  rubygems_version: 1.8.24
223
213
  signing_key:
224
214
  specification_version: 3
225
- summary: rspec-mocks-2.12.2
226
- test_files:
215
+ summary: rspec-mocks-2.13.0
216
+ test_files:
227
217
  - features/README.md
228
218
  - features/Scope.md
229
219
  - features/Upgrade.md