diff --git a/src/spectator/dsl/examples.cr b/src/spectator/dsl/examples.cr index 1442720..c8d3d59 100644 --- a/src/spectator/dsl/examples.cr +++ b/src/spectator/dsl/examples.cr @@ -21,11 +21,24 @@ module Spectator::DSL # # The example will be marked as pending if the block is omitted. # A block or name must be provided. - macro {{name.id}}(what = nil, &block) + macro {{name.id}}(what = nil, *tags, **metadata, &block) \{% 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 %} \{% raise "Block argument count '{{name.id}}' hook must be 0..1" if block.args.size > 1 %} + def self.\%metadata + \{% if tags.empty? && metadata.empty? %} + _spectator_metadata + \{% else %} + _spectator_metadata.merge( + \{% for tag in tags %} + \{{tag.id.stringify}}: true, + \{% end %} + \{{metadata.double_splat}} + ) + \{% end %} + end + def \%test(\{{block.args.splat}}) : Nil \{{block.body}} end @@ -33,7 +46,8 @@ module Spectator::DSL ::Spectator::DSL::Builder.add_example( _spectator_example_name(\{{what}}), ::Spectator::Source.new(\{{block.filename}}, \{{block.line_number}}), - \{{@type.name}}.new.as(::Spectator::Context) + \{{@type.name}}.new.as(::Spectator::Context), + \{{@type.name}}.\%metadata ) do |example| example.with_context(\{{@type.name}}) do \{% if block.args.empty? %} diff --git a/src/spectator/dsl/groups.cr b/src/spectator/dsl/groups.cr index 531ee3d..0fec1fe 100644 --- a/src/spectator/dsl/groups.cr +++ b/src/spectator/dsl/groups.cr @@ -10,12 +10,25 @@ module Spectator::DSL # The *what* argument is a name or description of the group. # # TODO: Handle string interpolation in example and group names. - macro {{name.id}}(what, &block) + macro {{name.id}}(what, *tags, **metadata, &block) \{% raise "Cannot use '{{name.id}}' inside of a test block" if @def %} class Group\%group < \{{@type.id}} _spectator_group_subject(\{{what}}) + def self._spectator_metadata + \{% if tags.empty? && metadata.empty? %} + super + \{% else %} + super.merge( + \{% for tag in tags %} + \{{tag.id.stringify}}: true, + \{% end %} + \{{metadata.double_splat}} + ) + \{% end %} + end + ::Spectator::DSL::Builder.start_group( _spectator_group_name(\{{what}}), ::Spectator::Source.new(\{{block.filename}}, \{{block.line_number}}) diff --git a/src/spectator/spec/builder.cr b/src/spectator/spec/builder.cr index 1f13171..42f4e11 100644 --- a/src/spectator/spec/builder.cr +++ b/src/spectator/spec/builder.cr @@ -93,8 +93,8 @@ 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, source, context, &block : Example -> _) : Example - Log.trace { "Add example: #{name} @ #{source}" } + def add_example(name, source, context, metadata, &block : Example -> _) : Example + Log.trace { "Add example: #{name} @ #{source}; metadata: #{metadata}" } Example.new(context, block, name, source, current_group) # 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 c32119f..caa77af 100644 --- a/src/spectator/test_context.cr +++ b/src/spectator/test_context.cr @@ -27,4 +27,10 @@ class SpectatorTestContext < SpectatorContext private def subject @subject.get { _spectator_implicit_subject } end + + # Initial metadata for tests. + # This method should be overridden by example groups and examples. + def self._spectator_metadata + NamedTuple.new + end end