2020-11-08 22:06:49 +00:00
|
|
|
require "./events"
|
2021-01-09 17:39:04 +00:00
|
|
|
require "./spec_node"
|
2021-01-16 23:28:33 +00:00
|
|
|
require "./example_procsy_hook"
|
2020-09-06 01:55:46 +00:00
|
|
|
|
2020-09-05 22:47:40 +00:00
|
|
|
module Spectator
|
|
|
|
# Collection of examples and sub-groups.
|
2021-01-09 17:39:04 +00:00
|
|
|
class ExampleGroup < SpecNode
|
|
|
|
include Enumerable(SpecNode)
|
2020-11-08 22:06:49 +00:00
|
|
|
include Events
|
2021-01-09 17:39:04 +00:00
|
|
|
include Iterable(SpecNode)
|
2020-09-05 22:47:40 +00:00
|
|
|
|
2021-01-09 19:48:53 +00:00
|
|
|
@nodes = [] of SpecNode
|
|
|
|
|
2020-11-15 18:22:52 +00:00
|
|
|
group_event before_all do |hooks|
|
2021-01-09 18:33:29 +00:00
|
|
|
Log.trace { "Processing before_all hooks for #{self}" }
|
2020-11-15 18:22:52 +00:00
|
|
|
|
|
|
|
if (parent = group?)
|
|
|
|
parent.call_once_before_all
|
|
|
|
end
|
|
|
|
|
2021-01-09 18:14:27 +00:00
|
|
|
hooks.each do |hook|
|
|
|
|
Log.trace { "Invoking hook #{hook}" }
|
|
|
|
hook.call
|
|
|
|
end
|
2020-11-15 18:22:52 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
group_event after_all do |hooks|
|
2021-01-09 18:33:29 +00:00
|
|
|
Log.trace { "Processing after_all hooks for #{self}" }
|
2020-11-15 18:22:52 +00:00
|
|
|
|
2021-01-09 18:14:27 +00:00
|
|
|
hooks.each do |hook|
|
|
|
|
Log.trace { "Invoking hook #{hook}" }
|
|
|
|
hook.call
|
|
|
|
end
|
2020-11-15 18:22:52 +00:00
|
|
|
|
|
|
|
if (parent = group?)
|
|
|
|
parent.call_once_after_all
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
example_event before_each do |hooks, example|
|
2021-01-09 18:33:29 +00:00
|
|
|
Log.trace { "Processing before_each hooks for #{self}" }
|
2020-11-15 18:22:52 +00:00
|
|
|
|
|
|
|
if (parent = group?)
|
|
|
|
parent.call_before_each(example)
|
|
|
|
end
|
|
|
|
|
2021-01-09 18:14:27 +00:00
|
|
|
hooks.each do |hook|
|
|
|
|
Log.trace { "Invoking hook #{hook}" }
|
|
|
|
hook.call(example)
|
|
|
|
end
|
2020-11-15 18:22:52 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
example_event after_each do |hooks, example|
|
2021-01-09 18:33:29 +00:00
|
|
|
Log.trace { "Processing after_each hooks for #{self}" }
|
2020-11-15 18:22:52 +00:00
|
|
|
|
2021-01-09 18:14:27 +00:00
|
|
|
hooks.each do |hook|
|
|
|
|
Log.trace { "Invoking hook #{hook}" }
|
|
|
|
hook.call(example)
|
|
|
|
end
|
2020-11-15 18:22:52 +00:00
|
|
|
|
|
|
|
if (parent = group?)
|
|
|
|
parent.call_after_each(example)
|
|
|
|
end
|
|
|
|
end
|
2020-11-08 22:06:49 +00:00
|
|
|
|
2020-09-05 22:47:40 +00:00
|
|
|
# Removes the specified *node* from the group.
|
|
|
|
# The node will be unassigned from this group.
|
2021-01-09 17:39:04 +00:00
|
|
|
def delete(node : SpecNode)
|
2020-09-05 22:47:40 +00:00
|
|
|
# Only remove from the group if it is associated with this group.
|
|
|
|
return unless node.group == self
|
|
|
|
|
|
|
|
node.group = nil
|
|
|
|
@nodes.delete(node)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Yields each node (example and sub-group).
|
|
|
|
def each
|
|
|
|
@nodes.each { |node| yield node }
|
|
|
|
end
|
|
|
|
|
2020-10-17 17:23:51 +00:00
|
|
|
# Returns an iterator for each (example and sub-group).
|
|
|
|
def each
|
|
|
|
@nodes.each
|
|
|
|
end
|
|
|
|
|
2020-09-12 22:02:11 +00:00
|
|
|
# Checks if all examples and sub-groups have finished.
|
|
|
|
def finished? : Bool
|
|
|
|
@nodes.all?(&.finished?)
|
|
|
|
end
|
|
|
|
|
2020-09-05 22:47:40 +00:00
|
|
|
# Adds the specified *node* to the group.
|
|
|
|
# Assigns the node to this group.
|
|
|
|
# If the node already belongs to a group,
|
|
|
|
# it will be removed from the previous group before adding it to this group.
|
2021-01-09 17:39:04 +00:00
|
|
|
def <<(node : SpecNode)
|
2020-09-05 22:47:40 +00:00
|
|
|
# Remove from existing group if the node is part of one.
|
|
|
|
if (previous = node.group?)
|
|
|
|
previous.delete(node)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Add the node to this group and associate with it.
|
|
|
|
@nodes << node
|
|
|
|
node.group = self
|
|
|
|
end
|
2021-01-16 23:28:33 +00:00
|
|
|
|
|
|
|
@around_hooks = [] of ExampleProcsyHook
|
|
|
|
|
2021-01-17 00:16:31 +00:00
|
|
|
# Adds a hook to be invoked when the *around_each* event occurs.
|
2021-01-16 23:28:33 +00:00
|
|
|
def add_around_each_hook(hook : ExampleProcsyHook) : Nil
|
|
|
|
@around_hooks << hook
|
|
|
|
end
|
|
|
|
|
|
|
|
# Defines a hook for the *around_each* event.
|
|
|
|
# The block of code given to this method is invoked when the event occurs.
|
|
|
|
# The current example is provided as a block argument.
|
|
|
|
def around_each(&block : Example::Procsy ->) : Nil
|
|
|
|
hook = ExampleProcsyHook.new(label: "around_each", &block)
|
|
|
|
add_around_each_hook(hook)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Signals that the *around_each* event has occurred.
|
|
|
|
# All hooks associated with the event will be called.
|
|
|
|
def call_around_each(example : Example, &block : -> _) : Nil
|
|
|
|
# Avoid overhead if there's no hooks.
|
|
|
|
return yield if @around_hooks.empty?
|
|
|
|
|
|
|
|
# Start with a procsy that wraps the original code.
|
|
|
|
procsy = Example::Procsy.new(example, &block)
|
|
|
|
procsy = wrap_around_each(procsy)
|
|
|
|
procsy.call
|
|
|
|
end
|
|
|
|
|
|
|
|
# Wraps a procsy with the *around_each* hooks from this example group.
|
|
|
|
# The returned procsy will call each hook then *procsy*.
|
|
|
|
protected def wrap_around_each(procsy : Example::Procsy) : Example::Procsy
|
|
|
|
# Avoid overhead if there's no hooks.
|
|
|
|
return procsy if @around_hooks.empty?
|
|
|
|
|
|
|
|
# Wrap each hook with the next.
|
|
|
|
outer = procsy
|
|
|
|
@around_hooks.each do |hook|
|
|
|
|
outer = hook.wrap(outer)
|
|
|
|
end
|
|
|
|
|
|
|
|
# If there's a parent, wrap the procsy with its hooks.
|
|
|
|
# Otherwise, return the outermost procsy.
|
|
|
|
return outer unless (parent = group?)
|
|
|
|
|
|
|
|
parent.wrap_around_each(outer)
|
|
|
|
end
|
2020-09-05 22:47:40 +00:00
|
|
|
end
|
|
|
|
end
|