Initial work on type reflection for verifying doubles

This commit is contained in:
Michael Miller 2019-12-08 14:52:54 -07:00
parent 074aff531c
commit 067c789019
4 changed files with 62 additions and 30 deletions

View file

@ -31,6 +31,7 @@ module Spectator::DSL
macro define_double(type_name, name, **stubs, &block)
{% begin %}
{% if (name.is_a?(Path) || name.is_a?(Generic)) && (resolved = name.resolve?) %}
verify_double({{name}})
class {{type_name}} < ::Spectator::Mocks::VerifyingDouble(::{{resolved.id}})
{% else %}
class {{type_name}} < ::Spectator::Mocks::Double
@ -119,6 +120,26 @@ module Spectator::DSL
{% end %}
end
macro verify_double(name, &block)
{% resolved = name.resolve
type = if resolved < Reference
:class
elsif resolved < Value
:struct
else
:module
end %}
{% begin %}
{{type.id}} ::{{resolved.id}}
include ::Spectator::Mocks::Reflection
macro finished
_spectator_reflect
end
end
{% end %}
end
def allow(thing)
Mocks::Allow.new(thing)
end

View file

@ -1,30 +0,0 @@
module Spectator::Mocks
module Mock
macro included
{% for meth in @type.methods %}
{% if meth.visibility != :public %}{{meth.visibility.id}} {% end %}def {{meth.name.id}}(
{% for arg, i in meth.args %}
{% if meth.splat_index && i == meth.splat_index %}
*{{arg}}{% if i + (meth.accepts_block? ? 0 : 1) < meth.args.size %},{% end %}
{% else %}
{{arg}}{% if i + (meth.accepts_block? ? 0 : 1) < meth.args.size %},{% end %}
{% end %}
{% end %}
{% if meth.accepts_block? %}&{% if meth.block_arg %}{{meth.block_arg}}{% else %}__spec_block{% end %}{% end %}
){% if meth.return_type %} : {{meth.return_type}}{% end %}
previous_def(
{% for arg, i in meth.args %}
{% if !meth.splat_index || i < meth.splat_index %}
{{arg.name.id}}{% if i + (meth.accepts_block? ? 0 : 1) < meth.args.size %},{% end %}
{% elsif meth.splat_index && i > meth.splat_index %}
{{arg.name.id}}: {{arg.name}}{% if i + (meth.accepts_block? ? 0 : 1) < meth.args.size %},{% end %}
{% end %}
{% end %}
{% if meth.accepts_block? %}&{% if meth.block_arg %}{{meth.block_arg}}{% else %}__spec_block{% end %}{% end %}
)
end
{% end %}
{% debug %}
end
end
end

View file

@ -0,0 +1,22 @@
require "../anything"
module Spectator::Mocks
module Reflection
private macro _spectator_reflect
{% for meth in @type.methods %}
%source = ::Spectator::Source.new({{meth.filename}}, {{meth.line_number}})
%args = ::Spectator::Mocks::GenericArguments.create(
{% for arg, i in meth.args %}
{% if meth.splat_index && i == meth.splat_index %}
*{{arg.restriction || "::Spectator::Anything.new".id}}{% if i < meth.args.size %},{% end %}
{% else %}
{{arg.restriction || "::Spectator::Anything.new".id}}{% if i < meth.args.size %},{% end %}
{% end %}
{% end %}
)
::Spectator::Mocks::TypeRegistry.add({{@type.id.stringify}}, {{meth.name.symbolize}}, %source, %args)
{% end %}
{% debug %}
end
end
end

View file

@ -0,0 +1,19 @@
module Spectator::Mocks
module TypeRegistry
extend self
alias Key = Tuple(String, Symbol)
@@entries = {} of Key => Deque(MethodStub)
def add(type_name : String, method_name : Symbol, source : Source, args : Arguments) : Nil
key = {type_name, method_name}
list = if @@entries.has_key?(key)
@@entries[key]
else
@@entries[key] = Deque(MethodStub).new
end
list << NilMethodStub.new(method_name, source, args)
end
end
end