Add return type restriction

This overrides the previous definition which doesn't have a restriction.
This is a workaround for the inability to infer a stub's return type.
This commit is contained in:
Michael Miller 2022-03-30 21:10:36 -06:00
parent b3f98cd50c
commit 231323bbf1
No known key found for this signature in database
GPG key ID: 32B47AE8F388A1FF
2 changed files with 7 additions and 6 deletions

View file

@ -210,15 +210,15 @@ Spectator.describe Spectator::NullDouble do
context "with common object methods" do context "with common object methods" do
Spectator::NullDouble.define(TestDouble) do Spectator::NullDouble.define(TestDouble) do
@[Spectator::ReturnType(Crystal::Hasher)] stub abstract def hash(hasher) : Crystal::Hasher
stub abstract def hash(hasher)
end end
let(stub) { Spectator::ValueStub.new(:hash, 12345, arguments).as(Spectator::Stub) } let(hasher) { Crystal::Hasher.new }
let(stub) { Spectator::ValueStub.new(:hash, hasher, arguments).as(Spectator::Stub) }
subject(dbl) { TestDouble.new([stub]) } subject(dbl) { TestDouble.new([stub]) }
it "returns the response when constraint satisfied" do it "returns the response when constraint satisfied" do
expect(dbl.hash("foobar")).to eq(12345) expect(dbl.hash("foobar")).to be(hasher)
end end
it "raises when constraint unsatisfied" do it "raises when constraint unsatisfied" do

View file

@ -163,7 +163,7 @@ module Spectator
# The value of the stub could be returned as-is. # The value of the stub could be returned as-is.
# This may produce a "bloated" union of all known stub types, # This may produce a "bloated" union of all known stub types,
# and generally causes more annoying problems. # and generally causes more annoying problems.
raise TypeCastError.new("#{_spectator_stubbed_name} received message #{%call} but cannot resolve the return type.") raise TypeCastError.new("#{_spectator_stubbed_name} received message #{%call} but cannot resolve the return type. Please add a return type restriction.")
{% end %} {% end %}
else else
# A stub wasn't found, invoke the type-specific fallback logic. # A stub wasn't found, invoke the type-specific fallback logic.
@ -239,13 +239,14 @@ module Spectator
# Finding a suitable stub is delegated to the type including the `Stubbable` module. # Finding a suitable stub is delegated to the type including the `Stubbable` module.
if %stub = _spectator_find_stub(%call) if %stub = _spectator_find_stub(%call)
{% if method.return_type %} {% if method.return_type %}
# Return type was provided with a restriction.
_spectator_cast_stub_value(%stub, %call, {{method.return_type}}, {{method.return_type.resolve >= Nil}}) _spectator_cast_stub_value(%stub, %call, {{method.return_type}}, {{method.return_type.resolve >= Nil}})
{% else %} {% else %}
# Stubbed method is abstract and there's no return type annotation. # Stubbed method is abstract and there's no return type annotation.
# The value of the stub could be returned as-is. # The value of the stub could be returned as-is.
# This may produce a "bloated" union of all known stub types, # This may produce a "bloated" union of all known stub types,
# and generally causes more annoying problems. # and generally causes more annoying problems.
raise TypeCastError.new("#{_spectator_stubbed_name} received message #{%call} but cannot resolve the return type.") raise TypeCastError.new("#{_spectator_stubbed_name} received message #{%call} but cannot resolve the return type. Please add a return type restriction.")
{% end %} {% end %}
else else
# A stub wasn't found, invoke the type-specific fallback logic. # A stub wasn't found, invoke the type-specific fallback logic.