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
|
module Builder
|
||||||
extend self
|
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()
|
private class_getter root_group = RootExampleGroupBuilder.new()
|
||||||
|
|
||||||
|
@ -10,13 +10,13 @@ module Spectator::DSL
|
||||||
@@group_stack.last
|
@@group_stack.last
|
||||||
end
|
end
|
||||||
|
|
||||||
private def push_group(group : ExampleGroupBuilder)
|
private def push_group(group : NestedExampleGroupBuilder)
|
||||||
current_group.add_child(group)
|
current_group.add_child(group)
|
||||||
@@group_stack.push(group)
|
@@group_stack.push(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_group(*args) : Nil
|
def start_group(*args) : Nil
|
||||||
group = ::Spectator::DSL::ExampleGroupBuilder.new(*args)
|
group = ::Spectator::DSL::NestedExampleGroupBuilder.new(*args)
|
||||||
push_group(group)
|
push_group(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
require "./example_group_builder"
|
require "./nested_example_group_builder"
|
||||||
|
|
||||||
module Spectator::DSL
|
module Spectator::DSL
|
||||||
class GivenExampleGroupBuilder(T) < ExampleGroupBuilder
|
class GivenExampleGroupBuilder(T) < NestedExampleGroupBuilder
|
||||||
def initialize(what : String, @collection : Array(T), @symbol : Symbol)
|
def initialize(what : String, @collection : Array(T), @symbol : Symbol)
|
||||||
super(what)
|
super(what)
|
||||||
end
|
end
|
||||||
|
|
||||||
def build(parent : ExampleGroup?, sample_values : Internals::SampleValues) : ExampleGroup
|
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
|
||||||
ExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
NestedExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
||||||
group.children = @collection.map do |value|
|
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
|
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)
|
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|
|
group.children = @children.map do |child|
|
||||||
child.build(group, sub_values).as(ExampleGroup::Child)
|
child.build(group, sub_values).as(ExampleComponent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module Spectator::DSL
|
module Spectator::DSL
|
||||||
class ExampleGroupBuilder
|
class NestedExampleGroupBuilder
|
||||||
alias Child = ExampleFactory | ExampleGroupBuilder
|
alias Child = ExampleFactory | NestedExampleGroupBuilder
|
||||||
|
|
||||||
@children = [] of Child
|
@children = [] of Child
|
||||||
@before_all_hooks = [] of ->
|
@before_all_hooks = [] of ->
|
||||||
|
@ -36,10 +36,10 @@ module Spectator::DSL
|
||||||
@around_each_hooks << block
|
@around_each_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
def build(parent : ExampleGroup?, sample_values : Internals::SampleValues) : ExampleGroup
|
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : ExampleGroup
|
||||||
ExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
NestedExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
||||||
group.children = @children.map do |child|
|
group.children = @children.map do |child|
|
||||||
child.build(group, sample_values).as(ExampleGroup::Child)
|
child.build(group, sample_values).as(ExampleComponent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,13 +1,13 @@
|
||||||
module Spectator::DSL
|
module Spectator::DSL
|
||||||
class RootExampleGroupBuilder < ExampleGroupBuilder
|
class RootExampleGroupBuilder < NestedExampleGroupBuilder
|
||||||
def initialize
|
def initialize
|
||||||
super("ROOT")
|
super("ROOT")
|
||||||
end
|
end
|
||||||
|
|
||||||
def build(sample_values : Internals::SampleValues) : ExampleGroup
|
def build(sample_values : Internals::SampleValues) : RootExampleGroup
|
||||||
RootExampleGroup.new(build_hooks).tap do |group|
|
RootExampleGroup.new(build_hooks).tap do |group|
|
||||||
group.children = @children.map do |child|
|
group.children = @children.map do |child|
|
||||||
child.build(group, sample_values).as(ExampleGroup::Child)
|
child.build(group, sample_values).as(ExampleComponent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
require "./example_component"
|
||||||
|
|
||||||
module Spectator
|
module Spectator
|
||||||
# Base class for all types of examples.
|
# Base class for all types of examples.
|
||||||
# Concrete types must implement the `#run_inner` and `#what` methods.
|
# 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.
|
# Indicates whether the example has already been run.
|
||||||
getter? finished = false
|
getter? finished = false
|
||||||
|
|
||||||
|
@ -21,9 +23,6 @@ module Spectator
|
||||||
# Implementation-specific for running the example code.
|
# Implementation-specific for running the example code.
|
||||||
private abstract def run_inner : Result
|
private abstract def run_inner : Result
|
||||||
|
|
||||||
# Message that describes what the example tests.
|
|
||||||
abstract def what : String
|
|
||||||
|
|
||||||
# Creates the base of the example.
|
# Creates the base of the example.
|
||||||
# The group should be the example group the example belongs to.
|
# The group should be the example group the example belongs to.
|
||||||
# The `sample_values` are passed to the example code.
|
# 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
|
module Spectator
|
||||||
class ExampleGroup
|
abstract class ExampleGroup < ExampleComponent
|
||||||
alias Child = Example | ExampleGroup
|
include Enumerable(ExampleComponent)
|
||||||
|
include Iterable(ExampleComponent)
|
||||||
|
|
||||||
getter what : String
|
def initialize(@hooks : ExampleHooks)
|
||||||
|
|
||||||
getter! parent : ExampleGroup
|
|
||||||
|
|
||||||
private getter! children : Array(Child)
|
|
||||||
setter children
|
|
||||||
|
|
||||||
def initialize(@what, @parent, @hooks : ExampleHooks)
|
|
||||||
@before_all_hooks_run = false
|
@before_all_hooks_run = false
|
||||||
@after_all_hooks_run = false
|
@after_all_hooks_run = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def example_count
|
private getter! children : Array(ExampleComponent)
|
||||||
children.sum do |child|
|
|
||||||
child.is_a?(Example) ? 1 : child.example_count
|
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
|
||||||
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
|
def all_examples
|
||||||
Array(Example).new(example_count).tap do |array|
|
Array(Example).new(example_count).tap do |array|
|
||||||
children.each do |child|
|
children.each do |child|
|
||||||
if child.is_a?(Example)
|
if child.is_a?(Example)
|
||||||
array << child
|
array << child
|
||||||
else
|
else
|
||||||
array.concat(child.all_examples)
|
array.concat(child.as(ExampleGroup).all_examples)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_before_all_hooks
|
def finished? : Bool
|
||||||
if (parent = @parent)
|
children.all?(&.finished?)
|
||||||
parent.run_before_all_hooks
|
end
|
||||||
end
|
|
||||||
|
def run_before_all_hooks : Nil
|
||||||
unless @before_all_hooks_run
|
unless @before_all_hooks_run
|
||||||
@hooks.run_before_all
|
@hooks.run_before_all
|
||||||
@before_all_hooks_run = true
|
@before_all_hooks_run = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_before_each_hooks
|
def run_before_each_hooks : Nil
|
||||||
if (parent = @parent)
|
|
||||||
parent.run_before_each_hooks
|
|
||||||
end
|
|
||||||
@hooks.run_before_each
|
@hooks.run_before_each
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_after_all_hooks
|
def run_after_all_hooks : Nil
|
||||||
unless @after_all_hooks_run
|
unless @after_all_hooks_run
|
||||||
if all_examples.all?(&.finished?)
|
if finished?
|
||||||
@hooks.run_after_all
|
@hooks.run_after_all
|
||||||
@after_all_hooks_run = true
|
@after_all_hooks_run = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if (parent = @parent)
|
|
||||||
parent.run_after_all_hooks
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_after_each_hooks
|
def run_after_each_hooks : Nil
|
||||||
@hooks.run_after_each
|
@hooks.run_after_each
|
||||||
if (parent = @parent)
|
|
||||||
parent.run_after_each_hooks
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def wrap_around_each_hooks(&block : ->)
|
def wrap_around_each_hooks(&block : ->) : ->
|
||||||
wrapper = @hooks.wrap_around_each(&block)
|
@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
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,12 +12,14 @@ require "./matchers"
|
||||||
require "./formatters"
|
require "./formatters"
|
||||||
|
|
||||||
# Then all of the top-level types.
|
# Then all of the top-level types.
|
||||||
|
require "./example_component"
|
||||||
require "./example"
|
require "./example"
|
||||||
require "./runnable_example"
|
require "./runnable_example"
|
||||||
require "./pending_example"
|
require "./pending_example"
|
||||||
|
|
||||||
require "./example_hooks"
|
require "./example_hooks"
|
||||||
require "./example_group"
|
require "./example_group"
|
||||||
|
require "./nested_example_group"
|
||||||
require "./root_example_group"
|
require "./root_example_group"
|
||||||
|
|
||||||
require "./expectation_failed"
|
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
|
module Spectator
|
||||||
class RootExampleGroup < ExampleGroup
|
class RootExampleGroup < ExampleGroup
|
||||||
def initialize(hooks)
|
def what : String
|
||||||
super("ROOT", nil, hooks)
|
"ROOT"
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s(io)
|
def to_s(io)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue