mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Refactor UnorderedArrayMatcher
This commit is contained in:
parent
3ae16c6ec1
commit
9bffb30041
1 changed files with 37 additions and 84 deletions
|
@ -3,18 +3,45 @@ require "./value_matcher"
|
||||||
module Spectator::Matchers
|
module Spectator::Matchers
|
||||||
# Matcher for checking that the contents of one array (or similar type)
|
# Matcher for checking that the contents of one array (or similar type)
|
||||||
# has the exact same contents as another, but in any order.
|
# has the exact same contents as another, but in any order.
|
||||||
struct UnorderedArrayMatcher(ExpectedType) < ValueMatcher(Enumerable(ExpectedType))
|
struct UnorderedArrayMatcher(ExpectedType) < Matcher
|
||||||
# Determines whether the matcher is satisfied with the partial given to it.
|
private getter expected
|
||||||
def match(partial, negated = false)
|
|
||||||
expected_elements = expected.to_a
|
def initialize(@expected : TestValue(Enumerable(ExpectedType)))
|
||||||
actual = partial.actual.to_a
|
end
|
||||||
missing, extra = array_diff(expected, actual)
|
|
||||||
|
def description
|
||||||
|
"contains #{expected.label} in any order"
|
||||||
|
end
|
||||||
|
|
||||||
|
def match(actual)
|
||||||
|
actual_elements = actual.value.to_a
|
||||||
|
expected_elements = expected.value.to_a
|
||||||
|
missing, extra = array_diff(expected_elements, actual_elements)
|
||||||
|
|
||||||
values = ExpectedActual.new(expected_elements, label, actual, partial.label)
|
|
||||||
if missing.empty? && extra.empty?
|
if missing.empty? && extra.empty?
|
||||||
IdenticalMatchData.new(values)
|
SuccessfulMatchData.new
|
||||||
else
|
else
|
||||||
ContentMatchData.new(values, missing, extra)
|
FailedMatchData.new("#{actual_label} does not contain #{expected.label} (unordered)",
|
||||||
|
expected: expected_elements.inspect,
|
||||||
|
actual: actual_elements.inspect,
|
||||||
|
missing: missing.inspect,
|
||||||
|
extra: extra.inspect,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def negated_match(actual)
|
||||||
|
actual_elements = actual.value.to_a
|
||||||
|
expected_elements = expected.value.to_a
|
||||||
|
missing, extra = array_diff(expected_elements, actual_elements)
|
||||||
|
|
||||||
|
if missing.empty? && extra.empty?
|
||||||
|
FailedMatchData.new("#{actual_label} contains #{expected.label} (unordered)",
|
||||||
|
expected: "Not #{expected_elements.inspect}",
|
||||||
|
actual: actual_elements.inspect,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
SuccessfulMatchData.new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -24,7 +51,7 @@ module Spectator::Matchers
|
||||||
extra = actual.dup
|
extra = actual.dup
|
||||||
missing = [] of ExpectedType
|
missing = [] of ExpectedType
|
||||||
|
|
||||||
# TODO: OPTIMIZE
|
# OPTIMIZE: Not very efficient at finding the difference.
|
||||||
expected.each do |item|
|
expected.each do |item|
|
||||||
index = extra.index(item)
|
index = extra.index(item)
|
||||||
if index
|
if index
|
||||||
|
@ -36,79 +63,5 @@ module Spectator::Matchers
|
||||||
|
|
||||||
{missing, extra}
|
{missing, extra}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates the value matcher.
|
|
||||||
# The label should be a string representation of the expectation.
|
|
||||||
# The expected value is stored for later use.
|
|
||||||
def initialize(expected : Enumerable(ExpectedType), label : String)
|
|
||||||
super
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates the value matcher.
|
|
||||||
# The label is generated by calling `#to_s` on the expected value.
|
|
||||||
# The expected value is stored for later use.
|
|
||||||
def initialize(expected : Enumerable(ExpectedType))
|
|
||||||
super
|
|
||||||
end
|
|
||||||
|
|
||||||
# Common functionality for all match data for this matcher.
|
|
||||||
private abstract struct CommonMatchData(ExpectedType, ActualType) < MatchData
|
|
||||||
# Creates the match data.
|
|
||||||
def initialize(matched, @values : ExpectedActual(Array(ExpectedType), Array(ActualType)))
|
|
||||||
super(matched)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Basic information about the match.
|
|
||||||
def named_tuple
|
|
||||||
{
|
|
||||||
expected: NegatableMatchDataValue.new(@values.expected),
|
|
||||||
actual: @values.actual,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Describes the condition that satisfies the matcher.
|
|
||||||
# This is informational and displayed to the end-user.
|
|
||||||
def message
|
|
||||||
"#{@values.actual_label} contains #{@values.expected_label} (unordered)"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Match data specific to this matcher.
|
|
||||||
# This type is used when the actual value matches the expected value.
|
|
||||||
private struct IdenticalMatchData(ExpectedType, ActualType) < CommonMatchData(ExpectedType, ActualType)
|
|
||||||
# Creates the match data.
|
|
||||||
def initialize(values : ExpectedActual(Array(ExpectedType), Array(ActualType)))
|
|
||||||
super(true, values)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Describes the condition that won't satsify the matcher.
|
|
||||||
# This is informational and displayed to the end-user.
|
|
||||||
def negated_message
|
|
||||||
"#{@values.actual_label} does not contain #{@values.expected_label} (unordered)"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Match data specific to this matcher.
|
|
||||||
# This type is used when the actual contents differs from the expected contents.
|
|
||||||
private struct ContentMatchData(ExpectedType, ActualType) < CommonMatchData(ExpectedType, ActualType)
|
|
||||||
# Creates the match data.
|
|
||||||
def initialize(values : ExpectedActual(Array(ExpectedType), Array(ActualType)), @missing : Array(ExpectedType), @extra : Array(ActualType))
|
|
||||||
super(false, values)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Information about the match.
|
|
||||||
def named_tuple
|
|
||||||
super.merge({
|
|
||||||
missing: @missing,
|
|
||||||
extra: @extra,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
# Describes the condition that won't satsify the matcher.
|
|
||||||
# This is informational and displayed to the end-user.
|
|
||||||
def negated_message
|
|
||||||
"#{@values.actual_label} does not contain #{@values.expected_label} (content differs)"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue