diff --git a/src/spectator/dsl/mocks.cr b/src/spectator/dsl/mocks.cr index 6e29045..452fd65 100644 --- a/src/spectator/dsl/mocks.cr +++ b/src/spectator/dsl/mocks.cr @@ -34,10 +34,12 @@ module Spectator::DSL {{type.id}} ::{{resolved.id}} include ::Spectator::Mocks::Stubs + @spectator_stubs = Deque(::Spectator::Mocks::MethodStub).new + @spectator_stub_calls = Deque(::Spectator::Mocks::MethodCall).new + {{block.body}} end {% end %} - {% debug %} end def allow(double : ::Spectator::Mocks::Double) diff --git a/src/spectator/mocks/stubs.cr b/src/spectator/mocks/stubs.cr index acb68ff..2ae8e4e 100644 --- a/src/spectator/mocks/stubs.cr +++ b/src/spectator/mocks/stubs.cr @@ -1,4 +1,4 @@ -module Spectator +module Spectator::Mocks module Stubs private macro stub(definition, &block) {% @@ -7,9 +7,15 @@ module Spectator args = nil body = nil if definition.is_a?(Call) # stub foo { :bar } + named = false name = definition.name.id params = definition.args - args = params.map { |p| p.is_a?(TypeDeclaration) ? p.var : p.id } + args = params.map do |p| + n = p.is_a?(TypeDeclaration) ? p.var : p.id + r = named ? "#{n}: #{n}".id : n + named = true if n.starts_with?('*') + r + end body = definition.block.is_a?(Nop) ? block : definition.block elsif definition.is_a?(TypeDeclaration) # stub foo : Symbol name = definition.var @@ -20,63 +26,30 @@ module Spectator raise "Unrecognized stub format" end %} - def {{name}}{% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} - %method - end - {% if name.ends_with?('=') && name.id != "[]=" %} - def {{name}}(arg) - call = ::Spectator::GenericMethodCall.new({{name.symbolize}}, {arg}, NamedTuple.new) - @spectator_stub_calls << call - stub = @spectator_stubs.find(&.callable?(call)) - if stub - stub.as(::Spectator::GenericMethodStub(typeof(%method(arg)))).call(call) - else - %method(arg) - end + def {{name}}({{params.splat}}){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} + %args = ::Spectator::Mocks::GenericArguments.create({{args.splat}}) + %call = ::Spectator::Mocks::GenericMethodCall.new({{name.symbolize}}, %args) + @spectator_stub_calls << %call + if (%stub = @spectator_stubs.find(&.callable?(%call))) + %stub.call(%args, typeof(previous_def({{args.splat}}))) + else + previous_def({{args.splat}}) + end + end + + def {{name}}({{params.splat}}){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} + %args = ::Spectator::Mocks::GenericArguments.create({{args.splat}}) + %call = ::Spectator::Mocks::GenericMethodCall.new({{name.symbolize}}, %args) + @spectator_stub_calls << %call + if (%stub = @spectator_stubs.find(&.callable?(%call))) + %stub.call(%args, typeof(previous_def({{args.splat}}) { |*%ya| yield *%ya })) + else + previous_def({{args.splat}}) do |*%yield_args| + yield *%yield_args + end end - {% else %} - def {{name}}(*args, **options){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} - call = ::Spectator::GenericMethodCall.new({{name.symbolize}}, args, options) - @spectator_stub_calls << call - stub = @spectator_stubs.find(&.callable?(call)) - if stub - stub.as(::Spectator::GenericMethodStub(typeof(%method(*args, **options)))).call(call) - else - %method(*args, **options) - end - end - - {% if name != "[]=" %} - def {{name}}(*args, **options){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} - call = ::Spectator::GenericMethodCall.new({{name.symbolize}}, args, options) - @spectator_stub_calls << call - stub = @spectator_stubs.find(&.callable?(call)) - if stub - stub.as(::Spectator::GenericMethodStub(typeof(%method(*args, **options) { |*yield_args| yield *yield_args }))).call(call) - else - %method(*args, **options) do |*yield_args| - yield *yield_args - end - end - end - {% end %} - {% end %} - - def %method({{params.splat}}){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} - {% if body && !body.is_a?(Nop) %} - {{body.body}} - {% else %} - raise "Stubbed method called without being allowed" - # This code shouldn't be reached, but makes the compiler happy to have a matching type. - {% if definition.is_a?(TypeDeclaration) %} - %x = uninitialized {{definition.type}} - {% else %} - nil - {% end %} - {% end %} end - {% debug %} end end end