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,56 @@
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
+
@@ -0,0 +1,107 @@
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 = 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
+ # 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)
27
+ end
28
+ end
29
+
30
+ describe "a double acting as a null object" do
31
+ before(:each) do
32
+ @double = double('null object').as_null_object
33
+ end
34
+
35
+ it "says it responds to everything" do
36
+ expect(@double).to respond_to(:any_message_it_gets)
37
+ end
38
+
39
+ it "allows explicit stubs" do
40
+ Spy.on(@double, :foo) { "bar" }
41
+ expect(@double.foo).to eq("bar")
42
+ end
43
+
44
+ it "allows explicit expectation" do
45
+ @double.should_receive(:something)
46
+ @double.something
47
+ end
48
+
49
+ it 'continues to return self from an explicit expectation' do
50
+ @double.should_receive(:bar)
51
+ expect(@double.foo.bar).to be(@double)
52
+ end
53
+
54
+ it 'returns an explicitly stubbed value from an expectation with no implementation' do
55
+ Spy.on(@double, :foo => "bar")
56
+ @double.should_receive(:foo)
57
+ 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)
82
+ end
83
+
84
+ it "can be interpolated in a string as an integer" do
85
+ # This form of string interpolation calls
86
+ # @double.to_int.to_int.to_int...etc until it gets an integer,
87
+ # and thus gets stuck in an infinite loop unless our double
88
+ # returns an int value from #to_int.
89
+ expect(("%i" % @double)).to eq("0")
90
+ end
91
+ end
92
+
93
+ describe "#as_null_object" do
94
+ it "sets the object to null_object" do
95
+ obj = double('anything').as_null_object
96
+ expect(obj).to be_null_object
97
+ end
98
+ end
99
+
100
+ describe "#null_object?" do
101
+ it "defaults to false" do
102
+ obj = double('anything')
103
+ expect(obj).not_to be_null_object
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ describe "calling :should_receive with an options hash" do
6
+ it "reports the file and line submitted with :expected_from" do
7
+ begin
8
+ mock = RSpec::Mocks::Mock.new("a mock")
9
+ mock.should_receive(:message, :expected_from => "/path/to/blah.ext:37")
10
+ mock.rspec_verify
11
+ rescue Exception => e
12
+ ensure
13
+ expect(e.backtrace.to_s).to match /\/path\/to\/blah.ext:37/m
14
+ end
15
+ end
16
+
17
+ it "uses the message supplied with :message" do
18
+ expect {
19
+ m = RSpec::Mocks::Mock.new("a mock")
20
+ m.should_receive(:message, :message => "recebi nada")
21
+ m.rspec_verify
22
+ }.to raise_error("recebi nada")
23
+ end
24
+
25
+ it "uses the message supplied with :message after a similar stub" do
26
+ expect {
27
+ m = RSpec::Mocks::Mock.new("a mock")
28
+ Spy.on(m, :message)
29
+ m.should_receive(:message, :message => "from mock")
30
+ m.rspec_verify
31
+ }.to raise_error("from mock")
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,196 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ describe "using a Partial Mock," do
6
+ let(:object) { Object.new }
7
+
8
+ it "names the class in the failure message" do
9
+ object.should_receive(:foo)
10
+ expect do
11
+ object.rspec_verify
12
+ end.to raise_error(RSpec::Mocks::MockExpectationError, /\(#<Object:.*>\).foo/)
13
+ end
14
+
15
+ it "names the class in the failure message when expectation is on class" do
16
+ Object.should_receive(:foo)
17
+ expect {
18
+ Object.rspec_verify
19
+ }.to raise_error(RSpec::Mocks::MockExpectationError, /<Object \(class\)>/)
20
+ end
21
+
22
+ it "does not conflict with @options in the object" do
23
+ object.instance_eval { @options = Object.new }
24
+ object.should_receive(:blah)
25
+ object.blah
26
+ end
27
+
28
+ it "should_not_receive mocks out the method" do
29
+ object.should_not_receive(:fuhbar)
30
+ expect {
31
+ object.fuhbar
32
+ }.to raise_error(
33
+ RSpec::Mocks::MockExpectationError,
34
+ /expected\: 0 times\n received\: 1 time/
35
+ )
36
+ end
37
+
38
+ it "should_not_receive returns a negative message expectation" do
39
+ expect(object.should_not_receive(:foobar)).to be_kind_of(RSpec::Mocks::NegativeMessageExpectation)
40
+ end
41
+
42
+ it "should_receive mocks out the method" do
43
+ object.should_receive(:foobar).with(:test_param).and_return(1)
44
+ expect(object.foobar(:test_param)).to equal(1)
45
+ end
46
+
47
+ it "should_receive handles a hash" do
48
+ object.should_receive(:foobar).with(:key => "value").and_return(1)
49
+ expect(object.foobar(:key => "value")).to equal(1)
50
+ end
51
+
52
+ it "should_receive handles an inner hash" do
53
+ hash = {:a => {:key => "value"}}
54
+ object.should_receive(:foobar).with(:key => "value").and_return(1)
55
+ expect(object.foobar(hash[:a])).to equal(1)
56
+ end
57
+
58
+ it "should_receive returns a message expectation" do
59
+ expect(object.should_receive(:foobar)).to be_kind_of(RSpec::Mocks::MessageExpectation)
60
+ object.foobar
61
+ end
62
+
63
+ it "should_receive verifies method was called" do
64
+ object.should_receive(:foobar).with(:test_param).and_return(1)
65
+ expect {
66
+ object.rspec_verify
67
+ }.to raise_error(RSpec::Mocks::MockExpectationError)
68
+ end
69
+
70
+ it "should_receive also takes a String argument" do
71
+ object.should_receive('foobar')
72
+ object.foobar
73
+ end
74
+
75
+ it "should_not_receive also takes a String argument" do
76
+ object.should_not_receive('foobar')
77
+ expect {
78
+ object.foobar
79
+ }.to raise_error(RSpec::Mocks::MockExpectationError)
80
+ end
81
+
82
+ it "uses reports nil in the error message" do
83
+ allow_message_expectations_on_nil
84
+
85
+ _nil = nil
86
+ _nil.should_receive(:foobar)
87
+ expect {
88
+ _nil.rspec_verify
89
+ }.to raise_error(
90
+ RSpec::Mocks::MockExpectationError,
91
+ %Q|(nil).foobar(any args)\n expected: 1 time\n received: 0 times|
92
+ )
93
+ end
94
+
95
+ it "includes the class name in the error when mocking a class method that is called an extra time with the wrong args" do
96
+ klass = Class.new do
97
+ def self.inspect
98
+ "MyClass"
99
+ end
100
+ end
101
+
102
+ klass.should_receive(:bar).with(1)
103
+ klass.bar(1)
104
+
105
+ expect {
106
+ klass.bar(2)
107
+ }.to raise_error(RSpec::Mocks::MockExpectationError, /MyClass/)
108
+ end
109
+ end
110
+
111
+ describe "Using a partial mock on a proxy object", :if => defined?(::BasicObject) do
112
+ let(:proxy_class) do
113
+ Class.new(::BasicObject) do
114
+ def initialize(target)
115
+ @target = target
116
+ end
117
+
118
+ def proxied?
119
+ true
120
+ end
121
+
122
+ def method_missing(*a)
123
+ @target.send(*a)
124
+ end
125
+ end
126
+ end
127
+
128
+ let(:instance) { proxy_class.new(Object.new) }
129
+
130
+ it 'works properly' do
131
+ instance.should_receive(:proxied?).and_return(false)
132
+ expect(instance).not_to be_proxied
133
+ end
134
+ end
135
+
136
+ describe "Partially mocking an object that defines ==, after another mock has been defined" do
137
+ before(:each) do
138
+ stub("existing mock", :foo => :foo)
139
+ end
140
+
141
+ let(:klass) do
142
+ Class.new do
143
+ attr_reader :val
144
+ def initialize(val)
145
+ @val = val
146
+ end
147
+
148
+ def ==(other)
149
+ @val == other.val
150
+ end
151
+ end
152
+ end
153
+
154
+ it "does not raise an error when stubbing the object" do
155
+ o = klass.new :foo
156
+ expect { Spy.on(o, :bar) }.not_to raise_error(NoMethodError)
157
+ end
158
+ end
159
+
160
+ describe "Method visibility when using partial mocks" do
161
+ let(:klass) do
162
+ Class.new do
163
+ def public_method
164
+ private_method
165
+ protected_method
166
+ end
167
+ protected
168
+ def protected_method; end
169
+ private
170
+ def private_method; end
171
+ end
172
+ end
173
+
174
+ let(:object) { klass.new }
175
+
176
+ it 'keeps public methods public' do
177
+ object.should_receive(:public_method)
178
+ expect(object.public_methods).to include_method(:public_method)
179
+ object.public_method
180
+ end
181
+
182
+ it 'keeps private methods private' do
183
+ object.should_receive(:private_method)
184
+ expect(object.private_methods).to include_method(:private_method)
185
+ object.public_method
186
+ end
187
+
188
+ it 'keeps protected methods protected' do
189
+ object.should_receive(:protected_method)
190
+ expect(object.protected_methods).to include_method(:protected_method)
191
+ object.public_method
192
+ end
193
+
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ describe Methods, :broken do
6
+ before(:each) do
7
+ @double = double('double')
8
+ Spy.on(Kernel, :warn)
9
+ end
10
+
11
+ after(:each) do
12
+ @double.rspec_verify
13
+ end
14
+
15
+ context "handling argument matchers" do
16
+ it "accepts true as boolean()" do
17
+ @double.should_receive(:random_call).with(boolean())
18
+ @double.random_call(true)
19
+ end
20
+
21
+ it "accepts false as boolean()" do
22
+ @double.should_receive(:random_call).with(boolean())
23
+ @double.random_call(false)
24
+ end
25
+
26
+ it "accepts fixnum as kind_of(Numeric)" do
27
+ @double.should_receive(:random_call).with(kind_of(Numeric))
28
+ @double.random_call(1)
29
+ end
30
+
31
+ it "accepts float as an_instance_of(Numeric)" do
32
+ @double.should_receive(:random_call).with(kind_of(Numeric))
33
+ @double.random_call(1.5)
34
+ end
35
+
36
+ it "accepts fixnum as instance_of(Fixnum)" do
37
+ @double.should_receive(:random_call).with(instance_of(Fixnum))
38
+ @double.random_call(1)
39
+ end
40
+
41
+ it "does NOT accept fixnum as instance_of(Numeric)" do
42
+ @double.should_not_receive(:random_call).with(instance_of(Numeric))
43
+ @double.random_call(1)
44
+ end
45
+
46
+ it "does NOT accept float as instance_of(Numeric)" do
47
+ @double.should_not_receive(:random_call).with(instance_of(Numeric))
48
+ @double.random_call(1.5)
49
+ end
50
+
51
+ it "accepts string as anything()" do
52
+ @double.should_receive(:random_call).with("a", anything(), "c")
53
+ @double.random_call("a", "whatever", "c")
54
+ end
55
+
56
+ it "matches duck type with one method" do
57
+ @double.should_receive(:random_call).with(duck_type(:length))
58
+ @double.random_call([])
59
+ end
60
+
61
+ it "matches duck type with two methods" do
62
+ @double.should_receive(:random_call).with(duck_type(:abs, :div))
63
+ @double.random_call(1)
64
+ end
65
+
66
+ it "matches no args against any_args()" do
67
+ @double.should_receive(:random_call).with(any_args)
68
+ @double.random_call()
69
+ end
70
+
71
+ it "matches one arg against any_args()" do
72
+ @double.should_receive(:random_call).with(any_args)
73
+ @double.random_call("a string")
74
+ end
75
+
76
+ it "matches no args against no_args()" do
77
+ @double.should_receive(:random_call).with(no_args)
78
+ @double.random_call()
79
+ end
80
+
81
+ it "matches hash with hash_including same hash" do
82
+ @double.should_receive(:random_call).with(hash_including(:a => 1))
83
+ @double.random_call(:a => 1)
84
+ end
85
+ end
86
+
87
+ context "handling block matchers" do
88
+ it "matches arguments against RSpec expectations" do
89
+ @double.should_receive(:random_call).with {|arg1, arg2, arr, *rest|
90
+ expect(arg1).to eq 5
91
+ expect(arg2).to have_at_least(3).characters
92
+ expect(arg2).to have_at_most(10).characters
93
+ expect(arr.map {|i| i * 2}).to eq [2,4,6]
94
+ expect(rest).to eq [:fee, "fi", 4]
95
+ }
96
+ @double.random_call 5, "hello", [1,2,3], :fee, "fi", 4
97
+ end
98
+
99
+ it "does not eval the block as the return value" do
100
+ eval_count = 0
101
+ @double.should_receive(:msg).with {|a| eval_count += 1}
102
+ @double.msg(:ignore)
103
+ expect(eval_count).to eq(1)
104
+ end
105
+ end
106
+
107
+ context "handling non-matcher arguments" do
108
+ it "matches non special symbol (can be removed when deprecated symbols are removed)" do
109
+ @double.should_receive(:random_call).with(:some_symbol)
110
+ @double.random_call(:some_symbol)
111
+ end
112
+
113
+ it "matches string against regexp" do
114
+ @double.should_receive(:random_call).with(/bcd/)
115
+ @double.random_call("abcde")
116
+ end
117
+
118
+ it "matches regexp against regexp" do
119
+ @double.should_receive(:random_call).with(/bcd/)
120
+ @double.random_call(/bcd/)
121
+ end
122
+
123
+ it "matches against a hash submitted and received by value" do
124
+ @double.should_receive(:random_call).with(:a => "a", :b => "b")
125
+ @double.random_call(:a => "a", :b => "b")
126
+ end
127
+
128
+ it "matches against a hash submitted by reference and received by value" do
129
+ opts = {:a => "a", :b => "b"}
130
+ @double.should_receive(:random_call).with(opts)
131
+ @double.random_call(:a => "a", :b => "b")
132
+ end
133
+
134
+ it "matches against a hash submitted by value and received by reference" do
135
+ opts = {:a => "a", :b => "b"}
136
+ @double.should_receive(:random_call).with(:a => "a", :b => "b")
137
+ @double.random_call(opts)
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end