From 76d09a22fff62c5674f8b01759beb370919c40ea Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Wed, 6 Mar 2019 02:19:12 -0700 Subject: [PATCH] Update HaveValueMatcher to use MatchData --- spec/matchers/have_value_matcher_spec.cr | 191 ++++++++++++------- src/spectator/matchers/have_value_matcher.cr | 45 +++-- 2 files changed, 154 insertions(+), 82 deletions(-) diff --git a/spec/matchers/have_value_matcher_spec.cr b/spec/matchers/have_value_matcher_spec.cr index 9f1e385..3d3220a 100644 --- a/spec/matchers/have_value_matcher_spec.cr +++ b/spec/matchers/have_value_matcher_spec.cr @@ -1,84 +1,139 @@ require "../spec_helper" +private struct FakeValueSet + def has_value?(value) + true + end +end + describe Spectator::Matchers::HaveValueMatcher do - describe "#match?" do - context "with an existing value" do - it "is true" do - hash = Hash{"foo" => "bar"} - value = "bar" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - matcher.match?(partial).should be_true + describe "#match" do + context "returned MatchData" do + describe "#matched?" do + context "with an existing value" do + it "is true" do + hash = Hash{"foo" => "bar"} + value = "bar" + partial = new_partial(hash) + matcher = Spectator::Matchers::HaveValueMatcher.new(value) + match_data = matcher.match(partial) + match_data.matched?.should be_true + end + end + + context "with a non-existent value" do + it "is false" do + hash = Hash{"foo" => "bar"} + value = "baz" + partial = new_partial(hash) + matcher = Spectator::Matchers::HaveValueMatcher.new(value) + match_data = matcher.match(partial) + match_data.matched?.should be_false + end + end end - end - context "with a non-existent value" do - it "is false" do - hash = Hash{"foo" => "bar"} - value = "baz" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - matcher.match?(partial).should be_false + describe "#values" do + context "value" do + it "is the expected value" do + hash = {"foo" => "bar"} + value = "baz" + partial = new_partial(hash) + matcher = Spectator::Matchers::HaveValueMatcher.new(value) + match_data = matcher.match(partial) + match_data.values[:value].should eq(value) + end + end + + context "actual" do + context "when #values is available" do + it "is the list of values" do + hash = Hash{"foo" => "bar"} + value = "baz" + partial = new_partial(hash) + matcher = Spectator::Matchers::HaveValueMatcher.new(value) + match_data = matcher.match(partial) + match_data.values[:actual].should eq(hash.values) + end + end + + context "when #values isn't available" do + it "is the actual value" do + actual = FakeValueSet.new + value = "baz" + partial = new_partial(actual) + matcher = Spectator::Matchers::HaveValueMatcher.new(value) + match_data = matcher.match(partial) + match_data.values[:actual].should eq(actual) + end + end + end end - end - end - describe "#message" do - it "contains the actual label" do - hash = Hash{"foo" => "bar"} - value = "bar" - label = "blah" - partial = new_partial(hash, label) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - matcher.message(partial).should contain(label) - end + describe "#message" do + it "contains the actual label" do + hash = Hash{"foo" => "bar"} + value = "bar" + label = "blah" + partial = new_partial(hash, label) + matcher = Spectator::Matchers::HaveValueMatcher.new(value) + match_data = matcher.match(partial) + match_data.message.should contain(label) + end - it "contains the expected label" do - hash = Hash{"foo" => "bar"} - value = "bar" - label = "blah" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value, label) - matcher.message(partial).should contain(label) - end + it "contains the expected label" do + hash = Hash{"foo" => "bar"} + value = "bar" + label = "blah" + partial = new_partial(hash) + matcher = Spectator::Matchers::HaveValueMatcher.new(value, label) + match_data = matcher.match(partial) + match_data.message.should contain(label) + end - context "when the expected label is omitted" do - it "contains the stringified key" do - hash = Hash{"foo" => "bar"} - value = "bar" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - matcher.message(partial).should contain(value.to_s) + context "when the expected label is omitted" do + it "contains the stringified key" do + hash = Hash{"foo" => "bar"} + value = "bar" + partial = new_partial(hash) + matcher = Spectator::Matchers::HaveValueMatcher.new(value) + match_data = matcher.match(partial) + match_data.message.should contain(value.to_s) + end + end end - end - end - describe "#negated_message" do - it "contains the actual label" do - hash = Hash{"foo" => "bar"} - value = "bar" - label = "blah" - partial = new_partial(hash, label) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - matcher.negated_message(partial).should contain(label) - end + describe "#negated_message" do + it "contains the actual label" do + hash = Hash{"foo" => "bar"} + value = "bar" + label = "blah" + partial = new_partial(hash, label) + matcher = Spectator::Matchers::HaveValueMatcher.new(value) + match_data = matcher.match(partial) + match_data.negated_message.should contain(label) + end - it "contains the expected label" do - hash = Hash{"foo" => "bar"} - value = "bar" - label = "blah" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value, label) - matcher.negated_message(partial).should contain(label) - end + it "contains the expected label" do + hash = Hash{"foo" => "bar"} + value = "bar" + label = "blah" + partial = new_partial(hash) + matcher = Spectator::Matchers::HaveValueMatcher.new(value, label) + match_data = matcher.match(partial) + match_data.negated_message.should contain(label) + end - context "when the expected label is omitted" do - it "contains the stringified key" do - hash = Hash{"foo" => "bar"} - value = "bar" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - matcher.negated_message(partial).should contain(value.to_s) + context "when the expected label is omitted" do + it "contains the stringified key" do + hash = Hash{"foo" => "bar"} + value = "bar" + partial = new_partial(hash) + matcher = Spectator::Matchers::HaveValueMatcher.new(value) + match_data = matcher.match(partial) + match_data.negated_message.should contain(value.to_s) + end + end end end end diff --git a/src/spectator/matchers/have_value_matcher.cr b/src/spectator/matchers/have_value_matcher.cr index 29e8043..fe6b66a 100644 --- a/src/spectator/matchers/have_value_matcher.cr +++ b/src/spectator/matchers/have_value_matcher.cr @@ -5,27 +5,44 @@ module Spectator::Matchers # The set is checked with the `has_value?` method. struct HaveValueMatcher(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.has_value?(expected) + private def match?(actual) + actual.has_value?(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") + def match(partial) + values = ExpectedActual.new(partial, self) + MatchData.new(match?(values.actual), values) end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message(partial) - "Expected #{partial.label} to have value #{label}" - 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 - # 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 have value #{label}" + # Information about the match. + def values + actual = @values.actual + { + value: @values.expected, + actual: actual.responds_to?(:values) ? actual.values : actual, + } + end + + # Describes the condition that satisfies the matcher. + # This is informational and displayed to the end-user. + def message + "#{@values.actual_label} has value #{@values.expected_label}" + end + + # Describes the condition that won't satsify the matcher. + # This is informational and displayed to the end-user. + def negated_message + "#{@values.actual_label} does not have value #{@values.expected_label}" + end end end end