mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Add docs for group builders and example factory
This commit is contained in:
parent
ee4623b471
commit
aea324a33b
5 changed files with 95 additions and 1 deletions
|
@ -1,8 +1,13 @@
|
||||||
module Spectator::DSL
|
module Spectator::DSL
|
||||||
|
# Creates instances of examples from a specified class.
|
||||||
class ExampleFactory
|
class ExampleFactory
|
||||||
|
# Creates the factory.
|
||||||
|
# The type passed to this constructor must be a sub-type of `Example`.
|
||||||
def initialize(@example_type : Example.class)
|
def initialize(@example_type : Example.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Constructs a new example instance and returns it.
|
||||||
|
# The `group` and `sample_valuees` are passed to `Example#initialize`.
|
||||||
def build(group : ExampleGroup, sample_values : Internals::SampleValues) : Example
|
def build(group : ExampleGroup, sample_values : Internals::SampleValues) : Example
|
||||||
@example_type.new(group, sample_values)
|
@example_type.new(group, sample_values)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,38 +1,57 @@
|
||||||
module Spectator::DSL
|
module Spectator::DSL
|
||||||
|
# Base class for building all example groups.
|
||||||
abstract class ExampleGroupBuilder
|
abstract class ExampleGroupBuilder
|
||||||
|
# Type alias for valid children of example groups.
|
||||||
|
# NOTE: `NestedExampleGroupBuilder` is used instead of `ExampleGroupBuilder`.
|
||||||
|
# That is because `RootExampleGroupBuilder` also inherits from this class,
|
||||||
|
# and the root example group can't be a child.
|
||||||
alias Child = ExampleFactory | NestedExampleGroupBuilder
|
alias Child = ExampleFactory | NestedExampleGroupBuilder
|
||||||
|
|
||||||
|
# Factories and builders for all examples and groups.
|
||||||
@children = [] of Child
|
@children = [] of Child
|
||||||
|
|
||||||
|
# Hooks added to the group so far.
|
||||||
@before_all_hooks = [] of ->
|
@before_all_hooks = [] of ->
|
||||||
@before_each_hooks = [] of ->
|
@before_each_hooks = [] of ->
|
||||||
@after_all_hooks = [] of ->
|
@after_all_hooks = [] of ->
|
||||||
@after_each_hooks = [] of ->
|
@after_each_hooks = [] of ->
|
||||||
@around_each_hooks = [] of Proc(Nil) ->
|
@around_each_hooks = [] of Proc(Nil) ->
|
||||||
|
|
||||||
|
# Adds a new example factory or group builder to this group.
|
||||||
def add_child(child : Child)
|
def add_child(child : Child)
|
||||||
@children << child
|
@children << child
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Adds a hook to run before all examples (and nested examples) in this group.
|
||||||
def add_before_all_hook(block : ->) : Nil
|
def add_before_all_hook(block : ->) : Nil
|
||||||
@before_all_hooks << block
|
@before_all_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Adds a hook to run before each example (and nested example) in this group.
|
||||||
def add_before_each_hook(block : ->) : Nil
|
def add_before_each_hook(block : ->) : Nil
|
||||||
@before_each_hooks << block
|
@before_each_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Adds a hook to run after all examples (and nested examples) in this group.
|
||||||
def add_after_all_hook(block : ->) : Nil
|
def add_after_all_hook(block : ->) : Nil
|
||||||
@after_all_hooks << block
|
@after_all_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Adds a hook to run after each example (and nested example) in this group.
|
||||||
def add_after_each_hook(block : ->) : Nil
|
def add_after_each_hook(block : ->) : Nil
|
||||||
@after_each_hooks << block
|
@after_each_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Adds a hook to run around each example (and nested example) in this group.
|
||||||
|
# The block of code will be given another proc as an argument.
|
||||||
|
# It is expected that the block will call the proc.
|
||||||
def add_around_each_hook(block : Proc(Nil) ->) : Nil
|
def add_around_each_hook(block : Proc(Nil) ->) : Nil
|
||||||
@around_each_hooks << block
|
@around_each_hooks << block
|
||||||
end
|
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.
|
||||||
private def hooks
|
private def hooks
|
||||||
ExampleHooks.new(
|
ExampleHooks.new(
|
||||||
@before_all_hooks,
|
@before_all_hooks,
|
||||||
|
|
|
@ -1,23 +1,63 @@
|
||||||
require "./nested_example_group_builder"
|
require "./nested_example_group_builder"
|
||||||
|
|
||||||
module Spectator::DSL
|
module Spectator::DSL
|
||||||
|
# Specialized example group builder for "given" groups.
|
||||||
|
# The type parameter `T` should be the type of each element in the given collection.
|
||||||
|
# This builder creates a container group with groups inside for each item in the collection.
|
||||||
|
# The hooks are only defined for the container group.
|
||||||
|
# By doing so, the hooks are defined once, are inherited, and use less memory.
|
||||||
class GivenExampleGroupBuilder(T) < NestedExampleGroupBuilder
|
class GivenExampleGroupBuilder(T) < NestedExampleGroupBuilder
|
||||||
|
# Creates a new group builder.
|
||||||
|
# The value for `what` should be the text the user specified for the collection.
|
||||||
|
# The `collection` is the actual array of items to create examples for.
|
||||||
|
#
|
||||||
|
# In this code:
|
||||||
|
# ```
|
||||||
|
# given random_integers do
|
||||||
|
# # ...
|
||||||
|
# end
|
||||||
|
# ```
|
||||||
|
# The `what` value would be "random_integers"
|
||||||
|
# and the collection would contain the items returned by calling `random_integers`.
|
||||||
|
#
|
||||||
|
# The `symbol` is passed along to the sample values
|
||||||
|
# so that the example code can retrieve the current item from the collection.
|
||||||
|
# The symbol should be unique.
|
||||||
def initialize(what : String, @collection : Array(T), @symbol : Symbol)
|
def initialize(what : String, @collection : Array(T), @symbol : Symbol)
|
||||||
super(what)
|
super(what)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Builds the example group.
|
||||||
|
# A new `NestedExampleGroup` will be returned
|
||||||
|
# which can have instances of `Example` and `ExampleGroup` nested in it.
|
||||||
|
# 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
|
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).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|
|
group.children = @collection.map do |value|
|
||||||
|
# Create a sub-group for each item in the collection.
|
||||||
build_sub_group(group, sample_values, value).as(ExampleComponent)
|
build_sub_group(group, sample_values, value).as(ExampleComponent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Builds a sub-group for one item in the collection.
|
||||||
|
# The `parent` should be the container group currently being built by the `#build` call.
|
||||||
|
# The `sample_values` should be the same as what was passed to the `#build` call.
|
||||||
|
# The `value` is the current item in the collection.
|
||||||
|
# The value will be added to the sample values for the sub-group,
|
||||||
|
# so it shouldn't be added prior to calling this method.
|
||||||
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : NestedExampleGroup
|
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : NestedExampleGroup
|
||||||
sub_values = sample_values.add(@symbol, @symbol.to_s, value) # TODO: Use real name instead of symbol as string.
|
# Add the value to sample values for this sub-group.
|
||||||
|
# TODO: Use real name instead of symbol as string.
|
||||||
|
sub_values = sample_values.add(@symbol, @symbol.to_s, value)
|
||||||
NestedExampleGroup.new(value.to_s, parent, ExampleHooks.empty).tap do |group|
|
NestedExampleGroup.new(value.to_s, parent, ExampleHooks.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|
|
group.children = @children.map do |child|
|
||||||
|
# Build the child and up-cast to prevent type errors.
|
||||||
child.build(group, sub_values).as(ExampleComponent)
|
child.build(group, sub_values).as(ExampleComponent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,34 @@
|
||||||
module Spectator::DSL
|
module Spectator::DSL
|
||||||
|
# Standard example group builder.
|
||||||
|
# Creates groups of examples and nested groups.
|
||||||
class NestedExampleGroupBuilder < ExampleGroupBuilder
|
class NestedExampleGroupBuilder < ExampleGroupBuilder
|
||||||
|
# Creates a new group builder.
|
||||||
|
# The value for `what` should be the context for the group.
|
||||||
|
#
|
||||||
|
# For example, in these samples:
|
||||||
|
# ```
|
||||||
|
# describe String do
|
||||||
|
# # ...
|
||||||
|
# context "with an empty string" do
|
||||||
|
# # ...
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# ```
|
||||||
|
# The value would be "String" for the describe block
|
||||||
|
# and "with an empty string" for the context block.
|
||||||
def initialize(@what : String)
|
def initialize(@what : String)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Builds the example group.
|
||||||
|
# A new `NestedExampleGroup` will be returned
|
||||||
|
# which can have instances of `Example` and `ExampleGroup` nested in it.
|
||||||
|
# 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
|
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
|
||||||
NestedExampleGroup.new(@what, parent, hooks).tap do |group|
|
NestedExampleGroup.new(@what, parent, hooks).tap do |group|
|
||||||
|
# Set the group's children to built versions of the children from this instance.
|
||||||
group.children = @children.map do |child|
|
group.children = @children.map do |child|
|
||||||
|
# Build the child and up-cast to prevent type errors.
|
||||||
child.build(group, sample_values).as(ExampleComponent)
|
child.build(group, sample_values).as(ExampleComponent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
module Spectator::DSL
|
module Spectator::DSL
|
||||||
|
# Top-level example group builder.
|
||||||
|
# There should only be one instance of this class,
|
||||||
|
# and it should be at the top of the spec "tree".
|
||||||
class RootExampleGroupBuilder < ExampleGroupBuilder
|
class RootExampleGroupBuilder < ExampleGroupBuilder
|
||||||
|
# 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
|
def build(sample_values : Internals::SampleValues) : RootExampleGroup
|
||||||
RootExampleGroup.new(hooks).tap do |group|
|
RootExampleGroup.new(hooks).tap do |group|
|
||||||
|
# Set the group's children to built versions of the children from this instance.
|
||||||
group.children = @children.map do |child|
|
group.children = @children.map do |child|
|
||||||
|
# Build the child and up-cast to prevent type errors.
|
||||||
child.build(group, sample_values).as(ExampleComponent)
|
child.build(group, sample_values).as(ExampleComponent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue