spy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+