Change ExampleFilter to a NodeFilter

Node filters may operate on example groups as well as examples.
This commit is contained in:
Michael Miller 2021-08-08 12:13:59 -06:00
parent 0f7a9ed9e8
commit aa81f1d948
No known key found for this signature in database
GPG key ID: FB9F12F7C646A4AD
16 changed files with 119 additions and 110 deletions

View file

@ -1,15 +0,0 @@
require "./example_filter"
module Spectator
# Filter that combines multiple other filters.
class CompositeExampleFilter < ExampleFilter
# Creates the example filter.
def initialize(@filters : Array(ExampleFilter))
end
# Checks whether the example satisfies the filter.
def includes?(example) : Bool
@filters.any?(&.includes?(example))
end
end
end

View file

@ -0,0 +1,15 @@
require "./node_filter"
module Spectator
# Filter that combines multiple other filters.
class CompositeNodeFilter < NodeFilter
# Creates the example filter.
def initialize(@filters : Array(NodeFilter))
end
# Checks whether the node satisfies the filter.
def includes?(node) : Bool
@filters.any?(&.includes?(node))
end
end
end

View file

@ -1,5 +1,5 @@
require "./config/*"
require "./example_filter"
require "./node_filter"
require "./example_group"
require "./example_iterator"
require "./formatting/formatter"
@ -18,7 +18,7 @@ module Spectator
getter random_seed : UInt64
# Filter used to select which examples to run.
getter example_filter : ExampleFilter
getter node_filter : NodeFilter
# List of hooks to run before all examples in the test suite.
protected getter before_suite_hooks : Deque(ExampleGroupHook)
@ -48,7 +48,7 @@ module Spectator
@formatter = source.formatter
@run_flags = source.run_flags
@random_seed = source.random_seed
@example_filter = source.example_filter
@node_filter = source.node_filter
@before_suite_hooks = source.before_suite_hooks
@before_all_hooks = source.before_all_hooks
@ -86,7 +86,7 @@ module Spectator
# Creates an iterator configured to select the filtered examples.
def iterator(group : ExampleGroup)
ExampleIterator.new(group).select(@example_filter)
ExampleIterator.new(group).select(@node_filter)
end
# Retrieves the configured random number generator.

View file

@ -1,7 +1,7 @@
require "../composite_example_filter"
require "../example_filter"
require "../composite_node_filter"
require "../node_filter"
require "../formatting"
require "../null_example_filter"
require "../null_node_filter"
require "../run_flags"
module Spectator
@ -18,7 +18,7 @@ module Spectator
@primary_formatter : Formatting::Formatter?
@additional_formatters = [] of Formatting::Formatter
@filters = [] of ExampleFilter
@filters = [] of NodeFilter
# List of hooks to run before all examples in the test suite.
protected getter before_suite_hooks = Deque(ExampleGroupHook).new
@ -259,18 +259,18 @@ module Spectator
end
# Adds a filter to determine which examples can run.
def add_example_filter(filter : ExampleFilter)
def add_node_filter(filter : NodeFilter)
@filters << filter
end
# Retrieves a filter that determines which examples can run.
# If no filters were added with `#add_example_filter`,
# If no filters were added with `#add_node_filter`,
# then the returned filter will allow all examples to be run.
protected def example_filter
protected def node_filter
case (filters = @filters)
when .empty? then NullExampleFilter.new
when .empty? then NullNodeFilter.new
when .one? then filters.first
else CompositeExampleFilter.new(filters)
else CompositeNodeFilter.new(filters)
end
end
end

View file

@ -1,10 +1,10 @@
require "colorize"
require "option_parser"
require "../formatting"
require "../line_example_filter"
require "../line_node_filter"
require "../location"
require "../location_example_filter"
require "../name_example_filter"
require "../location_node_filter"
require "../name_node_filter"
module Spectator
class Config
@ -111,8 +111,8 @@ module Spectator
private def example_option(parser, builder)
parser.on("-e", "--example STRING", "Run examples whose full nested names include STRING") do |pattern|
Log.debug { "Filtering for examples named '#{pattern}' (-e '#{pattern}')" }
filter = NameExampleFilter.new(pattern)
builder.add_example_filter(filter)
filter = NameNodeFilter.new(pattern)
builder.add_node_filter(filter)
end
end
@ -120,8 +120,8 @@ module Spectator
private def line_option(parser, builder)
parser.on("-l", "--line LINE", "Run examples whose line matches LINE") do |line|
Log.debug { "Filtering for examples on line #{line} (-l #{line})" }
filter = LineExampleFilter.new(line.to_i)
builder.add_example_filter(filter)
filter = LineNodeFilter.new(line.to_i)
builder.add_node_filter(filter)
end
end
@ -130,8 +130,8 @@ module Spectator
parser.on("--location FILE:LINE", "Run the example at line 'LINE' in the file 'FILE', multiple allowed") do |location|
Log.debug { "Filtering for examples at #{location} (--location '#{location}')" }
location = Location.parse(location)
filter = LocationExampleFilter.new(location)
builder.add_example_filter(filter)
filter = LocationNodeFilter.new(location)
builder.add_node_filter(filter)
end
end

View file

@ -1,14 +0,0 @@
module Spectator
# Base class for all example filters.
# Checks whether an example should be run.
# Sub-classes must implement the `#includes?` method.
abstract class ExampleFilter
# Checks if an example is in the filter, and should be run.
abstract def includes?(example : Example) : Bool
# :ditto:
def ===(example : Example)
includes?(example)
end
end
end

View file

@ -7,7 +7,7 @@
require "./abstract_expression"
require "./anything"
require "./block"
require "./composite_example_filter"
require "./composite_node_filter"
require "./config"
require "./context"
require "./context_delegate"
@ -17,7 +17,7 @@ require "./error_result"
require "./example_context_delegate"
require "./example_context_method"
require "./example"
require "./example_filter"
require "./node_filter"
require "./example_group"
require "./example_group_hook"
require "./example_hook"
@ -33,15 +33,15 @@ require "./hooks"
require "./label"
require "./lazy"
require "./lazy_wrapper"
require "./line_example_filter"
require "./line_node_filter"
require "./location"
require "./location_example_filter"
require "./location_node_filter"
require "./matchers"
require "./metadata"
require "./mocks"
require "./name_example_filter"
require "./name_node_filter"
require "./null_context"
require "./null_example_filter"
require "./null_node_filter"
require "./pass_result"
require "./pending_result"
require "./profile"

View file

@ -1,17 +0,0 @@
module Spectator
# Filter that matches examples on a given line.
class LineExampleFilter < ExampleFilter
# Creates the example filter.
def initialize(@line : Int32)
end
# Checks whether the example satisfies the filter.
def includes?(example) : Bool
return false unless location = example.location?
start_line = location.line
end_line = location.end_line
(start_line..end_line).covers?(@line)
end
end
end

View file

@ -0,0 +1,19 @@
require "./node_filter"
module Spectator
# Filter that matches nodes on a given line.
class LineNodeFilter < NodeFilter
# Creates the node filter.
def initialize(@line : Int32)
end
# Checks whether the node satisfies the filter.
def includes?(node) : Bool
return false unless location = node.location?
start_line = location.line
end_line = location.end_line
(start_line..end_line).covers?(@line)
end
end
end

View file

@ -1,14 +0,0 @@
module Spectator
# Filter that matches examples in a given file and line.
class LocationExampleFilter < ExampleFilter
# Creates the filter.
# The *location* indicates which file and line the example must be on.
def initialize(@location : Location)
end
# Checks whether the example satisfies the filter.
def includes?(example) : Bool
@location === example.location?
end
end
end

View file

@ -0,0 +1,17 @@
require "./location"
require "./node_filter"
module Spectator
# Filter that matches nodes in a given file and line.
class LocationNodeFilter < NodeFilter
# Creates the filter.
# The *location* indicates which file and line the node must contain.
def initialize(@location : Location)
end
# Checks whether the node satisfies the filter.
def includes?(node) : Bool
@location === node.location?
end
end
end

View file

@ -1,13 +0,0 @@
module Spectator
# Filter that matches examples based on their name.
class NameExampleFilter < ExampleFilter
# Creates the example filter.
def initialize(@name : String)
end
# Checks whether the example satisfies the filter.
def includes?(example) : Bool
@name == example.to_s
end
end
end

View file

@ -0,0 +1,15 @@
require "./node_filter"
module Spectator
# Filter that matches nodes based on their name.
class NameNodeFilter < NodeFilter
# Creates the node filter.
def initialize(@name : String)
end
# Checks whether the node satisfies the filter.
def includes?(node) : Bool
@name == node.to_s
end
end
end

View file

@ -0,0 +1,14 @@
module Spectator
# Base class for all node filters.
# Checks whether a node should be included in the test run.
# Sub-classes must implement the `#includes?` method.
abstract class NodeFilter
# Checks if a node is in the filter, and should be included in the test run.
abstract def includes?(node) : Bool
# :ditto:
def ===(node)
includes?(node)
end
end
end

View file

@ -1,9 +0,0 @@
module Spectator
# Filter that matches all examples.
class NullExampleFilter < ExampleFilter
# Checks whether the example satisfies the filter.
def includes?(example) : Bool
true
end
end
end

View file

@ -0,0 +1,11 @@
require "./node_filter"
module Spectator
# Filter that matches all nodes.
class NullNodeFilter < NodeFilter
# Checks whether the node satisfies the filter.
def includes?(_node) : Bool
true
end
end
end