mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Merge branch 'specs' of gitlab.com:arctic-fox/spectator into specs
This commit is contained in:
commit
1d44f582e2
4 changed files with 140 additions and 59 deletions
49
spec/rspec/expectations/change_matcher_spec.cr
Normal file
49
spec/rspec/expectations/change_matcher_spec.cr
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
require "../../spec_helper"
|
||||||
|
|
||||||
|
# Examples taken from:
|
||||||
|
# https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/built-in-matchers/change-matcher
|
||||||
|
# and modified to fit Spectator and Crystal.
|
||||||
|
Spectator.describe "`change` matcher" do
|
||||||
|
# Modified this example type to work in Crystal.
|
||||||
|
module Counter
|
||||||
|
extend self
|
||||||
|
|
||||||
|
@@count = 0
|
||||||
|
|
||||||
|
def increment
|
||||||
|
@@count += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def count
|
||||||
|
@@count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "expect change" do
|
||||||
|
describe "Counter#increment" do # TODO: Allow multiple arguments to context/describe.
|
||||||
|
it "should increment the count" do
|
||||||
|
expect { Counter.increment }.to change { Counter.count }.from(0).to(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
# deliberate failure
|
||||||
|
# TODO: Add support for expected failures.
|
||||||
|
xit "should increment the count by 2" do
|
||||||
|
expect { Counter.increment }.to change { Counter.count }.by(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "expect no change" do
|
||||||
|
describe "Counter#increment" do # TODO: Allow multiple arguments to context/describe.
|
||||||
|
# deliberate failures
|
||||||
|
# TODO: Add support for expected failures.
|
||||||
|
xit "should not increment the count by 1 (using not_to)" do
|
||||||
|
expect { Counter.increment }.not_to change { Counter.count }
|
||||||
|
end
|
||||||
|
|
||||||
|
xit "should not increment the count by 1 (using to_not)" do
|
||||||
|
expect { Counter.increment }.to_not change { Counter.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
32
spec/rspec/expectations/contain_exactly_matcher_spec.cr
Normal file
32
spec/rspec/expectations/contain_exactly_matcher_spec.cr
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
require "../../spec_helper"
|
||||||
|
|
||||||
|
# Examples taken from:
|
||||||
|
# https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/built-in-matchers/contain-exactly-matcher
|
||||||
|
# and modified to fit Spectator and Crystal.
|
||||||
|
Spectator.describe "`contain_exactly` matcher" do
|
||||||
|
context "Array is expected to contain every value" do
|
||||||
|
describe [1, 2, 3] do
|
||||||
|
it { is_expected.to contain_exactly(1, 2, 3) }
|
||||||
|
it { is_expected.to contain_exactly(1, 3, 2) }
|
||||||
|
it { is_expected.to contain_exactly(2, 1, 3) }
|
||||||
|
it { is_expected.to contain_exactly(2, 3, 1) }
|
||||||
|
it { is_expected.to contain_exactly(3, 1, 2) }
|
||||||
|
it { is_expected.to contain_exactly(3, 2, 1) }
|
||||||
|
|
||||||
|
# deliberate failures
|
||||||
|
# TODO: Add support for expected failures.
|
||||||
|
xit { is_expected.to contain_exactly(1, 2, 1) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Array is not expected to contain every value" do
|
||||||
|
describe [1, 2, 3] do
|
||||||
|
it { is_expected.to_not contain_exactly(1, 2, 3, 4) }
|
||||||
|
it { is_expected.to_not contain_exactly(1, 2) }
|
||||||
|
|
||||||
|
# deliberate failures
|
||||||
|
# TODO: Add support for expected failures.
|
||||||
|
xit { is_expected.to_not contain_exactly(1, 3, 2) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -520,22 +520,23 @@ module Spectator
|
||||||
have_value({{expected}})
|
have_value({{expected}})
|
||||||
end
|
end
|
||||||
|
|
||||||
# Indicates that some set should contain some values in exact order.
|
# Indicates that some set should contain some values in any order.
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
# ```
|
# ```
|
||||||
# expect([1, 2, 3]).to contain_exactly(1, 2, 3)
|
# expect([1, 2, 3]).to contain_exactly(3, 2, 1)
|
||||||
# ```
|
# ```
|
||||||
macro contain_exactly(*expected)
|
macro contain_exactly(*expected)
|
||||||
%test_value = ::Spectator::TestValue.new({{expected}}, {{expected.stringify}})
|
%test_value = ::Spectator::TestValue.new({{expected}}, {{expected.stringify}})
|
||||||
::Spectator::Matchers::ArrayMatcher.new(%test_value)
|
::Spectator::Matchers::ArrayMatcher.new(%test_value)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Indicates that some set should contain the same values in exact order as another set.
|
# Indicates that some set should contain the same values in any order as another set.
|
||||||
|
# This is the same as `#contain_exactly`, but takes an array as an argument.
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
# ```
|
# ```
|
||||||
# expect([1, 2, 3]).to match_array([1, 2, 3])
|
# expect([1, 2, 3]).to match_array([3, 2, 1])
|
||||||
# ```
|
# ```
|
||||||
macro match_array(expected)
|
macro match_array(expected)
|
||||||
%test_value = ::Spectator::TestValue.new({{expected}}, {{expected.stringify}})
|
%test_value = ::Spectator::TestValue.new({{expected}}, {{expected.stringify}})
|
||||||
|
|
|
@ -5,7 +5,7 @@ require "./unordered_array_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 and in the same order.
|
# has the exact same contents as another but may be in any order.
|
||||||
struct ArrayMatcher(ExpectedType) < Matcher
|
struct ArrayMatcher(ExpectedType) < Matcher
|
||||||
# Expected value and label.
|
# Expected value and label.
|
||||||
private getter expected
|
private getter expected
|
||||||
|
@ -25,15 +25,19 @@ module Spectator::Matchers
|
||||||
def match(actual : TestExpression(T)) : MatchData forall T
|
def match(actual : TestExpression(T)) : MatchData forall T
|
||||||
actual_elements = actual.value.to_a
|
actual_elements = actual.value.to_a
|
||||||
expected_elements = expected.value.to_a
|
expected_elements = expected.value.to_a
|
||||||
index = compare_arrays(expected_elements, actual_elements)
|
missing, extra = compare_arrays(expected_elements, actual_elements)
|
||||||
|
|
||||||
case index
|
if missing.empty? && extra.empty?
|
||||||
when Int # Content differs.
|
# Contents are identical.
|
||||||
failed_content_mismatch(expected_elements, actual_elements, index, actual.label)
|
|
||||||
when true # Contents are identical.
|
|
||||||
SuccessfulMatchData.new(description)
|
SuccessfulMatchData.new(description)
|
||||||
else # Size differs.
|
else
|
||||||
failed_size_mismatch(expected_elements, actual_elements, actual.label)
|
# Content differs.
|
||||||
|
FailedMatchData.new(description, "#{actual.label} does not contain exactly #{expected.label}",
|
||||||
|
expected: expected_elements.inspect,
|
||||||
|
actual: actual_elements.inspect,
|
||||||
|
missing: missing.empty? ? "None" : missing.inspect,
|
||||||
|
extra: extra.empty? ? "None" : extra.inspect
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -42,13 +46,16 @@ module Spectator::Matchers
|
||||||
def negated_match(actual : TestExpression(T)) : MatchData forall T
|
def negated_match(actual : TestExpression(T)) : MatchData forall T
|
||||||
actual_elements = actual.value.to_a
|
actual_elements = actual.value.to_a
|
||||||
expected_elements = expected.value.to_a
|
expected_elements = expected.value.to_a
|
||||||
|
missing, extra = compare_arrays(expected_elements, actual_elements)
|
||||||
|
|
||||||
case compare_arrays(expected_elements, actual_elements)
|
if missing.empty? && extra.empty?
|
||||||
when Int # Contents differ.
|
# Contents are identical.
|
||||||
SuccessfulMatchData.new(description)
|
FailedMatchData.new(description, "#{actual.label} contains exactly #{expected.label}",
|
||||||
when true # Contents are identical.
|
expected: "Not #{expected_elements.inspect}",
|
||||||
failed_content_identical(expected_elements, actual_elements, actual.label)
|
actual: actual_elements.inspect
|
||||||
else # Size differs.
|
)
|
||||||
|
else
|
||||||
|
# Content differs.
|
||||||
SuccessfulMatchData.new(description)
|
SuccessfulMatchData.new(description)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -65,49 +72,41 @@ module Spectator::Matchers
|
||||||
UnorderedArrayMatcher.new(expected)
|
UnorderedArrayMatcher.new(expected)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Compares two arrays to determine whether they contain the same elements, and in the same order.
|
# Compares two arrays to determine whether they contain the same elements, but in any order.
|
||||||
# If the arrays are the same, then `true` is returned.
|
# A tuple of two arrays is returned.
|
||||||
# If they are different, `false` or an integer is returned.
|
# The first array is the missing elements (present in expected, missing in actual).
|
||||||
# `false` is returned when the sizes of the arrays don't match.
|
# The second array array is the extra elements (not present in expected, present in actual).
|
||||||
# An integer is returned, that is the index of the mismatched elements in the arrays.
|
|
||||||
private def compare_arrays(expected_elements, actual_elements)
|
private def compare_arrays(expected_elements, actual_elements)
|
||||||
if expected_elements.size == actual_elements.size
|
# Produce hashes where the array elements are the keys, and the values are the number of occurances.
|
||||||
index = 0
|
expected_hash = expected_elements.group_by(&.itself).map { |k, v| {k, v.size} }.to_h
|
||||||
expected_elements.zip(actual_elements) do |expected_element, actual_element|
|
actual_hash = actual_elements.group_by(&.itself).map { |k, v| {k, v.size} }.to_h
|
||||||
return index unless expected_element == actual_element
|
|
||||||
index += 1
|
{
|
||||||
|
hash_count_difference(expected_hash, actual_hash),
|
||||||
|
hash_count_difference(actual_hash, expected_hash),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Expects two hashes, with values as counts for keys.
|
||||||
|
# Produces an array of differences with elements repeated if needed.
|
||||||
|
private def hash_count_difference(first, second)
|
||||||
|
# Subtract the number of occurances from the other array.
|
||||||
|
# A duplicate hash is used here because the original can't be modified,
|
||||||
|
# since it there's a two-way comparison.
|
||||||
|
#
|
||||||
|
# Then reject elements that have zero (or less) occurances.
|
||||||
|
# Lastly, expand to the correct number of elements.
|
||||||
|
first.map do |element, count|
|
||||||
|
if second_count = second[element]?
|
||||||
|
{element, count - second_count}
|
||||||
|
else
|
||||||
|
{element, count}
|
||||||
end
|
end
|
||||||
true
|
end.reject do |(_, count)|
|
||||||
else
|
count <= 0
|
||||||
false
|
end.map do |(element, count)|
|
||||||
end
|
Array.new(count, element)
|
||||||
end
|
end.flatten
|
||||||
|
|
||||||
# Produces match data for a failure when the array sizes differ.
|
|
||||||
private def failed_size_mismatch(expected_elements, actual_elements, actual_label)
|
|
||||||
FailedMatchData.new(description, "#{actual_label} does not contain exactly #{expected.label} (size mismatch)",
|
|
||||||
expected: expected_elements.inspect,
|
|
||||||
actual: actual_elements.inspect,
|
|
||||||
"expected size": expected_elements.size.to_s,
|
|
||||||
"actual size": actual_elements.size.to_s
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Produces match data for a failure when the array content is mismatched.
|
|
||||||
private def failed_content_mismatch(expected_elements, actual_elements, index, actual_label)
|
|
||||||
FailedMatchData.new(description, "#{actual_label} does not contain exactly #{expected.label} (element mismatch)",
|
|
||||||
expected: expected_elements[index].inspect,
|
|
||||||
actual: actual_elements[index].inspect,
|
|
||||||
index: index.to_s
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Produces match data for a failure when the arrays are identical, but they shouldn't be (negation).
|
|
||||||
private def failed_content_identical(expected_elements, actual_elements, actual_label)
|
|
||||||
FailedMatchData.new(description, "#{actual_label} contains exactly #{expected.label}",
|
|
||||||
expected: "Not #{expected_elements.inspect}",
|
|
||||||
actual: actual_elements.inspect
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue