spy 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.travis.yml +5 -0
  2. data/Gemfile +1 -0
  3. data/README.md +22 -7
  4. data/Rakefile +2 -0
  5. data/lib/spy.rb +39 -6
  6. data/lib/spy/agency.rb +42 -27
  7. data/lib/spy/call_log.rb +26 -0
  8. data/lib/spy/constant.rb +72 -14
  9. data/lib/spy/core_ext/marshal.rb +1 -0
  10. data/lib/spy/double.rb +17 -0
  11. data/lib/spy/nest.rb +27 -0
  12. data/lib/spy/subroutine.rb +146 -44
  13. data/lib/spy/version.rb +1 -1
  14. data/spec/spy/any_instance_spec.rb +518 -0
  15. data/spec/spy/mock_spec.rb +46 -554
  16. data/spec/spy/mutate_const_spec.rb +21 -63
  17. data/spec/spy/null_object_mock_spec.rb +11 -39
  18. data/spec/spy/partial_mock_spec.rb +3 -62
  19. data/spec/spy/stash_spec.rb +30 -37
  20. data/spec/spy/stub_spec.rb +0 -6
  21. data/spec/spy/to_ary_spec.rb +5 -5
  22. data/test/integration/test_constant_spying.rb +1 -1
  23. data/test/integration/test_instance_method.rb +32 -0
  24. data/test/integration/test_subroutine_spying.rb +7 -4
  25. data/test/spy/test_double.rb +4 -0
  26. data/test/spy/test_subroutine.rb +28 -3
  27. data/test/support/pen.rb +15 -0
  28. metadata +8 -30
  29. data/spec/spy/bug_report_10260_spec.rb +0 -8
  30. data/spec/spy/bug_report_10263_spec.rb +0 -24
  31. data/spec/spy/bug_report_496_spec.rb +0 -18
  32. data/spec/spy/bug_report_600_spec.rb +0 -24
  33. data/spec/spy/bug_report_7611_spec.rb +0 -16
  34. data/spec/spy/bug_report_8165_spec.rb +0 -31
  35. data/spec/spy/bug_report_830_spec.rb +0 -21
  36. data/spec/spy/bug_report_957_spec.rb +0 -22
  37. data/spec/spy/double_spec.rb +0 -12
  38. data/spec/spy/failing_argument_matchers_spec.rb +0 -94
  39. data/spec/spy/options_hash_spec.rb +0 -35
  40. data/spec/spy/precise_counts_spec.rb +0 -68
  41. data/spec/spy/stubbed_message_expectations_spec.rb +0 -47
  42. data/spec/spy/test_double_spec.rb +0 -54
@@ -29,8 +29,12 @@ module Spy
29
29
  end
30
30
 
31
31
  def on_const(const_name)
32
- parent_const = recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
33
- Spy.on_const(parent_const, const_name.split('::').last.to_sym)
32
+ if const_name.include? "::"
33
+ args = [recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, '')), const_name.split('::').last.to_sym]
34
+ else
35
+ args = [const_name.to_sym]
36
+ end
37
+ Spy.get_const(*args) || Spy.on_const(*args)
34
38
  end
35
39
 
36
40
  def stub_const(const_name, value)
@@ -172,17 +176,9 @@ module Spy
172
176
  it_behaves_like "unloaded constant hiding", "TestClass::Hash"
173
177
 
174
178
  it 'does not hide the top-level constant' do
175
- top_level_hash = ::Hash
176
-
177
- hide_const("TestClass::Hash")
178
- expect(::Hash).to equal(top_level_hash)
179
- end
180
-
181
- it 'does not affect the ability to access the top-level constant from nested contexts', :silence_warnings do
182
- top_level_hash = ::Hash
183
-
184
- hide_const("TestClass::Hash")
185
- expect(TestClass::Hash).to equal(top_level_hash)
179
+ expect {
180
+ hide_const("TestClass::Hash")
181
+ }.to raise_error
186
182
  end
187
183
  end
188
184
 
@@ -318,14 +314,6 @@ module Spy
318
314
  it_behaves_like "loaded constant stubbing", "TestClass::Nested"
319
315
  end
320
316
 
321
- context 'for a loaded constant prefixed with ::' do
322
- it_behaves_like 'loaded constant stubbing', "::TestClass"
323
- end
324
-
325
- context 'for an unloaded constant prefixed with ::' do
326
- it_behaves_like 'unloaded constant stubbing', "::SomeUndefinedConst"
327
- end
328
-
329
317
  context 'for an unloaded constant with nested name that matches a top-level constant' do
330
318
  it_behaves_like "unloaded constant stubbing", "TestClass::Hash"
331
319
  end
@@ -338,28 +326,6 @@ module Spy
338
326
  it_behaves_like "unloaded constant stubbing", "X"
339
327
  end
340
328
 
341
- context 'for an unloaded nested constant' do
342
- it_behaves_like "unloaded constant stubbing", "X::Y"
343
-
344
- it 'removes the root constant when rspec clears its mocks' do
345
- expect(defined?(X)).to be_false
346
- stub_const("X::Y", 7)
347
- reset_rspec_mocks
348
- expect(defined?(X)).to be_false
349
- end
350
- end
351
-
352
- context 'for an unloaded deeply nested constant' do
353
- it_behaves_like "unloaded constant stubbing", "X::Y::Z"
354
-
355
- it 'removes the root constant when rspec clears its mocks' do
356
- expect(defined?(X)).to be_false
357
- stub_const("X::Y::Z", 7)
358
- reset_rspec_mocks
359
- expect(defined?(X)).to be_false
360
- end
361
- end
362
-
363
329
  context 'for an unloaded constant nested within a loaded constant' do
364
330
  it_behaves_like "unloaded constant stubbing", "TestClass::X"
365
331
 
@@ -402,8 +368,12 @@ module Spy
402
368
  end
403
369
 
404
370
  def on_const(const_name)
405
- parent_const = recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
406
- Spy.on_const(parent_const, const_name.split('::').last.to_sym)
371
+ if const_name.include? "::"
372
+ args = [recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, '')), const_name.split('::').last.to_sym]
373
+ else
374
+ args = [const_name.to_sym]
375
+ end
376
+ Spy.get_const(*args) || Spy.on_const(*args)
407
377
  end
408
378
 
409
379
  def stub_const(const_name, value)
@@ -415,8 +385,12 @@ module Spy
415
385
  end
416
386
 
417
387
  def original(const_name)
418
- parent_const = recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
419
- Spy.get_const(parent_const, const_name.split('::').last.to_sym)
388
+ if const_name.include? "::"
389
+ args = [recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, '')), const_name.split('::').last.to_sym]
390
+ else
391
+ args = [const_name.to_sym]
392
+ end
393
+ Spy.get_const(*args)
420
394
  end
421
395
 
422
396
  describe ".original" do
@@ -425,8 +399,6 @@ module Spy
425
399
 
426
400
  it("exposes its name") { expect(const.name).to eq("TestClass::M") }
427
401
  it("indicates it was previously defined") { expect(const).to be_previously_defined }
428
- it("indicates it has not been mutated") { expect(const).not_to be_mutated }
429
- it("indicates it has not been stubbed") { expect(const).not_to be_stubbed }
430
402
  it("indicates it has not been hidden") { expect(const).not_to be_hidden }
431
403
  it("exposes its original value") { expect(const.original_value).to eq(:m) }
432
404
  end
@@ -437,8 +409,6 @@ module Spy
437
409
 
438
410
  it("exposes its name") { expect(const.name).to eq("TestClass::M") }
439
411
  it("indicates it was previously defined") { expect(const).to be_previously_defined }
440
- it("indicates it has been mutated") { expect(const).to be_mutated }
441
- it("indicates it has been stubbed") { expect(const).to be_stubbed }
442
412
  it("indicates it has not been hidden") { expect(const).not_to be_hidden }
443
413
  it("exposes its original value") { expect(const.original_value).to eq(:m) }
444
414
  end
@@ -449,8 +419,6 @@ module Spy
449
419
 
450
420
  it("exposes its name") { expect(const.name).to eq("TestClass::Undefined") }
451
421
  it("indicates it was not previously defined") { expect(const).not_to be_previously_defined }
452
- it("indicates it has been mutated") { expect(const).to be_mutated }
453
- it("indicates it has been stubbed") { expect(const).to be_stubbed }
454
422
  it("indicates it has not been hidden") { expect(const).not_to be_hidden }
455
423
  it("returns nil for the original value") { expect(const.original_value).to be_nil }
456
424
  end
@@ -460,8 +428,6 @@ module Spy
460
428
 
461
429
  it("exposes its name") { expect(const.name).to eq("TestClass::Undefined") }
462
430
  it("indicates it was not previously defined") { expect(const).not_to be_previously_defined }
463
- it("indicates it has not been mutated") { expect(const).not_to be_mutated }
464
- it("indicates it has not been stubbed") { expect(const).not_to be_stubbed }
465
431
  it("indicates it has not been hidden") { expect(const).not_to be_hidden }
