spy 0.0.1
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/.gitignore +18 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +133 -0
- data/Rakefile +8 -0
- data/TODO.md +8 -0
- data/lib/spy.rb +259 -0
- data/lib/spy/double.rb +11 -0
- data/lib/spy/dsl.rb +7 -0
- data/lib/spy/version.rb +3 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/spy/and_call_original_spec.rb +152 -0
- data/spec/spy/and_yield_spec.rb +114 -0
- data/spec/spy/bug_report_10260_spec.rb +8 -0
- data/spec/spy/bug_report_10263_spec.rb +24 -0
- data/spec/spy/bug_report_496_spec.rb +18 -0
- data/spec/spy/bug_report_600_spec.rb +24 -0
- data/spec/spy/bug_report_7611_spec.rb +16 -0
- data/spec/spy/bug_report_8165_spec.rb +31 -0
- data/spec/spy/bug_report_830_spec.rb +21 -0
- data/spec/spy/bug_report_957_spec.rb +22 -0
- data/spec/spy/double_spec.rb +12 -0
- data/spec/spy/failing_argument_matchers_spec.rb +94 -0
- data/spec/spy/hash_excluding_matcher_spec.rb +67 -0
- data/spec/spy/hash_including_matcher_spec.rb +90 -0
- data/spec/spy/mock_spec.rb +734 -0
- data/spec/spy/multiple_return_value_spec.rb +119 -0
- data/spec/spy/mutate_const_spec.rb +481 -0
- data/spec/spy/nil_expectation_warning_spec.rb +56 -0
- data/spec/spy/null_object_mock_spec.rb +107 -0
- data/spec/spy/options_hash_spec.rb +35 -0
- data/spec/spy/partial_mock_spec.rb +196 -0
- data/spec/spy/passing_argument_matchers_spec.rb +142 -0
- data/spec/spy/precise_counts_spec.rb +68 -0
- data/spec/spy/serialization_spec.rb +110 -0
- data/spec/spy/stash_spec.rb +54 -0
- data/spec/spy/stub_implementation_spec.rb +62 -0
- data/spec/spy/stub_spec.rb +85 -0
- data/spec/spy/stubbed_message_expectations_spec.rb +47 -0
- data/spec/spy/test_double_spec.rb +57 -0
- data/spec/spy/to_ary_spec.rb +40 -0
- data/spy.gemspec +21 -0
- data/test/spy/test_double.rb +19 -0
- data/test/test_helper.rb +6 -0
- data/test/test_spy.rb +258 -0
- metadata +157 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
describe "a message expectation with multiple return values and no specified count" do
|
6
|
+
before(:each) do
|
7
|
+
@double = double
|
8
|
+
@return_values = [1,2,3]
|
9
|
+
@double.should_receive(:do_something).and_return(@return_values[0],@return_values[1],@return_values[2])
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns values in order" do
|
13
|
+
expect(@double.do_something).to eq @return_values[0]
|
14
|
+
expect(@double.do_something).to eq @return_values[1]
|
15
|
+
expect(@double.do_something).to eq @return_values[2]
|
16
|
+
@double.rspec_verify
|
17
|
+
end
|
18
|
+
|
19
|
+
it "falls back to a previously stubbed value" do
|
20
|
+
@double.stub :do_something => :stub_result
|
21
|
+
expect(@double.do_something).to eq @return_values[0]
|
22
|
+
expect(@double.do_something).to eq @return_values[1]
|
23
|
+
expect(@double.do_something).to eq @return_values[2]
|
24
|
+
expect(@double.do_something).to eq :stub_result
|
25
|
+
end
|
26
|
+
|
27
|
+
it "fails when there are too few calls (if there is no stub)" do
|
28
|
+
@double.do_something
|
29
|
+
@double.do_something
|
30
|
+
expect { @double.rspec_verify }.to raise_error
|
31
|
+
end
|
32
|
+
|
33
|
+
it "fails when there are too many calls (if there is no stub)" do
|
34
|
+
@double.do_something
|
35
|
+
@double.do_something
|
36
|
+
@double.do_something
|
37
|
+
@double.do_something
|
38
|
+
expect { @double.rspec_verify }.to raise_error
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "a message expectation with multiple return values with a specified count equal to the number of values" do
|
43
|
+
before(:each) do
|
44
|
+
@double = double
|
45
|
+
@return_values = [1,2,3]
|
46
|
+
@double.should_receive(:do_something).exactly(3).times.and_return(@return_values[0],@return_values[1],@return_values[2])
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns values in order to consecutive calls" do
|
50
|
+
expect(@double.do_something).to eq @return_values[0]
|
51
|
+
expect(@double.do_something).to eq @return_values[1]
|
52
|
+
expect(@double.do_something).to eq @return_values[2]
|
53
|
+
@double.rspec_verify
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "a message expectation with multiple return values specifying at_least less than the number of values" do
|
58
|
+
before(:each) do
|
59
|
+
@double = double
|
60
|
+
@double.should_receive(:do_something).at_least(:twice).with(no_args).and_return(11, 22)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "uses the last return value for subsequent calls" do
|
64
|
+
expect(@double.do_something).to equal(11)
|
65
|
+
expect(@double.do_something).to equal(22)
|
66
|
+
expect(@double.do_something).to equal(22)
|
67
|
+
@double.rspec_verify
|
68
|
+
end
|
69
|
+
|
70
|
+
it "fails when called less than the specified number" do
|
71
|
+
expect(@double.do_something).to equal(11)
|
72
|
+
expect { @double.rspec_verify }.to raise_error(RSpec::Mocks::MockExpectationError)
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when method is stubbed too" do
|
76
|
+
before { Spy.on(@double, :do_something).and_return :stub_result }
|
77
|
+
|
78
|
+
it "uses the last value for subsequent calls" do
|
79
|
+
expect(@double.do_something).to equal(11)
|
80
|
+
expect(@double.do_something).to equal(22)
|
81
|
+
expect(@double.do_something).to equal(22)
|
82
|
+
@double.rspec_verify
|
83
|
+
end
|
84
|
+
|
85
|
+
it "fails when called less than the specified number" do
|
86
|
+
expect(@double.do_something).to equal(11)
|
87
|
+
expect { @double.rspec_verify }.to raise_error(RSpec::Mocks::MockExpectationError)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "a message expectation with multiple return values with a specified count larger than the number of values" do
|
93
|
+
before(:each) do
|
94
|
+
@double = RSpec::Mocks::Mock.new("double")
|
95
|
+
@double.should_receive(:do_something).exactly(3).times.and_return(11, 22)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "uses the last return value for subsequent calls" do
|
99
|
+
expect(@double.do_something).to equal(11)
|
100
|
+
expect(@double.do_something).to equal(22)
|
101
|
+
expect(@double.do_something).to equal(22)
|
102
|
+
@double.rspec_verify
|
103
|
+
end
|
104
|
+
|
105
|
+
it "fails when called less than the specified number" do
|
106
|
+
@double.do_something
|
107
|
+
@double.do_something
|
108
|
+
expect { @double.rspec_verify }.to raise_error
|
109
|
+
end
|
110
|
+
|
111
|
+
it "fails fast when called greater than the specified number" do
|
112
|
+
@double.do_something
|
113
|
+
@double.do_something
|
114
|
+
@double.do_something
|
115
|
+
expect { @double.do_something }.to raise_error
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,481 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
TOP_LEVEL_VALUE_CONST = 7
|
4
|
+
|
5
|
+
class TestClass
|
6
|
+
M = :m
|
7
|
+
N = :n
|
8
|
+
|
9
|
+
class Nested
|
10
|
+
class NestedEvenMore
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class TestSubClass < TestClass
|
16
|
+
P = :p
|
17
|
+
end
|
18
|
+
|
19
|
+
module RSpec
|
20
|
+
module Mocks
|
21
|
+
describe "Constant Mutating", :broken do
|
22
|
+
include RSpec::Mocks::RecursiveConstMethods
|
23
|
+
|
24
|
+
def reset_rspec_mocks
|
25
|
+
::RSpec::Mocks.space.reset_all
|
26
|
+
end
|
27
|
+
|
28
|
+
shared_context "constant example methods" do |const_name|
|
29
|
+
define_method :const do
|
30
|
+
recursive_const_get(const_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
define_method :parent_const do
|
34
|
+
recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
|
35
|
+
end
|
36
|
+
|
37
|
+
define_method :last_const_part do
|
38
|
+
const_name.split('::').last
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
shared_examples_for "loaded constant stubbing" do |const_name|
|
43
|
+
include_context "constant example methods", const_name
|
44
|
+
|
45
|
+
let!(:original_const_value) { const }
|
46
|
+
after { change_const_value_to(original_const_value) }
|
47
|
+
|
48
|
+
def change_const_value_to(value)
|
49
|
+
parent_const.send(:remove_const, last_const_part)
|
50
|
+
parent_const.const_set(last_const_part, value)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'allows it to be stubbed' do
|
54
|
+
expect(const).not_to eq(7)
|
55
|
+
stub_const(const_name, 7)
|
56
|
+
expect(const).to eq(7)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'resets it to its original value when rspec clears its mocks' do
|
60
|
+
original_value = const
|
61
|
+
expect(original_value).not_to eq(:a)
|
62
|
+
stub_const(const_name, :a)
|
63
|
+
reset_rspec_mocks
|
64
|
+
expect(const).to be(original_value)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'returns the stubbed value' do
|
68
|
+
expect(stub_const(const_name, 7)).to eq(7)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
shared_examples_for "loaded constant hiding" do |const_name|
|
73
|
+
before do
|
74
|
+
expect(recursive_const_defined?(const_name)).to be_true
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'allows it to be hidden' do
|
78
|
+
hide_const(const_name)
|
79
|
+
expect(recursive_const_defined?(const_name)).to be_false
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'resets the constant when rspec clear its mocks' do
|
83
|
+
hide_const(const_name)
|
84
|
+
reset_rspec_mocks
|
85
|
+
expect(recursive_const_defined?(const_name)).to be_true
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns nil' do
|
89
|
+
expect(hide_const(const_name)).to be_nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
shared_examples_for "unloaded constant stubbing" do |const_name|
|
94
|
+
include_context "constant example methods", const_name
|
95
|
+
|
96
|
+
before do
|
97
|
+
expect(recursive_const_defined?(const_name)).to be_false
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'allows it to be stubbed' do
|
101
|
+
stub_const(const_name, 7)
|
102
|
+
expect(const).to eq(7)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'removes the constant when rspec clears its mocks' do
|
106
|
+
stub_const(const_name, 7)
|
107
|
+
reset_rspec_mocks
|
108
|
+
expect(recursive_const_defined?(const_name)).to be_false
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'returns the stubbed value' do
|
112
|
+
expect(stub_const(const_name, 7)).to eq(7)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'ignores the :transfer_nested_constants option if passed' do
|
116
|
+
stub = Module.new
|
117
|
+
stub_const(const_name, stub, :transfer_nested_constants => true)
|
118
|
+
expect(stub.constants).to eq([])
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
shared_examples_for "unloaded constant hiding" do |const_name|
|
123
|
+
include_context "constant example methods", const_name
|
124
|
+
|
125
|
+
before do
|
126
|
+
expect(recursive_const_defined?(const_name)).to be_false
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'allows it to be hidden, though the operation has no effect' do
|
130
|
+
hide_const(const_name)
|
131
|
+
expect(recursive_const_defined?(const_name)).to be_false
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'remains undefined after rspec clears its mocks' do
|
135
|
+
hide_const(const_name)
|
136
|
+
reset_rspec_mocks
|
137
|
+
expect(recursive_const_defined?(const_name)).to be_false
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'returns nil' do
|
141
|
+
expect(hide_const(const_name)).to be_nil
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "#hide_const" do
|
146
|
+
context 'for a loaded nested constant' do
|
147
|
+
it_behaves_like "loaded constant hiding", "TestClass::Nested"
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'for a loaded constant prefixed with ::' do
|
151
|
+
it_behaves_like 'loaded constant hiding', "::TestClass"
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'for an unloaded constant with nested name that matches a top-level constant' do
|
155
|
+
it_behaves_like "unloaded constant hiding", "TestClass::Hash"
|
156
|
+
|
157
|
+
it 'does not hide the top-level constant' do
|
158
|
+
top_level_hash = ::Hash
|
159
|
+
|
160
|
+
hide_const("TestClass::Hash")
|
161
|
+
expect(::Hash).to equal(top_level_hash)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'does not affect the ability to access the top-level constant from nested contexts', :silence_warnings do
|
165
|
+
top_level_hash = ::Hash
|
166
|
+
|
167
|
+
hide_const("TestClass::Hash")
|
168
|
+
expect(TestClass::Hash).to equal(top_level_hash)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'for a loaded deeply nested constant' do
|
173
|
+
it_behaves_like "loaded constant hiding", "TestClass::Nested::NestedEvenMore"
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'for an unloaded unnested constant' do
|
177
|
+
it_behaves_like "unloaded constant hiding", "X"
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'for an unloaded nested constant' do
|
181
|
+
it_behaves_like "unloaded constant hiding", "X::Y"
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'can be hidden multiple times but still restores the original value properly' do
|
185
|
+
orig_value = TestClass
|
186
|
+
hide_const("TestClass")
|
187
|
+
hide_const("TestClass")
|
188
|
+
|
189
|
+
reset_rspec_mocks
|
190
|
+
expect(TestClass).to be(orig_value)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'allows a constant to be hidden, then stubbed, restoring it to its original value properly' do
|
194
|
+
orig_value = TOP_LEVEL_VALUE_CONST
|
195
|
+
|
196
|
+
hide_const("TOP_LEVEL_VALUE_CONST")
|
197
|
+
expect(recursive_const_defined?("TOP_LEVEL_VALUE_CONST")).to be_false
|
198
|
+
|
199
|
+
stub_const("TOP_LEVEL_VALUE_CONST", 12345)
|
200
|
+
expect(TOP_LEVEL_VALUE_CONST).to eq 12345
|
201
|
+
|
202
|
+
reset_rspec_mocks
|
203
|
+
expect(TOP_LEVEL_VALUE_CONST).to eq orig_value
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "#stub_const" do
|
208
|
+
context 'for a loaded unnested constant' do
|
209
|
+
it_behaves_like "loaded constant stubbing", "TestClass"
|
210
|
+
|
211
|
+
it 'can be stubbed multiple times but still restores the original value properly' do
|
212
|
+
orig_value = TestClass
|
213
|
+
stub1, stub2 = Module.new, Module.new
|
214
|
+
stub_const("TestClass", stub1)
|
215
|
+
stub_const("TestClass", stub2)
|
216
|
+
|
217
|
+
reset_rspec_mocks
|
218
|
+
expect(TestClass).to be(orig_value)
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'allows nested constants to be transferred to a stub module' do
|
222
|
+
tc_nested = TestClass::Nested
|
223
|
+
stub = Module.new
|
224
|
+
stub_const("TestClass", stub, :transfer_nested_constants => true)
|
225
|
+
expect(stub::M).to eq(:m)
|
226
|
+
expect(stub::N).to eq(:n)
|
227
|
+
expect(stub::Nested).to be(tc_nested)
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'does not transfer nested constants that are inherited from a superclass' do
|
231
|
+
stub = Module.new
|
232
|
+
stub_const("TestSubClass", stub, :transfer_nested_constants => true)
|
233
|
+
expect(stub::P).to eq(:p)
|
234
|
+
expect(defined?(stub::M)).to be_false
|
235
|
+
expect(defined?(stub::N)).to be_false
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'raises an error when asked to transfer a nested inherited constant' do
|
239
|
+
original_tsc = TestSubClass
|
240
|
+
|
241
|
+
expect {
|
242
|
+
stub_const("TestSubClass", Module.new, :transfer_nested_constants => [:M])
|
243
|
+
}.to raise_error(ArgumentError)
|
244
|
+
|
245
|
+
expect(TestSubClass).to be(original_tsc)
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'allows nested constants to be selectively transferred to a stub module' do
|
249
|
+
stub = Module.new
|
250
|
+
stub_const("TestClass", stub, :transfer_nested_constants => [:M, :N])
|
251
|
+
expect(stub::M).to eq(:m)
|
252
|
+
expect(stub::N).to eq(:n)
|
253
|
+
expect(defined?(stub::Nested)).to be_false
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'raises an error if asked to transfer nested constants but given an object that does not support them' do
|
257
|
+
original_tc = TestClass
|
258
|
+
stub = Object.new
|
259
|
+
expect {
|
260
|
+
stub_const("TestClass", stub, :transfer_nested_constants => true)
|
261
|
+
}.to raise_error(ArgumentError)
|
262
|
+
|
263
|
+
expect(TestClass).to be(original_tc)
|
264
|
+
|
265
|
+
expect {
|
266
|
+
stub_const("TestClass", stub, :transfer_nested_constants => [:M])
|
267
|
+
}.to raise_error(ArgumentError)
|
268
|
+
|
269
|
+
expect(TestClass).to be(original_tc)
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'raises an error if asked to transfer nested constants on a constant that does not support nested constants' do
|
273
|
+
stub = Module.new
|
274
|
+
expect {
|
275
|
+
stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => true)
|
276
|
+
}.to raise_error(ArgumentError)
|
277
|
+
|
278
|
+
expect(TOP_LEVEL_VALUE_CONST).to eq(7)
|
279
|
+
|
280
|
+
expect {
|
281
|
+
stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => [:M])
|
282
|
+
}.to raise_error(ArgumentError)
|
283
|
+
|
284
|
+
expect(TOP_LEVEL_VALUE_CONST).to eq(7)
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'raises an error if asked to transfer a nested constant that is not defined' do
|
288
|
+
original_tc = TestClass
|
289
|
+
expect(defined?(TestClass::V)).to be_false
|
290
|
+
stub = Module.new
|
291
|
+
|
292
|
+
expect {
|
293
|
+
stub_const("TestClass", stub, :transfer_nested_constants => [:V])
|
294
|
+
}.to raise_error(/cannot transfer nested constant.*V/i)
|
295
|
+
|
296
|
+
expect(TestClass).to be(original_tc)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
context 'for a loaded nested constant' do
|
301
|
+
it_behaves_like "loaded constant stubbing", "TestClass::Nested"
|
302
|
+
end
|
303
|
+
|
304
|
+
context 'for a loaded constant prefixed with ::' do
|
305
|
+
it_behaves_like 'loaded constant stubbing', "::TestClass"
|
306
|
+
end
|
307
|
+
|
308
|
+
context 'for an unloaded constant prefixed with ::' do
|
309
|
+
it_behaves_like 'unloaded constant stubbing', "::SomeUndefinedConst"
|
310
|
+
end
|
311
|
+
|
312
|
+
context 'for an unloaded constant with nested name that matches a top-level constant' do
|
313
|
+
it_behaves_like "unloaded constant stubbing", "TestClass::Hash"
|
314
|
+
end
|
315
|
+
|
316
|
+
context 'for a loaded deeply nested constant' do
|
317
|
+
it_behaves_like "loaded constant stubbing", "TestClass::Nested::NestedEvenMore"
|
318
|
+
end
|
319
|
+
|
320
|
+
context 'for an unloaded unnested constant' do
|
321
|
+
it_behaves_like "unloaded constant stubbing", "X"
|
322
|
+
end
|
323
|
+
|
324
|
+
context 'for an unloaded nested constant' do
|
325
|
+
it_behaves_like "unloaded constant stubbing", "X::Y"
|
326
|
+
|
327
|
+
it 'removes the root constant when rspec clears its mocks' do
|
328
|
+
expect(defined?(X)).to be_false
|
329
|
+
stub_const("X::Y", 7)
|
330
|
+
reset_rspec_mocks
|
331
|
+
expect(defined?(X)).to be_false
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
context 'for an unloaded deeply nested constant' do
|
336
|
+
it_behaves_like "unloaded constant stubbing", "X::Y::Z"
|
337
|
+
|
338
|
+
it 'removes the root constant when rspec clears its mocks' do
|
339
|
+
expect(defined?(X)).to be_false
|
340
|
+
stub_const("X::Y::Z", 7)
|
341
|
+
reset_rspec_mocks
|
342
|
+
expect(defined?(X)).to be_false
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
context 'for an unloaded constant nested within a loaded constant' do
|
347
|
+
it_behaves_like "unloaded constant stubbing", "TestClass::X"
|
348
|
+
|
349
|
+
it 'removes the unloaded constant but leaves the loaded constant when rspec resets its mocks' do
|
350
|
+
expect(defined?(TestClass)).to be_true
|
351
|
+
expect(defined?(TestClass::X)).to be_false
|
352
|
+
stub_const("TestClass::X", 7)
|
353
|
+
reset_rspec_mocks
|
354
|
+
expect(defined?(TestClass)).to be_true
|
355
|
+
expect(defined?(TestClass::X)).to be_false
|
356
|
+
end
|
357
|
+
|
358
|
+
it 'raises a helpful error if it cannot be stubbed due to an intermediary constant that is not a module' do
|
359
|
+
expect(TestClass::M).to be_a(Symbol)
|
360
|
+
expect { stub_const("TestClass::M::X", 5) }.to raise_error(/cannot stub/i)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
context 'for an unloaded constant nested deeply within a deeply nested loaded constant' do
|
365
|
+
it_behaves_like "unloaded constant stubbing", "TestClass::Nested::NestedEvenMore::X::Y::Z"
|
366
|
+
|
367
|
+
it 'removes the first unloaded constant but leaves the loaded nested constant when rspec resets its mocks' do
|
368
|
+
expect(defined?(TestClass::Nested::NestedEvenMore)).to be_true
|
369
|
+
expect(defined?(TestClass::Nested::NestedEvenMore::X)).to be_false
|
370
|
+
stub_const("TestClass::Nested::NestedEvenMore::X::Y::Z", 7)
|
371
|
+
reset_rspec_mocks
|
372
|
+
expect(defined?(TestClass::Nested::NestedEvenMore)).to be_true
|
373
|
+
expect(defined?(TestClass::Nested::NestedEvenMore::X)).to be_false
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
describe Constant do
|
380
|
+
describe ".original" do
|
381
|
+
context 'for a previously defined unstubbed constant' do
|
382
|
+
let(:const) { Constant.original("TestClass::M") }
|
383
|
+
|
384
|
+
it("exposes its name") { expect(const.name).to eq("TestClass::M") }
|
385
|
+
it("indicates it was previously defined") { expect(const).to be_previously_defined }
|
386
|
+
it("indicates it has not been mutated") { expect(const).not_to be_mutated }
|
387
|
+
it("indicates it has not been stubbed") { expect(const).not_to be_stubbed }
|
388
|
+
it("indicates it has not been hidden") { expect(const).not_to be_hidden }
|
389
|
+
it("exposes its original value") { expect(const.original_value).to eq(:m) }
|
390
|
+
end
|
391
|
+
|
392
|
+
context 'for a previously defined stubbed constant' do
|
393
|
+
before { stub_const("TestClass::M", :other) }
|
394
|
+
let(:const) { Constant.original("TestClass::M") }
|
395
|
+
|
396
|
+
it("exposes its name") { expect(const.name).to eq("TestClass::M") }
|
397
|
+
it("indicates it was previously defined") { expect(const).to be_previously_defined }
|
398
|
+
it("indicates it has been mutated") { expect(const).to be_mutated }
|
399
|
+
it("indicates it has been stubbed") { expect(const).to be_stubbed }
|
400
|
+
it("indicates it has not been hidden") { expect(const).not_to be_hidden }
|
401
|
+
it("exposes its original value") { expect(const.original_value).to eq(:m) }
|
402
|
+
end
|
403
|
+
|
404
|
+
context 'for a previously undefined stubbed constant' do
|
405
|
+
before { stub_const("TestClass::Undefined", :other) }
|
406
|
+
let(:const) { Constant.original("TestClass::Undefined") }
|
407
|
+
|
408
|
+
it("exposes its name") { expect(const.name).to eq("TestClass::Undefined") }
|
409
|
+
it("indicates it was not previously defined") { expect(const).not_to be_previously_defined }
|
410
|
+
it("indicates it has been mutated") { expect(const).to be_mutated }
|
411
|
+
it("indicates it has been stubbed") { expect(const).to be_stubbed }
|
412
|
+
it("indicates it has not been hidden") { expect(const).not_to be_hidden }
|
413
|
+
it("returns nil for the original value") { expect(const.original_value).to be_nil }
|
414
|
+
end
|
415
|
+
|
416
|
+
context 'for a previously undefined unstubbed constant' do
|
417
|
+
let(:const) { Constant.original("TestClass::Undefined") }
|
418
|
+
|
419
|
+
it("exposes its name") { expect(const.name).to eq("TestClass::Undefined") }
|
420
|
+
it("indicates it was not previously defined") { expect(const).not_to be_previously_defined }
|
421
|
+
it("indicates it has not been mutated") { expect(const).not_to be_mutated }
|
422
|
+
it("indicates it has not been stubbed") { expect(const).not_to be_stubbed }
|
423
|
+
it("indicates it has not been hidden") { expect(const).not_to be_hidden }
|
424
|
+
it("returns nil for the original value") { expect(const.original_value).to be_nil }
|
425
|
+
end
|
426
|
+
|
427
|
+
context 'for a previously defined constant that has been stubbed twice' do
|
428
|
+
before { stub_const("TestClass::M", 1) }
|
429
|
+
before { stub_const("TestClass::M", 2) }
|
430
|
+
let(:const) { Constant.original("TestClass::M") }
|
431
|
+
|
432
|
+
it("exposes its name") { expect(const.name).to eq("TestClass::M") }
|
433
|
+
it("indicates it was previously defined") { expect(const).to be_previously_defined }
|
434
|
+
it("indicates it has been mutated") { expect(const).to be_mutated }
|
435
|
+
it("indicates it has been stubbed") { expect(const).to be_stubbed }
|
436
|
+
it("indicates it has not been hidden") { expect(const).not_to be_hidden }
|
437
|
+
it("exposes its original value") { expect(const.original_value).to eq(:m) }
|
438
|
+
end
|
439
|
+
|
440
|
+
context 'for a previously undefined constant that has been stubbed twice' do
|
441
|
+
before { stub_const("TestClass::Undefined", 1) }
|
442
|
+
before { stub_const("TestClass::Undefined", 2) }
|
443
|
+
let(:const) { Constant.original("TestClass::Undefined") }
|
444
|
+
|
445
|
+
it("exposes its name") { expect(const.name).to eq("TestClass::Undefined") }
|
446
|
+
it("indicates it was not previously defined") { expect(const).not_to be_previously_defined }
|
447
|
+
it("indicates it has been mutated") { expect(const).to be_mutated }
|
448
|
+
it("indicates it has been stubbed") { expect(const).to be_stubbed }
|
449
|
+
it("indicates it has not been hidden") { expect(const).not_to be_hidden }
|
450
|
+
it("returns nil for the original value") { expect(const.original_value).to be_nil }
|
451
|
+
end
|
452
|
+
|
453
|
+
context 'for a previously defined hidden constant' do
|
454
|
+
before { hide_const("TestClass::M") }
|
455
|
+
let(:const) { Constant.original("TestClass::M") }
|
456
|
+
|
457
|
+
it("exposes its name") { expect(const.name).to eq("TestClass::M") }
|
458
|
+
it("indicates it was previously defined") { expect(const).to be_previously_defined }
|
459
|
+
it("indicates it has been mutated") { expect(const).to be_mutated }
|
460
|
+
it("indicates it has not been stubbed") { expect(const).not_to be_stubbed }
|
461
|
+
it("indicates it has been hidden") { expect(const).to be_hidden }
|
462
|
+
it("exposes its original value") { expect(const.original_value).to eq(:m) }
|
463
|
+
end
|
464
|
+
|
465
|
+
context 'for a previously defined constant that has been hidden twice' do
|
466
|
+
before { hide_const("TestClass::M") }
|
467
|
+
before { hide_const("TestClass::M") }
|
468
|
+
let(:const) { Constant.original("TestClass::M") }
|
469
|
+
|
470
|
+
it("exposes its name") { expect(const.name).to eq("TestClass::M") }
|
471
|
+
it("indicates it was previously defined") { expect(const).to be_previously_defined }
|
472
|
+
it("indicates it has been mutated") { expect(const).to be_mutated }
|
473
|
+
it("indicates it has not been stubbed") { expect(const).not_to be_stubbed }
|
474
|
+
it("indicates it has been hidden") { expect(const).to be_hidden }
|
475
|
+
it("exposes its original value") { expect(const.original_value).to eq(:m) }
|
476
|
+
end
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|