From 067c789019cbccad5ec36f7ce28392d45e059608 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sun, 8 Dec 2019 14:52:54 -0700 Subject: [PATCH] Initial work on type reflection for verifying doubles --- src/spectator/dsl/mocks.cr | 21 +++++++++++++++++++ src/spectator/mocks/mock.cr | 30 ---------------------------- src/spectator/mocks/reflection.cr | 22 ++++++++++++++++++++ src/spectator/mocks/type_registry.cr | 19 ++++++++++++++++++ 4 files changed, 62 insertions(+), 30 deletions(-) delete mode 100644 src/spectator/mocks/mock.cr create mode 100644 src/spectator/mocks/reflection.cr create mode 100644 src/spectator/mocks/type_registry.cr diff --git a/src/spectator/dsl/mocks.cr b/src/spectator/dsl/mocks.cr index 93a50ec..07d3c00 100644 --- a/src/spectator/dsl/mocks.cr +++ b/src/spectator/dsl/mocks.cr @@ -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 diff --git a/src/spectator/mocks/mock.cr b/src/spectator/mocks/mock.cr deleted file mode 100644 index e46b6a9..0000000 --- a/src/spectator/mocks/mock.cr +++ /dev/null @@ -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 diff --git a/src/spectator/mocks/reflection.cr b/src/spectator/mocks/reflection.cr new file mode 100644 index 0000000..32ddee4 --- /dev/null +++ b/src/spectator/mocks/reflection.cr @@ -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 diff --git a/src/spectator/mocks/type_registry.cr b/src/spectator/mocks/type_registry.cr new file mode 100644 index 0000000..5c4481e --- /dev/null +++ b/src/spectator/mocks/type_registry.cr @@ -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