466
432
  it("returns nil for the original value") { expect(const.original_value).to be_nil }
467
433
  end
@@ -473,8 +439,6 @@ module Spy
473
439
 
474
440
  it("exposes its name") { expect(const.name).to eq("TestClass::M") }
475
441
  it("indicates it was previously defined") { expect(const).to be_previously_defined }
476
- it("indicates it has been mutated") { expect(const).to be_mutated }
477
- it("indicates it has been stubbed") { expect(const).to be_stubbed }
478
442
  it("indicates it has not been hidden") { expect(const).not_to be_hidden }
479
443
  it("exposes its original value") { expect(const.original_value).to eq(:m) }
480
444
  end
@@ -486,8 +450,6 @@ module Spy
486
450
 
487
451
  it("exposes its name") { expect(const.name).to eq("TestClass::Undefined") }
488
452
  it("indicates it was not previously defined") { expect(const).not_to be_previously_defined }
489
- it("indicates it has been mutated") { expect(const).to be_mutated }
490
- it("indicates it has been stubbed") { expect(const).to be_stubbed }
491
453
  it("indicates it has not been hidden") { expect(const).not_to be_hidden }
492
454
  it("returns nil for the original value") { expect(const.original_value).to be_nil }
493
455
  end
@@ -498,8 +460,6 @@ module Spy
498
460
 
499
461
  it("exposes its name") { expect(const.name).to eq("TestClass::M") }
500
462
  it("indicates it was previously defined") { expect(const).to be_previously_defined }
501
- it("indicates it has been mutated") { expect(const).to be_mutated }
502
- it("indicates it has not been stubbed") { expect(const).not_to be_stubbed }
503
463
  it("indicates it has been hidden") { expect(const).to be_hidden }
504
464
  it("exposes its original value") { expect(const.original_value).to eq(:m) }
505
465
  end
@@ -511,8 +471,6 @@ module Spy
511
471
 
512
472
  it("exposes its name") { expect(const.name).to eq("TestClass::M") }
513
473
  it("indicates it was previously defined") { expect(const).to be_previously_defined }
514
- it("indicates it has been mutated") { expect(const).to be_mutated }
515
- it("indicates it has not been stubbed") { expect(const).not_to be_stubbed }
516
474
  it("indicates it has been hidden") { expect(const).to be_hidden }
517
475
  it("exposes its original value") { expect(const.original_value).to eq(:m) }
518
476
  end
@@ -4,7 +4,7 @@ module RSpec
4
4
  module Mocks
5
5
  describe "a double _not_ acting as a null object" do
6
6
  before(:each) do
7
- @double = double('non-null object')
7
+ @double = Spy.double('non-null object')
8
8
  end
9
9
 
10
10
  it "says it does not respond to messages it doesn't understand" do
@@ -17,19 +17,13 @@ module RSpec
17
17
  end
18
18
 
19
19
  it "raises an error when interpolated in a string as an integer" do
20
- # Not sure why, but 1.9.2 (but not JRuby --1.9) raises a different
21
- # error than 1.8.7 and 1.9.3...
22
- expected_error = (RUBY_VERSION == '1.9.2' && RUBY_PLATFORM !~ /java/) ?
23
- RSpec::Mocks::MockExpectationError :
24
- TypeError
25
-
26
- expect { "%i" % @double }.to raise_error(expected_error)
20
+ expect { "%i" % @double }.to raise_error(TypeError)
27
21
  end
28
22
  end
29
23
 
30
24
  describe "a double acting as a null object" do
31
25
  before(:each) do
32
- @double = double('null object').as_null_object
26
+ @double = Spy.double('null object').as_null_object
33
27
  end
34
28
 
35
29
  it "says it responds to everything" do
@@ -42,43 +36,21 @@ module RSpec
42
36
  end
43
37
 
44
38
  it "allows explicit expectation" do
45
- @double.should_receive(:something)
39
+ spy = Spy.on(@double, :something)
46
40
  @double.something
41
+ expect(spy).to have_been_called
47
42
  end
48
43
 
49
44
  it 'continues to return self from an explicit expectation' do
50
- @double.should_receive(:bar)
45
+ spy = Spy.on(@double, :bar)
51
46
  expect(@double.foo.bar).to be(@double)
47
+ expect(spy).to have_been_called
52
48
  end
53
49
 
54
50
  it 'returns an explicitly stubbed value from an expectation with no implementation' do
55
- Spy.on(@double, :foo => "bar")
56
- @double.should_receive(:foo)
51
+ spy = Spy.on(@double, :foo => "bar")
57
52
  expect(@double.foo).to eq("bar")
58
- end
59
-
60
- it "fails verification when explicit exception not met" do
61
- expect {
62
- @double.should_receive(:something)
63
- @double.rspec_verify
64
- }.to raise_error(RSpec::Mocks::MockExpectationError)
65
- end
66
-
67
- it "ignores unexpected methods" do
68
- @double.random_call("a", "d", "c")
69
- @double.rspec_verify
70
- end
71
-
72
- it "allows expected message with different args first" do
73
- @double.should_receive(:message).with(:expected_arg)
74
- @double.message(:unexpected_arg)
75
- @double.message(:expected_arg)
76
- end
77
-
78
- it "allows expected message with different args second" do
79
- @double.should_receive(:message).with(:expected_arg)
80
- @double.message(:expected_arg)
81
- @double.message(:unexpected_arg)
53
+ expect(spy).to have_been_called
82
54
  end
83
55
 
84
56
  it "can be interpolated in a string as an integer" do
@@ -92,14 +64,14 @@ module RSpec
92
64
 
93
65
  describe "#as_null_object" do
94
66
  it "sets the object to null_object" do
95
- obj = double('anything').as_null_object
67
+ obj = Spy.double('anything').as_null_object
96
68
  expect(obj).to be_null_object
97
69
  end
98
70
  end
99
71
 
100
72
  describe "#null_object?" do
101
73
  it "defaults to false" do
102
- obj = double('anything')
74
+ obj = Spy.double('anything')
103
75
  expect(obj).not_to be_null_object
104
76
  end
105
77
  end
@@ -26,72 +26,13 @@ module Spy
26
26
  expect(spy).to have_been_called
27
27
  end
28
28
 
29
- it "should_receive mocks out the method" do
30
- stub(object, :foobar).with(:test_param).and_return(1)
31
- expect(object.foobar(:test_param)).to equal(1)
32
- end
33
-
34
- it "should_receive handles a hash" do
35
- stub(object, :foobar).with(:key => "value").and_return(1)
36
- expect(object.foobar(:key => "value")).to equal(1)
37
- end
38
-
39
- it "should_receive handles an inner hash" do
40
- hash = {:a => {:key => "value"}}
41
- object.should_receive(:foobar).with(:key => "value").and_return(1)
42
- expect(object.foobar(hash[:a])).to equal(1)
43
- end
44
-
45
- it "should_receive returns a message expectation" do
46
- expect(object.should_receive(:foobar)).to be_kind_of(RSpec::Mocks::MessageExpectation)
47
- object.foobar
48
- end
49
-
50
- it "should_receive verifies method was called" do
51
- object.should_receive(:foobar).with(:test_param).and_return(1)
52
- expect {
53
- object.rspec_verify
54
- }.to raise_error(RSpec::Mocks::MockExpectationError)
55
- end
56
-
57
- it "should_receive also takes a String argument" do
58
- object.should_receive('foobar')
59
- object.foobar
60
- end
61
-
62
- it "should_not_receive also takes a String argument" do
63
- object.should_not_receive('foobar')
64
- expect {
65
- object.foobar
66
- }.to raise_error(RSpec::Mocks::MockExpectationError)
67
- end
68
-
69
29
  it "uses reports nil in the error message" do
70
30
  allow_message_expectations_on_nil
71
31
 
72
32
  _nil = nil
73
- _nil.should_receive(:foobar)
74
- expect {
75
- _nil.rspec_verify
76
- }.to raise_error(
77
- RSpec::Mocks::MockExpectationError,
78
- %Q|(nil).foobar(any args)\n expected: 1 time\n received: 0 times|
79
- )
80
- end
81
-
82
- it "includes the class name in the error when mocking a class method that is called an extra time with the wrong args" do
83
- klass = Class.new do
84
- def self.inspect
85
- "MyClass"
86
- end
87
- end
88
-
89
- klass.should_receive(:bar).with(1)
90
- klass.bar(1)
91
-
92
- expect {
93
- klass.bar(2)
94
- }.to raise_error(RSpec::Mocks::MockExpectationError, /MyClass/)
33
+ spy = stub(_nil, :foobar)
34
+ _nil.foobar
35
+ expect(spy).to have_been_called
95
36
  end
96
37
  end
97
38
 
@@ -1,54 +1,47 @@
1
1
  require 'spec_helper'
2
2
 
3
- module RSpec
4
- module Mocks
5
-
6
- describe "only stashing the original method" do
7
- let(:klass) do
8
- Class.new do
9
- def self.foo(arg)
10
- :original_value
11
- end
3
+ module Spy
4
+ describe "only stashing the original method" do
5
+ let(:klass) do
6
+ Class.new do
7
+ def self.foo(arg)
8
+ :original_value
12
9
  end
13
10
  end
11
+ end
14
12
 
15
- it "keeps the original method intact after multiple expectations are added on the same method" do
16
- klass.should_receive(:foo).with(:fizbaz).and_return(:wowwow)
17
- klass.should_receive(:foo).with(:bazbar).and_return(:okay)
18
-
19
- klass.foo(:fizbaz)
20
- klass.foo(:bazbar)
21
- klass.rspec_verify
13
+ it "keeps the original method intact after multiple expectations are added on the same method" do
14
+ spy = Spy.on(klass, :foo)
15
+ klass.foo(:bazbar)
16
+ expect(spy).to have_been_called
17
+ Spy.off(klass, :foo)
22
18
 
23
- klass.rspec_reset
24
- expect(klass.foo(:yeah)).to equal(:original_value)
25
- end
19
+ expect(klass.foo(:yeah)).to equal(:original_value)
26
20
  end
21
+ end
27
22
 
28
- describe "when a class method is aliased on a subclass and the method is mocked" do
29
- let(:klass) do
30
- Class.new do
31
- class << self
32
- alias alternate_new new
33
- end
23
+ describe "when a class method is aliased on a subclass and the method is mocked" do
24
+ let(:klass) do
25
+ Class.new do
26
+ class << self
27
+ alias alternate_new new
34
28
  end
35
29
  end
30
+ end
36
31
 
37
- it "restores the original aliased public method" do
38
- klass = Class.new do
39
- class << self
40
- alias alternate_new new
41
- end
32
+ it "restores the original aliased public method" do
33
+ klass = Class.new do
34
+ class << self
35
+ alias alternate_new new
42
36
  end
37
+ end
43
38
 
44
- klass.should_receive(:alternate_new)
45
- expect(klass.alternate_new).to be_nil
46
-
47
- klass.rspec_verify
39
+ spy = Spy.on(klass, :alternate_new)
40
+ expect(klass.alternate_new).to be_nil
41
+ expect(spy).to have_been_called
48
42
 
49
- klass.rspec_reset
50
- expect(klass.alternate_new).to be_an_instance_of(klass)
51
- end
43
+ Spy.off(klass, :alternate_new)
44
+ expect(klass.alternate_new).to be_an_instance_of(klass)
52
45
  end
53
46
  end
54
47
  end
@@ -46,12 +46,6 @@ module RSpec
46
46
  expect(@class).to respond_to(:msg)
47
47
  end
48
48
 
49
- it "handles multiple stubbed methods" do
50
- Spy::Subroutine.new(@instance, :msg1 => 1, :msg2 => 2).hook(force: true)
51
- expect(@instance.msg1).to eq(1)
52
- expect(@instance.msg2).to eq(2)
53
- end
54
-
55
49
  it "yields a specified object" do
56
50
  Spy::Subroutine.new(@instance, :method_that_yields).hook(force: true).and_yield(:yielded_obj)
57
51
  current_value = :value_before
@@ -13,28 +13,28 @@ describe "a double receiving to_ary" do
13
13
  end
14
14
 
15
15
  it "can be overridden with a stub" do
16
- Spy.on(obj, :to_ary) { :non_nil_value }
16
+ Spy::Subroutine.new(obj, :to_ary).hook(force: true).and_return(:non_nil_value)
17
17
  expect(obj.to_ary).to be(:non_nil_value)
18
18
  end
19
19
 
20
20
  it "responds when overriden" do
21
- Spy.on(obj, :to_ary) { :non_nil_value }
21
+ Spy::Subroutine.new(obj, :to_ary).hook(force: true).and_return(:non_nil_value)
22
22
  expect(obj).to respond_to(:to_ary)
23
23
  end
24
24
 
25
25
  it "supports Array#flatten" do
26
- obj = double('foo')
26
+ obj = Spy.double('foo')
27
27
  expect([obj].flatten).to eq([obj])
28
28
  end
29
29
  end
30
30
 
31
31
  context "double as_null_object" do
32
- let(:obj) { double('obj').as_null_object }
32
+ let(:obj) { Spy.double('obj').as_null_object }
33
33
  include_examples "to_ary"
34
34
  end
35
35
 
36
36
  context "double without as_null_object" do
37
- let(:obj) { double('obj') }
37
+ let(:obj) { Spy.double('obj') }
38
38
  include_examples "to_ary"
39
39
  end
40
40
  end