mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Some initial work on cleaned up groups
This commit is contained in:
parent
1d32946760
commit
225c358cb8
2 changed files with 68 additions and 45 deletions
|
@ -1,55 +1,66 @@
|
||||||
require "../spec_builder"
|
module Spectator::DSL
|
||||||
|
# DSL methods and macros for creating example groups.
|
||||||
module Spectator
|
# This module should be included as a mix-in.
|
||||||
module DSL
|
module Groups
|
||||||
macro context(what, _source_file = __FILE__, _source_line = __LINE__, &block)
|
# Defines a new example group.
|
||||||
class Context%context < {{@type.id}}
|
# The *what* argument is a name or description of the group.
|
||||||
{%
|
# If it isn't a string literal, then it is symbolized for `ExampleNode#name`.
|
||||||
description = if what.is_a?(StringLiteral)
|
macro example_group(what, *, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
if what.starts_with?("#") || what.starts_with?(".")
|
# Example group {{name.stringify}}
|
||||||
what.id.symbolize
|
# Source: {{_source_file}}:{{_source_line}}
|
||||||
else
|
class Group%group < {{@type.id}}
|
||||||
what
|
_spectator_group_subject({{what}})
|
||||||
end
|
|
||||||
else
|
|
||||||
what.symbolize
|
|
||||||
end
|
|
||||||
%}
|
|
||||||
|
|
||||||
%source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
|
%source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
|
||||||
::Spectator::SpecBuilder.start_group({{description}}, %source)
|
::Spectator::DSL::Builder.start_group({{what.is_a?(StringLiteral) ? what : what.stringify}}, %source)
|
||||||
|
|
||||||
# Oddly, `#resolve?` can return a constant's value, which isn't a TypeNode.
|
|
||||||
# Ensure `described_class` and `subject` are only set for real types (is a `TypeNode`).
|
|
||||||
{% if (what.is_a?(Path) || what.is_a?(Generic)) && (described_type = what.resolve?).is_a?(TypeNode) %}
|
|
||||||
macro described_class
|
|
||||||
{{what}}
|
|
||||||
end
|
|
||||||
|
|
||||||
subject do
|
|
||||||
{% if described_type < Reference || described_type < Value %}
|
|
||||||
described_class.new
|
|
||||||
{% else %}
|
|
||||||
described_class
|
|
||||||
{% end %}
|
|
||||||
end
|
|
||||||
{% else %}
|
|
||||||
def _spectator_implicit_subject(*args)
|
|
||||||
{{what}}
|
|
||||||
end
|
|
||||||
{% end %}
|
|
||||||
|
|
||||||
{{block.body}}
|
{{block.body}}
|
||||||
|
|
||||||
::Spectator::SpecBuilder.end_group
|
::Spectator::DSL::Builder.end_group
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
macro describe(what, &block)
|
macro describe(what, *, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
context({{what}}) {{block}}
|
example_group({{what}}, _source_file: {{_source_file}}, _source_line: {{_source_line}}) {{block}}
|
||||||
end
|
end
|
||||||
|
|
||||||
macro sample(collection, count = nil, _source_file = __FILE__, _source_line = __LINE__, &block)
|
macro context(what, *, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
|
example_group({{what}}, _source_file: {{_source_file}}, _source_line: {{_source_line}}) {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Defines the implicit subject for the test context.
|
||||||
|
# If *what* is a type, then the `described_class` method will be defined.
|
||||||
|
# Additionally, the implicit subject is set to an instance of *what* if it's not a module.
|
||||||
|
#
|
||||||
|
# There is no common macro type that has the `#resolve?` method.
|
||||||
|
# Also, `#responds_to?` can't be used in macros.
|
||||||
|
# So the large if statement in this macro is used to look for type signatures.
|
||||||
|
private macro _spectator_group_subject(what)
|
||||||
|
{% if (what.is_a?(Generic) ||
|
||||||
|
what.is_a?(Path) ||
|
||||||
|
what.is_a?(TypeNode) ||
|
||||||
|
what.is_a?(Union)) &&
|
||||||
|
(described_type = what.resolve?).is_a?(TypeNode) %}
|
||||||
|
private def described_class
|
||||||
|
{{described_type}}
|
||||||
|
end
|
||||||
|
|
||||||
|
private def _spectator_implicit_subject
|
||||||
|
{% if described_type < Reference || described_type < Value %}
|
||||||
|
described_class.new
|
||||||
|
{% else %}
|
||||||
|
described_class
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
{% else %}
|
||||||
|
private def _spectator_implicit_subject
|
||||||
|
{{what}}
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro sample(collection, count = nil, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
{% name = block.args.empty? ? :value.id : block.args.first.id %}
|
{% name = block.args.empty? ? :value.id : block.args.first.id %}
|
||||||
|
|
||||||
def %collection
|
def %collection
|
||||||
|
@ -81,7 +92,7 @@ module Spectator
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
macro random_sample(collection, count = nil, _source_file = __FILE__, _source_line = __LINE__, &block)
|
macro random_sample(collection, count = nil, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
{% name = block.args.empty? ? :value.id : block.args.first.id %}
|
{% name = block.args.empty? ? :value.id : block.args.first.id %}
|
||||||
|
|
||||||
def %collection
|
def %collection
|
||||||
|
@ -118,7 +129,7 @@ module Spectator
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
macro given(*assignments, &block)
|
macro given(*assignments, &block)
|
||||||
context({{assignments.splat.stringify}}) do
|
context({{assignments.splat.stringify}}) do
|
||||||
{% for assignment in assignments %}
|
{% for assignment in assignments %}
|
||||||
let({{assignment.target}}) { {{assignment.value}} }
|
let({{assignment.target}}) { {{assignment.value}} }
|
||||||
|
@ -150,5 +161,4 @@ module Spectator
|
||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,4 +4,17 @@
|
||||||
# This type is intentionally outside the `Spectator` module.
|
# This type is intentionally outside the `Spectator` module.
|
||||||
# The reason for this is to prevent name collision when using the DSL to define a spec.
|
# The reason for this is to prevent name collision when using the DSL to define a spec.
|
||||||
abstract class SpectatorContext
|
abstract class SpectatorContext
|
||||||
|
# Initial implicit subject for tests.
|
||||||
|
# This method should be overridden by example groups when an object is described.
|
||||||
|
private def _spectator_implicit_subject
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Initial subject for tests.
|
||||||
|
# Returns the implicit subject.
|
||||||
|
# This method should be overridden when an explicit subject is defined by the DSL.
|
||||||
|
# TODO: Subject needs to be cached.
|
||||||
|
private def subject
|
||||||
|
_spectator_implicit_subject
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue