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,21 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ describe 'Calling a method that catches StandardError' do
6
+ class Foo
7
+ def self.foo
8
+ bar
9
+ rescue StandardError
10
+ end
11
+ end
12
+
13
+ it 'still reports mock failures' do
14
+ Foo.should_not_receive :bar
15
+ expect {
16
+ Foo.foo
17
+ }.to raise_error(RSpec::Mocks::MockExpectationError)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ describe "stubbing a base class class method" do
6
+ before do
7
+ @base_class = Class.new
8
+ @concrete_class = Class.new(@base_class)
9
+
10
+ Spy.stub(@base_class, :find).and_return "stubbed_value"
11
+ end
12
+
13
+ it "returns the value for the stub on the base class" do
14
+ expect(@base_class.find).to eq "stubbed_value"
15
+ end
16
+
17
+ it "returns the value for the descendent class" do
18
+ expect(@concrete_class.find).to eq "stubbed_value"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ require "spec_helper"
2
+
3
+ describe "double" do
4
+ it "is an alias for stub and mock" do
5
+ expect(double()).to be_a(RSpec::Mocks::Mock)
6
+ end
7
+
8
+ it "uses 'Double' in failure messages" do
9
+ double = double('name')
10
+ expect {double.foo}.to raise_error(/Double "name" received/)
11
+ end
12
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ describe "failing MockArgumentMatchers" do
6
+ before(:each) do
7
+ @double = double("double")
8
+ @reporter = double("reporter").as_null_object
9
+ end
10
+
11
+ after(:each) do
12
+ @double.rspec_reset
13
+ end
14
+
15
+ it "rejects non boolean" do
16
+ @double.should_receive(:random_call).with(boolean())
17
+ expect do
18
+ @double.random_call("false")
19
+ end.to raise_error(RSpec::Mocks::MockExpectationError)
20
+ end
21
+
22
+ it "rejects non numeric" do
23
+ @double.should_receive(:random_call).with(an_instance_of(Numeric))
24
+ expect do
25
+ @double.random_call("1")
26
+ end.to raise_error(RSpec::Mocks::MockExpectationError)
27
+ end
28
+
29
+ it "rejects non string" do
30
+ @double.should_receive(:random_call).with(an_instance_of(String))
31
+ expect do
32
+ @double.random_call(123)
33
+ end.to raise_error(RSpec::Mocks::MockExpectationError)
34
+ end
35
+
36
+ it "rejects goose when expecting a duck" do
37
+ @double.should_receive(:random_call).with(duck_type(:abs, :div))
38
+ expect { @double.random_call("I don't respond to :abs or :div") }.to raise_error(RSpec::Mocks::MockExpectationError)
39
+ end
40
+
41
+ it "fails if regexp does not match submitted string" do
42
+ @double.should_receive(:random_call).with(/bcd/)
43
+ expect { @double.random_call("abc") }.to raise_error(RSpec::Mocks::MockExpectationError)
44
+ end
45
+
46
+ it "fails if regexp does not match submitted regexp" do
47
+ @double.should_receive(:random_call).with(/bcd/)
48
+ expect { @double.random_call(/bcde/) }.to raise_error(RSpec::Mocks::MockExpectationError)
49
+ end
50
+
51
+ it "fails for a hash w/ wrong values" do
52
+ @double.should_receive(:random_call).with(:a => "b", :c => "d")
53
+ expect do
54
+ @double.random_call(:a => "b", :c => "e")
55
+ end.to raise_error(RSpec::Mocks::MockExpectationError, /Double "double" received :random_call with unexpected arguments\n expected: \(\{(:a=>\"b\", :c=>\"d\"|:c=>\"d\", :a=>\"b\")\}\)\n got: \(\{(:a=>\"b\", :c=>\"e\"|:c=>\"e\", :a=>\"b\")\}\)/)
56
+ end
57
+
58
+ it "fails for a hash w/ wrong keys" do
59
+ @double.should_receive(:random_call).with(:a => "b", :c => "d")
60
+ expect do
61
+ @double.random_call("a" => "b", "c" => "d")
62
+ end.to raise_error(RSpec::Mocks::MockExpectationError, /Double "double" received :random_call with unexpected arguments\n expected: \(\{(:a=>\"b\", :c=>\"d\"|:c=>\"d\", :a=>\"b\")\}\)\n got: \(\{(\"a\"=>\"b\", \"c\"=>\"d\"|\"c\"=>\"d\", \"a\"=>\"b\")\}\)/)
63
+ end
64
+
65
+ it "matches against a Matcher" do
66
+ expect do
67
+ @double.should_receive(:msg).with(equal(3))
68
+ @double.msg(37)
69
+ end.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"double\" received :msg with unexpected arguments\n expected: (equal 3)\n got: (37)")
70
+ end
71
+
72
+ it "fails no_args with one arg" do
73
+ expect do
74
+ @double.should_receive(:msg).with(no_args)
75
+ @double.msg(37)
76
+ end.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"double\" received :msg with unexpected arguments\n expected: (no args)\n got: (37)")
77
+ end
78
+
79
+ it "fails hash_including with missing key" do
80
+ expect do
81
+ @double.should_receive(:msg).with(hash_including(:a => 1))
82
+ @double.msg({})
83
+ end.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"double\" received :msg with unexpected arguments\n expected: (hash_including(:a=>1))\n got: ({})")
84
+ end
85
+
86
+ it "fails with block matchers" do
87
+ expect do
88
+ @double.should_receive(:msg).with {|arg| expect(arg).to eq :received }
89
+ @double.msg :no_msg_for_you
90
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected: :received.*\s*.*got: :no_msg_for_you/)
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ module ArgumentMatchers
6
+ describe HashExcludingMatcher do
7
+
8
+ it "describes itself properly" do
9
+ expect(HashExcludingMatcher.new(:a => 5).description).to eq "hash_not_including(:a=>5)"
10
+ end
11
+
12
+ describe "passing" do
13
+ it "matches a hash without the specified key" do
14
+ expect(hash_not_including(:c)).to eq({:a => 1, :b => 2})
15
+ end
16
+
17
+ it "matches a hash with the specified key, but different value" do
18
+ expect(hash_not_including(:b => 3)).to eq({:a => 1, :b => 2})
19
+ end
20
+
21
+ it "matches a hash without the specified key, given as anything()" do
22
+ expect(hash_not_including(:c => anything)).to eq({:a => 1, :b => 2})
23
+ end
24
+
25
+ it "matches an empty hash" do
26
+ expect(hash_not_including(:a)).to eq({})
27
+ end
28
+
29
+ it "matches a hash without any of the specified keys" do
30
+ expect(hash_not_including(:a, :b, :c)).to eq(:d => 7)
31
+ end
32
+
33
+ end
34
+
35
+ describe "failing" do
36
+ it "does not match a non-hash" do
37
+ expect(hash_not_including(:a => 1)).not_to eq 1
38
+ end
39
+
40
+ it "does not match a hash with a specified key" do
41
+ expect(hash_not_including(:b)).not_to eq(:b => 2)
42
+ end
43
+
44
+ it "does not match a hash with the specified key/value pair" do
45
+ expect(hash_not_including(:b => 2)).not_to eq(:a => 1, :b => 2)
46
+ end
47
+
48
+ it "does not match a hash with the specified key" do
49
+ expect(hash_not_including(:a, :b => 3)).not_to eq(:a => 1, :b => 2)
50
+ end
51
+
52
+ it "does not match a hash with one of the specified keys" do
53
+ expect(hash_not_including(:a, :b)).not_to eq(:b => 2)
54
+ end
55
+
56
+ it "does not match a hash with some of the specified keys" do
57
+ expect(hash_not_including(:a, :b, :c)).not_to eq(:a => 1, :b => 2)
58
+ end
59
+
60
+ it "does not match a hash with one key/value pair included" do
61
+ expect(hash_not_including(:a, :b, :c, :d => 7)).not_to eq(:d => 7)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ module ArgumentMatchers
6
+ describe HashIncludingMatcher do
7
+
8
+ it "describes itself properly" do
9
+ expect(HashIncludingMatcher.new(:a => 1).description).to eq "hash_including(:a=>1)"
10
+ end
11
+
12
+ describe "passing" do
13
+ it "matches the same hash" do
14
+ expect(hash_including(:a => 1)).to eq({:a => 1})
15
+ end
16
+
17
+ it "matches a hash with extra stuff" do
18
+ expect(hash_including(:a => 1)).to eq({:a => 1, :b => 2})
19
+ end
20
+
21
+ describe "when matching against other matchers" do
22
+ it "matches an int against anything()" do
23
+ expect(hash_including(:a => anything, :b => 2)).to eq({:a => 1, :b => 2})
24
+ end
25
+
26
+ it "matches a string against anything()" do
27
+ expect(hash_including(:a => anything, :b => 2)).to eq({:a => "1", :b => 2})
28
+ end
29
+ end
30
+
31
+ describe "when passed only keys or keys mixed with key/value pairs" do
32
+ it "matches if the key is present" do
33
+ expect(hash_including(:a)).to eq({:a => 1, :b => 2})
34
+ end
35
+
36
+ it "matches if more keys are present" do
37
+ expect(hash_including(:a, :b)).to eq({:a => 1, :b => 2, :c => 3})
38
+ end
39
+
40
+ it "matches a string against a given key" do
41
+ expect(hash_including(:a)).to eq({:a => "1", :b => 2})
42
+ end
43
+
44
+ it "matches if passed one key and one key/value pair" do
45
+ expect(hash_including(:a, :b => 2)).to eq({:a => 1, :b => 2})
46
+ end
47
+
48
+ it "matches if passed many keys and one key/value pair" do
49
+ expect(hash_including(:a, :b, :c => 3)).to eq({:a => 1, :b => 2, :c => 3, :d => 4})
50
+ end
51
+
52
+ it "matches if passed many keys and many key/value pairs" do
53
+ expect(hash_including(:a, :b, :c => 3, :e => 5)).to eq({:a => 1, :b => 2, :c => 3, :d => 4, :e => 5})
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "failing" do
59
+ it "does not match a non-hash" do
60
+ expect(hash_including(:a => 1)).not_to eq 1
61
+ end
62
+
63
+ it "does not match a hash with a missing key" do
64
+ expect(hash_including(:a => 1)).not_to eq(:b => 2)
65
+ end
66
+
67
+ it "does not match a hash with a missing key" do
68
+ expect(hash_including(:a)).not_to eq(:b => 2)
69
+ end
70
+
71
+ it "does not match an empty hash with a given key" do
72
+ expect(hash_including(:a)).not_to eq({})
73
+ end
74
+
75
+ it "does not match a hash with a missing key when one pair is matching" do
76
+ expect(hash_including(:a, :b => 2)).not_to eq(:b => 2)
77
+ end
78
+
79
+ it "does not match a hash with an incorrect value" do
80
+ expect(hash_including(:a => 1, :b => 2)).not_to eq(:a => 1, :b => 3)
81
+ end
82
+
83
+ it "does not match when values are nil but keys are different" do
84
+ expect(hash_including(:a => nil)).not_to eq(:b => nil)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,734 @@
1
+ require 'spec_helper'
2
+
3
+ module RSpec
4
+ module Mocks
5
+ describe Mock do
6
+ before(:each) { @double = double("test double") }
7
+ after(:each) { @double.rspec_reset }
8
+
9
+ it "has method_missing as private" do
10
+ expect(RSpec::Mocks::Mock.private_instance_methods).to include_method(:method_missing)
11
+ end
12
+
13
+ it "does not respond_to? method_missing (because it's private)" do
14
+ expect(RSpec::Mocks::Mock.new).not_to respond_to(:method_missing)
15
+ end
16
+
17
+ it "reports line number of expectation of unreceived message" do
18
+ expected_error_line = __LINE__; @double.should_receive(:wont_happen).with("x", 3)
19
+ begin
20
+ @double.rspec_verify
21
+ violated
22
+ rescue RSpec::Mocks::MockExpectationError => e
23
+ # NOTE - this regexp ended w/ $, but jruby adds extra info at the end of the line
24
+ expect(e.backtrace[0]).to match(/#{File.basename(__FILE__)}:#{expected_error_line}/)
25
+ end
26
+ end
27
+
28
+ it "reports line number of expectation of unreceived message after #should_receive after similar stub" do
29
+ Spy.on(@double, :wont_happen)
30
+ expected_error_line = __LINE__; @double.should_receive(:wont_happen).with("x", 3)
31
+ begin
32
+ @double.rspec_verify
33
+ violated
34
+ rescue RSpec::Mocks::MockExpectationError => e
35
+ # NOTE - this regexp ended w/ $, but jruby adds extra info at the end of the line
36
+ expect(e.backtrace[0]).to match(/#{File.basename(__FILE__)}:#{expected_error_line}/)
37
+ end
38
+ end
39
+
40
+ it "passes when not receiving message specified as not to be received" do
41
+ @double.should_not_receive(:not_expected)
42
+ @double.rspec_verify
43
+ end
44
+
45
+ it "warns when should_not_receive is followed by and_return" do
46
+ RSpec::Mocks.should_receive(:warn_deprecation).
47
+ with(/`and_return` with `should_not_receive` is deprecated/)
48
+
49
+ @double.should_not_receive(:do_something).and_return(1)
50
+ end
51
+
52
+ it "passes when receiving message specified as not to be received with different args" do
53
+ @double.should_not_receive(:message).with("unwanted text")
54
+ @double.should_receive(:message).with("other text")
55
+ @double.message "other text"
56
+ @double.rspec_verify
57
+ end
58
+
59
+ it "fails when receiving message specified as not to be received" do
60
+ @double.should_not_receive(:not_expected)
61
+ expect {
62
+ @double.not_expected
63
+ violated
64
+ }.to raise_error(
65
+ RSpec::Mocks::MockExpectationError,
66
+ %Q|(Double "test double").not_expected(no args)\n expected: 0 times\n received: 1 time|
67
+ )
68
+ end
69
+
70
+ it "fails when receiving message specified as not to be received with args" do
71
+ @double.should_not_receive(:not_expected).with("unexpected text")
72
+ expect {
73
+ @double.not_expected("unexpected text")
74
+ violated
75
+ }.to raise_error(
76
+ RSpec::Mocks::MockExpectationError,
77
+ %Q|(Double "test double").not_expected("unexpected text")\n expected: 0 times\n received: 1 time|
78
+ )
79
+ end
80
+
81
+ it "passes when receiving message specified as not to be received with wrong args" do
82
+ @double.should_not_receive(:not_expected).with("unexpected text")
83
+ @double.not_expected "really unexpected text"
84
+ @double.rspec_verify
85
+ end
86
+
87
+ it "allows block to calculate return values" do
88
+ @double.should_receive(:something).with("a","b","c").and_return { |a,b,c| c+b+a }
89
+ expect(@double.something("a","b","c")).to eq "cba"
90
+ @double.rspec_verify
91
+ end
92
+
93
+ it "allows parameter as return value" do
94
+ @double.should_receive(:something).with("a","b","c").and_return("booh")
95
+ expect(@double.something("a","b","c")).to eq "booh"
96
+ @double.rspec_verify
97
+ end
98
+
99
+ it "returns the previously stubbed value if no return value is set" do
100
+ Spy.on(@double, :something).with("a","b","c").and_return(:stubbed_value)
101
+ @double.should_receive(:something).with("a","b","c")
102
+ expect(@double.something("a","b","c")).to eq :stubbed_value
103
+ @double.rspec_verify
104
+ end
105
+
106
+ it "returns nil if no return value is set and there is no previously stubbed value" do
107
+ @double.should_receive(:something).with("a","b","c")
108
+ expect(@double.something("a","b","c")).to be_nil
109
+ @double.rspec_verify
110
+ end
111
+
112
+ it "raises exception if args don't match when method called" do
113
+ @double.should_receive(:something).with("a","b","c").and_return("booh")
114
+ expect {
115
+ @double.something("a","d","c")
116
+ violated
117
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
118
+ end
119
+
120
+ describe "even when a similar expectation with different arguments exist" do
121
+ it "raises exception if args don't match when method called, correctly reporting the offending arguments" do
122
+ @double.should_receive(:something).with("a","b","c").once
123
+ @double.should_receive(:something).with("z","x","c").once
124
+ expect {
125
+ @double.something("a","b","c")
126
+ @double.something("z","x","g")
127
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"z\", \"x\", \"c\")\n got: (\"z\", \"x\", \"g\")")
128
+ end
129
+ end
130
+
131
+ it "raises exception if args don't match when method called even when the method is stubbed" do
132
+ Spy.on(@double, :something)
133
+ @double.should_receive(:something).with("a","b","c")
134
+ expect {
135
+ @double.something("a","d","c")
136
+ @double.rspec_verify
137
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
138
+ end
139
+
140
+ it "raises exception if args don't match when method called even when using null_object" do
141
+ @double = double("test double").as_null_object
142
+ @double.should_receive(:something).with("a","b","c")
143
+ expect {
144
+ @double.something("a","d","c")
145
+ @double.rspec_verify
146
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
147
+ end
148
+
149
+ describe 'with a method that has a default argument' do
150
+ it "raises an exception if the arguments don't match when the method is called, correctly reporting the offending arguments" do
151
+ def @double.method_with_default_argument(arg={}); end
152
+ @double.should_receive(:method_with_default_argument).with({})
153
+
154
+ expect {
155
+ @double.method_with_default_argument(nil)
156
+ @double.rspec_verify
157
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :method_with_default_argument with unexpected arguments\n expected: ({})\n got: (nil)")
158
+ end
159
+ end
160
+
161
+ it "fails if unexpected method called" do
162
+ expect {
163
+ @double.something("a","b","c")
164
+ violated
165
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received unexpected message :something with (\"a\", \"b\", \"c\")")
166
+ end
167
+
168
+ it "uses block for expectation if provided" do
169
+ @double.should_receive(:something) do | a, b |
170
+ expect(a).to eq "a"
171
+ expect(b).to eq "b"
172
+ "booh"
173
+ end
174
+ expect(@double.something("a", "b")).to eq "booh"
175
+ @double.rspec_verify
176
+ end
177
+
178
+ it "fails if expectation block fails" do
179
+ @double.should_receive(:something) do |bool|
180
+ expect(bool).to be_true
181
+ end
182
+
183
+ expect {
184
+ @double.something false
185
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
186
+ end
187
+
188
+ context "with Ruby > 1.8.6", :unless => RUBY_VERSION.to_s == '1.8.6' do
189
+ it "passes proc to expectation block without an argument" do
190
+ # We eval this because Ruby 1.8.6's syntax parser barfs on { |&block| ... }
191
+ # and prevents the entire spec suite from running.
192
+ eval("@double.should_receive(:foo) {|&block| expect(block.call).to eq(:bar)}")
193
+ @double.foo { :bar }
194
+ end
195
+
196
+ it "passes proc to expectation block with an argument" do
197
+ eval("@double.should_receive(:foo) {|arg, &block| expect(block.call).to eq(:bar)}")
198
+ @double.foo(:arg) { :bar }
199
+ end
200
+
201
+ it "passes proc to stub block without an argurment" do
202
+ eval("Spy.on(@double, :foo) {|&block| expect(block.call).to eq(:bar)}")
203
+ @double.foo { :bar }
204
+ end
205
+
206
+ it "passes proc to stub block with an argument" do
207
+ eval("Spy.on(@double, :foo) {|arg, &block| expect(block.call).to eq(:bar)}")
208
+ @double.foo(:arg) { :bar }
209
+ end
210
+ end
211
+
212
+ it "fails right away when method defined as never is received" do
213
+ @double.should_receive(:not_expected).never
214
+ expect { @double.not_expected }.
215
+ to raise_error(RSpec::Mocks::MockExpectationError,
216
+ %Q|(Double "test double").not_expected(no args)\n expected: 0 times\n received: 1 time|
217
+ )
218
+ end
219
+
220
+ it "raises RuntimeError by default" do
221
+ @double.should_receive(:something).and_raise
222
+ expect { @double.something }.to raise_error(RuntimeError)
223
+ end
224
+
225
+ it "raises RuntimeError with a message by default" do
226
+ @double.should_receive(:something).and_raise("error message")
227
+ expect { @double.something }.to raise_error(RuntimeError, "error message")
228
+ end
229
+
230
+ it "raises an exception of a given type without an error message" do
231
+ @double.should_receive(:something).and_raise(StandardError)
232
+ expect { @double.something }.to raise_error(StandardError)
233
+ end
234
+
235
+ it "raises an exception of a given type with a message" do
236
+ @double.should_receive(:something).and_raise(RuntimeError, "error message")
237
+ expect { @double.something }.to raise_error(RuntimeError, "error message")
238
+ end
239
+
240
+ it "raises a given instance of an exception" do
241
+ @double.should_receive(:something).and_raise(RuntimeError.new("error message"))
242
+ expect { @double.something }.to raise_error(RuntimeError, "error message")
243
+ end
244
+
245
+ class OutOfGas < StandardError
246
+ attr_reader :amount, :units
247
+ def initialize(amount, units)
248
+ @amount = amount
249
+ @units = units
250
+ end
251
+ end
252
+
253
+ it "raises a given instance of an exception with arguments other than the standard 'message'" do
254
+ @double.should_receive(:something).and_raise(OutOfGas.new(2, :oz))
255
+
256
+ begin
257
+ @double.something
258
+ fail "OutOfGas was not raised"
259
+ rescue OutOfGas => e
260
+ expect(e.amount).to eq 2
261
+ expect(e.units).to eq :oz
262
+ end
263
+ end
264
+
265
+ it "does not raise when told to if args dont match" do
266
+ @double.should_receive(:something).with(2).and_raise(RuntimeError)
267
+ expect {
268
+ @double.something 1
269
+ }.to raise_error(RSpec::Mocks::MockExpectationError)
270
+ end
271
+
272
+ it "throws when told to" do
273
+ @double.should_receive(:something).and_throw(:blech)
274
+ expect {
275
+ @double.something
276
+ }.to throw_symbol(:blech)
277
+ end
278
+
279
+ it "ignores args on any args" do
280
+ @double.should_receive(:something).at_least(:once).with(any_args)
281
+ @double.something
282
+ @double.something 1
283
+ @double.something "a", 2
284
+ @double.something [], {}, "joe", 7
285
+ @double.rspec_verify
286
+ end
287
+
288
+ it "fails on no args if any args received" do
289
+ @double.should_receive(:something).with(no_args())
290
+ expect {
291
+ @double.something 1
292
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (no args)\n got: (1)")
293
+ end
294
+
295
+ it "fails when args are expected but none are received" do
296
+ @double.should_receive(:something).with(1)
297
+ expect {
298
+ @double.something
299
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (1)\n got: (no args)")
300
+ end
301
+
302
+ it "returns value from block by default" do
303
+ Spy.on(@double, :method_that_yields).and_yield
304
+ value = @double.method_that_yields { :returned_obj }
305
+ expect(value).to eq :returned_obj
306
+ @double.rspec_verify
307
+ end
308
+
309
+ it "yields 0 args to blocks that take a variable number of arguments" do
310
+ @double.should_receive(:yield_back).with(no_args()).once.and_yield
311
+ a = nil
312
+ @double.yield_back {|*x| a = x}
313
+ expect(a).to eq []
314
+ @double.rspec_verify
315
+ end
316
+
317
+ it "yields 0 args multiple times to blocks that take a variable number of arguments" do
318
+ @double.should_receive(:yield_back).once.with(no_args()).once.and_yield.
319
+ and_yield
320
+ b = []
321
+ @double.yield_back {|*a| b << a}
322
+ expect(b).to eq [ [], [] ]
323
+ @double.rspec_verify
324
+ end
325
+
326
+ it "yields one arg to blocks that take a variable number of arguments" do
327
+ @double.should_receive(:yield_back).with(no_args()).once.and_yield(99)
328
+ a = nil
329
+ @double.yield_back {|*x| a = x}
330
+ expect(a).to eq [99]
331
+ @double.rspec_verify
332
+ end
333
+
334
+ it "yields one arg 3 times consecutively to blocks that take a variable number of arguments" do
335
+ @double.should_receive(:yield_back).once.with(no_args()).once.and_yield(99).
336
+ and_yield(43).
337
+ and_yield("something fruity")
338
+ b = []
339
+ @double.yield_back {|*a| b << a}
340
+ expect(b).to eq [[99], [43], ["something fruity"]]
341
+ @double.rspec_verify
342
+ end
343
+
344
+ it "yields many args to blocks that take a variable number of arguments" do
345
+ @double.should_receive(:yield_back).with(no_args()).once.and_yield(99, 27, "go")
346
+ a = nil
347
+ @double.yield_back {|*x| a = x}
348
+ expect(a).to eq [99, 27, "go"]
349
+ @double.rspec_verify
350
+ end
351
+
352
+ it "yields many args 3 times consecutively to blocks that take a variable number of arguments" do
353
+ @double.should_receive(:yield_back).once.with(no_args()).once.and_yield(99, :green, "go").
354
+ and_yield("wait", :amber).
355
+ and_yield("stop", 12, :red)
356
+ b = []
357
+ @double.yield_back {|*a| b << a}
358
+ expect(b).to eq [[99, :green, "go"], ["wait", :amber], ["stop", 12, :red]]
359
+ @double.rspec_verify
360
+ end
361
+
362
+ it "yields single value" do
363
+ @double.should_receive(:yield_back).with(no_args()).once.and_yield(99)
364
+ a = nil
365
+ @double.yield_back {|x| a = x}
366
+ expect(a).to eq 99
367
+ @double.rspec_verify
368
+ end
369
+
370
+ it "yields single value 3 times consecutively" do
371
+ @double.should_receive(:yield_back).once.with(no_args()).once.and_yield(99).
372
+ and_yield(43).
373
+ and_yield("something fruity")
374
+ b = []
375
+ @double.yield_back {|a| b << a}
376
+ expect(b).to eq [99, 43, "something fruity"]
377
+ @double.rspec_verify
378
+ end
379
+
380
+ it "yields two values" do
381
+ @double.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
382
+ a, b = nil
383
+ @double.yield_back {|x,y| a=x; b=y}
384
+ expect(a).to eq 'wha'
385
+ expect(b).to eq 'zup'
386
+ @double.rspec_verify
387
+ end
388
+
389
+ it "yields two values 3 times consecutively" do
390
+ @double.should_receive(:yield_back).once.with(no_args()).once.and_yield('wha', 'zup').
391
+ and_yield('not', 'down').
392
+ and_yield(14, 65)
393
+ c = []
394
+ @double.yield_back {|a,b| c << [a, b]}
395
+ expect(c).to eq [['wha', 'zup'], ['not', 'down'], [14, 65]]
396
+ @double.rspec_verify
397
+ end
398
+
399
+ it "fails when calling yielding method with wrong arity" do
400
+ @double.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
401
+ expect {
402
+ @double.yield_back {|a|}
403
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" yielded |\"wha\", \"zup\"| to block with arity of 1")
404
+ end
405
+
406
+ it "fails when calling yielding method consecutively with wrong arity" do
407
+ @double.should_receive(:yield_back).once.with(no_args()).once.and_yield('wha', 'zup').
408
+ and_yield('down').
409
+ and_yield(14, 65)
410
+ expect {
411
+ c = []
412
+ @double.yield_back {|a,b| c << [a, b]}
413
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" yielded |\"down\"| to block with arity of 2")
414
+ end
415
+
416
+ it "fails when calling yielding method without block" do
417
+ @double.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
418
+ expect {
419
+ @double.yield_back
420
+ }.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" asked to yield |[\"wha\", \"zup\"]| but no block was passed")
421
+ end
422
+
423
+ it "is able to double send" do
424
+ @double.should_receive(:send).with(any_args)
425
+ @double.send 'hi'
426
+ @double.rspec_verify
427
+ end
428
+
429
+ it "is able to raise from method calling yielding double" do
430
+ @double.should_receive(:yield_me).and_yield 44
431
+
432
+ expect {
433
+ @double.yield_me do |x|
434
+ raise "Bang"
435
+ end
436
+ }.to raise_error(StandardError, "Bang")
437
+
438
+ @double.rspec_verify
439
+ end
440
+
441
+ it "clears expectations after verify" do
442
+ @double.should_receive(:foobar)
443
+ @double.foobar
444
+ @double.rspec_verify
445
+ expect {
446
+ @double.foobar
447
+ }.to raise_error(RSpec::Mocks::MockExpectationError, %q|Double "test double" received unexpected message :foobar with (no args)|)
448
+ end
449
+
450
+ it "restores objects to their original state on rspec_reset" do
451
+ double = double("this is a double")
452
+ double.should_receive(:blah)
453
+ double.rspec_reset
454
+ double.rspec_verify #should throw if reset didn't work
455
+ end
456
+
457
+ it "works even after method_missing starts raising NameErrors instead of NoMethodErrors" do
458
+ # Object#method_missing throws either NameErrors or NoMethodErrors.
459
+ #
460
+ # On a fresh ruby program Object#method_missing:
461
+ # * raises a NoMethodError when called directly
462
+ # * raises a NameError when called indirectly
463
+ #
464
+ # Once Object#method_missing has been called at least once (on any object)
465
+ # it starts behaving differently:
466
+ # * raises a NameError when called directly
467
+ # * raises a NameError when called indirectly
468
+ #
469
+ # There was a bug in Mock#method_missing that relied on the fact
470
+ # that calling Object#method_missing directly raises a NoMethodError.
471
+ # This example tests that the bug doesn't exist anymore.
472
+
473
+
474
+ # Ensures that method_missing always raises NameErrors.
475
+ a_method_that_doesnt_exist rescue
476
+
477
+
478
+ @double.should_receive(:foobar)
479
+ @double.foobar
480
+ @double.rspec_verify
481
+
482
+ expect { @double.foobar }.to_not raise_error(NameError)
483
+ expect { @double.foobar }.to raise_error(RSpec::Mocks::MockExpectationError)
484
+ end
485
+
486
+ it "temporarily replaces a method stub on a double" do
487
+ Spy.on(@double, :msg).and_return(:stub_value)
488
+ @double.should_receive(:msg).with(:arg).and_return(:double_value)
489
+ expect(@double.msg(:arg)).to equal(:double_value)
490
+ expect(@double.msg).to equal(:stub_value)
491
+ expect(@double.msg).to equal(:stub_value)
492
+ @double.rspec_verify
493
+ end
494
+
495
+ it "does not require a different signature to replace a method stub" do
496
+ Spy.on(@double, :msg).and_return(:stub_value)
497
+ @double.should_receive(:msg).and_return(:double_value)
498
+ expect(@double.msg(:arg)).to equal(:double_value)
499
+ expect(@double.msg).to equal(:stub_value)
500
+ expect(@double.msg).to equal(:stub_value)
501
+ @double.rspec_verify
502
+ end
503
+
504
+ it "raises an error when a previously stubbed method has a negative expectation" do
505
+ Spy.on(@double, :msg).and_return(:stub_value)
506
+ @double.should_not_receive(:msg)
507
+ expect { @double.msg(:arg) }.to raise_error(RSpec::Mocks::MockExpectationError)
508
+ end
509
+
510
+ it "temporarily replaces a method stub on a non-double" do
511
+ non_double = Object.new
512
+ Spy.on(non_double, :msg).and_return(:stub_value)
513
+ non_double.should_receive(:msg).with(:arg).and_return(:double_value)
514
+ expect(non_double.msg(:arg)).to equal(:double_value)
515
+ expect(non_double.msg).to equal(:stub_value)
516
+ expect(non_double.msg).to equal(:stub_value)
517
+ non_double.rspec_verify
518
+ end
519
+
520
+ it "returns the stubbed value when no new value specified" do
521
+ Spy.on(@double, :msg).and_return(:stub_value)
522
+ @double.should_receive(:msg)
523
+ expect(@double.msg).to equal(:stub_value)
524
+ @double.rspec_verify
525
+ end
526
+
527
+ it "returns the stubbed value when stubbed with args and no new value specified" do
528
+ Spy.on(@double, :msg).with(:arg).and_return(:stub_value)
529
+ @double.should_receive(:msg).with(:arg)
530
+ expect(@double.msg(:arg)).to equal(:stub_value)
531
+ @double.rspec_verify
532
+ end
533
+
534
+ it "does not mess with the stub's yielded values when also doubleed" do
535
+ Spy.on(@double, :yield_back).and_yield(:stub_value)
536
+ @double.should_receive(:yield_back).and_yield(:double_value)
537
+ @double.yield_back{|v| expect(v).to eq :double_value }
538
+ @double.yield_back{|v| expect(v).to eq :stub_value }
539
+ @double.rspec_verify
540
+ end
541
+
542
+ it "yields multiple values after a similar stub" do
543
+ FSpy.on(ile, :open).and_yield(:stub_value)
544
+ File.should_receive(:open).and_yield(:first_call).and_yield(:second_call)
545
+ yielded_args = []
546
+ File.open {|v| yielded_args << v }
547
+ expect(yielded_args).to eq [:first_call, :second_call]
548
+ File.open {|v| expect(v).to eq :stub_value }
549
+ File.rspec_verify
550
+ end
551
+
552
+ it "assigns stub return values" do
553
+ double = RSpec::Mocks::Mock.new('name', :message => :response)
554
+ expect(double.message).to eq :response
555
+ end
556
+
557
+ end
558
+
559
+ describe "a double message receiving a block" do
560
+ before(:each) do
561
+ @double = double("double")
562
+ @calls = 0
563
+ end
564
+
565
+ def add_call
566
+ @calls = @calls + 1
567
+ end
568
+
569
+ it "calls the block after #should_receive" do
570
+ @double.should_receive(:foo) { add_call }
571
+
572
+ @double.foo
573
+
574
+ expect(@calls).to eq 1
575
+ end
576
+
577
+ it "calls the block after #should_receive after a similar stub" do
578
+ Spy.on(@double, :foo).and_return(:bar)
579
+ @double.should_receive(:foo) { add_call }
580
+
581
+ @double.foo
582
+
583
+ expect(@calls).to eq 1
584
+ end
585
+
586
+ it "calls the block after #once" do
587
+ @double.should_receive(:foo).once { add_call }
588
+
589
+ @double.foo
590
+
591
+ expect(@calls).to eq 1
592
+ end
593
+
594
+ it "calls the block after #twice" do
595
+ @double.should_receive(:foo).twice { add_call }
596
+
597
+ @double.foo
598
+ @double.foo
599
+
600
+ expect(@calls).to eq 2
601
+ end
602
+
603
+ it "calls the block after #times" do
604
+ @double.should_receive(:foo).exactly(10).times { add_call }
605
+
606
+ (1..10).each { @double.foo }
607
+
608
+ expect(@calls).to eq 10
609
+ end
610
+
611
+ it "calls the block after #any_number_of_times" do
612
+ @double.should_receive(:foo).any_number_of_times { add_call }
613
+
614
+ (1..7).each { @double.foo }
615
+
616
+ expect(@calls).to eq 7
617
+ end
618
+
619
+ it "calls the block after #ordered" do
620
+ @double.should_receive(:foo).ordered { add_call }
621
+ @double.should_receive(:bar).ordered { add_call }
622
+
623
+ @double.foo
624
+ @double.bar
625
+
626
+ expect(@calls).to eq 2
627
+ end
628
+ end
629
+
630
+ describe 'string representation generated by #to_s' do
631
+ it 'does not contain < because that might lead to invalid HTML in some situations' do
632
+ double = double("Dog")
633
+ valid_html_str = "#{double}"
634
+ expect(valid_html_str).not_to include('<')
635
+ end
636
+ end
637
+
638
+ describe "string representation generated by #to_str" do
639
+ it "looks the same as #to_s" do
640
+ double = double("Foo")
641
+ expect(double.to_str).to eq double.to_s
642
+ end
643
+ end
644
+
645
+ describe "double created with no name" do
646
+ it "does not use a name in a failure message" do
647
+ double = double()
648
+ expect {double.foo}.to raise_error(/Double received/)
649
+ end
650
+
651
+ it "does respond to initially stubbed methods" do
652
+ double = double(:foo => "woo", :bar => "car")
653
+ expect(double.foo).to eq "woo"
654
+ expect(double.bar).to eq "car"
655
+ end
656
+ end
657
+
658
+ describe "==" do
659
+ it "sends '== self' to the comparison object" do
660
+ first = double('first')
661
+ second = double('second')
662
+
663
+ first.should_receive(:==).with(second)
664
+ second == first
665
+ end
666
+ end
667
+
668
+ describe "with" do
669
+ before { @double = double('double') }
670
+ context "with args" do
671
+ context "with matching args" do
672
+ it "passes" do
673
+ @double.should_receive(:foo).with('bar')
674
+ @double.foo('bar')
675
+ end
676
+ end
677
+
678
+ context "with non-matching args" do
679
+ it "fails" do
680
+ @double.should_receive(:foo).with('bar')
681
+ expect do
682
+ @double.foo('baz')
683
+ end.to raise_error
684
+ @double.rspec_reset
685
+ end
686
+ end
687
+
688
+ context "with non-matching doubles" do
689
+ it "fails" do
690
+ d1 = double('1')
691
+ d2 = double('2')
692
+ @double.should_receive(:foo).with(d1)
693
+ expect do
694
+ @double.foo(d2)
695
+ end.to raise_error
696
+ @double.rspec_reset
697
+ end
698
+ end
699
+
700
+ context "with non-matching doubles as_null_object" do
701
+ it "fails" do
702
+ d1 = double('1').as_null_object
703
+ d2 = double('2').as_null_object
704
+ @double.should_receive(:foo).with(d1)
705
+ expect do
706
+ @double.foo(d2)
707
+ end.to raise_error
708
+ @double.rspec_reset
709
+ end
710
+ end
711
+ end
712
+
713
+ context "with a block" do
714
+ context "with matching args" do
715
+ it "returns the result of the block" do
716
+ @double.should_receive(:foo).with('bar') { 'baz' }
717
+ expect(@double.foo('bar')).to eq('baz')
718
+ end
719
+ end
720
+
721
+ context "with non-matching args" do
722
+ it "fails" do
723
+ @double.should_receive(:foo).with('bar') { 'baz' }
724
+ expect do
725
+ expect(@double.foo('wrong')).to eq('baz')
726
+ end.to raise_error(/received :foo with unexpected arguments/)
727
+ @double.rspec_reset
728
+ end
729
+ end
730
+ end
731
+ end
732
+
733
+ end
734
+ end