thoughtbot--shoulda-matchers/spec/support/unit/matchers/match_against.rb

217 lines
5.1 KiB
Ruby

module UnitTests
module Matchers
def match_against(object)
MatchAgainstMatcher.new(object)
end
class MatchAgainstMatcher
DIVIDER = ('-' * Shoulda::Matchers::WordWrap::TERMINAL_WIDTH).freeze
attr_reader :failure_message, :failure_message_when_negated
def initialize(object)
@object = object
@failure_message = nil
@failure_message_when_negated = nil
@should_be_negated = nil
end
def and_fail_with(message, wrap: false)
@expected_message =
if wrap
Shoulda::Matchers.word_wrap(message.strip_heredoc.strip)
else
message.strip_heredoc.strip
end
@should_be_negated = true
self
end
def or_fail_with(message, wrap: false)
@expected_message =
if wrap
Shoulda::Matchers.word_wrap(message.strip_heredoc.strip)
else
message.strip_heredoc.strip
end
@should_be_negated = false
self
end
def matches?(generate_matcher)
@positive_matcher = generate_matcher.call
@negative_matcher = generate_matcher.call
if expected_message && should_be_negated?
raise ArgumentError.new(
'Use `or_fail_with`, not `and_fail_with`, when using '\
'`should match_against(...)`!',
)
end
if positive_matcher.matches?(object)
matcher_fails_in_negative?
else
@failure_message = <<-MESSAGE
Expected the matcher to match in the positive, but it failed with this message:
#{DIVIDER}
#{positive_matcher.failure_message}
#{DIVIDER}
MESSAGE
false
end
end
def does_not_match?(generate_matcher)
@positive_matcher = generate_matcher.call
@negative_matcher = generate_matcher.call
if expected_message && !should_be_negated?
raise ArgumentError.new(
'Use `and_fail_with`, not `or_fail_with`, when using '\
'`should_not match_against(...)`!',
)
end
if matcher_fails_in_positive?
if (
negative_matcher.respond_to?(:does_not_match?) &&
!negative_matcher.does_not_match?(object)
)
@failure_message_when_negated = <<-MESSAGE
Expected the matcher to match in the negative, but it failed with this message:
#{DIVIDER}
#{negative_matcher.failure_message_when_negated}
#{DIVIDER}
MESSAGE
false
else
true
end
end
end
def supports_block_expectations?
true
end
private
attr_reader(
:object,
:expected_message,
:positive_matcher,
:negative_matcher,
)
def should_be_negated?
@should_be_negated
end
def matcher_fails_in_negative?
if does_not_match_in_negative?
if (
!expected_message ||
expected_message == negative_matcher.failure_message_when_negated.strip
)
true
else
diff_result = diff(
expected_message,
negative_matcher.failure_message_when_negated.strip,
)
@failure_message = <<-MESSAGE
Expected the negative version of the matcher not to match and for the failure
message to be:
#{DIVIDER}
#{expected_message.chomp}
#{DIVIDER}
However, it was:
#{DIVIDER}
#{negative_matcher.failure_message_when_negated}
#{DIVIDER}
Diff:
#{Shoulda::Matchers::Util.indent(diff_result, 2)}
MESSAGE
false
end
else
@failure_message =
'Expected the negative version of the matcher not to match, '\
'but it did.'
false
end
end
def does_not_match_in_negative?
if negative_matcher.respond_to?(:does_not_match?)
!negative_matcher.does_not_match?(object)
else
# generate failure_message_when_negated
negative_matcher.matches?(object)
true
end
end
def matcher_fails_in_positive?
if !positive_matcher.matches?(object)
if (
!expected_message ||
expected_message == positive_matcher.failure_message.strip
)
true
else
diff_result = diff(
expected_message,
positive_matcher.failure_message.strip,
)
@failure_message_when_negated = <<-MESSAGE
Expected the positive version of the matcher not to match and for the failure
message to be:
#{DIVIDER}
#{expected_message.chomp}
#{DIVIDER}
However, it was:
#{DIVIDER}
#{positive_matcher.failure_message}
#{DIVIDER}
Diff:
#{Shoulda::Matchers::Util.indent(diff_result, 2)}
MESSAGE
false
end
else
@failure_message_when_negated =
'Expected the positive version of the matcher not to match, '\
'but it did.'
false
end
end
def diff(expected, actual)
differ.diff(expected, actual)[1..]
end
def differ
@_differ ||= RSpec::Support::Differ.new
end
end
end
end