Update GreaterThanEqualMatcher to use MatchData

Add PrefixedValue type to help convey values better (without string
concat).
This commit is contained in:
Michael Miller 2019-03-05 15:39:30 -07:00
parent 0288e1d6f8
commit 83d398465f
3 changed files with 214 additions and 103 deletions

View file

@ -1,111 +1,183 @@
require "../spec_helper" require "../spec_helper"
describe Spectator::Matchers::GreaterThanEqualMatcher do describe Spectator::Matchers::GreaterThanEqualMatcher do
describe "#match?" do describe "#match" do
it "compares using #>=" do it "compares using #>=" do
spy = SpySUT.new spy = SpySUT.new
partial = new_partial(spy) partial = new_partial(spy)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(42) matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(42)
matcher.match?(partial).should be_true matcher.match(partial)
spy.ge_call_count.should be > 0 spy.ge_call_count.should be > 0
end end
context "with a larger value" do context "returned MatchData" do
it "is false" do describe "#matched?" do
actual = 42 context "with a larger value" do
expected = 777 it "is false" do
partial = new_partial(actual) actual = 42
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected) expected = 777
matcher.match?(partial).should be_false partial = new_partial(actual)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected)
match_data = matcher.match(partial)
match_data.matched?.should be_false
end
end
context "with a smaller value" do
it "is true" do
actual = 777
expected = 42
partial = new_partial(actual)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected)
match_data = matcher.match(partial)
match_data.matched?.should be_true
end
end
context "with an equal value" do
it "is true" do
value = 42
partial = new_partial(value)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value)
match_data = matcher.match(partial)
match_data.matched?.should be_true
end
end
end end
end
context "with a smaller value" do describe "#values" do
it "is true" do context "expected" do
actual = 777 it "is the expected value" do
expected = 42 actual = 777
partial = new_partial(actual) expected = 42
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected) partial = new_partial(actual)
matcher.match?(partial).should be_true matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected)
match_data = matcher.match(partial)
match_data.values[:expected].value.should eq(expected)
end
it "is prefixed with >=" do
actual = 777
expected = 42
partial = new_partial(actual)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected)
match_data = matcher.match(partial)
match_data.values[:expected].to_s.should start_with(">=")
end
end
context "actual" do
it "is the actual value" do
actual = 777
expected = 42
partial = new_partial(actual)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected)
match_data = matcher.match(partial)
match_data.values[:actual].value.should eq(actual)
end
context "when #matched? is true" do
it "is prefixed with >=" do
actual = 777
expected = 42
partial = new_partial(actual)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected)
match_data = matcher.match(partial)
match_data.matched?.should be_true # Sanity check.
match_data.values[:actual].to_s.should start_with(">=")
end
end
context "when #matched? is false" do
it "is prefixed with <" do
actual = 42
expected = 777
partial = new_partial(actual)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected)
match_data = matcher.match(partial)
match_data.matched?.should be_false # Sanity check.
match_data.values[:actual].to_s.should start_with("<")
end
end
end
end end
end
context "with an equal value" do describe "#message" do
it "is true" do it "mentions >=" do
value = 42 value = 42
partial = new_partial(value) partial = new_partial(value)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value) matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value)
matcher.match?(partial).should be_true match_data = matcher.match(partial)
match_data.message.should contain(">=")
end
it "contains the actual label" do
value = 42
label = "everything"
partial = new_partial(value, label)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value)
match_data = matcher.match(partial)
match_data.message.should contain(label)
end
it "contains the expected label" do
value = 42
label = "everything"
partial = new_partial(value)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value, label)
match_data = matcher.match(partial)
match_data.message.should contain(label)
end
context "when expected label is omitted" do
it "contains stringified form of expected value" do
value1 = 42
value2 = 777
partial = new_partial(value1)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value2)
match_data = matcher.match(partial)
match_data.message.should contain(value2.to_s)
end
end
end end
end
end
describe "#message" do describe "#negated_message" do
it "mentions >=" do it "mentions >=" do
value = 42 value = 42
partial = new_partial(value) partial = new_partial(value)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value) matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value)
matcher.message(partial).should contain(">=") match_data = matcher.match(partial)
end match_data.negated_message.should contain(">=")
end
it "contains the actual label" do it "contains the actual label" do
value = 42 value = 42
label = "everything" label = "everything"
partial = new_partial(value, label) partial = new_partial(value, label)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value) matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value)
matcher.message(partial).should contain(label) match_data = matcher.match(partial)
end match_data.negated_message.should contain(label)
end
it "contains the expected label" do it "contains the expected label" do
value = 42 value = 42
label = "everything" label = "everything"
partial = new_partial(value) partial = new_partial(value)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value, label) matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value, label)
matcher.message(partial).should contain(label) match_data = matcher.match(partial)
end match_data.negated_message.should contain(label)
end
context "when expected label is omitted" do context "when expected label is omitted" do
it "contains stringified form of expected value" do it "contains stringified form of expected value" do
value1 = 42 value1 = 42
value2 = 777 value2 = 777
partial = new_partial(value1) partial = new_partial(value1)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value2) matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value2)
matcher.message(partial).should contain(value2.to_s) match_data = matcher.match(partial)
end match_data.negated_message.should contain(value2.to_s)
end end
end end
describe "#negated_message" do
it "mentions >=" do
value = 42
partial = new_partial(value)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value)
matcher.negated_message(partial).should contain(">=")
end
it "contains the actual label" do
value = 42
label = "everything"
partial = new_partial(value, label)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value)
matcher.negated_message(partial).should contain(label)
end
it "contains the expected label" do
value = 42
label = "everything"
partial = new_partial(value)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value, label)
matcher.negated_message(partial).should contain(label)
end
context "when expected label is omitted" do
it "contains stringified form of expected value" do
value1 = 42
value2 = 777
partial = new_partial(value1)
matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value2)
matcher.negated_message(partial).should contain(value2.to_s)
end end
end end
end end

View file

@ -5,27 +5,48 @@ module Spectator::Matchers
# The values are compared with the >= operator. # The values are compared with the >= operator.
struct GreaterThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType) struct GreaterThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType)
# Determines whether the matcher is satisfied with the value given to it. # Determines whether the matcher is satisfied with the value given to it.
# True is returned if the match was successful, false otherwise. private def match?(actual)
def match?(partial) actual >= expected
partial.actual >= expected
end end
# Determines whether the matcher is satisfied with the partial given to it. # Determines whether the matcher is satisfied with the partial given to it.
# `MatchData` is returned that contains information about the match. # `MatchData` is returned that contains information about the match.
def match(partial) : MatchData def match(partial)
raise NotImplementedError.new("#match") values = ExpectedActual.new(partial, self)
MatchData.new(match?(values.actual), values)
end end
# Describes the condition that satisfies the matcher. # Match data specific to this matcher.
# This is informational and displayed to the end-user. private struct MatchData(ExpectedType, ActualType) < MatchData
def message(partial) # Creates the match data.
"Expected #{partial.label} to be greater than or equal to #{label} (using >=)" def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType))
end super(matched)
end
# Describes the condition that won't satsify the matcher. # Information about the match.
# This is informational and displayed to the end-user. def values
def negated_message(partial) {
"Expected #{partial.label} to not be greater than or equal to #{label} (using >=)" expected: PrefixedValue.new(">=", @values.expected),
actual: PrefixedValue.new(actual_operator, @values.actual),
}
end
# Textual operator for the actual value.
private def actual_operator
matched? ? ">=" : "<"
end
# Describes the condition that satisfies the matcher.
# This is informational and displayed to the end-user.
def message
"#{@values.actual_label} is greater than or equal to #{@values.expected_label} (using >=)"
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} is less than #{@values.expected_label} (using >=)"
end
end end
end end
end end

View file

@ -0,0 +1,18 @@
module Spectator::Matchers
# Prefixes (for output formatting) an actual or expected value.
private struct PrefixedValue(T)
# Value being prefixed.
getter value : T
# Creates the prefixed value.
def initialize(@prefix : String, @value : T)
end
# Outputs the formatted value with a prefix.
def to_s(io)
io << @prefix
io << ' '
io << @value
end
end
end