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.
- data/Changelog.md +25 -0
- data/features/message_expectations/allow_any_instance_of.feature +26 -0
- data/features/message_expectations/expect_any_instance_of.feature +27 -0
- data/features/message_expectations/expect_message_using_expect.feature +4 -0
- data/features/method_stubs/README.md +28 -2
- data/features/method_stubs/any_instance.feature +5 -1
- data/features/method_stubs/as_null_object.feature +6 -1
- data/features/method_stubs/simple_return_value_with_allow.feature +44 -0
- data/features/method_stubs/{simple_return_value.feature → simple_return_value_with_stub.feature} +0 -0
- data/features/method_stubs/stub_implementation.feature +23 -1
- data/lib/rspec/mocks.rb +35 -0
- data/lib/rspec/mocks/any_instance/chain.rb +27 -18
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +1 -28
- data/lib/rspec/mocks/any_instance/recorder.rb +1 -2
- data/lib/rspec/mocks/any_instance/stub_chain.rb +2 -1
- data/lib/rspec/mocks/error_generator.rb +7 -0
- data/lib/rspec/mocks/extensions/marshal.rb +7 -7
- data/lib/rspec/mocks/matchers/receive.rb +5 -1
- data/lib/rspec/mocks/message_expectation.rb +142 -63
- data/lib/rspec/mocks/method_double.rb +0 -9
- data/lib/rspec/mocks/proxy.rb +0 -5
- data/lib/rspec/mocks/proxy_for_nil.rb +2 -1
- data/lib/rspec/mocks/syntax.rb +15 -5
- data/lib/rspec/mocks/test_double.rb +2 -2
- data/lib/rspec/mocks/version.rb +1 -1
- data/spec/rspec/mocks/any_instance_spec.rb +26 -0
- data/spec/rspec/mocks/block_return_value_spec.rb +18 -0
- data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +205 -0
- data/spec/rspec/mocks/extensions/marshal_spec.rb +54 -0
- data/spec/rspec/mocks/matchers/receive_spec.rb +10 -0
- data/spec/rspec/mocks/mock_spec.rb +31 -3
- data/spec/rspec/mocks/partial_mock_spec.rb +3 -3
- data/spec/rspec/mocks/syntax_agnostic_message_matchers_spec.rb +81 -0
- data/spec/rspec/mocks/test_double_spec.rb +16 -6
- metadata +24 -9
data/lib/rspec/mocks/proxy.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/rspec/mocks/syntax.rb
CHANGED
@@ -12,20 +12,21 @@ module RSpec
|
|
12
12
|
|
13
13
|
syntax_host.class_eval do
|
14
14
|
def should_receive(message, opts={}, &block)
|
15
|
-
|
16
|
-
|
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
|
-
|
21
|
-
|
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
|
-
|
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
|
-
|
113
|
+
Mocks.allow_message(self, message).and_return(response)
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
data/lib/rspec/mocks/version.rb
CHANGED
@@ -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
|