mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Add lazy double
This commit is contained in:
parent
162ad4df33
commit
bed84b315d
4 changed files with 397 additions and 13 deletions
|
@ -33,7 +33,7 @@ module Spectator::DSL
|
|||
{% end %}
|
||||
end
|
||||
|
||||
private macro new_double(name)
|
||||
private macro new_double(name = nil, **value_methods)
|
||||
{% # Find tuples with the same name.
|
||||
found_tuples = ::Spectator::DSL::Mocks::DOUBLES.select { |tuple| tuple[0] == name.id.symbolize }
|
||||
|
||||
|
@ -57,25 +57,25 @@ module Spectator::DSL
|
|||
found_tuples = found_tuples.sort_by do |tuple|
|
||||
tuple[1].id.split("::").size
|
||||
end
|
||||
found_tuple = found_tuples.last
|
||||
raise "Undefined double type '#{name}'" unless found_tuple
|
||||
found_tuple = found_tuples.last %}
|
||||
|
||||
# Store the type name used to define the underlying double.
|
||||
double_type_name = found_tuple[2].id %}
|
||||
|
||||
{{double_type_name}}.new
|
||||
{% if found_tuple %}
|
||||
{{found_tuple[2].id}}.new
|
||||
{% else %}
|
||||
::Spectator::LazyDouble.new({{name}}, {{**value_methods}})
|
||||
{% end %}
|
||||
end
|
||||
|
||||
macro double(name, **value_methods, &block)
|
||||
{% if @def %}
|
||||
new_double({{name}}){% if block %} do
|
||||
{{block.body}}
|
||||
end{% end %}
|
||||
{% else %}
|
||||
def_double({{name}}, {{**value_methods}}){% if block %} do
|
||||
{% begin %}
|
||||
{% if @def %}new_double{% else %}def_double{% end %}({{name}}, {{**value_methods}}){% if block %} do
|
||||
{{block.body}}
|
||||
end{% end %}
|
||||
{% end %}
|
||||
end
|
||||
|
||||
macro double(**value_methods)
|
||||
new_double({{**value_methods}})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
60
src/spectator/mocks/lazy_double.cr
Normal file
60
src/spectator/mocks/lazy_double.cr
Normal file
|
@ -0,0 +1,60 @@
|
|||
require "../label"
|
||||
require "./arguments"
|
||||
require "./double"
|
||||
require "./method_call"
|
||||
require "./stub"
|
||||
|
||||
module Spectator
|
||||
# Stands in for an object for testing that a SUT calls expected methods.
|
||||
#
|
||||
# Handles all messages (method calls), but only responds to those configured.
|
||||
# Methods called that were not configured will raise `UnexpectedMessage`.
|
||||
#
|
||||
# Use `#_spectator_define_stub` to override behavior of a method in the double.
|
||||
# Only methods defined in the double's type can have stubs.
|
||||
# New methods are not defines when a stub is added that doesn't have a matching method name.
|
||||
class LazyDouble(Messages) < Double
|
||||
@name : String?
|
||||
|
||||
def initialize(_spectator_double_name = nil, _spectator_double_stubs = [] of Stub, **@messages : **Messages)
|
||||
super(_spectator_double_stubs)
|
||||
@name = _spectator_double_name.try &.inspect
|
||||
end
|
||||
|
||||
# Returns the double's name formatted for user output.
|
||||
private def _spectator_stubbed_name : String
|
||||
"#<LazyDouble #{@name || "Anonymous"}>"
|
||||
end
|
||||
|
||||
# Handles all messages.
|
||||
macro method_missing(call)
|
||||
# Capture information about the call.
|
||||
%args = ::Spectator::Arguments.capture({{call.args.splat(", ")}}{% if call.named_args %}{{*call.named_args}}{% end %})
|
||||
%call = ::Spectator::MethodCall.new({{call.name.symbolize}}, %args)
|
||||
|
||||
# Attempt to find a stub that satisfies the method call and arguments.
|
||||
if %stub = _spectator_find_stub(%call)
|
||||
# Cast the stub or return value to the expected type.
|
||||
# This is necessary to match the expected return type of the original message.
|
||||
\{% if Messages.keys.includes?({{call.name.symbolize}}) %}
|
||||
_spectator_cast_stub_value(%stub, %call, \{{Messages[{{call.name.symbolize}}.id]}}, \{{Messages[{{call.name.symbolize}}.id].resolve >= Nil}})
|
||||
\{% else %}
|
||||
# A method that was not defined during initialization was stubbed.
|
||||
# Return the value of the stub as-is.
|
||||
# Might want to give a warning here, as this may produce a "bloated" union of all known stub types.
|
||||
%stub.value
|
||||
\{% end %}
|
||||
else
|
||||
# A stub wasn't found, invoke the fallback logic.
|
||||
\{% if Messages.keys.includes?({{call.name.symbolize}}.id) %}
|
||||
# Pass along the message type and a block to invoke it.
|
||||
_spectator_stub_fallback(%call, \{{Messages[{{call.name.symbolize}}.id]}}) { @messages[{{call.name.symbolize}}] }
|
||||
\{% else %}
|
||||
# Message received for a methods that isn't stubbed nor defined when initialized.
|
||||
_spectator_abstract_stub_fallback(%call)
|
||||
nil # Necessary for compiler to infer return type as nil. Avoids runtime "can't execute ... `x` has no type errors".
|
||||
\{% end %}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue