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.
Files changed (46) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +133 -0
  5. data/Rakefile +8 -0
  6. data/TODO.md +8 -0
  7. data/lib/spy.rb +259 -0
  8. data/lib/spy/double.rb +11 -0
  9. data/lib/spy/dsl.rb +7 -0
  10. data/lib/spy/version.rb +3 -0
  11. data/spec/spec_helper.rb +39 -0
  12. data/spec/spy/and_call_original_spec.rb +152 -0
  13. data/spec/spy/and_yield_spec.rb +114 -0
  14. data/spec/spy/bug_report_10260_spec.rb +8 -0
  15. data/spec/spy/bug_report_10263_spec.rb +24 -0
  16. data/spec/spy/bug_report_496_spec.rb +18 -0
  17. data/spec/spy/bug_report_600_spec.rb +24 -0
  18. data/spec/spy/bug_report_7611_spec.rb +16 -0
  19. data/spec/spy/bug_report_8165_spec.rb +31 -0
  20. data/spec/spy/bug_report_830_spec.rb +21 -0
  21. data/spec/spy/bug_report_957_spec.rb +22 -0
  22. data/spec/spy/double_spec.rb +12 -0
  23. data/spec/spy/failing_argument_matchers_spec.rb +94 -0
  24. data/spec/spy/hash_excluding_matcher_spec.rb +67 -0
  25. data/spec/spy/hash_including_matcher_spec.rb +90 -0
  26. data/spec/spy/mock_spec.rb +734 -0
  27. data/spec/spy/multiple_return_value_spec.rb +119 -0
  28. data/spec/spy/mutate_const_spec.rb +481 -0
  29. data/spec/spy/nil_expectation_warning_spec.rb +56 -0
  30. data/spec/spy/null_object_mock_spec.rb +107 -0
  31. data/spec/spy/options_hash_spec.rb +35 -0
  32. data/spec/spy/partial_mock_spec.rb +196 -0
  33. data/spec/spy/passing_argument_matchers_spec.rb +142 -0
  34. data/spec/spy/precise_counts_spec.rb +68 -0
  35. data/spec/spy/serialization_spec.rb +110 -0
  36. data/spec/spy/stash_spec.rb +54 -0
  37. data/spec/spy/stub_implementation_spec.rb +62 -0
  38. data/spec/spy/stub_spec.rb +85 -0
  39. data/spec/spy/stubbed_message_expectations_spec.rb +47 -0
  40. data/spec/spy/test_double_spec.rb +57 -0
  41. data/spec/spy/to_ary_spec.rb +40 -0
  42. data/spy.gemspec +21 -0
  43. data/test/spy/test_double.rb +19 -0
  44. data/test/test_helper.rb +6 -0
  45. data/test/test_spy.rb +258 -0
  46. 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
+