diff --git a/spec/matchers/end_with_matcher_spec.cr b/spec/matchers/end_with_matcher_spec.cr index c2450c6..33f35dc 100644 --- a/spec/matchers/end_with_matcher_spec.cr +++ b/spec/matchers/end_with_matcher_spec.cr @@ -1,298 +1,336 @@ require "../spec_helper" describe Spectator::Matchers::EndWithMatcher do - describe "#match?" do - context "with a String" do - context "against a matching string" do - it "is true" do - value = "foobar" - last = "bar" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_true + describe "#match" do + context "returned MatchData" do + describe "#matched?" do + context "with a String" do + context "against a matching string" do + it "is true" do + value = "foobar" + last = "bar" + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_true + end + + context "not at end" do + it "is false" do + value = "foobar" + last = "foo" + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + end + + context "against a different string" do + it "is false" do + value = "foobar" + last = "baz" + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + + context "against a matching character" do + it "is true" do + value = "foobar" + last = 'r' + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_true + end + + context "not at end" do + it "is false" do + value = "foobar" + last = 'b' + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + end + + context "against a different character" do + it "is false" do + value = "foobar" + last = 'z' + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + + context "against a matching regex" do + it "is true" do + value = "FOOBAR" + last = /bar/i + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_true + end + + context "not at end" do + it "is false" do + value = "FOOBAR" + last = /foo/i + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + end + + context "against a non-matching regex" do + it "is false" do + value = "FOOBAR" + last = /baz/i + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end end - context "not at end" do - it "is false" do - value = "foobar" - last = "foo" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false + context "with an Enumberable" do + context "against an equal value" do + it "is true" do + array = %i[a b c] + last = :c + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_true + end + + context "not at end" do + it "is false" do + array = %i[a b c] + last = :b + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + end + + context "against a different value" do + it "is false" do + array = %i[a b c] + last = :z + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + + context "against matching element type" do + it "is true" do + array = %i[a b c] + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(Symbol) + match_data = matcher.match(partial) + match_data.matched?.should be_true + end + + context "not at end" do + it "is false" do + array = [1, 2, 3, :a, :b, :c] + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(Int32) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + end + + context "against different element type" do + it "is false" do + array = %i[a b c] + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(Int32) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + + context "against a matching regex" do + it "is true" do + array = %w[FOO BAR BAZ] + last = /baz/i + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_true + end + + context "not at end" do + it "is false" do + array = %w[FOO BAR BAZ] + last = /bar/i + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end + end + + context "against a non-matching regex" do + it "is false" do + array = %w[FOO BAR BAZ] + last = /qux/i + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end end end end - context "against a different string" do - it "is false" do + describe "#values" do + + end + + describe "#message" do + context "with a String" do + it "mentions #ends_with?" do + value = "foobar" + last = "baz" + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.message.should contain("#ends_with?") + end + end + + context "with an Enumerable" do + it "mentions ===" do + array = %i[a b c] + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(array.last) + match_data = matcher.match(partial) + match_data.message.should contain("===") + end + + it "mentions last" do + array = %i[a b c] + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(array.last) + match_data = matcher.match(partial) + match_data.message.should contain("last") + end + end + + it "contains the actual label" do value = "foobar" last = "baz" - partial = new_partial(value) + label = "everything" + partial = new_partial(value, label) matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false + match_data = matcher.match(partial) + match_data.message.should contain(label) end - end - context "against a matching character" do - it "is true" do + it "contains the expected label" do value = "foobar" - last = 'r' + last = "baz" + label = "everything" partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_true + matcher = Spectator::Matchers::EndWithMatcher.new(last, label) + match_data = matcher.match(partial) + match_data.message.should contain(label) end - context "not at end" do - it "is false" do + context "when expected label is omitted" do + it "contains stringified form of expected value" do value = "foobar" - last = 'b' + last = "baz" partial = new_partial(value) matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false + match_data = matcher.match(partial) + match_data.message.should contain(last) end end end - context "against a different character" do - it "is false" do - value = "foobar" - last = 'z' - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false - end - end - - context "against a matching regex" do - it "is true" do - value = "FOOBAR" - last = /bar/i - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_true - end - - context "not at end" do - it "is false" do - value = "FOOBAR" - last = /foo/i + describe "#negated_message" do + context "with a String" do + it "mentions #starts_with?" do + value = "foobar" + last = "baz" partial = new_partial(value) matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false + match_data = matcher.match(partial) + match_data.negated_message.should contain("#ends_with?") end end - end - context "against a non-matching regex" do - it "is false" do - value = "FOOBAR" - last = /baz/i - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false - end - end - end - - context "with an Enumberable" do - context "against an equal value" do - it "is true" do - array = %i[a b c] - last = :c - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_true - end - - context "not at end" do - it "is false" do + context "with an Enumerable" do + it "mentions ===" do array = %i[a b c] - last = :b partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(array.last) + match_data = matcher.match(partial) + match_data.negated_message.should contain("===") + end + + it "mentions last" do + array = %i[a b c] + partial = new_partial(array) + matcher = Spectator::Matchers::EndWithMatcher.new(array.last) + match_data = matcher.match(partial) + match_data.negated_message.should contain("last") + end + end + + it "contains the actual label" do + value = "foobar" + last = "baz" + label = "everything" + partial = new_partial(value, label) + matcher = Spectator::Matchers::EndWithMatcher.new(last) + match_data = matcher.match(partial) + match_data.negated_message.should contain(label) + end + + it "contains the expected label" do + value = "foobar" + last = "baz" + label = "everything" + partial = new_partial(value) + matcher = Spectator::Matchers::EndWithMatcher.new(last, label) + match_data = matcher.match(partial) + match_data.negated_message.should contain(label) + end + + context "when expected label is omitted" do + it "contains stringified form of expected value" do + value = "foobar" + last = "baz" + partial = new_partial(value) matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false + match_data = matcher.match(partial) + match_data.negated_message.should contain(last) end end end - - context "against a different value" do - it "is false" do - array = %i[a b c] - last = :z - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false - end - end - - context "against matching element type" do - it "is true" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(Symbol) - matcher.match?(partial).should be_true - end - - context "not at end" do - it "is false" do - array = [1, 2, 3, :a, :b, :c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(Int32) - matcher.match?(partial).should be_false - end - end - end - - context "against different element type" do - it "is false" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(Int32) - matcher.match?(partial).should be_false - end - end - - context "against a matching regex" do - it "is true" do - array = %w[FOO BAR BAZ] - last = /baz/i - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_true - end - - context "not at end" do - it "is false" do - array = %w[FOO BAR BAZ] - last = /bar/i - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false - end - end - end - - context "against a non-matching regex" do - it "is false" do - array = %w[FOO BAR BAZ] - last = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.match?(partial).should be_false - end - end - end - end - - describe "#message" do - context "with a String" do - it "mentions #ends_with?" do - value = "foobar" - last = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.message(partial).should contain("#ends_with?") - end - end - - context "with an Enumerable" do - it "mentions ===" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(array.last) - matcher.message(partial).should contain("===") - end - - it "mentions last" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(array.last) - matcher.message(partial).should contain("last") - end - end - - it "contains the actual label" do - value = "foobar" - last = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.message(partial).should contain(label) - end - - it "contains the expected label" do - value = "foobar" - last = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last, label) - matcher.message(partial).should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - last = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.message(partial).should contain(last) - end - end - end - - describe "#negated_message" do - context "with a String" do - it "mentions #starts_with?" do - value = "foobar" - last = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.negated_message(partial).should contain("#ends_with?") - end - end - - context "with an Enumerable" do - it "mentions ===" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(array.last) - matcher.negated_message(partial).should contain("===") - end - - it "mentions last" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(array.last) - matcher.negated_message(partial).should contain("last") - end - end - - it "contains the actual label" do - value = "foobar" - last = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.negated_message(partial).should contain(label) - end - - it "contains the expected label" do - value = "foobar" - last = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last, label) - matcher.negated_message(partial).should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - last = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - matcher.negated_message(partial).should contain(last) - end end end end diff --git a/src/spectator/matchers/end_with_matcher.cr b/src/spectator/matchers/end_with_matcher.cr index ede34f1..910c9bd 100644 --- a/src/spectator/matchers/end_with_matcher.cr +++ b/src/spectator/matchers/end_with_matcher.cr @@ -6,30 +6,15 @@ module Spectator::Matchers # Otherwise, it is treated as an `Indexable` and the `last` value is compared against. struct EndWithMatcher(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) - actual = partial.actual + private def match?(actual) compare_method(actual, &.eval(actual, expected)) end # Determines whether the matcher is satisfied with the partial given to it. # `MatchData` is returned that contains information about the match. - def match(partial) : MatchData - raise NotImplementedError.new("#match") - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message(partial) - method_string = compare_method(partial.actual, &.to_s) - "Expected #{partial.label} to end with #{label} (using #{method_string})" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message(partial) - method_string = compare_method(partial.actual, &.to_s) - "Expected #{partial.label} to not end with #{label} (using #{method_string})" + def match(partial) + values = ExpectedActual.new(partial, self) + MatchData.new(match?(values.actual), values) end # Returns the method that should be used for comparison. @@ -49,6 +34,36 @@ module Spectator::Matchers end end + # Match data specific to this matcher. + private struct MatchData(ExpectedType, ActualType) < MatchData + # Creates the match data. + def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) + super(matched) + end + + # Information about the match. + def values + { + expected: @values.expected, + actual: @values.actual, + } + end + + # Describes the condition that satisfies the matcher. + # This is informational and displayed to the end-user. + def message + method_string = compare_method(partial.actual, &.to_s) + "#{values.actual_label} ends with #{values.expected_label} (using #{method_string})" + end + + # Describes the condition that won't satsify the matcher. + # This is informational and displayed to the end-user. + def negated_message + method_string = compare_method(partial.actual, &.to_s) + "#{values.actual_label} does not end with #{values.expected_label} (using #{method_string})" + end + end + # Comparison method for types that define the `ends_with?` method. private struct EndsWithCompareMethod # Evaluates the condition to determine whether the matcher is satisfied.