spy 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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