mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Restructure to use a composite design pattern
Examples and example groups now have a common ancestor.
This commit is contained in:
parent
2070d7816b
commit
30a45a24d3
10 changed files with 134 additions and 72 deletions
|
@ -2,7 +2,7 @@ module Spectator::DSL
|
|||
module Builder
|
||||
extend self
|
||||
|
||||
@@group_stack = Array(ExampleGroupBuilder).new(1, root_group)
|
||||
@@group_stack = Array(NestedExampleGroupBuilder).new(1, root_group)
|
||||
|
||||
private class_getter root_group = RootExampleGroupBuilder.new()
|
||||
|
||||
|
@ -10,13 +10,13 @@ module Spectator::DSL
|
|||
@@group_stack.last
|
||||
end
|
||||
|
||||
private def push_group(group : ExampleGroupBuilder)
|
||||
private def push_group(group : NestedExampleGroupBuilder)
|
||||
current_group.add_child(group)
|
||||
@@group_stack.push(group)
|
||||
end
|
||||
|
||||
def start_group(*args) : Nil
|
||||
group = ::Spectator::DSL::ExampleGroupBuilder.new(*args)
|
||||
group = ::Spectator::DSL::NestedExampleGroupBuilder.new(*args)
|
||||
push_group(group)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
require "./example_group_builder"
|
||||
require "./nested_example_group_builder"
|
||||
|
||||
module Spectator::DSL
|
||||
class GivenExampleGroupBuilder(T) < ExampleGroupBuilder
|
||||
class GivenExampleGroupBuilder(T) < NestedExampleGroupBuilder
|
||||
def initialize(what : String, @collection : Array(T), @symbol : Symbol)
|
||||
super(what)
|
||||
end
|
||||
|
||||
def build(parent : ExampleGroup?, sample_values : Internals::SampleValues) : ExampleGroup
|
||||
ExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
||||
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
|
||||
NestedExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
||||
group.children = @collection.map do |value|
|
||||
build_sub_group(group, sample_values, value).as(ExampleGroup::Child)
|
||||
build_sub_group(group, sample_values, value).as(ExampleComponent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : ExampleGroup
|
||||
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : NestedExampleGroup
|
||||
sub_values = sample_values.add(@symbol, @symbol.to_s, value)
|
||||
ExampleGroup.new(value.to_s, parent, ExampleHooks.empty).tap do |group|
|
||||
NestedExampleGroup.new(value.to_s, parent, ExampleHooks.empty).tap do |group|
|
||||
group.children = @children.map do |child|
|
||||
child.build(group, sub_values).as(ExampleGroup::Child)
|
||||
child.build(group, sub_values).as(ExampleComponent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module Spectator::DSL
|
||||
class ExampleGroupBuilder
|
||||
alias Child = ExampleFactory | ExampleGroupBuilder
|
||||
class NestedExampleGroupBuilder
|
||||
alias Child = ExampleFactory | NestedExampleGroupBuilder
|
||||
|
||||
@children = [] of Child
|
||||
@before_all_hooks = [] of ->
|
||||
|
@ -36,10 +36,10 @@ module Spectator::DSL
|
|||
@around_each_hooks << block
|
||||
end
|
||||
|
||||
def build(parent : ExampleGroup?, sample_values : Internals::SampleValues) : ExampleGroup
|
||||
ExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
||||
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : ExampleGroup
|
||||
NestedExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
||||
group.children = @children.map do |child|
|
||||
child.build(group, sample_values).as(ExampleGroup::Child)
|
||||
child.build(group, sample_values).as(ExampleComponent)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +1,13 @@
|
|||
module Spectator::DSL
|
||||
class RootExampleGroupBuilder < ExampleGroupBuilder
|
||||
class RootExampleGroupBuilder < NestedExampleGroupBuilder
|
||||
def initialize
|
||||
super("ROOT")
|
||||
end
|
||||
|
||||
def build(sample_values : Internals::SampleValues) : ExampleGroup
|
||||
|
||||
def build(sample_values : Internals::SampleValues) : RootExampleGroup
|
||||
RootExampleGroup.new(build_hooks).tap do |group|
|
||||
group.children = @children.map do |child|
|
||||
child.build(group, sample_values).as(ExampleGroup::Child)
|
||||
child.build(group, sample_values).as(ExampleComponent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
require "./example_component"
|
||||
|
||||
module Spectator
|
||||
# Base class for all types of examples.
|
||||
# Concrete types must implement the `#run_inner` and `#what` methods.
|
||||
abstract class Example
|
||||
abstract class Example < ExampleComponent
|
||||
# Indicates whether the example has already been run.
|
||||
getter? finished = false
|
||||
|
||||
|
@ -21,9 +23,6 @@ module Spectator
|
|||
# Implementation-specific for running the example code.
|
||||
private abstract def run_inner : Result
|
||||
|
||||
# Message that describes what the example tests.
|
||||
abstract def what : String
|
||||
|
||||
# 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.
|
||||
|
|
11
src/spectator/example_component.cr
Normal file
11
src/spectator/example_component.cr
Normal file
|
@ -0,0 +1,11 @@
|
|||
module Spectator
|
||||
# Abstract base for all examples and collections of examples.
|
||||
# This is used as the base node type for the composite design pattern.
|
||||
abstract class ExampleComponent
|
||||
# Text that describes the context or test.
|
||||
abstract def what : String
|
||||
|
||||
# Indicates whether the example (or group) has been completely run.
|
||||
abstract def finished? : Bool
|
||||
end
|
||||
end
|
|
@ -1,89 +1,82 @@
|
|||
require "./example"
|
||||
require "./example_component"
|
||||
|
||||
module Spectator
|
||||
class ExampleGroup
|
||||
alias Child = Example | ExampleGroup
|
||||
abstract class ExampleGroup < ExampleComponent
|
||||
include Enumerable(ExampleComponent)
|
||||
include Iterable(ExampleComponent)
|
||||
|
||||
getter what : String
|
||||
|
||||
getter! parent : ExampleGroup
|
||||
|
||||
private getter! children : Array(Child)
|
||||
setter children
|
||||
|
||||
def initialize(@what, @parent, @hooks : ExampleHooks)
|
||||
def initialize(@hooks : ExampleHooks)
|
||||
@before_all_hooks_run = false
|
||||
@after_all_hooks_run = false
|
||||
end
|
||||
|
||||
def example_count
|
||||
children.sum do |child|
|
||||
child.is_a?(Example) ? 1 : child.example_count
|
||||
private getter! children : Array(ExampleComponent)
|
||||
|
||||
def children=(children : Array(ExampleComponent))
|
||||
raise "Attempted to reset example group children" if @children
|
||||
@children = children
|
||||
end
|
||||
|
||||
def each
|
||||
children.each do |child|
|
||||
yield child
|
||||
end
|
||||
end
|
||||
|
||||
def each : Iterator(ExampleComponent)
|
||||
raise NotImplementedError.new("ExampleGroup#each")
|
||||
end
|
||||
|
||||
# TODO: Remove this method.
|
||||
def example_count
|
||||
children.sum do |child|
|
||||
child.is_a?(Example) ? 1 : child.as(ExampleGroup).example_count
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Remove this method.
|
||||
def all_examples
|
||||
Array(Example).new(example_count).tap do |array|
|
||||
children.each do |child|
|
||||
if child.is_a?(Example)
|
||||
array << child
|
||||
else
|
||||
array.concat(child.all_examples)
|
||||
array.concat(child.as(ExampleGroup).all_examples)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run_before_all_hooks
|
||||
if (parent = @parent)
|
||||
parent.run_before_all_hooks
|
||||
end
|
||||
def finished? : Bool
|
||||
children.all?(&.finished?)
|
||||
end
|
||||
|
||||
def run_before_all_hooks : Nil
|
||||
unless @before_all_hooks_run
|
||||
@hooks.run_before_all
|
||||
@before_all_hooks_run = true
|
||||
end
|
||||
end
|
||||
|
||||
def run_before_each_hooks
|
||||
if (parent = @parent)
|
||||
parent.run_before_each_hooks
|
||||
end
|
||||
def run_before_each_hooks : Nil
|
||||
@hooks.run_before_each
|
||||
end
|
||||
|
||||
def run_after_all_hooks
|
||||
def run_after_all_hooks : Nil
|
||||
unless @after_all_hooks_run
|
||||
if all_examples.all?(&.finished?)
|
||||
if finished?
|
||||
@hooks.run_after_all
|
||||
@after_all_hooks_run = true
|
||||
end
|
||||
end
|
||||
if (parent = @parent)
|
||||
parent.run_after_all_hooks
|
||||
end
|
||||
end
|
||||
|
||||
def run_after_each_hooks
|
||||
def run_after_each_hooks : Nil
|
||||
@hooks.run_after_each
|
||||
if (parent = @parent)
|
||||
parent.run_after_each_hooks
|
||||
end
|
||||
end
|
||||
|
||||
def wrap_around_each_hooks(&block : ->)
|
||||
wrapper = @hooks.wrap_around_each(&block)
|
||||
if (parent = @parent)
|
||||
wrapper = parent.wrap_around_each_hooks(&wrapper)
|
||||
end
|
||||
wrapper
|
||||
end
|
||||
|
||||
def to_s(io)
|
||||
if (parent = @parent)
|
||||
parent.to_s(io)
|
||||
io << ' '
|
||||
end
|
||||
io << what
|
||||
def wrap_around_each_hooks(&block : ->) : ->
|
||||
@hooks.wrap_around_each(&block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,12 +12,14 @@ require "./matchers"
|
|||
require "./formatters"
|
||||
|
||||
# Then all of the top-level types.
|
||||
require "./example_component"
|
||||
require "./example"
|
||||
require "./runnable_example"
|
||||
require "./pending_example"
|
||||
|
||||
require "./example_hooks"
|
||||
require "./example_group"
|
||||
require "./nested_example_group"
|
||||
require "./root_example_group"
|
||||
|
||||
require "./expectation_failed"
|
||||
|
|
57
src/spectator/nested_example_group.cr
Normal file
57
src/spectator/nested_example_group.cr
Normal file
|
@ -0,0 +1,57 @@
|
|||
require "./example_group"
|
||||
|
||||
module Spectator
|
||||
class NestedExampleGroup < ExampleGroup
|
||||
getter what : String
|
||||
|
||||
getter! parent : ExampleGroup
|
||||
|
||||
def initialize(@what, @parent, hooks : ExampleHooks)
|
||||
super(hooks)
|
||||
end
|
||||
|
||||
def run_before_all_hooks : Nil
|
||||
if (parent = @parent)
|
||||
parent.run_before_all_hooks
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def run_before_each_hooks : Nil
|
||||
if (parent = @parent)
|
||||
parent.run_before_each_hooks
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def run_after_all_hooks : Nil
|
||||
super
|
||||
if (parent = @parent)
|
||||
parent.run_after_all_hooks
|
||||
end
|
||||
end
|
||||
|
||||
def run_after_each_hooks : Nil
|
||||
super
|
||||
if (parent = @parent)
|
||||
parent.run_after_each_hooks
|
||||
end
|
||||
end
|
||||
|
||||
def wrap_around_each_hooks(&block : ->) : ->
|
||||
super(&block).tap do |wrapper|
|
||||
if (parent = @parent)
|
||||
wrapper = parent.wrap_around_each_hooks(&wrapper)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def to_s(io)
|
||||
if (parent = @parent)
|
||||
parent.to_s(io)
|
||||
io << ' '
|
||||
end
|
||||
io << what
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,8 +2,8 @@ require "./example_group"
|
|||
|
||||
module Spectator
|
||||
class RootExampleGroup < ExampleGroup
|
||||
def initialize(hooks)
|
||||
super("ROOT", nil, hooks)
|
||||
def what : String
|
||||
"ROOT"
|
||||
end
|
||||
|
||||
def to_s(io)
|
||||
|
|
Loading…
Reference in a new issue