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
|
||||
# Creates instances of examples from a specified class.
|
||||
class ExampleFactory
|
||||
# Creates the factory.
|
||||
# The type passed to this constructor must be a sub-type of `Example`.
|
||||
def initialize(@example_type : Example.class)
|
||||
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
|
||||
@example_type.new(group, sample_values)
|
||||
end
|
||||
|
|
|
@ -1,38 +1,57 @@
|
|||
module Spectator::DSL
|
||||
# Base class for building all example groups.
|
||||
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
|
||||
|
||||
# Factories and builders for all examples and groups.
|
||||
@children = [] of Child
|
||||
|
||||
# Hooks added to the group so far.
|
||||
@before_all_hooks = [] of ->
|
||||
@before_each_hooks = [] of ->
|
||||
@after_all_hooks = [] of ->
|
||||
@after_each_hooks = [] of ->
|
||||
@around_each_hooks = [] of Proc(Nil) ->
|
||||
|
||||
# Adds a new example factory or group builder to this group.
|
||||
def add_child(child : Child)
|
||||
@children << child
|
||||
end
|
||||
|
||||
# Adds a hook to run before all examples (and nested examples) in this group.
|
||||
def add_before_all_hook(block : ->) : Nil
|
||||
@before_all_hooks << block
|
||||
end
|
||||
|
||||
# Adds a hook to run before each example (and nested example) in this group.
|
||||
def add_before_each_hook(block : ->) : Nil
|
||||
@before_each_hooks << block
|
||||
end
|
||||
|
||||
# Adds a hook to run after all examples (and nested examples) in this group.
|
||||
def add_after_all_hook(block : ->) : Nil
|
||||
@after_all_hooks << block
|
||||
end
|
||||
|
||||
# Adds a hook to run after each example (and nested example) in this group.
|
||||
def add_after_each_hook(block : ->) : Nil
|
||||
@after_each_hooks << block
|
||||
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
|
||||
@around_each_hooks << 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.
|
||||
private def hooks
|
||||
ExampleHooks.new(
|
||||
@before_all_hooks,
|
||||
|
|
|
@ -1,23 +1,63 @@
|
|||
require "./nested_example_group_builder"
|
||||
|
||||
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
|
||||
# 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)
|
||||
super(what)
|
||||
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
|
||||
# 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|
|
||||
# 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.
|
||||
build_sub_group(group, sample_values, value).as(ExampleComponent)
|
||||
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
|
||||
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|
|
||||
# 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.
|
||||
child.build(group, sub_values).as(ExampleComponent)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +1,34 @@
|
|||
module Spectator::DSL
|
||||
# Standard example group builder.
|
||||
# Creates groups of examples and nested groups.
|
||||
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)
|
||||
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
|
||||
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|
|
||||
# Build the child and up-cast to prevent type errors.
|
||||
child.build(group, sample_values).as(ExampleComponent)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
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
|
||||
# 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|
|
||||
# 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.
|
||||
child.build(group, sample_values).as(ExampleComponent)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue