Initial addition of pre- and post-conditions

This commit is contained in:
Michael Miller 2019-01-09 16:17:33 -07:00
parent 6caf5353e0
commit 38202ff605
11 changed files with 101 additions and 9 deletions

View file

@ -91,6 +91,14 @@ module Spectator::DSL
current_group.add_around_each_hook(block)
end
def add_pre_condition(&block : ->) : Nil
current_group.add_pre_condition(block)
end
def add_post_condition(&block : ->) : Nil
current_group.add_post_condition(block)
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 : TestSuite

View file

@ -17,6 +17,10 @@ module Spectator::DSL
@after_each_hooks = [] of ->
@around_each_hooks = [] of Proc(Nil) ->
# Pre and post conditions so far.
@pre_conditions = [] of ->
@post_conditions = [] of ->
# Adds a new example factory or group builder to this group.
def add_child(child : Child)
@children << child
@ -49,6 +53,14 @@ module Spectator::DSL
@around_each_hooks << block
end
def add_pre_condition(block : ->) : Nil
@pre_conditions << block
end
def add_post_condition(block : ->) : Nil
@post_conditions << block
end
# Constructs an `ExampleHooks` instance with all the hooks defined for this group.
# This method should be only when the group is being built,
# otherwise some hooks may be missing.
@ -61,5 +73,9 @@ module Spectator::DSL
@around_each_hooks
)
end
private def conditions
ExampleConditions.new(@pre_conditions, @post_conditions)
end
end
end

View file

@ -25,7 +25,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).tap do |group|
NestedExampleGroup.new(@what, parent, hooks, conditions).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).tap do |group|
RootExampleGroup.new(hooks, conditions).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

@ -37,7 +37,7 @@ module Spectator::DSL
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
# 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).tap do |group|
NestedExampleGroup.new(@what, parent, hooks, conditions).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.
@ -55,7 +55,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).tap do |group|
NestedExampleGroup.new(value.to_s, parent, ExampleHooks.empty, ExampleConditions.empty).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

@ -1182,6 +1182,30 @@ module Spectator::DSL
end
end
macro pre_condition(&block)
def %condition : Nil
{{block.body}}
end
::Spectator::DSL::Builder.add_pre_condition do
example = ::Spectator::Internals::Harness.current.example
instance = example.instance.as({{@type.id}})
instance.%condition
end
end
macro post_condition
def %condition : Nil
{{block.body}}
end
::Spectator::DSL::Builder.add_post_condition do
example = ::Spectator::Internals::Harness.current.example
instance = example.instance.as({{@type.id}})
instance.%condition
end
end
# Creates an example, or a test case.
# The `what` argument describes "what" is being tested or asserted.
# The block contains the code to run the test.

View file

@ -0,0 +1,24 @@
module Spectator
class ExampleConditions
def self.empty
new(
[] of ->,
[] of ->
)
end
def initialize(
@pre_conditions : Array(->),
@post_conditions : Array(->)
)
end
def run_pre_conditions
@pre_conditions.each &.call
end
def run_post_conditions
@post_conditions.each &.call
end
end
end

View file

@ -17,7 +17,7 @@ module Spectator
# Creates the example group.
# The hooks are stored to be triggered later.
def initialize(@hooks : ExampleHooks)
def initialize(@hooks : ExampleHooks, @conditions : ExampleConditions)
@before_all_hooks_run = false
@after_all_hooks_run = false
end
@ -129,6 +129,14 @@ module Spectator
run_before_each_hooks
end
def run_pre_conditions
@conditions.run_pre_conditions
end
def run_post_conditions
@conditions.run_post_conditions
end
# Runs all of the `before_all` hooks.
# This should run prior to any examples in the group.
# The hooks will be run only once.

View file

@ -18,6 +18,7 @@ require "./runnable_example"
require "./pending_example"
require "./dummy_example"
require "./example_conditions"
require "./example_hooks"
require "./example_group"
require "./nested_example_group"

View file

@ -17,8 +17,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)
super(hooks)
def initialize(@what, @parent, hooks : ExampleHooks, conditions : ExampleConditions)
super(hooks, conditions)
end
# Runs all of the `before_all` hooks.
@ -58,6 +58,16 @@ module Spectator
parent.run_after_each_hooks
end
def run_pre_conditions : Nil
super
parent.run_pre_conditions
end
def run_post_conditions : Nil
super
parent.run_post_conditions
end
# Creates a proc that runs the `around_each` hooks
# in addition to a block passed to this method.
# To call the block and all `around_each` hooks,

View file

@ -70,8 +70,9 @@ module Spectator
# Capture how long it takes to run the test code.
result.elapsed = Time.measure do
begin
# Actually run the example code.
run_instance
group.run_pre_conditions
run_instance # Actually run the example code.
group.run_post_conditions
rescue ex # Catch all errors and handle them later.
result.error = ex
end