Allow method calls with unconstrained arguments

Workaround for the expect-receive DSL syntax to allow methods to be called without matching arguments.
This commit is contained in:
Michael Miller 2022-07-12 19:23:13 -06:00
parent c91e288f61
commit 6e57a1c44a
No known key found for this signature in database
GPG key ID: 32B47AE8F388A1FF
4 changed files with 40 additions and 3 deletions

View file

@ -6,6 +6,7 @@ Spectator.describe "Deferred stub expectation DSL" do
# Ensure the original is never called.
stub abstract def foo : Nil
stub abstract def foo(arg) : Nil
stub abstract def value : Int32
end
let(dbl) { double(:dbl) }
@ -15,6 +16,11 @@ Spectator.describe "Deferred stub expectation DSL" do
dbl.foo
end
it "returns the correct value" do
expect(dbl).to receive(:value).and_return(42)
expect(dbl.value).to eq(42)
end
it "matches when a message isn't received" do
expect(dbl).to_not receive(:foo)
end
@ -54,6 +60,11 @@ Spectator.describe "Deferred stub expectation DSL" do
fake.foo(:bar)
end
it "returns the correct value" do
expect(fake).to receive(:foo).and_return(42)
expect(fake.foo).to eq(42)
end
it "matches when a message isn't received" do
expect(fake).to_not receive(:foo)
end
@ -64,7 +75,7 @@ Spectator.describe "Deferred stub expectation DSL" do
end
it "matches when a message without arguments is received" do
expect(fake).to_not receive(:foo).with(:bar)
expect(fake).to_not receive(:foo).with(:bar).and_return(42)
fake.foo
end

View file

@ -147,6 +147,19 @@ module Spectator
{% raise "The syntax `expect(...).to_eventually receive(...)` requires the expression passed to `expect` be stubbable (a mock or double)" unless T < ::Spectator::Stubbable || T < ::Spectator::StubbedType %}
stubbable = @expression.value
unless stubbable._spectator_stub_for_method?(stub.method)
# Add stub without an argument constraint.
# Avoids confusing logic like this:
# ```
# expect(dbl).to receive(:foo).with(:bar)
# dbl.foo(:baz)
# ```
# Notice that `#foo` is called, but with different arguments.
# Normally this would raise an error, but that should be prevented.
unconstrained_stub = stub.with(Arguments.any)
stubbable._spectator_define_stub(unconstrained_stub)
end
stubbable._spectator_define_stub(stub)
matcher = Matchers::ReceiveMatcher.new(stub)
to_eventually(matcher, message)
@ -164,6 +177,19 @@ module Spectator
{% raise "The syntax `expect(...).to_never receive(...)` requires the expression passed to `expect` be stubbable (a mock or double)" unless T < ::Spectator::Stubbable || T < ::Spectator::StubbedType %}
stubbable = @expression.value
unless stubbable._spectator_stub_for_method?(stub.method)
# Add stub without an argument constraint.
# Avoids confusing logic like this:
# ```
# expect(dbl).to receive(:foo).with(:bar)
# dbl.foo(:baz)
# ```
# Notice that `#foo` is called, but with different arguments.
# Normally this would raise an error, but that should be prevented.
unconstrained_stub = stub.with(Arguments.any)
stubbable._spectator_define_stub(unconstrained_stub)
end
stubbable._spectator_define_stub(stub)
matcher = Matchers::ReceiveMatcher.new(stub)
to_never(matcher, message)

View file

@ -115,7 +115,7 @@ module Spectator
stub
end
private def _spectator_stub_for_method?(method : Symbol) : Bool
def _spectator_stub_for_method?(method : Symbol) : Bool
@stubs.any? { |stub| stub.method == method }
end

View file

@ -34,7 +34,7 @@ module Spectator
_spectator_stubs.find &.===(call)
end
private def _spectator_stub_for_method?(method : Symbol) : Bool
def _spectator_stub_for_method?(method : Symbol) : Bool
_spectator_stubs.any? { |stub| stub.method == method }
end