mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Merge branch 'all-matcher' into 'release/0.8'
All matcher See merge request arctic-fox/spectator!14
This commit is contained in:
commit
db9715341e
4 changed files with 73 additions and 3 deletions
|
@ -296,7 +296,7 @@ Items not marked as completed may have partial implementations.
|
|||
- [X] `be_empty`
|
||||
- [X] `have_key`
|
||||
- [X] `have_value`
|
||||
- [ ] `all`
|
||||
- [X] `all`
|
||||
- [ ] `all_satisfy`
|
||||
- [X] Truthy matchers - `be`, `be_true`, `be_truthy`, `be_false`, `be_falsey`, `be_nil`
|
||||
- [X] Error matchers - `raise_error`
|
||||
|
|
|
@ -526,6 +526,19 @@ module Spectator::DSL
|
|||
::Spectator::Matchers::AttributesMatcher.new(%test_value)
|
||||
end
|
||||
|
||||
# Verifies that all elements of a collection satisfy some matcher.
|
||||
# The collection should implement `Enumerable`.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
# array = [1, 2, 3, 4]
|
||||
# expect(array).to all(be_even) # Fails.
|
||||
# expect(array).to all(be_lt(5)) # Passes.
|
||||
# ```
|
||||
macro all(matcher)
|
||||
::Spectator::Matchers::AllMatcher.new({{matcher}})
|
||||
end
|
||||
|
||||
# Indicates that some expression's value should change after taking an action.
|
||||
#
|
||||
# Examples:
|
||||
|
|
57
src/spectator/matchers/all_matcher.cr
Normal file
57
src/spectator/matchers/all_matcher.cr
Normal file
|
@ -0,0 +1,57 @@
|
|||
require "../test_value"
|
||||
require "./failed_match_data"
|
||||
require "./matcher"
|
||||
require "./successful_match_data"
|
||||
|
||||
module Spectator::Matchers
|
||||
# Matcher that checks if all elements of a collection apply to some other matcher.
|
||||
struct AllMatcher(TMatcher) < Matcher
|
||||
# Other matcher that all elements must match successfully.
|
||||
private getter matcher
|
||||
|
||||
# Creates the matcher with an expected successful matcher.
|
||||
def initialize(@matcher : TMatcher)
|
||||
end
|
||||
|
||||
# Short text about the matcher's purpose.
|
||||
# This explains what condition satisfies the matcher.
|
||||
# The description is used when the one-liner syntax is used.
|
||||
def description
|
||||
"all #{matcher.description}"
|
||||
end
|
||||
|
||||
# Actually performs the test against the expression.
|
||||
def match(actual : TestExpression(T)) : MatchData forall T
|
||||
found = test_values(actual).each do |element|
|
||||
match_data = matcher.match(element)
|
||||
break match_data unless match_data.matched?
|
||||
end
|
||||
found ? found : SuccessfulMatchData.new
|
||||
end
|
||||
|
||||
# Negated matching for this matcher is not supported.
|
||||
# Attempting to call this method will result in a compilation error.
|
||||
#
|
||||
# This syntax has a logical problem.
|
||||
# "All values do not satisfy some condition."
|
||||
# Does this mean that all values don't satisfy the matcher?
|
||||
# What if only one doesn't?
|
||||
# What if the collection is empty?
|
||||
#
|
||||
# RSpec doesn't support this syntax either.
|
||||
def negated_match(actual : TestExpression(T)) : MatchData forall T
|
||||
{% raise "The `expect { }.to_not all()` syntax is not supported (ambiguous)." %}
|
||||
end
|
||||
|
||||
# Maps all values in the test collection to their own test values.
|
||||
# Each value is given their own label,
|
||||
# which is the original label with an index appended.
|
||||
private def test_values(actual)
|
||||
label_prefix = actual.label
|
||||
actual.value.map_with_index do |value, index|
|
||||
label = "#{label_prefix}[#{index}]"
|
||||
TestValue.new(value, label)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -16,7 +16,7 @@ module Spectator
|
|||
|
||||
def self.create(proc : -> T, label : String) forall T
|
||||
{% if T.id == "ReturnType".id %}
|
||||
wrapper = -> { proc.call; nil }
|
||||
wrapper = ->{ proc.call; nil }
|
||||
TestBlock(Nil).new(wrapper, label)
|
||||
{% else %}
|
||||
TestBlock(T).new(proc, label)
|
||||
|
@ -31,7 +31,7 @@ module Spectator
|
|||
|
||||
def self.create(proc : -> T) forall T
|
||||
{% if T.id == "ReturnType".id %}
|
||||
wrapper = -> { proc.call; nil }
|
||||
wrapper = ->{ proc.call; nil }
|
||||
TestBlock(Nil).new(wrapper)
|
||||
{% else %}
|
||||
TestBlock(T).new(proc)
|
||||
|
|
Loading…
Reference in a new issue