mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Reduce nesting by collapsing modules with ::
This commit is contained in:
parent
0d282d3d50
commit
77b4c71c2a
14 changed files with 440 additions and 468 deletions
|
@ -1,65 +1,63 @@
|
||||||
module Spectator
|
module Spectator::DSL
|
||||||
module DSL
|
module Builder
|
||||||
module Builder
|
extend self
|
||||||
extend self
|
|
||||||
|
|
||||||
@@group_stack = [::Spectator::DSL::ExampleGroupBuilder.new("ROOT")]
|
@@group_stack = [::Spectator::DSL::ExampleGroupBuilder.new("ROOT")]
|
||||||
|
|
||||||
private def root_group
|
private def root_group
|
||||||
@@group_stack.first
|
@@group_stack.first
|
||||||
end
|
end
|
||||||
|
|
||||||
private def current_group
|
private def current_group
|
||||||
@@group_stack.last
|
@@group_stack.last
|
||||||
end
|
end
|
||||||
|
|
||||||
private def push_group(group : ExampleGroupBuilder)
|
private def push_group(group : ExampleGroupBuilder)
|
||||||
current_group.add_child(group)
|
current_group.add_child(group)
|
||||||
@@group_stack.push(group)
|
@@group_stack.push(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_group(*args) : Nil
|
def start_group(*args) : Nil
|
||||||
group = ::Spectator::DSL::ExampleGroupBuilder.new(*args)
|
group = ::Spectator::DSL::ExampleGroupBuilder.new(*args)
|
||||||
push_group(group)
|
push_group(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_given_group(*args) : Nil
|
def start_given_group(*args) : Nil
|
||||||
group = ::Spectator::DSL::GivenExampleGroupBuilder.new(*args)
|
group = ::Spectator::DSL::GivenExampleGroupBuilder.new(*args)
|
||||||
push_group(group)
|
push_group(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
def end_group : Nil
|
def end_group : Nil
|
||||||
@@group_stack.pop
|
@@group_stack.pop
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_example(example_type : Example.class) : Nil
|
def add_example(example_type : Example.class) : Nil
|
||||||
factory = ::Spectator::DSL::ExampleFactory.new(example_type)
|
factory = ::Spectator::DSL::ExampleFactory.new(example_type)
|
||||||
current_group.add_child(factory)
|
current_group.add_child(factory)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_before_all_hook(&block : ->) : Nil
|
def add_before_all_hook(&block : ->) : Nil
|
||||||
current_group.add_before_all_hook(block)
|
current_group.add_before_all_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_before_each_hook(&block : ->) : Nil
|
def add_before_each_hook(&block : ->) : Nil
|
||||||
current_group.add_before_each_hook(block)
|
current_group.add_before_each_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_after_all_hook(&block : ->) : Nil
|
def add_after_all_hook(&block : ->) : Nil
|
||||||
current_group.add_after_all_hook(block)
|
current_group.add_after_all_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_after_each_hook(&block : ->) : Nil
|
def add_after_each_hook(&block : ->) : Nil
|
||||||
current_group.add_after_each_hook(block)
|
current_group.add_after_each_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_around_each_hook(&block : Proc(Nil) ->) : Nil
|
def add_around_each_hook(&block : Proc(Nil) ->) : Nil
|
||||||
current_group.add_around_each_hook(block)
|
current_group.add_around_each_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
protected def build : ExampleGroup
|
protected def build : ExampleGroup
|
||||||
root_group.build(nil, Internals::SampleValues.empty)
|
root_group.build(nil, Internals::SampleValues.empty)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
require "./matcher_dsl"
|
require "./matcher_dsl"
|
||||||
|
|
||||||
module Spectator
|
module Spectator::DSL
|
||||||
module DSL
|
module ExampleDSL
|
||||||
module ExampleDSL
|
include MatcherDSL
|
||||||
include MatcherDSL
|
|
||||||
|
|
||||||
macro is_expected
|
macro is_expected
|
||||||
expect(subject)
|
expect(subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
macro expect(actual)
|
macro expect(actual)
|
||||||
::Spectator::Expectation.new({{actual.stringify}}, {{actual}})
|
::Spectator::Expectation.new({{actual.stringify}}, {{actual}})
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
module Spectator
|
module Spectator::DSL
|
||||||
module DSL
|
class ExampleFactory
|
||||||
class ExampleFactory
|
def initialize(@example_type : Example.class)
|
||||||
def initialize(@example_type : Example.class)
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def build(group : ExampleGroup, sample_values : Internals::SampleValues) : Example
|
def build(group : ExampleGroup, sample_values : Internals::SampleValues) : Example
|
||||||
@example_type.new(group, sample_values)
|
@example_type.new(group, sample_values)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,60 +1,58 @@
|
||||||
module Spectator
|
module Spectator::DSL
|
||||||
module DSL
|
class ExampleGroupBuilder
|
||||||
class ExampleGroupBuilder
|
alias Child = ExampleFactory | ExampleGroupBuilder
|
||||||
alias Child = ExampleFactory | ExampleGroupBuilder
|
|
||||||
|
|
||||||
@children = [] of Child
|
@children = [] of Child
|
||||||
@before_all_hooks = [] of ->
|
@before_all_hooks = [] of ->
|
||||||
@before_each_hooks = [] of ->
|
@before_each_hooks = [] of ->
|
||||||
@after_all_hooks = [] of ->
|
@after_all_hooks = [] of ->
|
||||||
@after_each_hooks = [] of ->
|
@after_each_hooks = [] of ->
|
||||||
@around_each_hooks = [] of Proc(Nil) ->
|
@around_each_hooks = [] of Proc(Nil) ->
|
||||||
|
|
||||||
def initialize(@what : String)
|
def initialize(@what : String)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_child(child : Child) : Nil
|
def add_child(child : Child) : Nil
|
||||||
@children << child
|
@children << child
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_before_all_hook(block : ->) : Nil
|
def add_before_all_hook(block : ->) : Nil
|
||||||
@before_all_hooks << block
|
@before_all_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_before_each_hook(block : ->) : Nil
|
def add_before_each_hook(block : ->) : Nil
|
||||||
@before_each_hooks << block
|
@before_each_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_after_all_hook(block : ->) : Nil
|
def add_after_all_hook(block : ->) : Nil
|
||||||
@after_all_hooks << block
|
@after_all_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_after_each_hook(block : ->) : Nil
|
def add_after_each_hook(block : ->) : Nil
|
||||||
@after_each_hooks << block
|
@after_each_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_around_each_hook(block : Proc(Nil) ->) : Nil
|
def add_around_each_hook(block : Proc(Nil) ->) : Nil
|
||||||
@around_each_hooks << block
|
@around_each_hooks << block
|
||||||
end
|
end
|
||||||
|
|
||||||
def build(parent : ExampleGroup?, sample_values : Internals::SampleValues) : ExampleGroup
|
def build(parent : ExampleGroup?, sample_values : Internals::SampleValues) : ExampleGroup
|
||||||
ExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
ExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
||||||
children = @children.map do |child|
|
children = @children.map do |child|
|
||||||
child.build(group, sample_values).as(ExampleGroup::Child)
|
child.build(group, sample_values).as(ExampleGroup::Child)
|
||||||
end
|
|
||||||
group.children = children
|
|
||||||
end
|
end
|
||||||
|
group.children = children
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private def build_hooks
|
private def build_hooks
|
||||||
ExampleHooks.new(
|
ExampleHooks.new(
|
||||||
@before_all_hooks,
|
@before_all_hooks,
|
||||||
@before_each_hooks,
|
@before_each_hooks,
|
||||||
@after_all_hooks,
|
@after_all_hooks,
|
||||||
@after_each_hooks,
|
@after_each_hooks,
|
||||||
@around_each_hooks
|
@around_each_hooks
|
||||||
)
|
)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,27 +1,25 @@
|
||||||
require "./example_group_builder"
|
require "./example_group_builder"
|
||||||
|
|
||||||
module Spectator
|
module Spectator::DSL
|
||||||
module DSL
|
class GivenExampleGroupBuilder(T) < ExampleGroupBuilder
|
||||||
class GivenExampleGroupBuilder(T) < ExampleGroupBuilder
|
|
||||||
|
|
||||||
def initialize(what : String, @collection : Array(T), @symbol : Symbol)
|
def initialize(what : String, @collection : Array(T), @symbol : Symbol)
|
||||||
super(what)
|
super(what)
|
||||||
end
|
end
|
||||||
|
|
||||||
def build(parent : ExampleGroup?, sample_values : Internals::SampleValues) : ExampleGroup
|
def build(parent : ExampleGroup?, sample_values : Internals::SampleValues) : ExampleGroup
|
||||||
ExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
ExampleGroup.new(@what, parent, build_hooks).tap do |group|
|
||||||
group.children = @collection.map do |value|
|
group.children = @collection.map do |value|
|
||||||
build_sub_group(group, sample_values, value).as(ExampleGroup::Child)
|
build_sub_group(group, sample_values, value).as(ExampleGroup::Child)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : ExampleGroup
|
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : ExampleGroup
|
||||||
sub_values = sample_values.add(@symbol, @symbol.to_s, value)
|
sub_values = sample_values.add(@symbol, @symbol.to_s, value)
|
||||||
ExampleGroup.new(value.to_s, parent, ExampleHooks.empty).tap do |group|
|
ExampleGroup.new(value.to_s, parent, ExampleHooks.empty).tap do |group|
|
||||||
group.children = @children.map do |child|
|
group.children = @children.map do |child|
|
||||||
child.build(group, sub_values).as(ExampleGroup::Child)
|
child.build(group, sub_values).as(ExampleGroup::Child)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
require "../matchers"
|
require "../matchers"
|
||||||
|
|
||||||
module Spectator
|
module Spectator::DSL
|
||||||
module DSL
|
module MatcherDSL
|
||||||
module MatcherDSL
|
macro eq(expected)
|
||||||
macro eq(expected)
|
::Spectator::Matchers::EqualityMatcher.new({{expected.stringify}}, {{expected}})
|
||||||
::Spectator::Matchers::EqualityMatcher.new({{expected.stringify}}, {{expected}})
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,198 +1,196 @@
|
||||||
require "../example_group"
|
require "../example_group"
|
||||||
|
|
||||||
module Spectator
|
module Spectator::DSL
|
||||||
module DSL
|
module StructureDSL
|
||||||
module StructureDSL
|
|
||||||
|
|
||||||
def initialize(sample_values : Internals::SampleValues)
|
def initialize(sample_values : Internals::SampleValues)
|
||||||
|
end
|
||||||
|
|
||||||
|
macro describe(what, &block)
|
||||||
|
context({{what}}) {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro context(what, &block)
|
||||||
|
module Group%group
|
||||||
|
include {{@type.id}}
|
||||||
|
|
||||||
|
{% if what.is_a?(Path) || what.is_a?(Generic) %}
|
||||||
|
_spectator_described_class {{what}}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
::Spectator::DSL::Builder.start_group(
|
||||||
|
{{what.is_a?(StringLiteral) ? what : what.stringify}}
|
||||||
|
)
|
||||||
|
|
||||||
|
{{block.body}}
|
||||||
|
|
||||||
|
::Spectator::DSL::Builder.end_group
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
macro describe(what, &block)
|
macro given(collection, &block)
|
||||||
context({{what}}) {{block}}
|
module Group%group
|
||||||
end
|
include {{@type.id}}
|
||||||
|
|
||||||
macro context(what, &block)
|
def %collection
|
||||||
module Group%group
|
{{collection}}
|
||||||
include {{@type.id}}
|
|
||||||
|
|
||||||
{% if what.is_a?(Path) || what.is_a?(Generic) %}
|
|
||||||
_spectator_described_class {{what}}
|
|
||||||
{% end %}
|
|
||||||
|
|
||||||
::Spectator::DSL::Builder.start_group(
|
|
||||||
{{what.is_a?(StringLiteral) ? what : what.stringify}}
|
|
||||||
)
|
|
||||||
|
|
||||||
{{block.body}}
|
|
||||||
|
|
||||||
::Spectator::DSL::Builder.end_group
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
macro given(collection, &block)
|
@%wrapper : ::Spectator::Internals::ValueWrapper
|
||||||
module Group%group
|
|
||||||
include {{@type.id}}
|
|
||||||
|
|
||||||
def %collection
|
def {{block.args.empty? ? "value".id : block.args.first}}
|
||||||
{{collection}}
|
@%wrapper.as(::Spectator::Internals::TypedValueWrapper(typeof(%collection.first))).value
|
||||||
end
|
|
||||||
|
|
||||||
@%wrapper : ::Spectator::Internals::ValueWrapper
|
|
||||||
|
|
||||||
def {{block.args.empty? ? "value".id : block.args.first}}
|
|
||||||
@%wrapper.as(::Spectator::Internals::TypedValueWrapper(typeof(%collection.first))).value
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(sample_values : ::Spectator::Internals::SampleValues)
|
|
||||||
super
|
|
||||||
@%wrapper = sample_values.get_wrapper(:%group)
|
|
||||||
end
|
|
||||||
|
|
||||||
_spectator_given_collection Collection%collection, %to_a, %collection
|
|
||||||
%to_a = Collection%collection.new.%to_a
|
|
||||||
|
|
||||||
::Spectator::DSL::Builder.start_given_group(
|
|
||||||
{{collection.stringify}},
|
|
||||||
%to_a,
|
|
||||||
:%group
|
|
||||||
)
|
|
||||||
|
|
||||||
{{block.body}}
|
|
||||||
|
|
||||||
::Spectator::DSL::Builder.end_group
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def initialize(sample_values : ::Spectator::Internals::SampleValues)
|
||||||
|
super
|
||||||
|
@%wrapper = sample_values.get_wrapper(:%group)
|
||||||
|
end
|
||||||
|
|
||||||
|
_spectator_given_collection Collection%collection, %to_a, %collection
|
||||||
|
%to_a = Collection%collection.new.%to_a
|
||||||
|
|
||||||
|
::Spectator::DSL::Builder.start_given_group(
|
||||||
|
{{collection.stringify}},
|
||||||
|
%to_a,
|
||||||
|
:%group
|
||||||
|
)
|
||||||
|
|
||||||
|
{{block.body}}
|
||||||
|
|
||||||
|
::Spectator::DSL::Builder.end_group
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
macro subject(&block)
|
macro subject(&block)
|
||||||
let(:subject) {{block}}
|
let(:subject) {{block}}
|
||||||
end
|
end
|
||||||
|
|
||||||
macro let(name, &block)
|
macro let(name, &block)
|
||||||
let!(%value) {{block}}
|
let!(%value) {{block}}
|
||||||
|
|
||||||
@%wrapper : ::Spectator::Internals::ValueWrapper?
|
@%wrapper : ::Spectator::Internals::ValueWrapper?
|
||||||
|
|
||||||
def {{name.id}}
|
def {{name.id}}
|
||||||
if (wrapper = @%wrapper)
|
if (wrapper = @%wrapper)
|
||||||
wrapper.unsafe_as(::Spectator::Internals::TypedValueWrapper(typeof(%value))).value
|
wrapper.unsafe_as(::Spectator::Internals::TypedValueWrapper(typeof(%value))).value
|
||||||
else
|
else
|
||||||
%value.tap do |value|
|
%value.tap do |value|
|
||||||
@%wrapper = ::Spectator::Internals::TypedValueWrapper(typeof(%value)).new(value)
|
@%wrapper = ::Spectator::Internals::TypedValueWrapper(typeof(%value)).new(value)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
macro let!(name, &block)
|
macro let!(name, &block)
|
||||||
def {{name.id}}
|
def {{name.id}}
|
||||||
|
{{block.body}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro before_all(&block)
|
||||||
|
::Spectator::DSL::Builder.add_before_all_hook {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro before_each(&block)
|
||||||
|
::Spectator::DSL::Builder.add_before_each_hook {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro after_all(&block)
|
||||||
|
::Spectator::DSL::Builder.add_after_all_hook {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro after_each(&block)
|
||||||
|
::Spectator::DSL::Builder.add_after_each_hook {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro around_each(&block)
|
||||||
|
::Spectator::DSL::Builder.add_around_each_hook {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_examples
|
||||||
|
raise NotImplementedError.new("Spectator::DSL#include_examples")
|
||||||
|
end
|
||||||
|
|
||||||
|
macro it(description, &block)
|
||||||
|
_spectator_example_wrapper(Wrapper%example, %run) {{block}}
|
||||||
|
|
||||||
|
_spectator_example(Example%example, Wrapper%example, ::Spectator::RunnableExample, {{description}}) do
|
||||||
|
protected def run_instance
|
||||||
|
@instance.%run
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
::Spectator::DSL::Builder.add_example(Example%example)
|
||||||
|
end
|
||||||
|
|
||||||
|
macro pending(description, &block)
|
||||||
|
_spectator_example_wrapper(Wrapper%example, %run) {{block}}
|
||||||
|
|
||||||
|
_spectator_example(Example%example, Wrapper%example, ::Spectator::PendingExample, {{description}})
|
||||||
|
|
||||||
|
::Spectator::DSL::Builder.add_example(Example%example)
|
||||||
|
end
|
||||||
|
|
||||||
|
macro it_behaves_like
|
||||||
|
{% raise NotImplementedError.new("it_behaves_like functionality is not implemented") %}
|
||||||
|
end
|
||||||
|
|
||||||
|
private macro _spectator_described_class(what)
|
||||||
|
def described_class
|
||||||
|
{{what}}.tap do |thing|
|
||||||
|
raise "#{thing} must be a type name to use #described_class or #subject,\
|
||||||
|
but it is a #{typeof(thing)}" unless thing.is_a?(Class)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
_spectator_implicit_subject
|
||||||
|
end
|
||||||
|
|
||||||
|
private macro _spectator_implicit_subject
|
||||||
|
def subject
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private macro _spectator_given_collection(class_name, to_a_method_name, collection_method_name)
|
||||||
|
class {{class_name.id}}
|
||||||
|
include {{@type.id}}
|
||||||
|
|
||||||
|
def {{to_a_method_name.id}}
|
||||||
|
{{collection_method_name.id}}.to_a
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private macro _spectator_example_wrapper(class_name, run_method_name, &block)
|
||||||
|
class {{class_name.id}}
|
||||||
|
include ::Spectator::DSL::ExampleDSL
|
||||||
|
include {{@type.id}}
|
||||||
|
|
||||||
|
def initialize(sample_values : ::Spectator::Internals::SampleValues)
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def {{run_method_name.id}}
|
||||||
{{block.body}}
|
{{block.body}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
macro before_all(&block)
|
private macro _spectator_example(example_class_name, wrapper_class_name, base_class, description, &block)
|
||||||
::Spectator::DSL::Builder.add_before_all_hook {{block}}
|
class {{example_class_name.id}} < {{base_class.id}}
|
||||||
end
|
def initialize(group : ::Spectator::ExampleGroup, sample_values : ::Spectator::Internals::SampleValues)
|
||||||
|
super
|
||||||
macro before_each(&block)
|
@instance = {{wrapper_class_name.id}}.new(sample_values)
|
||||||
::Spectator::DSL::Builder.add_before_each_hook {{block}}
|
|
||||||
end
|
|
||||||
|
|
||||||
macro after_all(&block)
|
|
||||||
::Spectator::DSL::Builder.add_after_all_hook {{block}}
|
|
||||||
end
|
|
||||||
|
|
||||||
macro after_each(&block)
|
|
||||||
::Spectator::DSL::Builder.add_after_each_hook {{block}}
|
|
||||||
end
|
|
||||||
|
|
||||||
macro around_each(&block)
|
|
||||||
::Spectator::DSL::Builder.add_around_each_hook {{block}}
|
|
||||||
end
|
|
||||||
|
|
||||||
def include_examples
|
|
||||||
raise NotImplementedError.new("Spectator::DSL#include_examples")
|
|
||||||
end
|
|
||||||
|
|
||||||
macro it(description, &block)
|
|
||||||
_spectator_example_wrapper(Wrapper%example, %run) {{block}}
|
|
||||||
|
|
||||||
_spectator_example(Example%example, Wrapper%example, ::Spectator::RunnableExample, {{description}}) do
|
|
||||||
protected def run_instance
|
|
||||||
@instance.%run
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
::Spectator::DSL::Builder.add_example(Example%example)
|
{% if block.is_a?(Block) %}
|
||||||
end
|
{{block.body}}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
macro pending(description, &block)
|
def description
|
||||||
_spectator_example_wrapper(Wrapper%example, %run) {{block}}
|
{{description.is_a?(StringLiteral) ? description : description.stringify}}
|
||||||
|
|
||||||
_spectator_example(Example%example, Wrapper%example, ::Spectator::PendingExample, {{description}})
|
|
||||||
|
|
||||||
::Spectator::DSL::Builder.add_example(Example%example)
|
|
||||||
end
|
|
||||||
|
|
||||||
macro it_behaves_like
|
|
||||||
{% raise NotImplementedError.new("it_behaves_like functionality is not implemented") %}
|
|
||||||
end
|
|
||||||
|
|
||||||
private macro _spectator_described_class(what)
|
|
||||||
def described_class
|
|
||||||
{{what}}.tap do |thing|
|
|
||||||
raise "#{thing} must be a type name to use #described_class or #subject,\
|
|
||||||
but it is a #{typeof(thing)}" unless thing.is_a?(Class)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
_spectator_implicit_subject
|
|
||||||
end
|
|
||||||
|
|
||||||
private macro _spectator_implicit_subject
|
|
||||||
def subject
|
|
||||||
described_class.new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private macro _spectator_given_collection(class_name, to_a_method_name, collection_method_name)
|
|
||||||
class {{class_name.id}}
|
|
||||||
include {{@type.id}}
|
|
||||||
|
|
||||||
def {{to_a_method_name.id}}
|
|
||||||
{{collection_method_name.id}}.to_a
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private macro _spectator_example_wrapper(class_name, run_method_name, &block)
|
|
||||||
class {{class_name.id}}
|
|
||||||
include ::Spectator::DSL::ExampleDSL
|
|
||||||
include {{@type.id}}
|
|
||||||
|
|
||||||
def initialize(sample_values : ::Spectator::Internals::SampleValues)
|
|
||||||
super
|
|
||||||
end
|
|
||||||
|
|
||||||
def {{run_method_name.id}}
|
|
||||||
{{block.body}}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private macro _spectator_example(example_class_name, wrapper_class_name, base_class, description, &block)
|
|
||||||
class {{example_class_name.id}} < {{base_class.id}}
|
|
||||||
def initialize(group : ::Spectator::ExampleGroup, sample_values : ::Spectator::Internals::SampleValues)
|
|
||||||
super
|
|
||||||
@instance = {{wrapper_class_name.id}}.new(sample_values)
|
|
||||||
end
|
|
||||||
|
|
||||||
{% if block.is_a?(Block) %}
|
|
||||||
{{block.body}}
|
|
||||||
{% end %}
|
|
||||||
|
|
||||||
def description
|
|
||||||
{{description.is_a?(StringLiteral) ? description : description.stringify}}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,120 +1,118 @@
|
||||||
require "./formatter"
|
require "./formatter"
|
||||||
require "colorize"
|
require "colorize"
|
||||||
|
|
||||||
module Spectator
|
module Spectator::Formatters
|
||||||
module Formatters
|
class DefaultFormatter < Formatter
|
||||||
class DefaultFormatter < Formatter
|
SUCCESS_COLOR = :green
|
||||||
SUCCESS_COLOR = :green
|
FAILURE_COLOR = :red
|
||||||
FAILURE_COLOR = :red
|
ERROR_COLOR = :magenta
|
||||||
ERROR_COLOR = :magenta
|
PENDING_COLOR = :yellow
|
||||||
PENDING_COLOR = :yellow
|
|
||||||
|
|
||||||
SUCCESS_CHAR = '.'.colorize(SUCCESS_COLOR)
|
SUCCESS_CHAR = '.'.colorize(SUCCESS_COLOR)
|
||||||
FAILURE_CHAR = 'F'.colorize(FAILURE_COLOR)
|
FAILURE_CHAR = 'F'.colorize(FAILURE_COLOR)
|
||||||
ERROR_CHAR = 'E'.colorize(ERROR_COLOR)
|
ERROR_CHAR = 'E'.colorize(ERROR_COLOR)
|
||||||
PENDING_CHAR = '*'.colorize(PENDING_COLOR)
|
PENDING_CHAR = '*'.colorize(PENDING_COLOR)
|
||||||
|
|
||||||
def start_suite
|
def start_suite
|
||||||
end
|
end
|
||||||
|
|
||||||
def end_suite(results : TestResults)
|
def end_suite(results : TestResults)
|
||||||
|
puts
|
||||||
|
puts
|
||||||
|
display_failures(results)
|
||||||
|
display_errors(results)
|
||||||
|
display_summary(results)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def display_failures(results)
|
||||||
|
failures = results.failures
|
||||||
|
if failures.any?
|
||||||
|
puts "Failures:"
|
||||||
puts
|
puts
|
||||||
puts
|
failures.each_with_index do |failure, index|
|
||||||
display_failures(results)
|
display_failure(failure.as(FailedResult), index + 1)
|
||||||
display_errors(results)
|
|
||||||
display_summary(results)
|
|
||||||
end
|
|
||||||
|
|
||||||
private def display_failures(results)
|
|
||||||
failures = results.failures
|
|
||||||
if failures.any?
|
|
||||||
puts "Failures:"
|
|
||||||
puts
|
|
||||||
failures.each_with_index do |failure, index|
|
|
||||||
display_failure(failure.as(FailedResult), index + 1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private def display_failure(failure, number)
|
private def display_failure(failure, number)
|
||||||
expected = "TODO"
|
expected = "TODO"
|
||||||
actual = "TODO"
|
actual = "TODO"
|
||||||
puts " #{number}) #{failure.example}"
|
puts " #{number}) #{failure.example}"
|
||||||
puts " Failure: #{failure.error.message}"
|
puts " Failure: #{failure.error.message}"
|
||||||
puts
|
puts
|
||||||
puts " Expected: #{expected}"
|
puts " Expected: #{expected}"
|
||||||
puts " got: #{actual}"
|
puts " got: #{actual}"
|
||||||
puts
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
private def display_errors(results)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def display_summary(results)
|
||||||
|
puts finish_time_string(results)
|
||||||
|
puts result_string(results)
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_example(example : Example)
|
||||||
|
end
|
||||||
|
|
||||||
|
def end_example(result : Result)
|
||||||
|
print result_char(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def result_char(result : Result)
|
||||||
|
case result
|
||||||
|
when SuccessfulResult
|
||||||
|
SUCCESS_CHAR
|
||||||
|
when PendingResult
|
||||||
|
PENDING_CHAR
|
||||||
|
when ErroredResult
|
||||||
|
ERROR_CHAR
|
||||||
|
when FailedResult
|
||||||
|
FAILURE_CHAR
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private def display_errors(results)
|
private def finish_time_string(results)
|
||||||
|
"Finished in #{human_time(results.runtime)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private def result_string(results)
|
||||||
|
examples = results.examples
|
||||||
|
failures = results.failed_examples
|
||||||
|
errors = results.errored_examples
|
||||||
|
pending = results.pending_examples
|
||||||
|
string = "#{examples} examples, #{failures} failures, #{errors} errors, #{pending} pending"
|
||||||
|
if failures > 0 || errors > 0
|
||||||
|
string.colorize(FAILURE_COLOR)
|
||||||
|
elsif pending != examples
|
||||||
|
string.colorize(PENDING_COLOR)
|
||||||
|
else
|
||||||
|
string.colorize(SUCCESS_COLOR)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private def display_summary(results)
|
private def human_time(span : Time::Span)
|
||||||
puts finish_time_string(results)
|
millis = span.total_milliseconds
|
||||||
puts result_string(results)
|
return "#{(millis * 1000).round.to_i} microseconds" if millis < 1
|
||||||
end
|
|
||||||
|
|
||||||
def start_example(example : Example)
|
seconds = span.total_seconds
|
||||||
end
|
return "#{millis.round(2)} milliseconds" if seconds < 1
|
||||||
|
return "#{seconds.round(2)} seconds" if seconds < 60
|
||||||
|
|
||||||
def end_example(result : Result)
|
int_seconds = seconds.to_i
|
||||||
print result_char(result)
|
minutes = int_seconds / 60
|
||||||
end
|
int_seconds %= 60
|
||||||
|
return sprintf("%i:%02i", minutes, int_seconds) if minutes < 60
|
||||||
|
|
||||||
private def result_char(result : Result)
|
hours = minutes / 60
|
||||||
case result
|
minutes %= 60
|
||||||
when SuccessfulResult
|
return sprintf("%i:%02i:%02i", hours, minutes, int_seconds) if hours < 24
|
||||||
SUCCESS_CHAR
|
|
||||||
when PendingResult
|
|
||||||
PENDING_CHAR
|
|
||||||
when ErroredResult
|
|
||||||
ERROR_CHAR
|
|
||||||
when FailedResult
|
|
||||||
FAILURE_CHAR
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def finish_time_string(results)
|
days = hours / 24
|
||||||
"Finished in #{human_time(results.runtime)}"
|
hours %= 24
|
||||||
end
|
return sprintf("%i days %i:%02i:%02i", days, hours, minutes, int_seconds)
|
||||||
|
|
||||||
private def result_string(results)
|
|
||||||
examples = results.examples
|
|
||||||
failures = results.failed_examples
|
|
||||||
errors = results.errored_examples
|
|
||||||
pending = results.pending_examples
|
|
||||||
string = "#{examples} examples, #{failures} failures, #{errors} errors, #{pending} pending"
|
|
||||||
if failures > 0 || errors > 0
|
|
||||||
string.colorize(FAILURE_COLOR)
|
|
||||||
elsif pending != examples
|
|
||||||
string.colorize(PENDING_COLOR)
|
|
||||||
else
|
|
||||||
string.colorize(SUCCESS_COLOR)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def human_time(span : Time::Span)
|
|
||||||
millis = span.total_milliseconds
|
|
||||||
return "#{(millis * 1000).round.to_i} microseconds" if millis < 1
|
|
||||||
|
|
||||||
seconds = span.total_seconds
|
|
||||||
return "#{millis.round(2)} milliseconds" if seconds < 1
|
|
||||||
return "#{seconds.round(2)} seconds" if seconds < 60
|
|
||||||
|
|
||||||
int_seconds = seconds.to_i
|
|
||||||
minutes = int_seconds / 60
|
|
||||||
int_seconds %= 60
|
|
||||||
return sprintf("%i:%02i", minutes, int_seconds) if minutes < 60
|
|
||||||
|
|
||||||
hours = minutes / 60
|
|
||||||
minutes %= 60
|
|
||||||
return sprintf("%i:%02i:%02i", hours, minutes, int_seconds) if hours < 24
|
|
||||||
|
|
||||||
days = hours / 24
|
|
||||||
hours %= 24
|
|
||||||
return sprintf("%i days %i:%02i:%02i", days, hours, minutes, int_seconds)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
module Spectator
|
module Spectator::Formatters
|
||||||
module Formatters
|
abstract class Formatter
|
||||||
abstract class Formatter
|
abstract def start_suite
|
||||||
abstract def start_suite
|
abstract def end_suite(results : TestResults)
|
||||||
abstract def end_suite(results : TestResults)
|
abstract def start_example(example : Example)
|
||||||
abstract def start_example(example : Example)
|
abstract def end_example(result : Result)
|
||||||
abstract def end_example(result : Result)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,27 +1,25 @@
|
||||||
require "./value_wrapper"
|
require "./value_wrapper"
|
||||||
|
|
||||||
module Spectator
|
module Spectator::Internals
|
||||||
module Internals
|
struct SampleValues
|
||||||
struct SampleValues
|
private record Entry, name : String, wrapper : ValueWrapper
|
||||||
private record Entry, name : String, wrapper : ValueWrapper
|
|
||||||
|
|
||||||
def self.empty
|
def self.empty
|
||||||
new({} of Symbol => Entry)
|
new({} of Symbol => Entry)
|
||||||
end
|
end
|
||||||
|
|
||||||
protected def initialize(@values = {} of Symbol => Entry)
|
protected def initialize(@values = {} of Symbol => Entry)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add(id : Symbol, name : String, value : T) : SampleValues forall T
|
def add(id : Symbol, name : String, value : T) : SampleValues forall T
|
||||||
wrapper = TypedValueWrapper(T).new(value)
|
wrapper = TypedValueWrapper(T).new(value)
|
||||||
SampleValues.new(@values.merge({
|
SampleValues.new(@values.merge({
|
||||||
id => Entry.new(name, wrapper)
|
id => Entry.new(name, wrapper)
|
||||||
}))
|
}))
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_wrapper(id : Symbol)
|
def get_wrapper(id : Symbol)
|
||||||
@values[id].wrapper
|
@values[id].wrapper
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
require "./value_wrapper"
|
require "./value_wrapper"
|
||||||
|
|
||||||
module Spectator
|
module Spectator::Internals
|
||||||
module Internals
|
class TypedValueWrapper(T) < ValueWrapper
|
||||||
class TypedValueWrapper(T) < ValueWrapper
|
getter value : T
|
||||||
getter value : T
|
|
||||||
|
|
||||||
def initialize(@value : T)
|
def initialize(@value : T)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
module Spectator
|
module Spectator::Internals
|
||||||
module Internals
|
# Base class for proxying test values to examples.
|
||||||
# Base class for proxying test values to examples.
|
# This abstraction is required for inferring types.
|
||||||
# This abstraction is required for inferring types.
|
# The `DSL#let` macro makes heavy use of this.
|
||||||
# The `DSL#let` macro makes heavy use of this.
|
abstract class ValueWrapper
|
||||||
abstract class ValueWrapper
|
# Retrieves the underlying value.
|
||||||
# Retrieves the underlying value.
|
abstract def value
|
||||||
abstract def value
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
require "./matcher"
|
require "./matcher"
|
||||||
|
|
||||||
module Spectator
|
module Spectator::Matchers
|
||||||
module Matchers
|
class EqualityMatcher(T) < Matcher
|
||||||
class EqualityMatcher(T) < Matcher
|
def initialize(label, @expected : T)
|
||||||
def initialize(label, @expected : T)
|
super(label)
|
||||||
super(label)
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def match?(expectation : Expectation)
|
def match?(expectation : Expectation)
|
||||||
expectation.actual == @expected
|
expectation.actual == @expected
|
||||||
end
|
end
|
||||||
|
|
||||||
def message(expectation : Expectation) : String
|
def message(expectation : Expectation) : String
|
||||||
"Expected #{expectation.label} to equal #{label} (using ==)"
|
"Expected #{expectation.label} to equal #{label} (using ==)"
|
||||||
end
|
end
|
||||||
|
|
||||||
def negated_message(expectation : Expectation) : String
|
def negated_message(expectation : Expectation) : String
|
||||||
"Expected #{expectation.label} to not equal #{label} (using ==)"
|
"Expected #{expectation.label} to not equal #{label} (using ==)"
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
module Spectator
|
module Spectator::Matchers
|
||||||
module Matchers
|
abstract class Matcher
|
||||||
abstract class Matcher
|
private getter label : String
|
||||||
private getter label : String
|
|
||||||
|
|
||||||
private def initialize(@label : String)
|
private def initialize(@label : String)
|
||||||
end
|
|
||||||
|
|
||||||
abstract def match?(expectation : Expectation)
|
|
||||||
abstract def message(expectation : Expectation) : String
|
|
||||||
abstract def negated_message(expectation : Expectation) : String
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
abstract def match?(expectation : Expectation)
|
||||||
|
abstract def message(expectation : Expectation) : String
|
||||||
|
abstract def negated_message(expectation : Expectation) : String
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue