rspec-mocks 2.12.2 → 2.13.0

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,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