spy 1.0.1 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,471 +0,0 @@
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 Spy
20
- describe "Constant Mutating" do
21
-
22
- def reset_rspec_mocks
23
- Spy.teardown
24
- end
25
-
26
- def on_const(const_name)
27
- if const_name.include? "::"
28
- args = [recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, '')), const_name.split('::').last.to_sym]
29
- else
30
- args = [const_name.to_sym]
31
- end
32
- Spy.get_const(*args) || Spy.on_const(*args)
33
- end
34
-
35
- def stub_const(const_name, value)
36
- on_const(const_name).and_return(value)
37
- value
38
- end
39
-
40
- def hide_const(const_name)
41
- on_const(const_name).and_hide
42
- end
43
-
44
- shared_context "constant example methods" do |const_name|
45
- define_method :const do
46
- recursive_const_get(const_name)
47
- end
48
-
49
- define_method :parent_const do
50
- recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
51
- end
52
-
53
- define_method :last_const_part do
54
- const_name.split('::').last
55
- end
56
- end
57
-
58
- shared_examples_for "loaded constant stubbing" do |const_name|
59
- include_context "constant example methods", const_name
60
-
61
- let!(:original_const_value) { const }
62
- after { change_const_value_to(original_const_value) }
63
-
64
- def change_const_value_to(value)
65
- parent_const.send(:remove_const, last_const_part)
66
- parent_const.const_set(last_const_part, value)
67
- end
68
-
69
- it 'allows it to be stubbed' do
70
- expect(const).not_to eq(7)
71
- stub_const(const_name, 7)
72
- expect(const).to eq(7)
73
- end
74
-
75
- it 'resets it to its original value when rspec clears its mocks' do
76
- original_value = const
77
- expect(original_value).not_to eq(:a)
78
- stub_const(const_name, :a)
79
- reset_rspec_mocks
80
- expect(const).to be(original_value)
81
- end
82
-
83
- it 'returns the stubbed value' do
84
- expect(stub_const(const_name, 7)).to eq(7)
85
- end
86
- end
87
-
88
- shared_examples_for "loaded constant hiding" do |const_name|
89
- before do
90
- expect(recursive_const_defined?(const_name)).to be_true
91
- end
92
-
93
- it 'allows it to be hidden' do
94
- hide_const(const_name)
95
- expect(recursive_const_defined?(const_name)).to be_false
96
- end
97
-
98
- it 'resets the constant when rspec clear its mocks' do
99
- hide_const(const_name)
100
- reset_rspec_mocks
101
- expect(recursive_const_defined?(const_name)).to be_true
102
- end
103
-
104
- it 'returns nil' do
105
- expect(hide_const(const_name)).to be_nil
106
- end
107
- end
108
-
109
- shared_examples_for "unloaded constant stubbing" do |const_name|
110
- include_context "constant example methods", const_name
111
-
112
- before do
113
- expect(recursive_const_defined?(const_name)).to be_false
114
- end
115
-
116
- it 'allows it to be stubbed' do
117
- stub_const(const_name, 7)
118
- expect(const).to eq(7)
119
- end
120
-
121
- it 'removes the constant when rspec clears its mocks' do
122
- stub_const(const_name, 7)
123
- reset_rspec_mocks
124
- expect(recursive_const_defined?(const_name)).to be_false
125
- end
126
-
127
- it 'returns the stubbed value' do
128
- expect(stub_const(const_name, 7)).to eq(7)
129
- end
130
-
131
- it 'ignores the :transfer_nested_constants option if passed' do
132
- stub = Module.new
133
- stub_const(const_name, stub, :transfer_nested_constants => true)
134
- expect(stub.constants).to eq([])
135
- end
136
- end
137
-
138
- shared_examples_for "unloaded constant hiding" do |const_name|
139
- include_context "constant example methods", const_name
140
-
141
- before do
142
- expect(recursive_const_defined?(const_name)).to be_false
143
- end
144
-
145
- it 'allows it to be hidden, though the operation has no effect' do
146
- hide_const(const_name)
147
- expect(recursive_const_defined?(const_name)).to be_false
148
- end
149
-
150
- it 'remains undefined after rspec clears its mocks' do
151
- hide_const(const_name)
152
- reset_rspec_mocks
153
- expect(recursive_const_defined?(const_name)).to be_false
154
- end
155
-
156
- it 'returns nil' do
157
- expect(hide_const(const_name)).to be_nil
158
- end
159
- end
160
-
161
- describe "#hide_const" do
162
- context 'for a loaded nested constant' do
163
- it_behaves_like "loaded constant hiding", "TestClass::Nested"
164
- end
165
-
166
- context 'for a loaded constant prefixed with ::' do
167
- it_behaves_like 'loaded constant hiding', "::TestClass"
168
- end
169
-
170
- context 'for an unloaded constant with nested name that matches a top-level constant' do
171
- it_behaves_like "unloaded constant hiding", "TestClass::Hash"
172
-
173
- it 'does not hide the top-level constant' do
174
- expect {
175
- hide_const("TestClass::Hash")
176
- }.to raise_error
177
- end
178
- end
179
-
180
- context 'for a loaded deeply nested constant' do
181
- it_behaves_like "loaded constant hiding", "TestClass::Nested::NestedEvenMore"
182
- end
183
-
184
- context 'for an unloaded unnested constant' do
185
- it_behaves_like "unloaded constant hiding", "X"
186
- end
187
-
188
- context 'for an unloaded nested constant' do
189
- it_behaves_like "unloaded constant hiding", "X::Y"
190
- end
191
-
192
- it 'can be hidden multiple times but still restores the original value properly' do
193
- orig_value = TestClass
194
- hide_const("TestClass")
195
- hide_const("TestClass")
196
-
197
- reset_rspec_mocks
198
- expect(TestClass).to be(orig_value)
199
- end
200
-
201
- it 'allows a constant to be hidden, then stubbed, restoring it to its original value properly' do
202
- orig_value = TOP_LEVEL_VALUE_CONST
203
-
204
- hide_const("TOP_LEVEL_VALUE_CONST")
205
- expect(recursive_const_defined?("TOP_LEVEL_VALUE_CONST")).to be_false
206
-
207
- stub_const("TOP_LEVEL_VALUE_CONST", 12345)
208
- expect(TOP_LEVEL_VALUE_CONST).to eq 12345
209
-
210
- reset_rspec_mocks
211
- expect(TOP_LEVEL_VALUE_CONST).to eq orig_value
212
- end
213
- end
214
-
215
- describe "#stub_const" do
216
- context 'for a loaded unnested constant' do
217
- it_behaves_like "loaded constant stubbing", "TestClass"
218
-
219
- it 'can be stubbed multiple times but still restores the original value properly' do
220
- orig_value = TestClass
221
- stub1, stub2 = Module.new, Module.new
222
- stub_const("TestClass", stub1)
223
- stub_const("TestClass", stub2)
224
-
225
- reset_rspec_mocks
226
- expect(TestClass).to be(orig_value)
227
- end
228
-
229
- it 'allows nested constants to be transferred to a stub module' do
230
- tc_nested = TestClass::Nested
231
- stub = Module.new
232
- stub_const("TestClass", stub, :transfer_nested_constants => true)
233
- expect(stub::M).to eq(:m)
234
- expect(stub::N).to eq(:n)
235
- expect(stub::Nested).to be(tc_nested)
236
- end
237
-
238
- it 'does not transfer nested constants that are inherited from a superclass' do
239
- stub = Module.new
240
- stub_const("TestSubClass", stub, :transfer_nested_constants => true)
241
- expect(stub::P).to eq(:p)
242
- expect(defined?(stub::M)).to be_false
243
- expect(defined?(stub::N)).to be_false
244
- end
245
-
246
- it 'raises an error when asked to transfer a nested inherited constant' do
247
- original_tsc = TestSubClass
248
-
249
- expect {
250
- stub_const("TestSubClass", Module.new, :transfer_nested_constants => [:M])
251
- }.to raise_error(ArgumentError)
252
-
253
- expect(TestSubClass).to be(original_tsc)
254
- end
255
-
256
- it 'allows nested constants to be selectively transferred to a stub module' do
257
- stub = Module.new
258
- stub_const("TestClass", stub, :transfer_nested_constants => [:M, :N])
259
- expect(stub::M).to eq(:m)
260
- expect(stub::N).to eq(:n)
261
- expect(defined?(stub::Nested)).to be_false
262
- end
263
-
264
- it 'raises an error if asked to transfer nested constants but given an object that does not support them' do
265
- original_tc = TestClass
266
- stub = Object.new
267
- expect {
268
- stub_const("TestClass", stub, :transfer_nested_constants => true)
269
- }.to raise_error(ArgumentError)
270
-
271
- expect(TestClass).to be(original_tc)
272
-
273
- expect {
274
- stub_const("TestClass", stub, :transfer_nested_constants => [:M])
275
- }.to raise_error(ArgumentError)
276
-
277
- expect(TestClass).to be(original_tc)
278
- end
279
-
280
- it 'raises an error if asked to transfer nested constants on a constant that does not support nested constants' do
281
- stub = Module.new
282
- expect {
283
- stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => true)
284
- }.to raise_error(ArgumentError)
285
-
286
- expect(TOP_LEVEL_VALUE_CONST).to eq(7)
287
-
288
- expect {
289
- stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => [:M])
290
- }.to raise_error(ArgumentError)
291
-
292
- expect(TOP_LEVEL_VALUE_CONST).to eq(7)
293
- end
294
-
295
- it 'raises an error if asked to transfer a nested constant that is not defined' do
296
- original_tc = TestClass
297
- expect(defined?(TestClass::V)).to be_false
298
- stub = Module.new
299
-
300
- expect {
301
- stub_const("TestClass", stub, :transfer_nested_constants => [:V])
302
- }.to raise_error(/cannot transfer nested constant.*V/i)
303
-
304
- expect(TestClass).to be(original_tc)
305
- end
306
- end
307
-
308
- context 'for a loaded nested constant' do
309
- it_behaves_like "loaded constant stubbing", "TestClass::Nested"
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 constant nested within a loaded constant' do
325
- it_behaves_like "unloaded constant stubbing", "TestClass::X"
326
-
327
- it 'removes the unloaded constant but leaves the loaded constant when rspec resets its mocks' do
328
- expect(defined?(TestClass)).to be_true
329
- expect(defined?(TestClass::X)).to be_false
330
- stub_const("TestClass::X", 7)
331
- reset_rspec_mocks
332
- expect(defined?(TestClass)).to be_true
333
- expect(defined?(TestClass::X)).to be_false
334
- end
335
-
336
- it 'raises a helpful error if it cannot be stubbed due to an intermediary constant that is not a module' do
337
- expect(TestClass::M).to be_a(Symbol)
338
- expect { stub_const("TestClass::M::X", 5) }.to raise_error(/cannot stub/i)
339
- end
340
- end
341
-
342
- context 'for an unloaded constant nested deeply within a deeply nested loaded constant' do
343
- it_behaves_like "unloaded constant stubbing", "TestClass::Nested::NestedEvenMore::X::Y::Z"
344
-
345
- it 'removes the first unloaded constant but leaves the loaded nested constant when rspec resets its mocks' do
346
- expect(defined?(TestClass::Nested::NestedEvenMore)).to be_true
347
- expect(defined?(TestClass::Nested::NestedEvenMore::X)).to be_false
348
- stub_const("TestClass::Nested::NestedEvenMore::X::Y::Z", 7)
349
- reset_rspec_mocks
350
- expect(defined?(TestClass::Nested::NestedEvenMore)).to be_true
351
- expect(defined?(TestClass::Nested::NestedEvenMore::X)).to be_false
352
- end
353
- end
354
- end
355
- end
356
-
357
- describe Constant do
358
- def reset_rspec_mocks
359
- Spy.teardown
360
- end
361
-
362
- def on_const(const_name)
363
- if const_name.include? "::"
364
- args = [recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, '')), const_name.split('::').last.to_sym]
365
- else
366
- args = [const_name.to_sym]
367
- end
368
- Spy.get_const(*args) || Spy.on_const(*args)
369
- end
370
-
371
- def stub_const(const_name, value)
372
- on_const(const_name).and_return(value)
373
- end
374
-
375
- def hide_const(const_name)
376
- on_const(const_name).and_hide
377
- end
378
-
379
- def original(const_name)
380
- if const_name.include? "::"
381
- args = [recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, '')), const_name.split('::').last.to_sym]
382
- else
383
- args = [const_name.to_sym]
384
- end
385
- Spy.get_const(*args)
386
- end
387
-
388
- describe ".original" do
389
- context 'for a previously defined unstubbed constant' do
390
- let(:const) { original("TestClass::M") }
391
-
392
- it("exposes its name") { expect(const.name).to eq("TestClass::M") }
393
- it("indicates it was previously defined") { expect(const).to be_previously_defined }
394
- it("indicates it has not been hidden") { expect(const).not_to be_hidden }
395
- it("exposes its original value") { expect(const.original_value).to eq(:m) }
396
- end
397
-
398
- context 'for a previously defined stubbed constant' do
399
- before { stub_const("TestClass::M", :other) }
400
- let(:const) { original("TestClass::M") }
401
-
402
- it("exposes its name") { expect(const.name).to eq("TestClass::M") }
403
- it("indicates it was previously defined") { expect(const).to be_previously_defined }
404
- it("indicates it has not been hidden") { expect(const).not_to be_hidden }
405
- it("exposes its original value") { expect(const.original_value).to eq(:m) }
406
- end
407
-
408
- context 'for a previously undefined stubbed constant' do
409
- before { stub_const("TestClass::Undefined", :other) }
410
- let(:const) { original("TestClass::Undefined") }
411
-
412
- it("exposes its name") { expect(const.name).to eq("TestClass::Undefined") }
413
- it("indicates it was not previously defined") { expect(const).not_to be_previously_defined }
414
- it("indicates it has not been hidden") { expect(const).not_to be_hidden }
415
- it("returns nil for the original value") { expect(const.original_value).to be_nil }
416
- end
417
-
418
- context 'for a previously undefined unstubbed constant' do
419
- let(:const) { original("TestClass::Undefined") }
420
-
421
- it("exposes its name") { expect(const.name).to eq("TestClass::Undefined") }
422
- it("indicates it was not previously defined") { expect(const).not_to be_previously_defined }
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) { 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 not been hidden") { expect(const).not_to be_hidden }
435
- it("exposes its original value") { expect(const.original_value).to eq(:m) }
436
- end
437
-
438
- context 'for a previously undefined constant that has been stubbed twice' do
439
- before { stub_const("TestClass::Undefined", 1) }
440
- before { stub_const("TestClass::Undefined", 2) }
441
- let(:const) { original("TestClass::Undefined") }
442
-
443
- it("exposes its name") { expect(const.name).to eq("TestClass::Undefined") }
444
- it("indicates it was not previously defined") { expect(const).not_to be_previously_defined }
445
- it("indicates it has not been hidden") { expect(const).not_to be_hidden }
446
- it("returns nil for the original value") { expect(const.original_value).to be_nil }
447
- end
448
-
449
- context 'for a previously defined hidden constant' do
450
- before { hide_const("TestClass::M") }
451
- let(:const) { original("TestClass::M") }
452
-
453
- it("exposes its name") { expect(const.name).to eq("TestClass::M") }
454
- it("indicates it was previously defined") { expect(const).to be_previously_defined }
455
- it("indicates it has been hidden") { expect(const).to be_hidden }
456
- it("exposes its original value") { expect(const.original_value).to eq(:m) }
457
- end
458
-
459
- context 'for a previously defined constant that has been hidden twice' do
460
- before { hide_const("TestClass::M") }
461
- before { hide_const("TestClass::M") }
462
- let(:const) { original("TestClass::M") }
463
-
464
- it("exposes its name") { expect(const.name).to eq("TestClass::M") }
465
- it("indicates it was previously defined") { expect(const).to be_previously_defined }
466
- it("indicates it has been hidden") { expect(const).to be_hidden }
467
- it("exposes its original value") { expect(const.original_value).to eq(:m) }
468
- end
469
- end
470
- end
471
- end
@@ -1,56 +0,0 @@
1
- require 'spec_helper'
2
-
3
- def remove_last_describe_from_world
4
- RSpec::world.example_groups.pop
5
- end
6
-
7
- def empty_example_group
8
- RSpec::Core::ExampleGroup.describe(Object, 'Empty Behaviour Group') { }
9
- remove_last_describe_from_world
10
- end
11
-
12
- module RSpec
13
- module Mocks
14
- describe "an expectation set on nil" do
15
- it "issues a warning with file and line number information" do
16
- expected_warning = %r%An expectation of :foo was set on nil. Called from #{__FILE__}:#{__LINE__+3}(:in .+)?. Use allow_message_expectations_on_nil to disable warnings.%
17
- Kernel.should_receive(:warn).with(expected_warning)
18
-
19
- nil.should_receive(:foo)
20
- nil.foo
21
- end
22
-
23
- it "issues a warning when the expectation is negative" do
24
- Kernel.should_receive(:warn)
25
-
26
- nil.should_not_receive(:foo)
27
- end
28
-
29
- it "does not issue a warning when expectations are set to be allowed" do
30
- allow_message_expectations_on_nil
31
- Kernel.should_not_receive(:warn)
32
-
33
- nil.should_receive(:foo)
34
- nil.should_not_receive(:bar)
35
- nil.foo
36
- end
37
- end
38
-
39
- describe "#allow_message_expectations_on_nil" do
40
- it "does not effect subsequent examples" do
41
- example_group = empty_example_group
42
- example_group.it("when called in one example that doesn't end up setting an expectation on nil") do
43
- allow_message_expectations_on_nil
44
- end
45
- example_group.it("should not effect the next exapmle ran") do
46
- Kernel.should_receive(:warn)
47
- nil.should_receive(:foo)
48
- nil.foo
49
- end
50
-
51
- example_group
52
- end
53
- end
54
- end
55
- end
56
-
@@ -1,79 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module RSpec
4
- module Mocks
5
- describe "a double _not_ acting as a null object" do
6
- before(:each) do
7
- @double = Spy.double('non-null object')
8
- end
9
-
10
- it "says it does not respond to messages it doesn't understand" do
11
- expect(@double).not_to respond_to(:foo)
12
- end
13
-
14
- it "says it responds to messages it does understand" do
15
- Spy.on(@double, :foo)
16
- expect(@double).to respond_to(:foo)
17
- end
18
-
19
- it "raises an error when interpolated in a string as an integer" do
20
- expect { "%i" % @double }.to raise_error(TypeError)
21
- end
22
- end
23
-
24
- describe "a double acting as a null object" do
25
- before(:each) do
26
- @double = Spy.double('null object').as_null_object
27
- end
28
-
29
- it "says it responds to everything" do
30
- expect(@double).to respond_to(:any_message_it_gets)
31
- end
32
-
33
- it "allows explicit stubs" do
34
- Spy.on(@double, :foo) { "bar" }
35
- expect(@double.foo).to eq("bar")
36
- end
37
-
38
- it "allows explicit expectation" do
39
- spy = Spy.on(@double, :something)
40
- @double.something
41
- expect(spy).to have_been_called
42
- end
43
-
44
- it 'continues to return self from an explicit expectation' do
45
- spy = Spy.on(@double, :bar)
46
- expect(@double.foo.bar).to be(@double)
47
- expect(spy).to have_been_called
48
- end
49
-
50
- it 'returns an explicitly stubbed value from an expectation with no implementation' do
51
- spy = Spy.on(@double, :foo => "bar")
52
- expect(@double.foo).to eq("bar")
53
- expect(spy).to have_been_called
54
- end
55
-
56
- it "can be interpolated in a string as an integer" do
57
- # This form of string interpolation calls
58
- # @double.to_int.to_int.to_int...etc until it gets an integer,
59
- # and thus gets stuck in an infinite loop unless our double
60
- # returns an int value from #to_int.
61
- expect(("%i" % @double)).to eq("0")
62
- end
63
- end
64
-
65
- describe "#as_null_object" do
66
- it "sets the object to null_object" do
67
- obj = Spy.double('anything').as_null_object
68
- expect(obj).to be_null_object
69
- end
70
- end
71
-
72
- describe "#null_object?" do
73
- it "defaults to false" do
74
- obj = Spy.double('anything')
75
- expect(obj).not_to be_null_object
76
- end
77
- end
78
- end
79
- end
@@ -1,81 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Spy
4
- describe "using a Partial Mock," do
5
-
6
- def stub(object, method_name)
7
- Spy::Subroutine.new(object, method_name).hook(force: true)
8
- end
9
-
10
- let(:object) { Object.new }
11
-
12
- it "names the class in the failure message" do
13
- spy = stub(object, :foo)
14
- expect(spy).to_not have_been_called
15
- end
16
-
17
- it "names the class in the failure message when expectation is on class" do
18
- spy = stub(Object, :foo)
19
- expect(spy).to_not have_been_called
20
- end
21
-
22
- it "does not conflict with @options in the object" do
23
- object.instance_eval { @options = Object.new }
24
- spy = stub(object, :blah)
25
- object.blah
26
- expect(spy).to have_been_called
27
- end
28
-
29
- it "uses reports nil in the error message" do
30
- allow_message_expectations_on_nil
31
-
32
- _nil = nil
33
- spy = stub(_nil, :foobar)
34
- _nil.foobar
35
- expect(spy).to have_been_called
36
- end
37
- end
38
-
39
- describe "Method visibility when using partial mocks" do
40
- def stub(o, method_name)
41
- Spy.on(o, method_name)
42
- end
43
-
44
- let(:klass) do
45
- Class.new do
46
- def public_method
47
- private_method
48
- protected_method
49
- end
50
- protected
51
- def protected_method; end
52
- private
53
- def private_method; end
54
- end
55
- end
56
-
57
- let(:object) { klass.new }
58
-
59
- it 'keeps public methods public' do
60
- spy = stub(object, :public_method)
61
- expect(object.public_methods).to include_method(:public_method)
62
- object.public_method
63
- expect(spy).to have_been_called
64
- end
65
-
66
- it 'keeps private methods private' do
67
- spy = stub(object, :private_method)
68
- expect(object.private_methods).to include_method(:private_method)
69
- object.public_method
70
- expect(spy).to have_been_called
71
- end
72
-
73
- it 'keeps protected methods protected' do
74
- spy = stub(object, :protected_method)
75
- expect(object.protected_methods).to include_method(:protected_method)
76
- object.public_method
77
- expect(spy).to have_been_called
78
- end
79
-
80
- end
81
- end