Source code for brunns.matchers.matcher

import difflib
from typing import Any, Union

from hamcrest import anything
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.core.isequal import IsEqual
from hamcrest.core.description import Description
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
from hamcrest.core.matcher import Matcher
from hamcrest.core.string_description import StringDescription


[docs] class MismatchesWith(BaseMatcher[Matcher]): def __init__(self, value_not_to_match: Any, expected_message: Union[str, Matcher[str]]) -> None: super().__init__() self.value_not_to_match = value_not_to_match self.expected_message: Matcher[str] = wrap_matcher(expected_message) def _matches(self, matcher_under_test: Matcher[Any]) -> bool: actual = StringDescription() matched = matcher_under_test.matches(self.value_not_to_match, actual) return not matched and self.expected_message.matches(actual.out)
[docs] def describe_to(self, description: Description) -> None: description.append_text("a matcher which mismatches the value ").append_description_of( self.value_not_to_match, ).append_text("\ngiving message ").append_description_of(self.expected_message)
[docs] def describe_mismatch(self, matcher_under_test: Matcher[Any], description: Description) -> None: actual_message = StringDescription() if matcher_under_test.matches(self.value_not_to_match, actual_message): description.append_text("matched") return description.append_text("got message ").append_description_of(actual_message) self.append_diff(actual_message, description)
def append_diff(self, actual_message, description): if isinstance(self.expected_message, IsEqual) and isinstance(self.expected_message.object, str): differ = difflib.Differ() diff = differ.compare([self.expected_message.object], [actual_message.out]) description.append_text("\ndiff:\n").append_text("\n".join(diff))
[docs] def mismatches_with(value_not_to_match: Any, expected_message: Union[str, Matcher[str]]) -> MismatchesWith: """Matches if the matcher under test fails to match the value, and provides the expected mismatch message. This is useful for testing custom matchers to ensure they reject invalid values and provide helpful diagnostics. :param value_not_to_match: The value that the matcher under test should reject. :param expected_message: The expected string (or matcher for the string) generated by the matcher's ``describe_mismatch`` method. """ return MismatchesWith(value_not_to_match, expected_message)
[docs] def mismatches(value_not_to_match: Any) -> MismatchesWith: """Matches if the matcher under test fails to match the value, regardless of the message. :param value_not_to_match: The value that the matcher under test should reject. """ return MismatchesWith(value_not_to_match, anything())
[docs] class MatchesWith(BaseMatcher[Matcher]): def __init__(self, value_to_match: Any, expected_message: Union[str, Matcher[str]]) -> None: super().__init__() self.value_to_match = value_to_match self.expected_message: Matcher[str] = wrap_matcher(expected_message) def _matches(self, matcher_under_test: Matcher[Any]) -> bool: actual = StringDescription() matched = matcher_under_test.matches(self.value_to_match) if matched: matcher_under_test.describe_match(self.value_to_match, actual) return matched and self.expected_message.matches(actual.out)
[docs] def describe_to(self, description: Description) -> None: description.append_text("a matcher which matches the value ").append_description_of( self.value_to_match, ).append_text("\ngiving message ").append_description_of(self.expected_message)
[docs] def describe_mismatch(self, matcher_under_test: Matcher[Any], description: Description) -> None: actual_message = StringDescription() if not matcher_under_test.matches(self.value_to_match): description.append_text("mismatched") return matcher_under_test.describe_match(self.value_to_match, actual_message) description.append_text("got message ").append_description_of(actual_message) self.append_diff(actual_message, description)
def append_diff(self, actual_message, description): if isinstance(self.expected_message, IsEqual) and isinstance(self.expected_message.object, str): differ = difflib.Differ() diff = differ.compare([self.expected_message.object], [actual_message.out]) description.append_text("\ndiff:\n").append_text("\n".join(diff))
[docs] def matches_with(value_to_match: Any, expected_message: Union[str, Matcher[str]]) -> MatchesWith: """Matches if the matcher under test successfully matches the value, and provides the expected match description. :param value_to_match: The value that the matcher under test should accept. :param expected_message: The expected string (or matcher for the string) generated by the matcher's ``describe_match`` method. """ return MatchesWith(value_to_match, expected_message)
[docs] def matches(value_to_match: Any) -> MatchesWith: """Matches if the matcher under test successfully matches the value, regardless of the message. :param value_to_match: The value that the matcher under test should accept. """ return MatchesWith(value_to_match, anything())