Prevent comparing range arguments with non-compatible types in stubs

Addresses https://github.com/icy-arctic-fox/spectator/issues/48
This commit is contained in:
Michael Miller 2022-12-18 11:35:43 -07:00
parent f55c60e01f
commit e6584c9f04
No known key found for this signature in database
GPG key ID: 32B47AE8F388A1FF
4 changed files with 37 additions and 24 deletions

View file

@ -11,13 +11,7 @@ module Spectator
return false if a.size != b.size
a.zip(b) do |a_value, b_value|
if a_value.is_a?(Proc)
# Using procs as argument matchers isn't supported currently.
# Compare directly instead.
return false unless a_value == b_value
else
return false unless a_value === b_value
end
return false unless compare_values(a_value, b_value)
end
true
end
@ -34,15 +28,31 @@ module Spectator
private def compare_named_tuples(a : NamedTuple, b : NamedTuple)
a.each do |k, v1|
v2 = b.fetch(k) { return false }
if v1.is_a?(Proc)
# Using procs as argument matchers isn't supported currently.
# Compare directly instead.
return false unless v1 == v2
else
return false unless v1 === v2
end
return false unless compare_values(v1, v2)
end
true
end
# Utility method for comparing two arguments considering special types.
# Some types used for case-equality don't work well with unexpected right-hand types.
# This can happen when the right side is a massive union of types.
private def compare_values(a, b)
case a
when Proc
# Using procs as argument matchers isn't supported currently.
# Compare directly instead.
a == b
when Range
# Ranges can only be matched against if their right side is comparable.
# Ensure the right side is comparable, otherwise compare directly.
if b.is_a?(Comparable(typeof(b)))
a === b
else
a == b
end
else
a === b
end
end
end
end

View file

@ -95,21 +95,13 @@ module Spectator
v1 = positional[i]
i += 1
if v1.is_a?(Proc)
return false unless v1 == v2
else
return false unless v1 === v2
end
return false unless compare_values(v1, v2)
end
other.splat.try &.each do |v2|
v1 = positional.fetch(i) { return false }
i += 1
if v1.is_a?(Proc)
return false unless v1 == v2
else
return false unless v1 === v2
end
return false unless compare_values(v1, v2)
end
i == positional.size