shard-spectator/src/spectator/dsl/hooks.cr

168 lines
6.4 KiB
Crystal
Raw Normal View History

2021-02-13 05:46:22 +00:00
require "../location"
2020-11-09 05:21:52 +00:00
require "./builder"
2020-11-08 05:04:37 +00:00
module Spectator::DSL
# DSL methods for adding custom logic to key times of the spec execution.
module Hooks
2021-01-09 20:17:42 +00:00
# Defines a macro to create an example group hook.
# The *type* indicates when the hook runs and must be a method on `Spectator::DSL::Builder`.
2021-07-31 20:16:39 +00:00
# A custom *name* can be used for the hook method.
# If not provided, *type* will be used instead.
# Additionally, a block can be provided.
# The block can perform any operations necessary and yield to invoke the end-user hook.
macro define_example_group_hook(type, name = nil, &block)
macro {{(name ||= type).id}}(&block)
\{% raise "Missing block for '{{name.id}}' hook" unless block %}
\{% raise "Cannot use '{{name.id}}' inside of a test block" if @def %}
2021-01-09 20:17:42 +00:00
2021-02-10 05:40:15 +00:00
private def self.\%hook : Nil
2021-01-09 20:17:42 +00:00
\{{block.body}}
end
2021-07-31 20:16:39 +00:00
{% if block %}
private def self.%wrapper : Nil
{{block.body}}
end
{% end %}
2021-01-09 20:17:42 +00:00
::Spectator::DSL::Builder.{{type.id}}(
2021-08-17 19:49:58 +00:00
::Spectator::Location.new(\{{block.filename}}, \{{block.line_number}}, \{{block.end_line_number}})
2021-07-31 20:16:39 +00:00
) do
{% if block %}
%wrapper do |*args|
\{% if block.args.empty? %}
\%hook
\{% else %}
\%hook(*args)
\{% end %}
end
{% else %}
\%hook
{% end %}
end
2020-11-08 05:04:37 +00:00
end
end
2021-01-09 20:17:42 +00:00
# Defines a macro to create an example hook.
# The *type* indicates when the hook runs and must be a method on `Spectator::DSL::Builder`.
2021-07-31 20:16:39 +00:00
# A custom *name* can be used for the hook method.
# If not provided, *type* will be used instead.
# Additionally, a block can be provided that takes the current example as an argument.
# The block can perform any operations necessary and yield to invoke the end-user hook.
macro define_example_hook(type, name = nil, &block)
macro {{(name ||= type).id}}(&block)
\{% raise "Missing block for '{{name.id}}' hook" unless block %}
\{% raise "Block argument count '{{name.id}}' hook must be 0..1" if block.args.size > 1 %}
\{% raise "Cannot use '{{name.id}}' inside of a test block" if @def %}
2019-09-15 16:40:53 +00:00
2021-02-10 05:40:15 +00:00
private def \%hook(\{{block.args.splat}}) : Nil
2021-01-09 20:17:42 +00:00
\{{block.body}}
end
2020-11-15 18:22:06 +00:00
2021-07-31 20:16:39 +00:00
{% if block %}
private def %wrapper({{block.args.splat}}) : Nil
{{block.body}}
end
{% end %}
2021-01-09 20:17:42 +00:00
::Spectator::DSL::Builder.{{type.id}}(
2021-02-13 05:46:22 +00:00
::Spectator::Location.new(\{{block.filename}}, \{{block.line_number}})
2021-01-09 20:34:15 +00:00
) do |example|
example.with_context(\{{@type.name}}) do
2021-07-31 20:16:39 +00:00
{% if block %}
{% if block.args.empty? %}
%wrapper do |*args|
\{% if block.args.empty? %}
\%hook
\{% else %}
\%hook(*args)
\{% end %}
end
{% else %}
%wrapper(example) do |*args|
\{% if block.args.empty? %}
\%hook
\{% else %}
\%hook(*args)
\{% end %}
end
{% end %}
{% else %}
\{% if block.args.empty? %}
\%hook
\{% else %}
\%hook(example)
\{% end %}
{% end %}
2021-01-09 20:34:15 +00:00
end
end
2020-11-15 18:22:06 +00:00
end
2019-09-27 03:37:29 +00:00
end
2021-07-17 20:19:16 +00:00
# Defines a block of code that will be invoked once before any examples in the suite.
# The block will not run in the context of the current running example.
# This means that values defined by `let` and `subject` are not available.
define_example_group_hook :before_suite
# Defines a block of code that will be invoked once after all examples in the suite.
# The block will not run in the context of the current running example.
# This means that values defined by `let` and `subject` are not available.
define_example_group_hook :after_suite
2021-01-09 20:17:42 +00:00
# Defines a block of code that will be invoked once before any examples in the group.
# The block will not run in the context of the current running example.
# This means that values defined by `let` and `subject` are not available.
define_example_group_hook :before_all
# Defines a block of code that will be invoked once after all examples in the group.
# The block will not run in the context of the current running example.
# This means that values defined by `let` and `subject` are not available.
define_example_group_hook :after_all
# Defines a block of code that will be invoked before every example in the group.
# The block will be run in the context of the current running example.
# This means that values defined by `let` and `subject` are available.
define_example_hook :before_each
2022-11-04 22:55:31 +00:00
# :ditto:
macro before(&block)
before_each {{block}}
end
2021-01-09 20:17:42 +00:00
# Defines a block of code that will be invoked after every example in the group.
# The block will be run in the context of the current running example.
# This means that values defined by `let` and `subject` are available.
define_example_hook :after_each
2022-11-04 22:55:31 +00:00
# :ditto:
macro after(&block)
after_each {{block}}
end
# Defines a block of code that will be invoked around every example in the group.
# The block will be run in the context of the current running example.
# This means that values defined by `let` and `subject` are available.
#
# The block will execute before the example.
# An `Example::Procsy` is passed to the block.
# The `Example::Procsy#run` method should be called to ensure the example runs.
# More code can run afterwards (in the block).
define_example_hook :around_each
2022-11-04 22:55:31 +00:00
# :ditto:
macro around(&block)
around_each {{block}}
end
# Defines a block of code that will be invoked before every example in the group.
# The block will be run in the context of the current running example.
# This means that values defined by `let` and `subject` are available.
define_example_hook :pre_condition
# Defines a block of code that will be invoked after every example in the group.
# The block will be run in the context of the current running example.
# This means that values defined by `let` and `subject` are available.
define_example_hook :post_condition
2019-09-15 16:40:53 +00:00
end
end