rspec-fire 0.5.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
1
  source :rubygems
2
2
 
3
3
  gemspec
4
+
data/HISTORY CHANGED
@@ -24,3 +24,7 @@
24
24
  0.5.0 - 4 July 2012
25
25
  * Performance improvements, overhead is now roughly 10% down from 100%
26
26
  * Allow both instance and class doubles for unloaded classes.
27
+
28
+ 1.0.0 - 9 July 2012
29
+ * RSpec 2.11 compatibility, no longer compatible with earlier versions.
30
+ * Removed `stub_const`, it is now in `rspec-mocks`.
data/README.md CHANGED
@@ -144,25 +144,6 @@ collaborators (a technique that can sometimes be cumbersome).
144
144
  This will probably become the default behaviour once we figure out a better
145
145
  name for it.
146
146
 
147
- ### Stubbing Constants
148
-
149
- The constant stubbing logic used when doubling class constants can be
150
- used for any constant.
151
-
152
- class MapReduceRunner
153
- ITEMS_PER_BATCH = 1000
154
- end
155
-
156
- describe MapReduceRunner, "when it has too many items for one batch" do
157
- it "breaks the items up into smaller batches" do
158
- # the test would be really slow if we had to make more than 1000 items,
159
- # so let's change the threshold for this one test.
160
- stub_const("MapReduceRunner::ITEMS_PER_BATCH", 10)
161
-
162
- MapReduceRunner.run_with(twenty_items)
163
- end
164
- end
165
-
166
147
  ### Transferring nested constants to doubled constants
167
148
 
168
149
  When you use `fire_replaced_class_double` to replace a class or module
@@ -186,9 +167,6 @@ to deal with this:
186
167
  # ...or give it a list of constants to transfer
187
168
  fire_class_double("MyCoolGem").as_replaced_constant(:transfer_nested_constants => [:Widget])
188
169
 
189
- # You can also use this when using #stub_const directly
190
- stub_const("MyCoolGem", :transfer_nested_constants => true)
191
-
192
170
  ### Doubling class methods
193
171
 
194
172
  Particularly handy for `ActiveRecord` finders. Use `fire_class_double`. If you
@@ -207,7 +185,7 @@ refactor or use a non-isolated test.
207
185
  Compatibility
208
186
  -------------
209
187
 
210
- Only RSpec 2 is supported. Tested on all the rubies thanks to [Travis
188
+ Only RSpec 2.11+ is supported. Tested on all the rubies thanks to [Travis
211
189
  CI][build-link].
212
190
 
213
191
  [build-link]: http://travis-ci.org/xaviershay/rspec-fire
data/lib/rspec/fire.rb CHANGED
@@ -135,7 +135,7 @@ module RSpec
135
135
  end
136
136
 
137
137
  def with_doubled_class
138
- ConstantStubber.find_original_value_for(@__doubled_class_name) do |value|
138
+ ::RSpec::Fire.find_original_value_for(@__doubled_class_name) do |value|
139
139
  yield value if value
140
140
  return
141
141
  end
@@ -230,7 +230,9 @@ module RSpec
230
230
  end
231
231
 
232
232
  def self.as_replaced_constant(options = {})
233
- @__original_class = ConstantStubber.stub!(@__doubled_class_name, self, options)
233
+ RSpec::Mocks::ConstantStubber.stub(@__doubled_class_name, self, options)
234
+ @__original_class = RSpec::Mocks::Constant.original(@__doubled_class_name).original_value
235
+
234
236
  extend AsReplacedConstant
235
237
  self
236
238
  end
@@ -256,161 +258,9 @@ module RSpec
256
258
  end
257
259
  end
258
260
 
259
- class ConstantStubber
260
- extend RecursiveConstMethods
261
-
262
- class DefinedConstantReplacer
263
- include RecursiveConstMethods
264
- attr_reader :original_value, :full_constant_name
265
-
266
- def initialize(full_constant_name, stubbed_value, transfer_nested_constants)
267
- @full_constant_name = full_constant_name
268
- @stubbed_value = stubbed_value
269
- @transfer_nested_constants = transfer_nested_constants
270
- end
271
-
272
- def stub!
273
- context_parts = @full_constant_name.split('::')
274
- @const_name = context_parts.pop
275
- @context = recursive_const_get(context_parts.join('::'))
276
- @original_value = @context.const_get(@const_name)
277
-
278
- constants_to_transfer = verify_constants_to_transfer!
279
-
280
- @context.send(:remove_const, @const_name)
281
- @context.const_set(@const_name, @stubbed_value)
282
-
283
- transfer_nested_constants(constants_to_transfer)
284
- end
285
-
286
- def rspec_reset
287
- if recursive_const_get(@full_constant_name).equal?(@stubbed_value)
288
- @context.send(:remove_const, @const_name)
289
- @context.const_set(@const_name, @original_value)
290
- end
291
- end
292
-
293
- def transfer_nested_constants(constants)
294
- constants.each do |const|
295
- @stubbed_value.const_set(const, original_value.const_get(const))
296
- end
297
- end
298
-
299
- def verify_constants_to_transfer!
300
- return [] unless @transfer_nested_constants
301
-
302
- { @original_value => "the original value", @stubbed_value => "the stubbed value" }.each do |value, description|
303
- unless value.respond_to?(:constants)
304
- raise ArgumentError,
305
- "Cannot transfer nested constants for #{@full_constant_name} " +
306
- "since #{description} is not a class or module and only classes " +
307
- "and modules support nested constants."
308
- end
309
- end
310
-
311
- if @transfer_nested_constants.is_a?(Array)
312
- @transfer_nested_constants = @transfer_nested_constants.map(&:to_s) if RUBY_VERSION == '1.8.7'
313
- undefined_constants = @transfer_nested_constants - @original_value.constants
314
-
315
- if undefined_constants.any?
316
- available_constants = @original_value.constants - @transfer_nested_constants
317
- raise ArgumentError,
318
- "Cannot transfer nested constant(s) #{undefined_constants.join(' and ')} " +
319
- "for #{@full_constant_name} since they are not defined. Did you mean " +
320
- "#{available_constants.join(' or ')}?"
321
- end
322
-
323
- @transfer_nested_constants
324
- else
325
- @original_value.constants
326
- end
327
- end
328
- end
329
-
330
- class UndefinedConstantSetter
331
- include RecursiveConstMethods
332
-
333
- attr_reader :full_constant_name
334
-
335
- def initialize(full_constant_name, stubbed_value)
336
- @full_constant_name = full_constant_name
337
- @stubbed_value = stubbed_value
338
- end
339
-
340
- def original_value
341
- # always nil
342
- end
343
-
344
- def stub!
345
- context_parts = @full_constant_name.split('::')
346
- const_name = context_parts.pop
347
-
348
- remaining_parts = context_parts.dup
349
- @deepest_defined_const = context_parts.inject(Object) do |klass, name|
350
- break klass unless klass.const_defined?(name)
351
- remaining_parts.shift
352
- klass.const_get(name)
353
- end
354
-
355
- context = remaining_parts.inject(@deepest_defined_const) do |klass, name|
356
- klass.const_set(name, Module.new)
357
- end
358
-
359
- @const_to_remove = remaining_parts.first || const_name
360
- context.const_set(const_name, @stubbed_value)
361
- end
362
-
363
- def rspec_reset
364
- if recursive_const_get(@full_constant_name).equal?(@stubbed_value)
365
- @deepest_defined_const.send(:remove_const, @const_to_remove)
366
- end
367
- end
368
- end
369
-
370
- def self.stub!(constant_name, value, options = {})
371
- stubber = if recursive_const_defined?(constant_name)
372
- DefinedConstantReplacer.new(constant_name, value, options[:transfer_nested_constants])
373
- else
374
- UndefinedConstantSetter.new(constant_name, value)
375
- end
376
-
377
- stubbers << stubber
378
-
379
- stubber.stub!
380
- ensure_registered_with_rspec_mocks
381
- stubber.original_value
382
- end
383
-
384
- def self.ensure_registered_with_rspec_mocks
385
- return if @registered_with_rspec_mocks
386
- ::RSpec::Mocks.space.add(self)
387
- @registered_with_rspec_mocks = true
388
- end
389
-
390
- def self.rspec_reset
391
- @registered_with_rspec_mocks = false
392
-
393
- # We use reverse order so that if the same constant
394
- # was stubbed multiple times, the original value gets
395
- # properly restored.
396
- stubbers.reverse.each { |s| s.rspec_reset }
397
-
398
- stubbers.clear
399
- end
400
-
401
- def self.stubbers
402
- @stubbers ||= []
403
- end
404
-
405
- def self.find_original_value_for(constant_name)
406
- stubber = stubbers.find { |s| s.full_constant_name == constant_name }
407
- yield stubber.original_value if stubber
408
- self
409
- end
410
- end
411
-
412
- def stub_const(name, value, options = {})
413
- ConstantStubber.stub!(name, value, options)
261
+ def self.find_original_value_for(constant_name)
262
+ const = ::RSpec::Mocks::Constant.original(constant_name)
263
+ yield const.original_value if const.stubbed?
414
264
  end
415
265
 
416
266
  def fire_double(*args)
data/rspec-fire.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rspec-fire'
3
- s.version = '0.5.0'
3
+ s.version = '1.0.0'
4
4
  s.summary = 'More resilient test doubles for RSpec.'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ["Xavier Shay"]
@@ -18,6 +18,6 @@ Gem::Specification.new do |s|
18
18
  rspec-fire.gemspec
19
19
  )
20
20
 
21
+ s.add_dependency 'rspec', '~> 2.11'
21
22
  s.add_development_dependency 'rake'
22
- s.add_development_dependency 'rspec', '~> 2.5'
23
23
  end
@@ -3,8 +3,6 @@ require 'spec_helper'
3
3
  def use; end
4
4
  private :use
5
5
 
6
- TOP_LEVEL_VALUE_CONST = 7
7
-
8
6
  module TestMethods
9
7
  def defined_method
10
8
  raise "Y U NO MOCK?"
@@ -26,11 +24,6 @@ class TestClass
26
24
  M = :m
27
25
  N = :n
28
26
 
29
- class Nested
30
- class NestedEvenMore
31
- end
32
- end
33
-
34
27
  def self.use
35
28
  raise "Y U NO MOCK?"
36
29
  end
@@ -294,248 +287,6 @@ describe '#fire_replaced_class_double (for a non-existant class)' do
294
287
  end
295
288
  end
296
289
 
297
- shared_examples_for "loaded constant stubbing" do |const_name|
298
- include RSpec::Fire::RecursiveConstMethods
299
- let!(:original_const_value) { const }
300
- after { change_const_value_to(original_const_value) }
301
-
302
- define_method :const do
303
- recursive_const_get(const_name)
304
- end
305
-
306
- define_method :parent_const do
307
- recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
308
- end
309
-
310
- define_method :last_const_part do
311
- const_name.split('::').last
312
- end
313
-
314
- def change_const_value_to(value)
315
- parent_const.send(:remove_const, last_const_part)
316
- parent_const.const_set(last_const_part, value)
317
- end
318
-
319
- it 'allows it to be stubbed' do
320
- const.should_not eq(7)
321
- stub_const(const_name, 7)
322
- const.should eq(7)
323
- end
324
-
325
- it 'resets it to its original value when rspec clears its mocks' do
326
- original_value = const
327
- original_value.should_not eq(:a)
328
- stub_const(const_name, :a)
329
- reset_rspec_mocks
330
- const.should be(original_value)
331
- end
332
-
333
- it 'does not reset the value to its original value when rspec clears its mocks if the example modifies the value of the constant' do
334
- stub_const(const_name, :a)
335
- change_const_value_to(new_const_value = Object.new)
336
- reset_rspec_mocks
337
- const.should be(new_const_value)
338
- end
339
-
340
- it 'returns the original value' do
341
- orig_value = const
342
- returned_value = stub_const(const_name, 7)
343
- returned_value.should be(orig_value)
344
- end
345
- end
346
-
347
- shared_examples_for "unloaded constant stubbing" do |const_name|
348
- include RSpec::Fire::RecursiveConstMethods
349
- before { recursive_const_defined?(const_name).should be_false }
350
-
351
- define_method :const do
352
- recursive_const_get(const_name)
353
- end
354
-
355
- define_method :parent_const do
356
- recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
357
- end
358
-
359
- define_method :last_const_part do
360
- const_name.split('::').last
361
- end
362
-
363
- def change_const_value_to(value)
364
- parent_const.send(:remove_const, last_const_part)
365
- parent_const.const_set(last_const_part, value)
366
- end
367
-
368
- it 'allows it to be stubbed' do
369
- stub_const(const_name, 7)
370
- const.should eq(7)
371
- end
372
-
373
- it 'removes the constant when rspec clears its mocks' do
374
- stub_const(const_name, 7)
375
- reset_rspec_mocks
376
- recursive_const_defined?(const_name).should be_false
377
- end
378
-
379
- it 'does not remove the constant when the example manually sets it' do
380
- begin
381
- stub_const(const_name, 7)
382
- stubber = RSpec::Fire::ConstantStubber.stubbers.first
383
- change_const_value_to(new_const_value = Object.new)
384
- reset_rspec_mocks
385
- const.should equal(new_const_value)
386
- ensure
387
- change_const_value_to(7)
388
- stubber.rspec_reset
389
- end
390
- end
391
-
392
- it 'returns nil since it was not originally set' do
393
- stub_const(const_name, 7).should be_nil
394
- end
395
-
396
- it 'ignores the :transfer_nested_constants if passed' do
397
- stub = Module.new
398
- stub_const(const_name, stub, :transfer_nested_constants => true)
399
- stub.constants.should eq([])
400
- end
401
- end
402
-
403
- describe "#stub_const" do
404
- context 'for a loaded unnested constant' do
405
- it_behaves_like "loaded constant stubbing", "TestClass"
406
-
407
- it 'can be stubbed multiple times but still restores the original value properly' do
408
- orig_value = TestClass
409
- stub1, stub2 = Module.new, Module.new
410
- stub_const("TestClass", stub1)
411
- stub_const("TestClass", stub2)
412
-
413
- reset_rspec_mocks
414
- TestClass.should be(orig_value)
415
- end
416
-
417
- it 'allows nested constants to be transferred to a stub module' do
418
- tc_nested = TestClass::Nested
419
- stub = Module.new
420
- stub_const("TestClass", stub, :transfer_nested_constants => true)
421
- stub::M.should eq(:m)
422
- stub::N.should eq(:n)
423
- stub::Nested.should be(tc_nested)
424
- end
425
-
426
- it 'allows nested constants to be selectively transferred to a stub module' do
427
- stub = Module.new
428
- stub_const("TestClass", stub, :transfer_nested_constants => [:M, :N])
429
- stub::M.should eq(:m)
430
- stub::N.should eq(:n)
431
- defined?(stub::Nested).should be_false
432
- end
433
-
434
- it 'raises an error if asked to transfer nested constants but given an object that does not support them' do
435
- original_tc = TestClass
436
- stub = Object.new
437
- expect {
438
- stub_const("TestClass", stub, :transfer_nested_constants => true)
439
- }.to raise_error(ArgumentError)
440
-
441
- TestClass.should be(original_tc)
442
-
443
- expect {
444
- stub_const("TestClass", stub, :transfer_nested_constants => [:M])
445
- }.to raise_error(ArgumentError)
446
-
447
- TestClass.should be(original_tc)
448
- end
449
-
450
- it 'raises an error if asked to transfer nested constants on a constant that does not support nested constants' do
451
- stub = Module.new
452
- expect {
453
- stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => true)
454
- }.to raise_error(ArgumentError)
455
-
456
- TOP_LEVEL_VALUE_CONST.should eq(7)
457
-
458
- expect {
459
- stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => [:M])
460
- }.to raise_error(ArgumentError)
461
-
462
- TOP_LEVEL_VALUE_CONST.should eq(7)
463
- end
464
-
465
- it 'raises an error if asked to transfer a nested constant that is not defined' do
466
- original_tc = TestClass
467
- defined?(TestClass::V).should be_false
468
- stub = Module.new
469
-
470
- expect {
471
- stub_const("TestClass", stub, :transfer_nested_constants => [:V])
472
- }.to raise_error(/cannot transfer nested constant.*V/i)
473
-
474
- TestClass.should be(original_tc)
475
- end
476
- end
477
-
478
- context 'for a loaded nested constant' do
479
- it_behaves_like "loaded constant stubbing", "TestClass::Nested"
480
- end
481
-
482
- context 'for a loaded deeply nested constant' do
483
- it_behaves_like "loaded constant stubbing", "TestClass::Nested::NestedEvenMore"
484
- end
485
-
486
- context 'for an unloaded unnested constant' do
487
- it_behaves_like "unloaded constant stubbing", "X"
488
- end
489
-
490
- context 'for an unloaded nested constant' do
491
- it_behaves_like "unloaded constant stubbing", "X::Y"
492
-
493
- it 'removes the root constant when rspec clears its mocks' do
494
- defined?(X).should be_false
495
- stub_const("X::Y", 7)
496
- reset_rspec_mocks
497
- defined?(X).should be_false
498
- end
499
- end
500
-
501
- context 'for an unloaded deeply nested constant' do
502
- it_behaves_like "unloaded constant stubbing", "X::Y::Z"
503
-
504
- it 'removes the root constant when rspec clears its mocks' do
505
- defined?(X).should be_false
506
- stub_const("X::Y::Z", 7)
507
- reset_rspec_mocks
508
- defined?(X).should be_false
509
- end
510
- end
511
-
512
- context 'for an unloaded constant nested within a loaded constant' do
513
- it_behaves_like "unloaded constant stubbing", "TestClass::X"
514
-
515
- it 'removes the unloaded constant but leaves the loaded constant when rspec resets its mocks' do
516
- defined?(TestClass).should be_true
517
- defined?(TestClass::X).should be_false
518
- stub_const("TestClass::X", 7)
519
- reset_rspec_mocks
520
- defined?(TestClass).should be_true
521
- defined?(TestClass::X).should be_false
522
- end
523
- end
524
-
525
- context 'for an unloaded constant nested deeply within a deeply nested loaded constant' do
526
- it_behaves_like "unloaded constant stubbing", "TestClass::Nested::NestedEvenMore::X::Y::Z"
527
-
528
- it 'removes the first unloaded constant but leaves the loaded nested constant when rspec resets its mocks' do
529
- defined?(TestClass::Nested::NestedEvenMore).should be_true
530
- defined?(TestClass::Nested::NestedEvenMore::X).should be_false
531
- stub_const("TestClass::Nested::NestedEvenMore::X::Y::Z", 7)
532
- reset_rspec_mocks
533
- defined?(TestClass::Nested::NestedEvenMore).should be_true
534
- defined?(TestClass::Nested::NestedEvenMore::X).should be_false
535
- end
536
- end
537
- end
538
-
539
290
  describe RSpec::Fire::SupportArityMatcher do
540
291
  def support_arity(arity)
541
292
  RSpec::Fire::SupportArityMatcher.new(arity)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-fire
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,30 +9,30 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-04 00:00:00.000000000Z
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: rake
16
- requirement: &2159223000 !ruby/object:Gem::Requirement
15
+ name: rspec
16
+ requirement: &2156163500 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ! '>='
19
+ - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
21
+ version: '2.11'
22
+ type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2159223000
24
+ version_requirements: *2156163500
25
25
  - !ruby/object:Gem::Dependency
26
- name: rspec
27
- requirement: &2159222320 !ruby/object:Gem::Requirement
26
+ name: rake
27
+ requirement: &2156162900 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
- - - ~>
30
+ - - ! '>='
31
31
  - !ruby/object:Gem::Version
32
- version: '2.5'
32
+ version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2159222320
35
+ version_requirements: *2156162900
36
36
  description:
37
37
  email:
38
38
  - hello@xaviershay.com
@@ -68,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
68
  version: '0'
69
69
  requirements: []
70
70
  rubyforge_project:
71
- rubygems_version: 1.8.10
71
+ rubygems_version: 1.8.6
72
72
  signing_key:
73
73
  specification_version: 3
74
74
  summary: More resilient test doubles for RSpec.