diff --git a/src/spectator/dsl/matcher_dsl.cr b/src/spectator/dsl/matcher_dsl.cr index eba6098..c99a31e 100644 --- a/src/spectator/dsl/matcher_dsl.cr +++ b/src/spectator/dsl/matcher_dsl.cr @@ -327,5 +327,22 @@ module Spectator::DSL macro end_with(expected) ::Spectator::Matchers::EndWithMatcher.new({{expected.stringify}}, {{expected}}) end + + # Indicates that some value or set should contain another value. + # This is typically used on a `String` or `Array` (any `Enumerable` works). + # The `expected` argument can be a `String` or `Char` + # when the actual type (being comapred against) is a `String`. + # For `Enumerable` types, each item is inspected until one matches. + # In both cases, the `includes?` method is used. + # + # Examples: + # ``` + # expect("foobar").to contain("foo") + # expect("foobar").to contain('o') + # expect(%i[a b c]).to contain(:b) + # ``` + macro contain(expected) + ::Spectator::Matchers::ContainMatcher.new({{expected.stringify}}, {{expected}}) + end end end diff --git a/src/spectator/matchers/contain_matcher.cr b/src/spectator/matchers/contain_matcher.cr new file mode 100644 index 0000000..bafcffa --- /dev/null +++ b/src/spectator/matchers/contain_matcher.cr @@ -0,0 +1,25 @@ +require "./value_matcher" + +module Spectator::Matchers + # Matcher that tests whether a value, such as a `String` or `Array`, contains a value. + # The values are checked with the `includes?` operator. + struct ContainMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Determines whether the matcher is satisfied with the value given to it. + # True is returned if the match was successful, false otherwise. + def match?(partial) + partial.actual.includes?(expected) + end + + # Describes the condition that satisfies the matcher. + # This is informational and displayed to the end-user. + def message(partial) + "Expected #{partial.label} to contain #{label}" + end + + # Describes the condition that won't satsify the matcher. + # This is informational and displayed to the end-user. + def negated_message(partial) + "Expected #{partial.label} to not contain #{label}" + end + end +end