mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Logic for around_each hooks
This commit is contained in:
parent
5ea83f51bb
commit
36c2a5d368
3 changed files with 173 additions and 14 deletions
|
@ -46,25 +46,48 @@ module Spectator
|
||||||
# Returns the result of the execution.
|
# Returns the result of the execution.
|
||||||
# The result will also be stored in `#result`.
|
# The result will also be stored in `#result`.
|
||||||
def run : Result
|
def run : Result
|
||||||
@@current = self
|
|
||||||
Log.debug { "Running example #{self}" }
|
Log.debug { "Running example #{self}" }
|
||||||
Log.warn { "Example #{self} already ran" } if @finished
|
Log.warn { "Example #{self} already ran" } if @finished
|
||||||
@result = Harness.run do
|
|
||||||
if (parent = group?)
|
|
||||||
parent.call_once_before_all
|
|
||||||
parent.call_before_each(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
@entrypoint.call(self)
|
previous_example = @@current
|
||||||
|
@@current = self
|
||||||
|
|
||||||
|
begin
|
||||||
|
@result = Harness.run do
|
||||||
|
if (parent = group?)
|
||||||
|
parent.call_around_each(self) { run_internal }
|
||||||
|
else
|
||||||
|
run_internal
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
@@current = previous_example
|
||||||
@finished = true
|
@finished = true
|
||||||
|
|
||||||
if (parent = group?)
|
|
||||||
parent.call_after_each(self)
|
|
||||||
parent.call_once_after_all if parent.finished?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
ensure
|
end
|
||||||
@@current = nil
|
|
||||||
|
private def run_internal
|
||||||
|
run_before_hooks
|
||||||
|
run_test
|
||||||
|
run_after_hooks
|
||||||
|
end
|
||||||
|
|
||||||
|
private def run_before_hooks : Nil
|
||||||
|
return unless (parent = group?)
|
||||||
|
|
||||||
|
parent.call_once_before_all
|
||||||
|
parent.call_before_each(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def run_after_hooks : Nil
|
||||||
|
return unless (parent = group?)
|
||||||
|
|
||||||
|
parent.call_after_each(self)
|
||||||
|
parent.call_once_after_all if parent.finished?
|
||||||
|
end
|
||||||
|
|
||||||
|
private def run_test : Nil
|
||||||
|
@entrypoint.call(self)
|
||||||
@finished = true
|
@finished = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -107,5 +130,37 @@ module Spectator
|
||||||
|
|
||||||
io << result
|
io << result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Wraps an example to behave like a `Proc`.
|
||||||
|
# This is typically used for an *around_each* hook.
|
||||||
|
# Invoking `#call` or `#run` will run the example.
|
||||||
|
struct Procsy
|
||||||
|
# Underlying example that will run.
|
||||||
|
getter example : Example
|
||||||
|
|
||||||
|
# Creates the example proxy.
|
||||||
|
# The *example* should be run eventually.
|
||||||
|
# The *proc* defines the block of code to run when `#call` or `#run` is invoked.
|
||||||
|
def initialize(@example : Example, &@proc : ->)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Invokes the proc.
|
||||||
|
def call : Nil
|
||||||
|
@proc.call
|
||||||
|
end
|
||||||
|
|
||||||
|
# Invokes the proc.
|
||||||
|
def run : Nil
|
||||||
|
@proc.call
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a new procsy for a block and the example from this instance.
|
||||||
|
def wrap(&block : ->) : self
|
||||||
|
self.class.new(@example, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Allow instance to behave like an example.
|
||||||
|
forward_missing_to @example
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
require "./events"
|
require "./events"
|
||||||
require "./spec_node"
|
require "./spec_node"
|
||||||
|
require "./example_procsy_hook"
|
||||||
|
|
||||||
module Spectator
|
module Spectator
|
||||||
# Collection of examples and sub-groups.
|
# Collection of examples and sub-groups.
|
||||||
|
@ -101,5 +102,52 @@ module Spectator
|
||||||
@nodes << node
|
@nodes << node
|
||||||
node.group = self
|
node.group = self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@around_hooks = [] of ExampleProcsyHook
|
||||||
|
|
||||||
|
# Adds a hook to be invoked when the *{{name.id}}* event occurs.
|
||||||
|
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
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
56
src/spectator/example_procsy_hook.cr
Normal file
56
src/spectator/example_procsy_hook.cr
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
require "./label"
|
||||||
|
require "./source"
|
||||||
|
|
||||||
|
module Spectator
|
||||||
|
# Information about a hook tied to an example and a proc to invoke it.
|
||||||
|
class ExampleProcsyHook
|
||||||
|
# Location of the hook in source code.
|
||||||
|
getter! source : Source
|
||||||
|
|
||||||
|
# User-defined description of the hook.
|
||||||
|
getter! label : Label
|
||||||
|
|
||||||
|
@proc : Example::Procsy ->
|
||||||
|
|
||||||
|
# Creates the hook with a proc.
|
||||||
|
# The *proc* will be called when the hook is invoked.
|
||||||
|
# A *source* and *label* can be provided for debugging.
|
||||||
|
def initialize(@proc : (Example::Procsy ->), *, @source : Source? = nil, @label : Label = nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates the hook with a block.
|
||||||
|
# The block must take a single argument - the current example wrapped in a procsy.
|
||||||
|
# The block will be executed when the hook is invoked.
|
||||||
|
# A *source* and *label* can be provided for debugging.
|
||||||
|
def initialize(*, @source : Source? = nil, @label : Label = nil, &block : Example::Procsy -> _)
|
||||||
|
@proc = block
|
||||||
|
end
|
||||||
|
|
||||||
|
# Invokes the hook.
|
||||||
|
# The *example* refers to the current example.
|
||||||
|
def call(procsy : Example::Procsy) : Nil
|
||||||
|
@proc.call(procsy)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates an example procsy that invokes this hook.
|
||||||
|
def wrap(procsy : Example::Procsy) : Example::Procsy
|
||||||
|
procsy.wrap { call(procsy) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Produces the string representation of the hook.
|
||||||
|
# Includes the source and label if they're not nil.
|
||||||
|
def to_s(io)
|
||||||
|
io << "example hook"
|
||||||
|
|
||||||
|
if (label = @label)
|
||||||
|
io << ' '
|
||||||
|
io << label
|
||||||
|
end
|
||||||
|
|
||||||
|
if (source = @source)
|
||||||
|
io << " @ "
|
||||||
|
io << source
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue