From e304224bd6ba563e10c3eede16892f6cc128609f Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sun, 8 Sep 2019 09:59:25 -0600 Subject: [PATCH] Move stack handling to its own type --- src/spectator/builders/example_group_stack.cr | 22 ++++++++ src/spectator/dsl/builder.cr | 52 +++++++------------ 2 files changed, 40 insertions(+), 34 deletions(-) create mode 100644 src/spectator/builders/example_group_stack.cr diff --git a/src/spectator/builders/example_group_stack.cr b/src/spectator/builders/example_group_stack.cr new file mode 100644 index 0000000..cf91a45 --- /dev/null +++ b/src/spectator/builders/example_group_stack.cr @@ -0,0 +1,22 @@ +module Spectator::Builders + struct ExampleGroupStack + getter root = RootExampleGroupBuilder.new + + @stack = Deque(ExampleGroupBuilder).new(1, @root) + + def current + @stack.last + end + + def push(group : NestedExampleGroupBuilder) + current.add_child(group) + @stack.push(group) + end + + def pop + raise "Attempted to pop root example group from stack" if current == root + + @stack.pop + end + end +end diff --git a/src/spectator/dsl/builder.cr b/src/spectator/dsl/builder.cr index a836559..b815dce 100644 --- a/src/spectator/dsl/builder.cr +++ b/src/spectator/dsl/builder.cr @@ -6,26 +6,7 @@ module Spectator::DSL module Builder extend self - # Root group that contains all examples and groups in the spec. - private class_getter root_group = RootExampleGroupBuilder.new - - # Stack for tracking the current group the spec is working in. - # The last item (top of the stack) is the current group. - # The first item (bottom of the stack) is the root group (`#root_group`). - # The root group should never be popped. - @@group_stack = Array(ExampleGroupBuilder).new(1, root_group) - - # Retrieves the current group the spec is working in. - private def current_group - @@group_stack.last - end - - # Adds a new group to the stack. - # Calling this method indicates the spec has entered a nested group. - private def push_group(group : NestedExampleGroupBuilder) - current_group.add_child(group) - @@group_stack.push(group) - end + @@stack = Builders::ExampleGroupStack.new # Begins a new nested group in the spec. # A corresponding `#end_group` call must be made @@ -34,7 +15,7 @@ module Spectator::DSL # as arguments to this method are passed directly to it. def start_group(*args) : Nil group = NestedExampleGroupBuilder.new(*args) - push_group(group) + @@stack.push(group) end # Begins a new sample group in the spec - @@ -45,7 +26,7 @@ module Spectator::DSL # as arguments to this method are passed directly to it. def start_sample_group(*args) : Nil group = SampleExampleGroupBuilder.new(*args) - push_group(group) + @@stack.push(group) end # Marks the end of a group in the spec. @@ -53,58 +34,61 @@ module Spectator::DSL # It is also important to line up the start and end calls. # Otherwise examples might get placed into wrong groups. def end_group : Nil - @@group_stack.pop + @@stack.pop end # Adds an example type to the current group. # The class name of the example should be passed as an argument. # The example will be instantiated later. - def add_example(example_type : Example.class) : Nil - factory = ExampleFactory.new(example_type) - current_group.add_child(factory) + def add_example(description : String, source : Source, + example_type : ::SpectatorTest.class, &runner : ::SpectatorTest ->) : Nil + builder = ->{ example_type.new.as(::SpectatorTest) } + wrapper = TestWrapper.new(description, source, builder, runner) + example = Example.new(current_group, wrapper) + # TODO: Add to stack. end # Adds a block of code to run before all examples in the current group. def add_before_all_hook(&block : ->) : Nil - current_group.add_before_all_hook(block) + @@stack.current.add_before_all_hook(block) end # Adds a block of code to run before each example in the current group. def add_before_each_hook(&block : ->) : Nil - current_group.add_before_each_hook(block) + @@stack.current.add_before_each_hook(block) end # Adds a block of code to run after all examples in the current group. def add_after_all_hook(&block : ->) : Nil - current_group.add_after_all_hook(block) + @@stack.current.add_after_all_hook(block) end # Adds a block of code to run after each example in the current group. def add_after_each_hook(&block : ->) : Nil - current_group.add_after_each_hook(block) + @@stack.current.add_after_each_hook(block) end # Adds a block of code to run before and after each example in the current group. # The block of code will be given another proc as an argument. # It is expected that the block will call the proc. def add_around_each_hook(&block : Proc(Nil) ->) : Nil - current_group.add_around_each_hook(block) + @@stack.current.add_around_each_hook(block) end # Adds a pre-condition to run at the start of every example in the current group. def add_pre_condition(&block : ->) : Nil - current_group.add_pre_condition(block) + @@stack.current.add_pre_condition(block) end # Adds a post-condition to run at the end of every example in the current group. def add_post_condition(&block : ->) : Nil - current_group.add_post_condition(block) + @@stack.current.add_post_condition(block) end # Builds the entire spec and returns it as a test suite. # This should be called only once after the entire spec has been defined. protected def build(filter : ExampleFilter) : TestSuite - group = root_group.build(Internals::SampleValues.empty) + group = @@stack.root.build(Internals::SampleValues.empty) TestSuite.new(group, filter) end end