Initial code for iterative (sample) groups

This commit is contained in:
Michael Miller 2021-06-13 13:16:31 -06:00
parent e51ad6d504
commit 4ff27defff
No known key found for this signature in database
GPG key ID: FB9F12F7C646A4AD
3 changed files with 68 additions and 0 deletions

View file

@ -21,6 +21,15 @@ module Spectator::DSL
@@builder.start_group(*args)
end
# Defines a new iterative 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_iterative_group` for usage details.
def start_iterative_group(*args)
@@builder.start_iterative_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.
#

View file

@ -0,0 +1,37 @@
require "./example_group"
require "./node"
module Spectator
# Collection of examples and sub-groups executed multiple times.
# Each sub-node is executed once for each item in a given collection.
class IterativeExampleGroup(T) < ExampleGroup
# Creates the iterative example group.
# The *collection* is a list of items to iterative over each sub-node over.
# The *location* tracks where the group exists in source code.
# This group will be assigned to the parent *group* if it is provided.
# A set of *metadata* can be used for filtering and modifying example behavior.
def initialize(collection : Enumerable(T), location : Location? = nil,
group : ExampleGroup? = nil, metadata : Metadata = Metadata.new)
super()
@nodes = collection.map do |item|
Iteration.new(item, location, group, metadata).as(Node)
end
end
# Adds the specified *node* to the group.
# Assigns the node to this group.
# If the node already belongs to a group,
# it will be removed from the previous group before adding it to this group.
def <<(node : Node)
@nodes.each { |child| child.as(Iteration(T)) << node.dup }
end
private class Iteration(T) < ExampleGroup
def initialize(@item : T, location : Location? = nil,
group : ExampleGroup? = nil, metadata : Metadata = Metadata.new)
super(@item.inspect, location, group, metadata)
end
end
end
end

View file

@ -2,6 +2,7 @@ require "../config"
require "../example"
require "../example_context_method"
require "../example_group"
require "../iterative_example_group"
require "../spec"
require "../metadata"
@ -65,6 +66,27 @@ module Spectator
end
end
# Defines a new iterative 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 *collection* is the set of items to iterate over.
# Child nodes in this group will be executed once for every item in the collection.
#
# The *location* optionally defined where the group originates in source code.
#
# A set of *metadata* can be used for filtering and modifying example behavior.
# For instance, adding a "pending" tag will mark tests as pending and skip execution.
#
# The newly created group is returned.
# It shouldn't be used outside of this class until a matching `#end_group` is called.
def start_iterative_group(collection, location = nil, metadata = Metadata.new) : ExampleGroup
Log.trace { "Start iterative group: #{typeof(collection)} @ #{location}; metadata: #{metadata}" }
IterativeExampleGroup.new(collection, location, current_group, metadata).tap do |group|
@group_stack << group
end
end
# Completes a previously defined example group and pops it off the group stack.
# Be sure to call `#start_group` and `#end_group` symmetically.
#