Add some docs

This commit is contained in:
Michael Miller 2020-09-26 18:14:22 -06:00
parent de99fce5b1
commit acb3b16496
No known key found for this signature in database
GPG key ID: FB9F12F7C646A4AD
3 changed files with 71 additions and 8 deletions

View file

@ -4,5 +4,9 @@ module Spectator
# Base class that all test cases run in.
# This type is used to store all test case contexts as a single type.
# The instance must be downcast to the correct type before calling a context method.
#
# Nested contexts, such as those defined by `context` and `describe` in the DSL, can define their own methods.
# The intent is that a proc will downcast to the correct type and call one of those methods.
# This is how methods that contain test cases, hooks, and other context-specific code blocks get invoked.
alias Context = ::SpectatorContext
end

View file

@ -1,19 +1,35 @@
require "../spec/builder"
module Spectator::DSL
# Incrementally builds up a test spec from the DSL.
# This is intended to be used only by the Spectator DSL.
module Builder
extend self
# Underlying spec builder.
@@builder = Spec::Builder.new
# Defines a new example group and pushes it onto the group stack.
# Examples and groups defined after calling this method will be nested under the new group.
# The group will be finished and popped off the stack when `#end_example` is called.
#
# See `Spec::Builder#start_group` for usage details.
def start_group(*args)
@@builder.start_group(*args)
end
# Completes a previously defined example group and pops it off the group stack.
# Be sure to call `#start_group` and `#end_group` symmetically.
#
# See `Spec::Builder#end_group` for usage details.
def end_group(*args)
@@builder.end_group(*args)
end
# Defines a new example.
# The example is added to the group currently on the top of the stack.
#
# See `Spec::Builder#add_example` for usage details.
def add_example(*args, &block : Example, Context ->)
@@builder.add_example(*args, &block)
end

View file

@ -3,6 +3,10 @@ require "../example_context_method"
require "../example_group"
module Spectator
# Progressively builds a test spec.
#
# A stack is used to track the current example group.
# Adding an example or group will nest it under the group at the top of the stack.
class Spec::Builder
# Stack tracking the current group.
# The bottom of the stack (first element) is the root group.
@ -11,16 +15,26 @@ module Spectator
# New examples should be added to the current group.
@group_stack : Deque(ExampleGroup)
# Creates a new spec builder.
# A root group is pushed onto the group stack.
def initialize
root_group = ExampleGroup.new
@group_stack = Deque(ExampleGroup).new
@group_stack.push(root_group)
end
def add_example
raise NotImplementedError.new("#add_example")
end
# Defines a new example group and pushes it onto the group stack.
# Examples and groups defined after calling this method will be nested under the new group.
# The group will be finished and popped off the stack when `#end_example` is called.
#
# The *name* is the name or brief description of the group.
# This should be a symbol when describing a type - the type name is represented as a symbol.
# Otherwise, a string should be used.
#
# The *source* optionally defined where the group originates in source code.
#
# The newly created group is returned.
# It shouldn't be used outside of this class until a matching `#end_group` is called.
def start_group(name, source = nil) : ExampleGroup
{% if flag?(:spectator_debug) %}
puts "Start group: #{name.inspect} @ #{source}"
@ -30,7 +44,13 @@ module Spectator
end
end
def end_group
# Completes a previously defined example group and pops it off the group stack.
# Be sure to call `#start_group` and `#end_group` symmetically.
#
# The completed group will be returned.
# At this point, it is safe to use the group.
# All of its examples and sub-groups have been populated.
def end_group : ExampleGroup
{% if flag?(:spectator_debug) %}
puts "End group: #{current_group}"
{% end %}
@ -39,7 +59,25 @@ module Spectator
@group_stack.pop
end
def add_example(name, source, context, &block : Example, Context ->)
# Defines a new example.
# The example is added to the group currently on the top of the stack.
#
# The *name* is the name or brief description of the example.
# This should be a string or nil.
# When nil, the example's name will be populated by the first expectation run inside of the test code.
#
# The *source* optionally defined where the example originates in source code.
#
# The *context* is an instance of the context the test code should run in.
# See `Context` for more information.
#
# A block must be provided.
# It will be yielded two arguments - the example created by this method, and the *context* argument.
# The return value of the block is ignored.
# It is expected that the test code runs when the block is called.
#
# The newly created example is returned.
def add_example(name, source, context, &block : Example, Context ->) : Example
{% if flag?(:spectator_debug) %}
puts "Add example: #{name} @ #{source}"
{% end %}
@ -48,7 +86,12 @@ module Spectator
# The example is added to the current group by `Example` initializer.
end
def build
# Constructs the test spec.
# Returns the spec instance.
#
# Raises an error if there were not symmetrical calls to `#start_group` and `#end_group`.
# This would indicate a logical error somewhere in Spectator or an extension of it.
def build : Spec
raise NotImplementedError.new("#build")
end
@ -62,7 +105,7 @@ module Spectator
@group_stack.first
end
# Retrieves the current group.
# Retrieves the current group, which is at the top of the stack.
# This is the group that new examples should be added to.
private def current_group
@group_stack.last