diff --git a/src/spectator/config.cr b/src/spectator/config.cr index efbdb6a..66e6501 100644 --- a/src/spectator/config.cr +++ b/src/spectator/config.cr @@ -3,6 +3,7 @@ require "./node_filter" require "./example_group" require "./filtered_example_iterator" require "./formatting/formatter" +require "./node_iterator" require "./run_flags" module Spectator @@ -23,6 +24,9 @@ module Spectator # Filter used to select which examples to _not_ run. getter node_reject : NodeFilter + # Tags to filter on if they're present in a spec. + protected getter match_filters : Metadata + # List of hooks to run before all examples in the test suite. protected getter before_suite_hooks : Deque(ExampleGroupHook) @@ -53,6 +57,7 @@ module Spectator @random_seed = source.random_seed @node_filter = source.node_filter @node_reject = source.node_reject + @match_filters = source.match_filters @before_suite_hooks = source.before_suite_hooks @before_all_hooks = source.before_all_hooks @@ -90,7 +95,20 @@ module Spectator # Creates an iterator configured to select the filtered examples. def iterator(group : ExampleGroup) - FilteredExampleIterator.new(group, @node_filter).reject(@node_reject) + match_filter = match_filter(group) + iterator = FilteredExampleIterator.new(group, @node_filter) + iterator = iterator.select(match_filter) if match_filter + iterator.reject(@node_reject) + end + + # Creates a node filter if any conditionally matching filters apply to an example group. + private def match_filter(group : ExampleGroup) : NodeFilter? + iterator = NodeIterator.new(group) + filters = @match_filters.compact_map do |key, value| + filter = TagNodeFilter.new(key.to_s, value) + filter.as(NodeFilter) if iterator.rewind.any?(filter) + end + CompositeNodeFilter.new(filters) unless filters.empty? end # Retrieves the configured random number generator. diff --git a/src/spectator/config/builder.cr b/src/spectator/config/builder.cr index 522734f..7866fc6 100644 --- a/src/spectator/config/builder.cr +++ b/src/spectator/config/builder.cr @@ -1,6 +1,7 @@ require "../composite_node_filter" require "../node_filter" require "../formatting" +require "../metadata" require "../null_node_filter" require "../run_flags" require "../tag_node_filter" @@ -17,6 +18,8 @@ module Spectator # Toggles indicating how the test spec should execute. property run_flags = RunFlags::None + protected getter match_filters : Metadata = {:focus => nil.as(String?)} + @primary_formatter : Formatting::Formatter? @additional_formatters = [] of Formatting::Formatter @filters = [] of NodeFilter @@ -282,6 +285,12 @@ module Spectator values.each { |tag, value| @rejects << TagNodeFilter.new(tag, value.to_s) } end + # Specifies one or more tags to filter on only if they're present in the spec. + def filter_run_when_matching(*tags : Symbol, **values) + tags.each { |tag| @match_filters[tag] = nil } + values.each { |tag, value| @match_filters[tag] = value.to_s } + end + # Retrieves a filter that determines which examples can run. # If no filters were added with `#add_node_filter`, # then the returned filter will allow all examples to be run.