Cleaner distinction between metadata and tags
This commit is contained in:
parent
704c28e822
commit
04d6c70f59
|
@ -1,12 +1,12 @@
|
|||
require "../context"
|
||||
require "../location"
|
||||
require "./builder"
|
||||
require "./tags"
|
||||
require "./metadata"
|
||||
|
||||
module Spectator::DSL
|
||||
# DSL methods for defining examples and test code.
|
||||
module Examples
|
||||
include Tags
|
||||
include Metadata
|
||||
|
||||
# Defines a macro to generate code for an example.
|
||||
# The *name* is the name given to the macro.
|
||||
|
@ -39,8 +39,8 @@ module Spectator::DSL
|
|||
\{% raise "Cannot use '{{name.id}}' inside of a test block" if @def %}
|
||||
\{% raise "A description or block must be provided. Cannot use '{{name.id}}' alone." unless what || block %}
|
||||
|
||||
_spectator_tags(%tags, :tags, {{tags.splat(",")}} {{metadata.double_splat}})
|
||||
_spectator_tags(\%tags, %tags, \{{tags.splat(",")}} \{{metadata.double_splat}})
|
||||
_spectator_metadata(%metadata, :metadata, {{tags.splat(",")}} {{metadata.double_splat}})
|
||||
_spectator_metadata(\%metadata, %metadata, \{{tags.splat(",")}} \{{metadata.double_splat}})
|
||||
|
||||
\{% if block %}
|
||||
\{% raise "Block argument count '{{name.id}}' hook must be 0..1" if block.args.size > 1 %}
|
||||
|
@ -53,7 +53,7 @@ module Spectator::DSL
|
|||
_spectator_example_name(\{{what}}),
|
||||
::Spectator::Location.new(\{{block.filename}}, \{{block.line_number}}, \{{block.end_line_number}}),
|
||||
new.as(::Spectator::Context),
|
||||
\%tags
|
||||
\%metadata
|
||||
) do |example|
|
||||
example.with_context(\{{@type.name}}) do
|
||||
\{% if block.args.empty? %}
|
||||
|
@ -68,7 +68,7 @@ module Spectator::DSL
|
|||
::Spectator::DSL::Builder.add_pending_example(
|
||||
_spectator_example_name(\{{what}}),
|
||||
::Spectator::Location.new(\{{what.filename}}, \{{what.line_number}}),
|
||||
\%tags,
|
||||
\%metadata,
|
||||
"Not yet implemented"
|
||||
)
|
||||
\{% end %}
|
||||
|
@ -105,13 +105,13 @@ module Spectator::DSL
|
|||
\{% raise "A description or block must be provided. Cannot use '{{name.id}}' alone." unless what || block %}
|
||||
\{% raise "Block argument count '{{name.id}}' hook must be 0..1" if block && block.args.size > 1 %}
|
||||
|
||||
_spectator_tags(%tags, :tags, {{tags.splat(",")}} {{metadata.double_splat}})
|
||||
_spectator_tags(\%tags, %tags, \{{tags.splat(",")}} \{{metadata.double_splat}})
|
||||
_spectator_metadata(%metadata, :metadata, {{tags.splat(",")}} {{metadata.double_splat}})
|
||||
_spectator_metadata(\%metadata, %metadata, \{{tags.splat(",")}} \{{metadata.double_splat}})
|
||||
|
||||
::Spectator::DSL::Builder.add_pending_example(
|
||||
_spectator_example_name(\{{what}}),
|
||||
::Spectator::Location.new(\{{(what || block).filename}}, \{{(what || block).line_number}}, \{{(what || block).end_line_number}}),
|
||||
\%tags,
|
||||
\%metadata,
|
||||
\{% if !block %}"Not yet implemented"\{% end %}
|
||||
)
|
||||
end
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
require "../location"
|
||||
require "./builder"
|
||||
require "./tags"
|
||||
require "./memoize"
|
||||
require "./metadata"
|
||||
|
||||
module Spectator::DSL
|
||||
# DSL methods and macros for creating example groups.
|
||||
# This module should be included as a mix-in.
|
||||
module Groups
|
||||
include Tags
|
||||
include Metadata
|
||||
|
||||
# Defines a macro to generate code for an example group.
|
||||
# The *name* is the name given to the macro.
|
||||
|
@ -36,13 +36,13 @@ module Spectator::DSL
|
|||
class Group\%group < \{{@type.id}}
|
||||
_spectator_group_subject(\{{what}})
|
||||
|
||||
_spectator_tags(:tags, :super, {{tags.splat(", ")}} {{metadata.double_splat}})
|
||||
_spectator_tags(:tags, :previous_def, \{{tags.splat(", ")}} \{{metadata.double_splat}})
|
||||
_spectator_metadata(:metadata, :super, {{tags.splat(", ")}} {{metadata.double_splat}})
|
||||
_spectator_metadata(:metadata, :previous_def, \{{tags.splat(", ")}} \{{metadata.double_splat}})
|
||||
|
||||
::Spectator::DSL::Builder.start_group(
|
||||
_spectator_group_name(\{{what}}),
|
||||
::Spectator::Location.new(\{{block.filename}}, \{{block.line_number}}),
|
||||
tags
|
||||
metadata
|
||||
)
|
||||
|
||||
\{{block.body}}
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
module Spectator::DSL
|
||||
module Tags
|
||||
# Defines a class method named *name* that combines tags
|
||||
module Metadata
|
||||
# Defines a class method named *name* that combines metadata
|
||||
# returned by *source* with *tags* and *metadata*.
|
||||
# Any falsey items from *metadata* are removed.
|
||||
private macro _spectator_tags(name, source, *tags, **metadata)
|
||||
private macro _spectator_metadata(name, source, *tags, **metadata)
|
||||
private def self.{{name.id}}
|
||||
%tags = {{source.id}}.dup
|
||||
%metadata = {{source.id}}.dup
|
||||
{% for k in tags %}
|
||||
%tags[{{k.id.symbolize}}] = nil
|
||||
%metadata[{{k.id.symbolize}}] = nil
|
||||
{% end %}
|
||||
{% for k, v in metadata %}
|
||||
%cond = begin
|
||||
{{v}}
|
||||
end
|
||||
if %cond
|
||||
%tags[{{k.id.symbolize}}] = %cond.to_s
|
||||
%metadata[{{k.id.symbolize}}] = %cond.to_s
|
||||
else
|
||||
%tags.delete({{k.id.symbolize}})
|
||||
%metadata.delete({{k.id.symbolize}})
|
||||
end
|
||||
{% end %}
|
||||
%tags
|
||||
%metadata
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,7 +5,7 @@ require "./location"
|
|||
require "./node"
|
||||
require "./pending_result"
|
||||
require "./result"
|
||||
require "./tags"
|
||||
require "./metadata"
|
||||
|
||||
module Spectator
|
||||
# Standard example that runs a test case.
|
||||
|
@ -35,12 +35,12 @@ module Spectator
|
|||
# It can be a `Symbol` to describe a type.
|
||||
# The *location* tracks where the example exists in source code.
|
||||
# The example will be assigned to *group* if it is provided.
|
||||
# A set of *tags* can be used for filtering and modifying example behavior.
|
||||
# Note: The tags will not be merged with the parent tags.
|
||||
# A set of *metadata* can be used for filtering and modifying example behavior.
|
||||
# Note: The metadata will not be merged with the parent metadata.
|
||||
def initialize(@context : Context, @entrypoint : self ->,
|
||||
name : String? = nil, location : Location? = nil,
|
||||
@group : ExampleGroup? = nil, tags = Tags.new)
|
||||
super(name, location, tags)
|
||||
@group : ExampleGroup? = nil, metadata = Metadata.new)
|
||||
super(name, location, metadata)
|
||||
|
||||
# Ensure group is linked.
|
||||
group << self if group
|
||||
|
@ -53,11 +53,11 @@ module Spectator
|
|||
# It can be a `Symbol` to describe a type.
|
||||
# The *location* tracks where the example exists in source code.
|
||||
# The example will be assigned to *group* if it is provided.
|
||||
# A set of *tags* can be used for filtering and modifying example behavior.
|
||||
# Note: The tags will not be merged with the parent tags.
|
||||
# A set of *metadata* can be used for filtering and modifying example behavior.
|
||||
# Note: The metadata will not be merged with the parent metadata.
|
||||
def initialize(name : String? = nil, location : Location? = nil,
|
||||
@group : ExampleGroup? = nil, tags = Tags.new, &block : self ->)
|
||||
super(name, location, tags)
|
||||
@group : ExampleGroup? = nil, metadata = Metadata.new, &block : self ->)
|
||||
super(name, location, metadata)
|
||||
|
||||
@context = NullContext.new
|
||||
@entrypoint = block
|
||||
|
@ -71,13 +71,13 @@ module Spectator
|
|||
# It can be a `Symbol` to describe a type.
|
||||
# The *location* tracks where the example exists in source code.
|
||||
# The example will be assigned to *group* if it is provided.
|
||||
# A set of *tags* can be used for filtering and modifying example behavior.
|
||||
# Note: The tags will not be merged with the parent tags.
|
||||
# A set of *metadata* can be used for filtering and modifying example behavior.
|
||||
# Note: The metadata will not be merged with the parent metadata.
|
||||
def self.pending(name : String? = nil, location : Location? = nil,
|
||||
group : ExampleGroup? = nil, tags = Tags.new, reason = nil)
|
||||
group : ExampleGroup? = nil, metadata = Metadata.new, reason = nil)
|
||||
# Add pending tag and reason if they don't exist.
|
||||
tags = tags.merge({:pending => nil, :reason => reason}) { |_, v, _| v }
|
||||
new(name, location, group, tags) { nil }
|
||||
metadata = metadata.merge({:pending => nil, :reason => reason}) { |_, v, _| v }
|
||||
new(name, location, group, metadata) { nil }
|
||||
end
|
||||
|
||||
# Executes the test case.
|
||||
|
|
|
@ -86,9 +86,9 @@ module Spectator
|
|||
# It can be a `Symbol` to describe a type.
|
||||
# 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 *tags* can be used for filtering and modifying example behavior.
|
||||
# A set of *metadata* can be used for filtering and modifying example behavior.
|
||||
def initialize(@name : Label = nil, @location : Location? = nil,
|
||||
@group : ExampleGroup? = nil, @tags : Tags = Tags.new)
|
||||
@group : ExampleGroup? = nil, @metadata : Metadata = Metadata.new)
|
||||
# Ensure group is linked.
|
||||
group << self if group
|
||||
end
|
||||
|
|
|
@ -37,6 +37,7 @@ require "./line_example_filter"
|
|||
require "./location"
|
||||
require "./location_example_filter"
|
||||
require "./matchers"
|
||||
require "./metadata"
|
||||
require "./mocks"
|
||||
require "./name_example_filter"
|
||||
require "./null_context"
|
||||
|
@ -47,7 +48,6 @@ require "./profile"
|
|||
require "./report"
|
||||
require "./result"
|
||||
require "./spec"
|
||||
require "./tags"
|
||||
require "./test_context"
|
||||
require "./value"
|
||||
require "./wrapper"
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
module Spectator
|
||||
# User-defined keywords used for filtering and behavior modification.
|
||||
alias Tags = Set(Symbol)
|
||||
|
||||
# User-defined keywords used for filtering and behavior modification.
|
||||
# The value of a tag is optional, but may contain useful information.
|
||||
# If the value is nil, the tag exists, but has no data.
|
||||
# However, when tags are given on examples and example groups,
|
||||
# if the value is falsey (false or nil), then the tag should be removed from the overall collection.
|
||||
alias Tags = Hash(Symbol, String?)
|
||||
alias Metadata = Hash(Symbol, String?)
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
require "./label"
|
||||
require "./location"
|
||||
require "./tags"
|
||||
require "./metadata"
|
||||
|
||||
module Spectator
|
||||
# A single item in a test spec.
|
||||
|
@ -29,15 +29,15 @@ module Spectator
|
|||
protected def name=(@name : String)
|
||||
end
|
||||
|
||||
# User-defined keywords used for filtering and behavior modification.
|
||||
getter tags : Tags
|
||||
# User-defined tags and values used for filtering and behavior modification.
|
||||
getter metadata : Metadata
|
||||
|
||||
# Creates the node.
|
||||
# The *name* describes the purpose of the node.
|
||||
# It can be a `Symbol` to describe a type.
|
||||
# The *location* tracks where the node exists in source code.
|
||||
# A set of *tags* can be used for filtering and modifying example behavior.
|
||||
def initialize(@name : Label = nil, @location : Location? = nil, @tags : Tags = Tags.new)
|
||||
# A set of *metadata* can be used for filtering and modifying example behavior.
|
||||
def initialize(@name : Label = nil, @location : Location? = nil, @metadata : Metadata = Metadata.new)
|
||||
end
|
||||
|
||||
# Indicates whether the node has completed.
|
||||
|
@ -46,12 +46,17 @@ module Spectator
|
|||
# Checks if the node has been marked as pending.
|
||||
# Pending items should be skipped during execution.
|
||||
def pending?
|
||||
tags.has_key?(:pending) || tags.has_key?(:skip)
|
||||
metadata.has_key?(:pending) || metadata.has_key?(:skip)
|
||||
end
|
||||
|
||||
# Gets the reason the node has been marked as pending.
|
||||
def pending_reason
|
||||
tags[:pending]? || tags[:skip]? || tags[:reason]? || DEFAULT_PENDING_REASON
|
||||
metadata[:pending]? || metadata[:skip]? || metadata[:reason]? || DEFAULT_PENDING_REASON
|
||||
end
|
||||
|
||||
# Retrieves just the tag names applied to the node.
|
||||
def tags
|
||||
Tags.new(metadata.keys)
|
||||
end
|
||||
|
||||
# Constructs the full name or description of the node.
|
||||
|
|
|
@ -3,7 +3,7 @@ require "../example"
|
|||
require "../example_context_method"
|
||||
require "../example_group"
|
||||
require "../spec"
|
||||
require "../tags"
|
||||
require "../metadata"
|
||||
|
||||
module Spectator
|
||||
class Spec
|
||||
|
@ -53,14 +53,14 @@ module Spectator
|
|||
#
|
||||
# The *location* optionally defined where the group originates in source code.
|
||||
#
|
||||
# A set of *tags* can be used for filtering and modifying example behavior.
|
||||
# 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_group(name, location = nil, tags = Tags.new) : ExampleGroup
|
||||
Log.trace { "Start group: #{name.inspect} @ #{location}; tags: #{tags}" }
|
||||
ExampleGroup.new(name, location, current_group, tags).tap do |group|
|
||||
def start_group(name, location = nil, metadata = Metadata.new) : ExampleGroup
|
||||
Log.trace { "Start group: #{name.inspect} @ #{location}; metadata: #{metadata}" }
|
||||
ExampleGroup.new(name, location, current_group, metadata).tap do |group|
|
||||
@group_stack << group
|
||||
end
|
||||
end
|
||||
|
@ -90,7 +90,7 @@ module Spectator
|
|||
# The *context* is an instance of the context the test code should run in.
|
||||
# See `Context` for more information.
|
||||
#
|
||||
# A set of *tags* can be used for filtering and modifying example behavior.
|
||||
# A set of *metadata* can be used for filtering and modifying example behavior.
|
||||
# For instance, adding a "pending" tag will mark the test as pending and skip execution.
|
||||
#
|
||||
# A block must be provided.
|
||||
|
@ -99,9 +99,9 @@ module Spectator
|
|||
# It is expected that the test code runs when the block is called.
|
||||
#
|
||||
# The newly created example is returned.
|
||||
def add_example(name, location, context, tags = Tags.new, &block : Example -> _) : Example
|
||||
Log.trace { "Add example: #{name} @ #{location}; tags: #{tags}" }
|
||||
Example.new(context, block, name, location, current_group, tags)
|
||||
def add_example(name, location, context, metadata = Metadata.new, &block : Example -> _) : Example
|
||||
Log.trace { "Add example: #{name} @ #{location}; metadata: #{metadata}" }
|
||||
Example.new(context, block, name, location, current_group, metadata)
|
||||
# The example is added to the current group by `Example` initializer.
|
||||
end
|
||||
|
||||
|
@ -114,14 +114,14 @@ module Spectator
|
|||
#
|
||||
# The *location* optionally defined where the example originates in source code.
|
||||
#
|
||||
# A set of *tags* can be used for filtering and modifying example behavior.
|
||||
# A set of *metadata* can be used for filtering and modifying example behavior.
|
||||
# For instance, adding a "pending" tag will mark the test as pending and skip execution.
|
||||
# A default *reason* can be given in case the user didn't provide one.
|
||||
#
|
||||
# The newly created example is returned.
|
||||
def add_pending_example(name, location, tags = Tags.new, reason = nil) : Example
|
||||
Log.trace { "Add pending example: #{name} @ #{location}; tags: #{tags}" }
|
||||
Example.pending(name, location, current_group, tags, reason)
|
||||
def add_pending_example(name, location, metadata = Metadata.new, reason = nil) : Example
|
||||
Log.trace { "Add pending example: #{name} @ #{location}; metadata: #{metadata}" }
|
||||
Example.pending(name, location, current_group, metadata, reason)
|
||||
# The example is added to the current group by `Example` initializer.
|
||||
end
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require "./context"
|
||||
require "./dsl"
|
||||
require "./lazy_wrapper"
|
||||
require "./tags"
|
||||
require "./metadata"
|
||||
|
||||
# Class used as the base for all specs using the DSL.
|
||||
# It adds methods and macros necessary to use the DSL from the spec.
|
||||
|
@ -32,9 +32,9 @@ class SpectatorTestContext < SpectatorContext
|
|||
@subject.get { _spectator_implicit_subject }
|
||||
end
|
||||
|
||||
# Initial tags for tests.
|
||||
# Initial metadata for tests.
|
||||
# This method should be overridden by example groups and examples.
|
||||
private def self.tags
|
||||
::Spectator::Tags.new
|
||||
private def self.metadata
|
||||
::Spectator::Metadata.new
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue