mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Create ExampleGroup and use shared ExampleNode type
This commit is contained in:
parent
0f9c1ad09c
commit
fbf574b0b9
3 changed files with 104 additions and 64 deletions
|
@ -1,52 +1,9 @@
|
||||||
require "./example_group"
|
require "./example_node"
|
||||||
require "./result"
|
require "./result"
|
||||||
require "./source"
|
|
||||||
|
|
||||||
module Spectator
|
module Spectator
|
||||||
# Common base type for all examples.
|
# Common base type for all examples.
|
||||||
abstract class ExampleBase
|
abstract class ExampleBase < ExampleNode
|
||||||
# Location of the example in source code.
|
|
||||||
getter! source : Source
|
|
||||||
|
|
||||||
# User-provided name or description of the test.
|
|
||||||
# This does not include the group name or descriptions.
|
|
||||||
# Use `#to_s` to get the full name.
|
|
||||||
#
|
|
||||||
# This value will be nil if no name was provided.
|
|
||||||
# In this case, the name should be set
|
|
||||||
# to the description of the first matcher that runs in the example.
|
|
||||||
#
|
|
||||||
# If this value is a `Symbol`, the user specified a type for the name.
|
|
||||||
getter! name : String | Symbol
|
|
||||||
|
|
||||||
# Group the example belongs to.
|
|
||||||
# Hooks are used from this group.
|
|
||||||
getter! group : ExampleGroup
|
|
||||||
|
|
||||||
# Assigns the group the example belongs to.
|
|
||||||
# If the example already belongs to a group,
|
|
||||||
# it will be removed from the previous group before adding it to the new group.
|
|
||||||
def group=(group : ExampleGroup?)
|
|
||||||
if (previous = @group)
|
|
||||||
previous.remove_example(self)
|
|
||||||
end
|
|
||||||
group.add_example(self) if group
|
|
||||||
@group = group
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates the base of the example.
|
|
||||||
# The *name* describes the purpose of the example.
|
|
||||||
# It can be a `Symbol` to describe a type.
|
|
||||||
# The *source* tracks where the example exists in source code.
|
|
||||||
# The example will be assigned to *group* if it is provided.
|
|
||||||
def initialize(@name : String | Symbol? = nil, @source : Source? = nil, group : ExampleGroup? = nil)
|
|
||||||
# Ensure group is linked.
|
|
||||||
self.group = group
|
|
||||||
end
|
|
||||||
|
|
||||||
# Indicates whether the example already ran.
|
|
||||||
abstract def finished? : Bool
|
|
||||||
|
|
||||||
# Retrieves the result of the last time the example ran.
|
# Retrieves the result of the last time the example ran.
|
||||||
# This will be nil if the example hasn't run,
|
# This will be nil if the example hasn't run,
|
||||||
# and should not be nil if it has.
|
# and should not be nil if it has.
|
||||||
|
@ -58,25 +15,6 @@ module Spectator
|
||||||
result? || raise(NilAssertionError("Example has no result"))
|
result? || raise(NilAssertionError("Example has no result"))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Constructs the full name or description of the example.
|
|
||||||
# This prepends names of groups this example is part of.
|
|
||||||
def to_s(io)
|
|
||||||
name = @name
|
|
||||||
|
|
||||||
# Prefix with group's full name if the example belongs to a group.
|
|
||||||
if (group = @group)
|
|
||||||
group.to_s(io)
|
|
||||||
|
|
||||||
# Add padding between the group name and example name,
|
|
||||||
# only if the names appear to be symbolic.
|
|
||||||
if group.name.is_a?(Symbol) && name.is_a?(String)
|
|
||||||
io << ' ' unless name.starts_with?('#') || name.starts_with?('.')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
name.to_s(io)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Exposes information about the example useful for debugging.
|
# Exposes information about the example useful for debugging.
|
||||||
def inspect(io)
|
def inspect(io)
|
||||||
raise NotImplementedError.new("#inspect")
|
raise NotImplementedError.new("#inspect")
|
||||||
|
|
38
src/spectator/example_group.cr
Normal file
38
src/spectator/example_group.cr
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
module Spectator
|
||||||
|
# Collection of examples and sub-groups.
|
||||||
|
class ExampleGroup < ExampleNode
|
||||||
|
include Enumerable(ExampleNode)
|
||||||
|
|
||||||
|
@nodes = [] of ExampleNode
|
||||||
|
|
||||||
|
# Removes the specified *node* from the group.
|
||||||
|
# The node will be unassigned from this group.
|
||||||
|
def delete(node : ExampleNode)
|
||||||
|
# Only remove from the group if it is associated with this group.
|
||||||
|
return unless node.group == self
|
||||||
|
|
||||||
|
node.group = nil
|
||||||
|
@nodes.delete(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Yields each node (example and sub-group).
|
||||||
|
def each
|
||||||
|
@nodes.each { |node| yield node }
|
||||||
|
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 : ExampleNode)
|
||||||
|
# Remove from existing group if the node is part of one.
|
||||||
|
if (previous = node.group?)
|
||||||
|
previous.delete(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add the node to this group and associate with it.
|
||||||
|
@nodes << node
|
||||||
|
node.group = self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
64
src/spectator/example_node.cr
Normal file
64
src/spectator/example_node.cr
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
require "./source"
|
||||||
|
|
||||||
|
module Spectator
|
||||||
|
# A single example or collection (group) of examples in an example tree.
|
||||||
|
abstract class ExampleNode
|
||||||
|
# Location of the node in source code.
|
||||||
|
getter! source : Source
|
||||||
|
|
||||||
|
# User-provided name or description of the test.
|
||||||
|
# This does not include the group name or descriptions.
|
||||||
|
# Use `#to_s` to get the full name.
|
||||||
|
#
|
||||||
|
# This value will be nil if no name was provided.
|
||||||
|
# In this case, and the node is a runnable example,
|
||||||
|
# the name should be set to the description
|
||||||
|
# of the first matcher that runs in the test case.
|
||||||
|
#
|
||||||
|
# If this value is a `Symbol`, the user specified a type for the name.
|
||||||
|
getter! name : String | Symbol
|
||||||
|
|
||||||
|
# Updates the name of the node.
|
||||||
|
protected def name=(@name : String)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Group the node belongs to.
|
||||||
|
getter! group : ExampleGroup
|
||||||
|
|
||||||
|
# Assigns the node to the specified *group*.
|
||||||
|
# This is an internal method and should only be called from `ExampleGroup`.
|
||||||
|
# `ExampleGroup` manages the association of nodes to groups.
|
||||||
|
protected setter group : ExampleGroup?
|
||||||
|
|
||||||
|
# Creates the node.
|
||||||
|
# The *name* describes the purpose of the node.
|
||||||
|
# It can be a `Symbol` to describe a type.
|
||||||
|
# The *source* tracks where the node exists in source code.
|
||||||
|
# The node will be assigned to *group* if it is provided.
|
||||||
|
def initialize(@name : String | Symbol? = nil, @source : Source? = nil, group : ExampleGroup? = nil)
|
||||||
|
# Ensure group is linked.
|
||||||
|
group << self if group
|
||||||
|
end
|
||||||
|
|
||||||
|
# Indicates whether the node has completed.
|
||||||
|
abstract def finished? : Bool
|
||||||
|
|
||||||
|
# Constructs the full name or description of the node.
|
||||||
|
# This prepends names of groups this node is part of.
|
||||||
|
def to_s(io)
|
||||||
|
name = @name
|
||||||
|
|
||||||
|
# Prefix with group's full name if the node belongs to a group.
|
||||||
|
if (group = @group)
|
||||||
|
io << group
|
||||||
|
|
||||||
|
# Add padding between the node names
|
||||||
|
# only if the names don't appear to be symbolic.
|
||||||
|
io << ' ' unless group.name.is_a?(Symbol) && name.is_a?(String) &&
|
||||||
|
(name.starts_with?('#') || name.starts_with?('.'))
|
||||||
|
end
|
||||||
|
|
||||||
|
io << name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue