Rename Response to Stub

This commit is contained in:
Michael Miller 2022-03-05 20:09:56 -07:00
parent ced98778a4
commit ae14a47329
No known key found for this signature in database
GPG key ID: AC78B32D30CE34A2
5 changed files with 54 additions and 46 deletions

View file

@ -134,8 +134,8 @@ Spectator.describe Spectator::Double do
context "with arguments constraints" do
let(arguments) { Spectator::Arguments.capture(/foo/) }
let(response) { Spectator::Response.new(:foo, "bar", arguments).as(Spectator::AbstractResponse) }
subject(dbl) { Spectator::Double({foo: String}).new([response]) }
let(stub) { Spectator::ValueStub.new(:foo, "bar", arguments).as(Spectator::Stub) }
subject(dbl) { Spectator::Double({foo: String}).new([stub]) }
it "returns the response when constraint satisfied" do
expect(dbl.foo("foobar")).to eq("bar")
@ -150,8 +150,8 @@ Spectator.describe Spectator::Double do
end
context "with common object methods" do
let(response) { Spectator::Response.new(:"same?", true, arguments).as(Spectator::AbstractResponse) }
subject(dbl) { Spectator::Double({"same?": Bool}).new([response]) }
let(stub) { Spectator::ValueStub.new(:"same?", true, arguments).as(Spectator::Stub) }
subject(dbl) { Spectator::Double({"same?": Bool}).new([stub]) }
it "returns the response when constraint satisfied" do
expect(dbl.same?("foobar")).to eq(true)

View file

@ -1,11 +0,0 @@
module Spectator
# Untyped response to a method call (message).
abstract class AbstractResponse
# Name of the method this response is for.
getter method : Symbol
# Creates the base of the response.
def initialize(@method : Symbol)
end
end
end

View file

@ -1,5 +1,6 @@
require "./abstract_response"
require "./unexpected_message"
require "./stub"
require "./value_stub"
module Spectator
# Stands in for an object for testing that a SUT calls expected methods.
@ -9,21 +10,21 @@ module Spectator
# `NT` must be a type of `NamedTuple` that maps method names to their return types.
class Double(NT)
# Stores responses to messages (method calls).
@responses : Array(AbstractResponse)
@stubs : Array(Stub)
# Creates a double with pre-configures responses.
# A *name* can be provided, otherwise it is considered an anonymous double.
def initialize(@responses : Array(AbstractResponse), @name : String? = nil)
def initialize(@stubs : Array(Stub), @name : String? = nil)
end
def initialize(@name : String? = nil, **methods : **NT)
@responses = {% if NT.keys.empty? %}
[] of AbstractResponse
@stubs = {% if NT.keys.empty? %}
[] of Stub
{% else %}
{% begin %}
[
{% for key in NT.keys %}
Response.new({{key.symbolize}}, methods[{{key.symbolize}}]).as(AbstractResponse),
ValueStub.new({{key.symbolize}}, methods[{{key.symbolize}}]).as(Stub),
{% end %}
]
{% end %}
@ -68,12 +69,12 @@ module Spectator
\{% if type <= {{meth.return_type}} %}
# Return type appears to match configured type.
# Find a suitable response.
response = @responses.find &.===(call)
# Find a suitable stub.
stub = @stubs.find &.===(call)
if response
if stub
# Return configured response.
response.as(Response(\{{type}})).value
stub.as(ValueStub(\{{type}})).value
else
# Response not configured for this method/message.
raise UnexpectedMessage.new("#{_spectator_double_name} received unexpected message :{{meth.name}} (masking ancestor) with #{arguments}")
@ -87,12 +88,12 @@ module Spectator
{% else %}
# No return type restriction, return configured response.
# Find a suitable response.
response = @responses.find &.===(call)
# Find a suitable stub.
stub = @stubs.find &.===(call)
if response
if stub
# Return configured response.
response.as(Response(\{{type}})).value
stub.as(ValueStub(\{{type}})).value
else
# Response not configured for this method/message.
raise UnexpectedMessage.new("#{_spectator_double_name} received unexpected message :{{meth.name}} (masking ancestor) with #{arguments}")
@ -119,12 +120,12 @@ module Spectator
call = MethodCall.new({{call.name.symbolize}}, arguments)
\{% if type = NT[{{call.name.symbolize}}] %}
# Find a suitable response.
response = @responses.find &.===(call)
# Find a suitable stub.
stub = @stubs.find &.===(call)
if response
if stub
# Return configured response.
response.as(Response(\{{type}})).value
stub.as(ValueStub(\{{type}})).value
else
# Response not configured for this method/message.
raise UnexpectedMessage.new("#{_spectator_double_name} received unexpected message :{{call.name}} with #{arguments}")

View file

@ -1,19 +1,22 @@
require "./abstract_arguments"
require "./abstract_response"
require "./arguments"
require "./method_call"
module Spectator
class Response(T) < AbstractResponse
# Return value.
getter value : T
# Untyped response to a method call (message).
abstract class Stub
# Name of the method this stub is for.
getter method : Symbol
# Arguments the method must have been called with to provide this response.
# Is nil when there's no constraint - only the method name must match.
getter constraint : AbstractArguments?
# Creates the response.
def initialize(@method : Symbol, @value : T, @constraint : Arguments? = nil)
# Creates the base of the stub.
def initialize(@method : Symbol, @constraint : Arguments? = nil)
end
# Checks if a method call should receive the response from this stub.
def ===(call : MethodCall)
return false if method != call.method
return true unless constraint = @constraint

View file

@ -0,0 +1,15 @@
require "./arguments"
require "./stub"
module Spectator
# Stub that responds with a static value.
class ValueStub(T) < Stub
# Return value.
getter value : T
# Creates the stub.
def initialize(method : Symbol, @value : T, constraint : Arguments? = nil)
super(method, constraint)
end
end
end