mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Remove append and prepend variants of hook definition methods
RSpec defines these as applying to a scope (example, context, suite) as opposed to example group. Mimicing this is currently not possible in Spectator and would require a substantial restructure of how hooks are handled. This may be implemented in the future.
This commit is contained in:
parent
91d21b38e2
commit
0f7a9ed9e8
5 changed files with 29 additions and 184 deletions
|
@ -7,9 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
## [Unreleased]
|
||||
### Fixed
|
||||
- Fix resolution of types with the same name in nested scopes. [#31](https://github.com/icy-arctic-fox/spectator/issues/31)
|
||||
- `around_each` hooks wrap `before_all` and `after_all` hooks. [#12](https://github.com/icy-arctic-fox/spectator/issues/12)
|
||||
- Hook execution order has been tweaked to match RSpec.
|
||||
|
||||
### Added
|
||||
- Hooks are yielded the current example as a block argument.
|
||||
- `before_each`, `after_each`, and `around_each` hooks are yielded the current example as a block argument.
|
||||
- The `let` and `subject` blocks are yielded the current example as a block argument.
|
||||
- Add internal logging that uses Crystal's `Log` utility. Provide the `LOG_LEVEL` environment variable to enable.
|
||||
- Support dynamic creation of examples.
|
||||
|
@ -26,11 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Support custom messages for failed expectations. [#28](https://gitlab.com/arctic-fox/spectator/-/issues/28)
|
||||
- Allow named arguments and assignments for `provided` (`given`) block.
|
||||
- Add `aggregate_failures` to capture and report multiple failed expectations. [#24](https://gitlab.com/arctic-fox/spectator/-/issues/24)
|
||||
- Add `append_` and `prepend_` variants of hook creation methods.
|
||||
|
||||
### Changed
|
||||
- `around_each` hooks wrap `before_all` and `after_all` hooks. [#12](https://github.com/icy-arctic-fox/spectator/issues/12)
|
||||
- Hook execution order has been tweaked to match RSpec.
|
||||
- `given` (now `provided`) blocks changed to produce a single example. `it` can no longer be nested in a `provided` block.
|
||||
- The "should" syntax no longer reports the source as inside Spectator.
|
||||
- Short-hand "should" syntax must be included by using `require "spectator/should"` - `it { should eq("foo") }`
|
||||
|
@ -38,7 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Prevent usage of reserved keywords in DSL (such as `initialize`).
|
||||
- The count argument for `sample` and `random_sample` groups must be named (use `count: 5` instead of just `5`).
|
||||
- Helper methods used as arguments for `sample` and `random_sample` must be class methods.
|
||||
- Simplify and reduce defined types and generics. Should speed up compilation times.
|
||||
- Simplify and reduce instanced types and generics. Should speed up compilation times.
|
||||
- Overhaul example creation and handling.
|
||||
- Overhaul storage of test values.
|
||||
- Overhaul reporting and formatting. Cleaner output for failures and pending tests.
|
||||
|
|
|
@ -60,84 +60,42 @@ module Spectator::DSL
|
|||
builder.before_suite(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute before any and all examples in the test suite.
|
||||
def prepend_before_suite(location = nil, label = "before_suite", &block)
|
||||
hook = ExampleGroupHook.new(location: location, label: label, &block)
|
||||
builder.prepend_before_suite(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute before any and all examples in the current group.
|
||||
def before_all(location = nil, label = "before_all", &block)
|
||||
hook = ExampleGroupHook.new(location: location, label: label, &block)
|
||||
builder.before_all(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute before any and all examples in the current group.
|
||||
def prepend_before_all(location = nil, label = "before_all", &block)
|
||||
hook = ExampleGroupHook.new(location: location, label: label, &block)
|
||||
builder.prepend_before_all(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute before every example in the current group
|
||||
def before_each(location = nil, label = "before_each", &block : Example -> _)
|
||||
hook = ExampleHook.new(location: location, label: label, &block)
|
||||
builder.before_each(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute before every example in the current group
|
||||
def prepend_before_each(location = nil, label = "before_each", &block : Example -> _)
|
||||
hook = ExampleHook.new(location: location, label: label, &block)
|
||||
builder.prepend_before_each(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute after any and all examples in the test suite.
|
||||
def after_suite(location = nil, label = "after_suite", &block)
|
||||
hook = ExampleGroupHook.new(location: location, label: label, &block)
|
||||
builder.after_suite(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute after any and all examples in the test suite.
|
||||
def append_after_suite(location = nil, label = "after_suite", &block)
|
||||
hook = ExampleGroupHook.new(location: location, label: label, &block)
|
||||
builder.append_after_suite(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute after any and all examples in the current group.
|
||||
def after_all(location = nil, label = "after_all", &block)
|
||||
hook = ExampleGroupHook.new(location: location, label: label, &block)
|
||||
builder.after_all(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute after any and all examples in the current group.
|
||||
def append_after_all(location = nil, label = "after_all", &block)
|
||||
hook = ExampleGroupHook.new(location: location, label: label, &block)
|
||||
builder.append_after_all(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute after every example in the current group.
|
||||
def after_each(location = nil, label = "after_each", &block : Example ->)
|
||||
hook = ExampleHook.new(location: location, label: label, &block)
|
||||
builder.after_each(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute after every example in the current group.
|
||||
def append_after_each(location = nil, label = "after_each", &block : Example ->)
|
||||
hook = ExampleHook.new(location: location, label: label, &block)
|
||||
builder.append_after_each(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute around every example in the current group.
|
||||
def around_each(location = nil, label = "around_each", &block : Example::Procsy ->)
|
||||
hook = ExampleProcsyHook.new(location: location, label: label, &block)
|
||||
builder.around_each(hook)
|
||||
end
|
||||
|
||||
# Defines a block of code to execute around every example in the current group.
|
||||
def prepend_around_each(location = nil, label = "around_each", &block : Example::Procsy ->)
|
||||
hook = ExampleProcsyHook.new(location: location, label: label, &block)
|
||||
builder.prepend_around_each(hook)
|
||||
end
|
||||
|
||||
# Constructs the test spec.
|
||||
# Returns the spec instance.
|
||||
#
|
||||
|
|
|
@ -104,67 +104,31 @@ module Spectator::DSL
|
|||
# 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 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.
|
||||
# The hook is added before all others others of the same type in this context.
|
||||
define_example_group_hook :prepend_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
|
||||
|
||||
# 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.
|
||||
# The hook is added after all others others of the same type in this context.
|
||||
define_example_group_hook :append_after_suite
|
||||
|
||||
# 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 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.
|
||||
# The hook is added before all others others of the same type in this context.
|
||||
define_example_group_hook :prepend_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 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.
|
||||
# The hook is added after all others others of the same type in this context.
|
||||
define_example_group_hook :append_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
|
||||
|
||||
# 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.
|
||||
# The hook is added before all others others of the same type in this context.
|
||||
define_example_hook :prepend_before_each
|
||||
|
||||
# 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
|
||||
|
||||
# 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.
|
||||
# The hook is added after all others others of the same type in this context.
|
||||
define_example_hook :append_after_each
|
||||
|
||||
# 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.
|
||||
|
@ -174,16 +138,5 @@ module Spectator::DSL
|
|||
# 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
|
||||
|
||||
# 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 hook is added before all others others of the same type in this context.
|
||||
#
|
||||
# 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 :prepend_around_each
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,11 +16,6 @@ module Spectator
|
|||
# These take a pre-built hook instance, or arguments to pass to the hook type's initializer.
|
||||
# The new hook is added a collection in the order specified by *order*.
|
||||
#
|
||||
# Alternate methods are also generated that add hooks in the opposite order of *order*.
|
||||
# These are prefixed with the opposite order word.
|
||||
# For instance, when *order* is "append", the prefix will be "prepend",
|
||||
# resulting in a method named `prepend_some_hook`.
|
||||
#
|
||||
# A private getter method is created so that the hooks can be accessed if needed.
|
||||
# The getter method has `_hooks` appended to the hook name.
|
||||
# For instance, if the *declaration* contains `important_thing`, then the getter is `important_thing_hooks`.
|
||||
|
@ -46,12 +41,8 @@ module Spectator
|
|||
macro define_hook(declaration, order = :append, &block)
|
||||
{% if order.id == :append.id
|
||||
method = :push.id
|
||||
alt_method = :unshift.id
|
||||
alt_prefix = :prepend.id
|
||||
elsif order.id == :prepend.id
|
||||
method = :unshift.id
|
||||
alt_method = :push.id
|
||||
alt_prefix = :append.id
|
||||
else
|
||||
raise "Unknown hook order type - #{order}"
|
||||
end %}
|
||||
|
@ -81,28 +72,6 @@ module Spectator
|
|||
{{declaration.var}}(hook)
|
||||
end
|
||||
|
||||
# Registers a new "{{declaration.var}}" hook.
|
||||
# The hook will be {{alt_prefix}}ed to the list.
|
||||
def {{alt_prefix}}_{{declaration.var}}(hook : {{declaration.type}}) : Nil
|
||||
@{{declaration.var}}_hooks.{{alt_method}}(hook)
|
||||
end
|
||||
|
||||
# Registers a new "{{declaration.var}}" hook.
|
||||
# The hook will be {{alt_prefix}}ed to the list.
|
||||
# A new hook will be created by passing args to `{{declaration.type}}.new`.
|
||||
def {{alt_prefix}}_{{declaration.var}}(*args, **kwargs) : Nil
|
||||
hook = {{declaration.type}}.new(*args, **kwargs)
|
||||
{{alt_prefix}}_{{declaration.var}}(hook)
|
||||
end
|
||||
|
||||
# Registers a new "{{declaration.var}}" hook.
|
||||
# The hook will be {{alt_prefix}}ed to the list.
|
||||
# A new hook will be created by passing args to `{{declaration.type}}.new`.
|
||||
def {{alt_prefix}}_{{declaration.var}}(*args, **kwargs, &block) : Nil
|
||||
hook = {{declaration.type}}.new(*args, **kwargs, &block)
|
||||
{{alt_prefix}}_{{declaration.var}}(hook)
|
||||
end
|
||||
|
||||
{% if block %}
|
||||
# Handles calling all "{{declaration.var}}" hooks.
|
||||
protected def call_{{declaration.var}}({{block.args.splat}})
|
||||
|
|
|
@ -18,17 +18,7 @@ module Spectator
|
|||
class SpecBuilder
|
||||
Log = ::Spectator::Log.for(self)
|
||||
|
||||
delegate before_all,
|
||||
prepend_before_all,
|
||||
after_all,
|
||||
append_after_all,
|
||||
before_each,
|
||||
prepend_before_each,
|
||||
after_each,
|
||||
append_after_each,
|
||||
around_each,
|
||||
prepend_around_each,
|
||||
to: current
|
||||
delegate before_all, after_all, before_each, after_each, around_each, to: current
|
||||
|
||||
# Stack tracking the current group.
|
||||
# The bottom of the stack (first element) is the root group.
|
||||
|
@ -73,6 +63,12 @@ module Spectator
|
|||
def start_group(name, location = nil, metadata = Metadata.new) : Nil
|
||||
Log.trace { "Start group: #{name.inspect} @ #{location}; metadata: #{metadata}" }
|
||||
builder = ExampleGroupBuilder.new(name, location, metadata)
|
||||
|
||||
# `before_all` and `after_all` hooks from config are slightly different.
|
||||
# They are applied to every top-level group (groups just under root).
|
||||
apply_top_level_config_hooks(builder) if root?
|
||||
|
||||
# Add group to the stack.
|
||||
current << builder
|
||||
@stack.push(builder)
|
||||
end
|
||||
|
@ -93,6 +89,12 @@ module Spectator
|
|||
def start_iterative_group(collection, name, iterator = nil, location = nil, metadata = Metadata.new) : Nil
|
||||
Log.trace { "Start iterative group: #{name} (#{typeof(collection)}) @ #{location}; metadata: #{metadata}" }
|
||||
builder = IterativeExampleGroupBuilder.new(collection, name, iterator, location, metadata)
|
||||
|
||||
# `before_all` and `after_all` hooks from config are slightly different.
|
||||
# They are applied to every top-level group (groups just under root).
|
||||
apply_top_level_config_hooks(builder) if root?
|
||||
|
||||
# Add group to the stack.
|
||||
current << builder
|
||||
@stack.push(builder)
|
||||
end
|
||||
|
@ -161,20 +163,6 @@ module Spectator
|
|||
root.before_all(*args, **kwargs, &block)
|
||||
end
|
||||
|
||||
# Registers a new "before_suite" hook.
|
||||
# The hook will be prepended to the list.
|
||||
# A new hook will be created by passing args to `ExampleGroupHook.new`.
|
||||
def prepend_before_suite(*args, **kwargs) : Nil
|
||||
root.prepend_before_all(*args, **kwargs)
|
||||
end
|
||||
|
||||
# Registers a new "before_suite" hook.
|
||||
# The hook will be prepended to the list.
|
||||
# A new hook will be created by passing args to `ExampleGroupHook.new`.
|
||||
def prepend_before_suite(*args, **kwargs, &block) : Nil
|
||||
root.prepend_before_all(*args, **kwargs, &block)
|
||||
end
|
||||
|
||||
# Registers a new "after_suite" hook.
|
||||
# The hook will be prepended to the list.
|
||||
# A new hook will be created by passing args to `ExampleGroupHook.new`.
|
||||
|
@ -189,20 +177,6 @@ module Spectator
|
|||
root.after_all(*args, **kwargs, &block)
|
||||
end
|
||||
|
||||
# Registers a new "after_suite" hook.
|
||||
# The hook will be appended to the list.
|
||||
# A new hook will be created by passing args to `ExampleGroupHook.new`.
|
||||
def append_after_suite(*args, **kwargs) : Nil
|
||||
root.append_after_all(*args, **kwargs)
|
||||
end
|
||||
|
||||
# Registers a new "after_suite" hook.
|
||||
# The hook will be appended to the list.
|
||||
# A new hook will be created by passing args to `ExampleGroupHook.new`.
|
||||
def append_after_suite(*args, **kwargs, &block) : Nil
|
||||
root.append_after_all(*args, **kwargs, &block)
|
||||
end
|
||||
|
||||
# Checks if the current group is the root group.
|
||||
private def root?
|
||||
@stack.size == 1
|
||||
|
@ -219,28 +193,20 @@ module Spectator
|
|||
@stack.last
|
||||
end
|
||||
|
||||
# Retrieves the configuration.
|
||||
# If one wasn't previously set, a default configuration is used.
|
||||
private def config : Config
|
||||
@config || Config.default
|
||||
end
|
||||
|
||||
# Copy all hooks from config to top-level group.
|
||||
# Copy all hooks from config to root group.
|
||||
private def apply_config_hooks(group)
|
||||
config.before_suite_hooks.reverse_each { |hook| group.prepend_before_all(hook) }
|
||||
config.after_suite_hooks.each { |hook| group.append_after_all(hook) }
|
||||
config.before_each_hooks.reverse_each { |hook| group.prepend_before_each(hook) }
|
||||
config.after_each_hooks.each { |hook| group.append_after_each(hook) }
|
||||
config.around_each_hooks.reverse_each { |hook| group.prepend_around_each(hook) }
|
||||
@config.before_suite_hooks.each { |hook| group.before_all(hook) }
|
||||
@config.after_suite_hooks.reverse_each { |hook| group.after_all(hook) }
|
||||
@config.before_each_hooks.each { |hook| group.before_each(hook) }
|
||||
@config.after_each_hooks.reverse_each { |hook| group.after_each(hook) }
|
||||
@config.around_each_hooks.each { |hook| group.around_each(hook) }
|
||||
end
|
||||
|
||||
# `before_all` and `after_all` hooks from config are slightly different.
|
||||
# They are applied to every top-level group (groups just under root).
|
||||
group.each do |node|
|
||||
next unless node.is_a?(Hooks)
|
||||
|
||||
config.before_all_hooks.reverse_each { |hook| node.prepend_before_all(hook.dup) }
|
||||
config.after_all_hooks.each { |hook| node.append_after_all(hook.dup) }
|
||||
end
|
||||
# Copy `before_all` and `after_all` hooks to a group.
|
||||
private def apply_top_level_config_hooks(group)
|
||||
# Hooks are dupped so that they retain their original state (call once).
|
||||
@config.before_all_hooks.each { |hook| group.before_all(hook.dup) }
|
||||
@config.after_all_hooks.reverse_each { |hook| group.after_all(hook.dup) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue