spy 1.0.3 → 1.0.5

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