Hacked in double instance creation

This commit is contained in:
Michael Miller 2019-08-26 22:48:15 -06:00
parent 3462bdea1a
commit 6e9633d001
12 changed files with 51 additions and 13 deletions

View file

@ -1,5 +1,5 @@
module Spectator
module Double
abstract struct Double
macro stub(definition)
def {{definition.name.id}}
{{definition.block.body}}

View file

@ -101,6 +101,11 @@ module Spectator::DSL
current_group.add_post_condition(block)
end
def add_double(id : Symbol, double_type : Double.class) : Nil
double_factory = DoubleFactory.new(double_type)
current_group.add_double(id, double_factory)
end
# Builds the entire spec and returns it as a test suite.
# This should be called only once after the entire spec has been defined.
protected def build(filter : ExampleFilter) : TestSuite

View file

@ -0,0 +1,17 @@
require "../double"
module Spectator::DSL
# Creates instances of doubles from a specified type.
class DoubleFactory
# Creates the factory.
# The type passed to this constructor must be a double.
def initialize(@double_type : Double.class)
end
# Constructs a new double instance and returns it.
# The *sample_values* are passed to `Double#initialize`.
def build(sample_values : Internals::SampleValues) : Double
@double_type.new
end
end
end

View file

@ -7,6 +7,8 @@ module Spectator::DSL
# and the root example group can't be a child.
alias Child = ExampleFactory | NestedExampleGroupBuilder
private getter doubles = {} of Symbol => DoubleFactory
# Factories and builders for all examples and groups.
@children = [] of Child
@ -63,6 +65,10 @@ module Spectator::DSL
@post_conditions << block
end
def add_double(id : Symbol, double_factory : DoubleFactory) : Nil
@doubles[id] = double_factory
end
# Constructs an `ExampleHooks` instance with all the hooks defined for this group.
# This method should be called only when the group is being built,
# otherwise some hooks may be missing.

View file

@ -26,7 +26,7 @@ module Spectator::DSL
# The *parent* should be the group that contains this group.
# The *sample_values* will be given to all of the examples (and groups) nested in this group.
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
NestedExampleGroup.new(@what, parent, hooks, conditions).tap do |group|
NestedExampleGroup.new(@what, parent, hooks, conditions, doubles).tap do |group|
# Set the group's children to built versions of the children from this instance.
group.children = @children.map do |child|
# Build the child and up-cast to prevent type errors.

View file

@ -6,7 +6,7 @@ module Spectator::DSL
# Creates a `RootExampleGroup` which can have instances of `Example` and `ExampleGroup` nested in it.
# The *sample_values* will be given to all of the examples (and groups) nested in this group.
def build(sample_values : Internals::SampleValues) : RootExampleGroup
RootExampleGroup.new(hooks, conditions).tap do |group|
RootExampleGroup.new(hooks, conditions, doubles).tap do |group|
# Set the group's children to built versions of the children from this instance.
group.children = @children.map do |child|
# Build the child and up-cast to prevent type errors.

View file

@ -43,7 +43,7 @@ module Spectator::DSL
# This creates the container for the sub-groups.
# The hooks are defined here, instead of repeating for each sub-group.
NestedExampleGroup.new(@what, parent, hooks, conditions).tap do |group|
NestedExampleGroup.new(@what, parent, hooks, conditions, doubles).tap do |group|
# Set the container group's children to be sub-groups for each item in the collection.
group.children = collection.map do |value|
# Create a sub-group for each item in the collection.
@ -61,7 +61,7 @@ module Spectator::DSL
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : NestedExampleGroup
# Add the value to sample values for this sub-group.
sub_values = sample_values.add(@symbol, @name, value)
NestedExampleGroup.new(value.to_s, parent, ExampleHooks.empty, ExampleConditions.empty).tap do |group|
NestedExampleGroup.new(value.to_s, parent, ExampleHooks.empty, ExampleConditions.empty, {} of Symbol => DoubleFactory).tap do |group|
# Set the sub-group's children to built versions of the children from this instance.
group.children = @children.map do |child|
# Build the child and up-cast to prevent type errors.

View file

@ -1440,15 +1440,15 @@ module Spectator::DSL
macro double(name, &block)
{% if block.is_a?(Nop) %}
# Create an instance of the double.
Double{{name.id}}.new
::Spectator::Internals::Harness.current.double({{name.id.symbolize}}).as(Double{{name.id}})
{% else %}
# Define a double.
struct Double{{name.id}} # TODO: Use fresh variable %double
include ::Spectator::Double
struct Double{{name.id}} < ::Spectator::Double # TODO: Use fresh variable %double
#include {{@type.id}} # Include parent type to allow contextual methods in the double.
{{block.body}}
end
# TODO: Register double in current context.
::Spectator::DSL::Builder.add_double({{name.id.symbolize}}, Double{{name.id}})
{% end %}
{% debug %}
end

View file

@ -16,6 +16,8 @@ module Spectator
# Source where the example originated from.
abstract def source : Source
protected getter sample_values : Internals::SampleValues
# Runs the example code.
# A result is returned, which represents the outcome of the test.
# An example can be run only once.
@ -32,7 +34,7 @@ module Spectator
# Creates the base of the example.
# The group should be the example group the example belongs to.
# The *sample_values* are passed to the example code.
def initialize(@group, sample_values : Internals::SampleValues)
def initialize(@group, @sample_values)
end
# Indicates there is only one example to run.

View file

@ -17,7 +17,7 @@ module Spectator
# Creates the example group.
# The hooks are stored to be triggered later.
def initialize(@hooks : ExampleHooks, @conditions : ExampleConditions)
def initialize(@hooks : ExampleHooks, @conditions : ExampleConditions, @doubles : Hash(Symbol, DSL::DoubleFactory))
@before_all_hooks_run = false
@after_all_hooks_run = false
end
@ -40,6 +40,10 @@ module Spectator
@example_count = children.sum(&.example_count)
end
def double(id, sample_values)
@doubles[id].build(sample_values)
end
# Yields each direct descendant.
def each
children.each do |child|

View file

@ -46,6 +46,10 @@ module Spectator::Internals
@reporter.expectations
end
def double(id)
example.group.double(id, example.sample_values)
end
# Creates a new harness.
# The example the harness is for should be passed in.
private def initialize(@example)

View file

@ -18,8 +18,8 @@ module Spectator
# The parent's children must contain this group,
# otherwise there may be unexpected behavior.
# The *hooks* are stored to be triggered later.
def initialize(@what, @parent, hooks : ExampleHooks, conditions : ExampleConditions)
super(hooks, conditions)
def initialize(@what, @parent, hooks : ExampleHooks, conditions : ExampleConditions, doubles : Hash(Symbol, DSL::DoubleFactory))
super(hooks, conditions, doubles)
end
# Indicates wheter the group references a type.