diff --git a/spec/spectator/mocks/mock_spec.cr b/spec/spectator/mocks/mock_spec.cr index fbf2b4e..b469dbb 100644 --- a/spec/spectator/mocks/mock_spec.cr +++ b/spec/spectator/mocks/mock_spec.cr @@ -1,43 +1,11 @@ require "../../spec_helper" -class MockedClass - getter method1 = 42 - - def method2 - :original - end - - def method3 - "original" - end - - def instance_variables - [{{@type.instance_vars.map(&.name.symbolize).splat}}] - end -end - -struct MockedStruct - getter method1 = 42 - - def method2 - :original - end - - def method3 - "original" - end - - def instance_variables - [{{@type.instance_vars.map(&.name.symbolize).splat}}] - end -end - Spectator.describe Spectator::Mock do let(stub1) { Spectator::ValueStub.new(:method1, 777) } let(stub2) { Spectator::ValueStub.new(:method2, :override) } let(stub3) { Spectator::ValueStub.new(:method3, "stubbed") } - describe "#define_subclass" do + describe "#define_subtype" do class Thing def method1 42 @@ -52,7 +20,7 @@ Spectator.describe Spectator::Mock do end end - Spectator::Mock.define_subclass(Thing, MockThing, :mock_name, method1: 123) do + Spectator::Mock.define_subtype(:class, Thing, MockThing, :mock_name, method1: 123) do stub def method2 :stubbed end @@ -102,11 +70,24 @@ Spectator.describe Spectator::Mock do end describe "#inject" do - # For some reason, `inject` can't find the types. - # Their definitions are outside of the spec as a workaround. - context "with a class" do - Spectator::Mock.inject(MockedClass, :mock_name, method1: 123) do + class MockedClass + getter method1 = 42 + + def method2 + :original + end + + def method3 + "original" + end + + def instance_variables + [{{@type.instance_vars.map(&.name.symbolize).splat}}] + end + end + + Spectator::Mock.inject(:class, MockedClass, :mock_name, method1: 123) do stub def method2 :stubbed end @@ -163,7 +144,23 @@ Spectator.describe Spectator::Mock do end context "with a struct" do - Spectator::Mock.inject(MockedStruct, :mock_name, method1: 123) do + struct MockedStruct + getter method1 = 42 + + def method2 + :original + end + + def method3 + "original" + end + + def instance_variables + [{{@type.instance_vars.map(&.name.symbolize).splat}}] + end + end + + Spectator::Mock.inject(:struct, MockedStruct, :mock_name, method1: 123) do stub def method2 :stubbed end diff --git a/src/spectator/mocks/mock.cr b/src/spectator/mocks/mock.cr index f10d1c9..c472569 100644 --- a/src/spectator/mocks/mock.cr +++ b/src/spectator/mocks/mock.cr @@ -8,63 +8,56 @@ require "./value_stub" module Spectator module Mock - macro define_subclass(mocked_type, type_name, name = nil, **value_methods, &block) - {% if name %}@[::Spectator::StubbedName({{name}})]{% end %} - class {{type_name.id}} < {{mocked_type.id}} - include ::Spectator::Mocked - - {% begin %} - private getter(_spectator_stubs) do - [ - {% for key, value in value_methods %} - ::Spectator::ValueStub.new({{key.id.symbolize}}, {{value}}), - {% end %} - ] of ::Spectator::Stub - end - {% end %} - - def _spectator_clear_stubs : Nil - @_spectator_stubs = nil - end - - # Returns the mock's name formatted for user output. - private def _spectator_stubbed_name : String - \{% if anno = @type.annotation(::Spectator::StubbedName) %} - "#" - \{% else %} - "#" - \{% end %} - end - - macro finished - stub_type {{mocked_type.id}} - - {% if block %}{{block.body}}{% end %} - end - end - end - - macro inject(type_name, name = nil, **value_methods, &block) - {% type = type_name.resolve - base = if type.class? - :class - elsif type.struct? - :struct - else - raise "Unsupported mockable type - #{type}" - end.id %} - + macro define_subtype(base, mocked_type, type_name, name = nil, **value_methods, &block) {% begin %} {% if name %}@[::Spectator::StubbedName({{name}})]{% end %} - {{base}} ::{{type.name}} + {{base.id}} {{type_name.id}} < {{mocked_type.id}} include ::Spectator::Mocked - {% if type.class? %} + {% begin %} + private getter(_spectator_stubs) do + [ + {% for key, value in value_methods %} + ::Spectator::ValueStub.new({{key.id.symbolize}}, {{value}}), + {% end %} + ] of ::Spectator::Stub + end + {% end %} + + def _spectator_clear_stubs : Nil + @_spectator_stubs = nil + end + + # Returns the mock's name formatted for user output. + private def _spectator_stubbed_name : String + \{% if anno = @type.annotation(::Spectator::StubbedName) %} + "#" + \{% else %} + "#" + \{% end %} + end + + macro finished + stub_type {{mocked_type.id}} + + {% if block %}{{block.body}}{% end %} + end + end + {% end %} + end + + macro inject(base, type_name, name = nil, **value_methods, &block) + {% begin %} + {% if name %}@[::Spectator::StubbedName({{name}})]{% end %} + {{base.id}} {{type_name.id}} + include ::Spectator::Mocked + + {% if base == :class %} @@_spectator_mock_registry = ::Spectator::ReferenceMockRegistry.new - {% elsif type.struct? %} + {% elsif base == :struct %} @@_spectator_mock_registry = ::Spectator::ValueMockRegistry(self).new {% else %} - {% raise "Unsupported type for injecting mock" %} + {% raise "Unsupported base type #{base} for injecting mock" %} {% end %} private def _spectator_stubs @@ -86,14 +79,14 @@ module Spectator # Returns the mock's name formatted for user output. private def _spectator_stubbed_name : String \{% if anno = @type.annotation(::Spectator::StubbedName) %} - "#" + "#" \{% else %} - "#" + "#" \{% end %} end macro finished - stub_type {{type.name}} + stub_type {{type_name.id}} {% if block %}{{block.body}}{% end %} end