Skip to content

Commit 02bc976

Browse files
committed
Expand receive to handle blocks and exceptions.
1 parent ceab624 commit 02bc976

File tree

3 files changed

+81
-25
lines changed

3 files changed

+81
-25
lines changed

lib/sus/receive.rb

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,16 @@
77

88
module Sus
99
class Receive
10-
CALL_ORIGINAL = Object.new
11-
12-
def initialize(base, method)
10+
def initialize(base, method, &block)
1311
@base = base
1412
@method = method
1513

1614
@times = Times.new
1715
@arguments = nil
1816
@options = nil
1917
@block = nil
20-
@returning = CALL_ORIGINAL
18+
19+
@returning = block
2120
end
2221

2322
def print(output)
@@ -60,12 +59,27 @@ def with_call_count(predicate)
6059
return self
6160
end
6261

63-
def and_return(*returning)
64-
if returning.size == 1
65-
@returning = returning.first
62+
def and_return(*returning, &block)
63+
if block_given?
64+
if returning.any?
65+
raise ArgumentError, "Cannot specify both a block and returning values."
66+
end
67+
68+
@returning = block
69+
elsif returning.size == 1
70+
@returning = proc{returning.first}
6671
else
67-
@returning = returning
72+
@returning = proc{returning}
73+
end
74+
75+
return self
76+
end
77+
78+
def and_raise(...)
79+
@returning = proc do
80+
raise(...)
6881
end
82+
6983
return self
7084
end
7185

@@ -97,7 +111,7 @@ def call(assertions, subject)
97111

98112
validate(mock, assertions, arguments, options, block)
99113

100-
next @returning
114+
next @returning.call(*arguments, **options, &block)
101115
end
102116
end
103117

@@ -110,7 +124,7 @@ def call(assertions, subject)
110124
end
111125

112126
def call_original?
113-
@returning == CALL_ORIGINAL
127+
@returning.nil?
114128
end
115129

116130
class WithArguments
@@ -128,7 +142,7 @@ def call(assertions, subject)
128142
end
129143
end
130144
end
131-
145+
132146
class WithOptions
133147
def initialize(predicate)
134148
@predicate = predicate
@@ -153,15 +167,15 @@ def initialize(predicate)
153167
def print(output)
154168
output.write("with block", @predicate)
155169
end
156-
170+
157171
def call(assertions, subject)
158172
assertions.nested(self) do |assertions|
159173

160174
Expect.new(assertions, subject).not.to(Be == nil)
161175
end
162176
end
163177
end
164-
178+
165179
class Times
166180
ONCE = Be.new(:==, 1)
167181

@@ -172,7 +186,7 @@ def initialize(condition = ONCE)
172186
def print(output)
173187
output.write("with call count ", @condition)
174188
end
175-
189+
176190
def call(assertions, subject)
177191
assertions.nested(self) do |assertions|
178192
Expect.new(assertions, subject).to(@condition)
@@ -182,8 +196,8 @@ def call(assertions, subject)
182196
end
183197

184198
class Base
185-
def receive(method)
186-
Receive.new(self, method)
199+
def receive(method, &block)
200+
Receive.new(self, method, &block)
187201
end
188202
end
189203
end

test/sus/mock.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ def implementation(*arguments)
4545
expect(interface.implementation).to be == 10
4646
end
4747

48+
it "can expect a method to be called and call a block" do
49+
expect(interface).to receive(:implementation){|*arguments|
50+
"Called with arguments: #{arguments.first}"
51+
}
52+
53+
expect(interface.implementation(10)).to be == "Called with arguments: 10"
54+
end
55+
56+
it "can expect a method to be called and raise an exception" do
57+
expect(interface).to receive(:implementation).and_raise(RuntimeError, "An error occurred")
58+
expect{interface.implementation}.to raise_exception(RuntimeError, message: be =~ /An error occurred/)
59+
end
60+
4861
it "can replace a method on an object" do
4962
mock(interface) do |mock|
5063
mock.replace(:implementation) do

test/sus/receive.rb

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,58 @@ def implementation(*arguments, **options)
2323

2424
describe Sus::Receive do
2525
let(:interface) {Interface.new}
26-
27-
it "can replace a method on an object" do
28-
expect(interface).to receive(:implementation).and_return(FakeImplementation.new)
29-
26+
27+
it "can validate a method call" do
28+
expect(interface).to receive(:implementation)
3029
expect(interface).to be(:kind_of?, Interface)
31-
expect(interface.implementation).to be(:kind_of?, FakeImplementation)
30+
expect(interface.implementation).to be(:kind_of?, RealImplementation)
3231
end
33-
32+
33+
with "#and_return" do
34+
it "can return a specific value" do
35+
expect(interface).to receive(:implementation).and_return(FakeImplementation.new)
36+
37+
expect(interface).to be(:kind_of?, Interface)
38+
expect(interface.implementation).to be(:kind_of?, FakeImplementation)
39+
end
40+
41+
it "can return multiple values" do
42+
expect(interface).to receive(:implementation).and_return(true, false)
43+
44+
expect(interface).to be(:kind_of?, Interface)
45+
expect(interface.implementation).to be == [true, false]
46+
end
47+
48+
it "can return a block" do
49+
expect(interface).to receive(:implementation).and_return{|value| "Block Result: #{value}"}
50+
51+
expect(interface).to be(:kind_of?, Interface)
52+
expect(interface.implementation(10)).to be == "Block Result: 10"
53+
end
54+
end
55+
56+
with "#and_raise" do
57+
it "can raise an error when the method is called" do
58+
expect(interface).to receive(:implementation).and_raise("Error!")
59+
expect{interface.implementation}.to raise_exception(RuntimeError, message: be =~ /Error!/)
60+
end
61+
end
62+
3463
it "can validate arguments" do
3564
expect(interface).to receive(:implementation).with(:foo, :bar)
36-
65+
3766
interface.implementation(:foo, :bar)
3867
end
3968

4069
it "can validate (not) arguments" do
4170
expect(interface).not.to receive(:implementation).with(:foo, :bar)
42-
71+
4372
interface.implementation(:foo, :bar2)
4473
end
4574

4675
it "can validate options" do
4776
expect(interface).to receive(:implementation).with(x: 1, y: 2)
48-
77+
4978
interface.implementation(x: 1, y: 2)
5079
end
5180
end

0 commit comments

Comments
 (0)