diff --git a/src/spectator/dsl/examples.cr b/src/spectator/dsl/examples.cr index 3310362..27e6b60 100644 --- a/src/spectator/dsl/examples.cr +++ b/src/spectator/dsl/examples.cr @@ -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 diff --git a/src/spectator/dsl/groups.cr b/src/spectator/dsl/groups.cr index d1ec249..9eb0091 100644 --- a/src/spectator/dsl/groups.cr +++ b/src/spectator/dsl/groups.cr @@ -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}} diff --git a/src/spectator/dsl/tags.cr b/src/spectator/dsl/metadata.cr similarity index 52% rename from src/spectator/dsl/tags.cr rename to src/spectator/dsl/metadata.cr index 0368cda..308bcbd 100644 --- a/src/spectator/dsl/tags.cr +++ b/src/spectator/dsl/metadata.cr @@ -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 diff --git a/src/spectator/example.cr b/src/spectator/example.cr index 651aee7..513cca8 100644 --- a/src/spectator/example.cr +++ b/src/spectator/example.cr @@ -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. diff --git a/src/spectator/example_group.cr b/src/spectator/example_group.cr index 7acf234..23e0f75 100644 --- a/src/spectator/example_group.cr +++ b/src/spectator/example_group.cr @@ -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 diff --git a/src/spectator/includes.cr b/src/spectator/includes.cr index 9e9dd5f..c611475 100644 --- a/src/spectator/includes.cr +++ b/src/spectator/includes.cr @@ -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" diff --git a/src/spectator/tags.cr b/src/spectator/metadata.cr similarity index 73% rename from src/spectator/tags.cr rename to src/spectator/metadata.cr index e37a473..9baaab6 100644 --- a/src/spectator/tags.cr +++ b/src/spectator/metadata.cr @@ -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 diff --git a/src/spectator/node.cr b/src/spectator/node.cr index 63153c4..4979f6e 100644 --- a/src/spectator/node.cr +++ b/src/spectator/node.cr @@ -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. diff --git a/src/spectator/spec/builder.cr b/src/spectator/spec/builder.cr index ca938c2..f1b401d 100644 --- a/src/spectator/spec/builder.cr +++ b/src/spectator/spec/builder.cr @@ -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 diff --git a/src/spectator/test_context.cr b/src/spectator/test_context.cr index f02f334..a68c5b9 100644 --- a/src/spectator/test_context.cr +++ b/src/spectator/test_context.cr @@ -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