rspec-mocks 2.14.0.rc1 → 2.14.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.
Files changed (35) hide show
  1. data/Changelog.md +25 -0
  2. data/features/message_expectations/allow_any_instance_of.feature +26 -0
  3. data/features/message_expectations/expect_any_instance_of.feature +27 -0
  4. data/features/message_expectations/expect_message_using_expect.feature +4 -0
  5. data/features/method_stubs/README.md +28 -2
  6. data/features/method_stubs/any_instance.feature +5 -1
  7. data/features/method_stubs/as_null_object.feature +6 -1
  8. data/features/method_stubs/simple_return_value_with_allow.feature +44 -0
  9. data/features/method_stubs/{simple_return_value.feature → simple_return_value_with_stub.feature} +0 -0
  10. data/features/method_stubs/stub_implementation.feature +23 -1
  11. data/lib/rspec/mocks.rb +35 -0
  12. data/lib/rspec/mocks/any_instance/chain.rb +27 -18
  13. data/lib/rspec/mocks/any_instance/expectation_chain.rb +1 -28
  14. data/lib/rspec/mocks/any_instance/recorder.rb +1 -2
  15. data/lib/rspec/mocks/any_instance/stub_chain.rb +2 -1
  16. data/lib/rspec/mocks/error_generator.rb +7 -0
  17. data/lib/rspec/mocks/extensions/marshal.rb +7 -7
  18. data/lib/rspec/mocks/matchers/receive.rb +5 -1
  19. data/lib/rspec/mocks/message_expectation.rb +142 -63
  20. data/lib/rspec/mocks/method_double.rb +0 -9
  21. data/lib/rspec/mocks/proxy.rb +0 -5
  22. data/lib/rspec/mocks/proxy_for_nil.rb +2 -1
  23. data/lib/rspec/mocks/syntax.rb +15 -5
  24. data/lib/rspec/mocks/test_double.rb +2 -2
  25. data/lib/rspec/mocks/version.rb +1 -1
  26. data/spec/rspec/mocks/any_instance_spec.rb +26 -0
  27. data/spec/rspec/mocks/block_return_value_spec.rb +18 -0
  28. data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +205 -0
  29. data/spec/rspec/mocks/extensions/marshal_spec.rb +54 -0
  30. data/spec/rspec/mocks/matchers/receive_spec.rb +10 -0
  31. data/spec/rspec/mocks/mock_spec.rb +31 -3
  32. data/spec/rspec/mocks/partial_mock_spec.rb +3 -3
  33. data/spec/rspec/mocks/syntax_agnostic_message_matchers_spec.rb +81 -0
  34. data/spec/rspec/mocks/test_double_spec.rb +16 -6
  35. metadata +24 -9
@@ -51,11 +51,6 @@ module RSpec
51
51
  meth_double.add_expectation @error_generator, @expectation_ordering, location, opts, &block
52
52
  end
53
53
 
54
- # @private
55
- def add_negative_message_expectation(location, method_name, &implementation)
56
- method_double[method_name].add_negative_expectation @error_generator, @expectation_ordering, location, &implementation
57
- end
58
-
59
54
  # @private
60
55
  def build_expectation(method_name)
61
56
  meth_double = method_double[method_name]
@@ -28,7 +28,8 @@ module RSpec
28
28
  private
29
29
 
30
30
  def warn method_name
31
- Kernel.warn("An expectation of :#{method_name} was set on nil. Called from #{caller[2]}. Use allow_message_expectations_on_nil to disable warnings.")
31
+ non_rspec_caller = caller.find { |line| !line.include?('lib/rspec/mocks') }
32
+ Kernel.warn("An expectation of :#{method_name} was set on nil. Called from #{non_rspec_caller}. Use allow_message_expectations_on_nil to disable warnings.")
32
33
  end
33
34
 
34
35
  end
@@ -12,20 +12,21 @@ module RSpec
12
12
 
13
13
  syntax_host.class_eval do
14
14
  def should_receive(message, opts={}, &block)
15
- proxy = ::RSpec::Mocks.proxy_for(self)
16
- proxy.add_message_expectation(opts[:expected_from] || caller(1)[0], message.to_sym, opts, &block)
15
+ opts[:expected_from] ||= caller(1)[0]
16
+ ::RSpec::Mocks.expect_message(self, message.to_sym, opts, &block)
17
17
  end
18
18
 
19
19
  def should_not_receive(message, &block)
20
- proxy = ::RSpec::Mocks.proxy_for(self)
21
- proxy.add_negative_message_expectation(caller(1)[0], message.to_sym, &block)
20
+ opts = {:expected_from => caller(1)[0]}
21
+ ::RSpec::Mocks.expect_message(self, message.to_sym, opts, &block).never
22
22
  end
23
23
 
24
24
  def stub(message_or_hash, opts={}, &block)
25
25
  if ::Hash === message_or_hash
26
26
  message_or_hash.each {|message, value| stub(message).and_return value }
27
27
  else
28
- ::RSpec::Mocks.proxy_for(self).add_stub(caller(1)[0], message_or_hash.to_sym, opts, &block)
28
+ opts[:expected_from] = caller(1)[0]
29
+ ::RSpec::Mocks.allow_message(self, message_or_hash, opts, &block)
29
30
  end
30
31
  end
31
32
 
@@ -155,6 +156,15 @@ module RSpec
155
156
  # @api private
156
157
  # Determines where the methods like `should_receive`, and `stub` are added.
157
158
  def self.default_should_syntax_host
159
+ # JRuby 1.7.4 introduces a regression whereby `defined?(::BasicObject) => nil`
160
+ # yet `BasicObject` still exists and patching onto ::Object breaks things
161
+ # e.g. SimpleDelegator expectations won't work
162
+ #
163
+ # See: https://github.com/jruby/jruby/issues/814
164
+ if defined?(JRUBY_VERSION) && JRUBY_VERSION == '1.7.4' && RUBY_VERSION.to_f > 1.8
165
+ return ::BasicObject
166
+ end
167
+
158
168
  # On 1.8.7, Object.ancestors.last == Kernel but
159
169
  # things blow up if we include `RSpec::Mocks::Methods`
160
170
  # into Kernel...not sure why.
@@ -62,7 +62,7 @@ module RSpec
62
62
 
63
63
  # @private
64
64
  def __build_mock_proxy
65
- Proxy.new(self, @name, @options)
65
+ Proxy.new(self, @name, @options || {})
66
66
  end
67
67
 
68
68
  private
@@ -110,7 +110,7 @@ module RSpec
110
110
 
111
111
  def assign_stubs(stubs)
112
112
  stubs.each_pair do |message, response|
113
- stub(message).and_return(response)
113
+ Mocks.allow_message(self, message).and_return(response)
114
114
  end
115
115
  end
116
116
 
@@ -1,7 +1,7 @@
1
1
  module RSpec
2
2
  module Mocks
3
3
  module Version
4
- STRING = '2.14.0.rc1'
4
+ STRING = '2.14.0'
5
5
  end
6
6
  end
7
7
  end
@@ -181,6 +181,26 @@ module RSpec
181
181
  end
182
182
  end
183
183
 
184
+ context 'with #and_call_original and competing #with' do
185
+ let(:klass) { Struct.new(:a_method) }
186
+
187
+ it 'can combine and_call_original, with, and_return' do
188
+ allow_any_instance_of(klass).to receive(:a_method).and_call_original
189
+ allow_any_instance_of(klass).to receive(:a_method).with(:arg).and_return('value')
190
+
191
+ expect(klass.new('org').a_method).to eq 'org'
192
+ expect(klass.new.a_method(:arg)).to eq 'value'
193
+ end
194
+
195
+ it 'can combine and_call_original, with, and_return (old syntax)' do
196
+ klass.any_instance.stub(:a_method).and_call_original
197
+ klass.any_instance.stub(:a_method).with(:arg).and_return('value')
198
+
199
+ expect(klass.new('org').a_method).to eq 'org'
200
+ expect(klass.new.a_method(:arg)).to eq 'value'
201
+ end
202
+ end
203
+
184
204
  context "with #and_raise" do
185
205
  it "stubs a method that doesn't exist" do
186
206
  klass.any_instance.stub(:foo).and_raise(CustomErrorForAnyInstanceSpec)
@@ -327,6 +347,12 @@ module RSpec
327
347
  RSpec::Mocks.space.verify_all
328
348
  end
329
349
  end
350
+
351
+ it "prevents confusing double-negative expressions involving `never`" do
352
+ expect {
353
+ klass.any_instance.should_not_receive(:not_expected).never
354
+ }.to raise_error(/trying to negate it again/)
355
+ end
330
356
  end
331
357
 
332
358
  context "with #should_receive" do
@@ -23,6 +23,12 @@ describe "a double declaration with a block handed to:" do
23
23
  obj.stub(:foo) { 'bar' }
24
24
  expect(obj.foo).to eq('bar')
25
25
  end
26
+
27
+ it "does not complain if a lambda block and mismatched arguments are passed" do
28
+ obj = Object.new
29
+ obj.stub(:foo, &lambda { 'bar' })
30
+ expect(obj.foo(1, 2)).to eq('bar')
31
+ end
26
32
  end
27
33
 
28
34
  describe "with" do
@@ -31,6 +37,12 @@ describe "a double declaration with a block handed to:" do
31
37
  obj.stub(:foo).with('baz') { 'bar' }
32
38
  expect(obj.foo('baz')).to eq('bar')
33
39
  end
40
+
41
+ it "does not complain if a lambda block and mismatched arguments are passed" do
42
+ obj = Object.new
43
+ obj.stub(:foo).with(1, 2, &lambda { 'bar' })
44
+ expect(obj.foo(1, 2)).to eq('bar')
45
+ end
34
46
  end
35
47
 
36
48
  %w[once twice ordered and_return].each do |method|
@@ -40,6 +52,12 @@ describe "a double declaration with a block handed to:" do
40
52
  obj.stub(:foo).send(method) { 'bar' }
41
53
  expect(obj.foo).to eq('bar')
42
54
  end
55
+
56
+ it "does not complain if a lambda block and mismatched arguments are passed" do
57
+ obj = Object.new
58
+ obj.stub(:foo).send(method, &lambda { 'bar' })
59
+ expect(obj.foo(1, 2)).to eq('bar')
60
+ end
43
61
  end
44
62
  end
45
63
 
@@ -0,0 +1,205 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ describe "Combining implementation instructions" do
6
+ it 'can combine and_yield and and_return' do
7
+ dbl = double
8
+ dbl.stub(:foo).and_yield(5).and_return(3)
9
+
10
+ expect { |b|
11
+ expect(dbl.foo(&b)).to eq(3)
12
+ }.to yield_with_args(5)
13
+ end
14
+
15
+ describe "combining and_yield, a block implementation and and_return" do
16
+ def verify_combined_implementation
17
+ dbl = double
18
+ (yield dbl).and_yield(5).and_return(3)
19
+
20
+ expect { |b|
21
+ expect(dbl.foo(:arg, &b)).to eq(3)
22
+ }.to yield_with_args(5)
23
+
24
+ expect(@block_called).to be_true
25
+ end
26
+
27
+ it 'works when passing a block to `stub`' do
28
+ verify_combined_implementation do |dbl|
29
+ dbl.stub(:foo) { @block_called = true }
30
+ end
31
+ end
32
+
33
+ it 'works when passing a block to `with`' do
34
+ verify_combined_implementation do |dbl|
35
+ dbl.stub(:foo).with(:arg) { @block_called = true }
36
+ end
37
+ end
38
+
39
+ it 'works when passing a block to `exactly`' do
40
+ verify_combined_implementation do |dbl|
41
+ dbl.should_receive(:foo).exactly(:once) { @block_called = true }
42
+ end
43
+ end
44
+
45
+ it 'works when passing a block to `at_least`' do
46
+ verify_combined_implementation do |dbl|
47
+ dbl.should_receive(:foo).at_least(:once) { @block_called = true }
48
+ end
49
+ end
50
+
51
+ it 'works when passing a block to `at_most`' do
52
+ verify_combined_implementation do |dbl|
53
+ dbl.should_receive(:foo).at_most(:once) { @block_called = true }
54
+ end
55
+ end
56
+
57
+ it 'works when passing a block to `times`' do
58
+ verify_combined_implementation do |dbl|
59
+ dbl.should_receive(:foo).exactly(1).times { @block_called = true }
60
+ end
61
+ end
62
+
63
+ it 'works when passing a block to `any_number_of_times`' do
64
+ verify_combined_implementation do |dbl|
65
+ dbl.should_receive(:foo).any_number_of_times { @block_called = true }
66
+ end
67
+ end
68
+
69
+ it 'works when passing a block to `once`' do
70
+ verify_combined_implementation do |dbl|
71
+ dbl.should_receive(:foo).once { @block_called = true }
72
+ end
73
+ end
74
+
75
+ it 'works when passing a block to `twice`' do
76
+ the_double = nil
77
+
78
+ verify_combined_implementation do |dbl|
79
+ the_double = dbl
80
+ dbl.should_receive(:foo).twice { @block_called = true }
81
+ end
82
+
83
+ the_double.foo { |a| } # to ensure it is called twice
84
+ end
85
+
86
+ it 'works when passing a block to `ordered`' do
87
+ verify_combined_implementation do |dbl|
88
+ dbl.should_receive(:foo).ordered { @block_called = true }
89
+ end
90
+ end
91
+ end
92
+
93
+ it 'can combine and_yield and and_return with a block' do
94
+ dbl = double
95
+ dbl.stub(:foo).and_yield(5).and_return { :return }
96
+
97
+ expect { |b|
98
+ expect(dbl.foo(&b)).to eq(:return)
99
+ }.to yield_with_args(5)
100
+ end
101
+
102
+ it 'can combine and_yield and and_raise' do
103
+ dbl = double
104
+ dbl.stub(:foo).and_yield(5).and_raise("boom")
105
+
106
+ expect { |b|
107
+ expect { dbl.foo(&b) }.to raise_error("boom")
108
+ }.to yield_with_args(5)
109
+ end
110
+
111
+ it 'can combine and_yield, a block implementation and and_raise' do
112
+ dbl = double
113
+ block_called = false
114
+ dbl.stub(:foo) { block_called = true }.and_yield(5).and_raise("boom")
115
+
116
+ expect { |b|
117
+ expect { dbl.foo(&b) }.to raise_error("boom")
118
+ }.to yield_with_args(5)
119
+
120
+ expect(block_called).to be_true
121
+ end
122
+
123
+ it 'can combine and_yield and and_throw' do
124
+ dbl = double
125
+ dbl.stub(:foo).and_yield(5).and_throw(:bar)
126
+
127
+ expect { |b|
128
+ expect { dbl.foo(&b) }.to throw_symbol(:bar)
129
+ }.to yield_with_args(5)
130
+ end
131
+
132
+ it 'can combine and_yield, a block implementation and and_throw' do
133
+ dbl = double
134
+ block_called = false
135
+ dbl.stub(:foo) { block_called = true }.and_yield(5).and_throw(:bar)
136
+
137
+ expect { |b|
138
+ expect { dbl.foo(&b) }.to throw_symbol(:bar)
139
+ }.to yield_with_args(5)
140
+
141
+ expect(block_called).to be_true
142
+ end
143
+
144
+ it 'returns `nil` from all terminal actions to discourage further configuration' do
145
+ expect(double.stub(:foo).and_return(1)).to be_nil
146
+ expect(double.stub(:foo).and_raise("boom")).to be_nil
147
+ expect(double.stub(:foo).and_throw(:foo)).to be_nil
148
+ end
149
+
150
+ it 'allows the terminal action to be overriden' do
151
+ dbl = double
152
+ stubbed_double = dbl.stub(:foo)
153
+
154
+ stubbed_double.and_return(1)
155
+ expect(dbl.foo).to eq(1)
156
+
157
+ stubbed_double.and_return(3)
158
+ expect(dbl.foo).to eq(3)
159
+
160
+ stubbed_double.and_raise("boom")
161
+ expect { dbl.foo }.to raise_error("boom")
162
+
163
+ stubbed_double.and_throw(:bar)
164
+ expect { dbl.foo }.to throw_symbol(:bar)
165
+ end
166
+
167
+ it 'allows the inner implementation block to be overriden' do
168
+ dbl = double
169
+ stubbed_double = dbl.stub(:foo)
170
+
171
+ stubbed_double.with(:arg) { :with_block }
172
+ expect(dbl.foo(:arg)).to eq(:with_block)
173
+
174
+ stubbed_double.at_least(:once) { :at_least_block }
175
+ expect(dbl.foo(:arg)).to eq(:at_least_block)
176
+ end
177
+
178
+ it 'can combine and_call_original, with, and_return' do
179
+ obj = Struct.new(:value).new('original')
180
+ obj.stub(:value).and_call_original
181
+ obj.stub(:value).with(:arg).and_return('value')
182
+ expect(obj.value).to eq 'original'
183
+ expect(obj.value(:arg)).to eq 'value'
184
+ end
185
+
186
+ it 'raises an error if `and_call_original` is followed by any other instructions' do
187
+ dbl = [1, 2, 3]
188
+ stubbed = dbl.stub(:size)
189
+ stubbed.and_call_original
190
+
191
+ msg_fragment = /cannot be modified further/
192
+
193
+ expect { stubbed.and_yield }.to raise_error(msg_fragment)
194
+ expect { stubbed.and_return(1) }.to raise_error(msg_fragment)
195
+ expect { stubbed.and_raise("a") }.to raise_error(msg_fragment)
196
+ expect { stubbed.and_throw(:bar) }.to raise_error(msg_fragment)
197
+
198
+ expect { stubbed.once { } }.to raise_error(msg_fragment)
199
+
200
+ expect(dbl.size).to eq(3)
201
+ end
202
+ end
203
+ end
204
+ end
205
+
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Marshal, 'extensions' do
4
+ # An object that raises when code attempts to dup it.
5
+ #
6
+ # Because we manipulate the internals of RSpec::Mocks.space below, we need
7
+ # an object that simply blows up when #dup is called without using any
8
+ # partial mocking or stubbing from rspec-mocks itself.
9
+ class UndupableObject
10
+ def dup
11
+ raise NotImplementedError
12
+ end
13
+ end
14
+
15
+ describe '#dump' do
16
+ context 'when rspec-mocks has not been fully initialized' do
17
+ def without_space
18
+ stashed_space, RSpec::Mocks.space = RSpec::Mocks.space, nil
19
+ yield
20
+ ensure
21
+ RSpec::Mocks.space = stashed_space
22
+ end
23
+
24
+ it 'does not duplicate the object before serialization' do
25
+ obj = UndupableObject.new
26
+ without_space do
27
+ serialized = Marshal.dump(obj)
28
+ expect(Marshal.load(serialized)).to be_an(UndupableObject)
29
+ end
30
+ end
31
+ end
32
+
33
+ context 'when rspec-mocks has been fully initialized' do
34
+ it 'duplicates objects with stubbed or mocked implementations before serialization' do
35
+ obj = double(:foo => "bar")
36
+
37
+ serialized = Marshal.dump(obj)
38
+ expect(Marshal.load(serialized)).to be_an(obj.class)
39
+ end
40
+
41
+ it 'does not duplicate other objects before serialization' do
42
+ obj = UndupableObject.new
43
+
44
+ serialized = Marshal.dump(obj)
45
+ expect(Marshal.load(serialized)).to be_an(UndupableObject)
46
+ end
47
+
48
+ it 'does not duplicate nil before serialization' do
49
+ serialized = Marshal.dump(nil)
50
+ expect(Marshal.load(serialized)).to be_nil
51
+ end
52
+ end
53
+ end
54
+ end
@@ -136,6 +136,16 @@ module RSpec
136
136
  receiver.foo(:a)
137
137
  }.to raise_error(/expected: 0 times.*received: 1 time/m)
138
138
  end
139
+
140
+ it 'prevents confusing double-negative expressions involving `never`' do
141
+ expect {
142
+ wrapped.not_to receive(:foo).never
143
+ }.to raise_error(/trying to negate it again/)
144
+
145
+ expect {
146
+ wrapped.to_not receive(:foo).never
147
+ }.to raise_error(/trying to negate it again/)
148
+ end
139
149
  end
140
150
 
141
151
  describe "allow(...).to receive" do