blob: 071b0d142e402dfbef542f1cb20ef7e1548e97de [file] [log] [blame] [edit]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! The components required to implement matchers.
use crate::description::Description;
use crate::internal::source_location::SourceLocation;
use crate::internal::test_outcome::TestAssertionFailure;
use crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher;
use crate::matchers::__internal_unstable_do_not_depend_on_these::DisjunctionMatcher;
use std::fmt::Debug;
/// An interface for checking an arbitrary condition on a datum.
pub trait Matcher {
/// The type against which this matcher matches.
type ActualT: Debug + ?Sized;
/// Returns whether the condition matches the datum `actual`.
///
/// The trait implementation defines what it means to "match". Often the
/// matching condition is based on data stored in the matcher. For example,
/// `eq` matches when its stored expected value is equal (in the sense of
/// the `==` operator) to the value `actual`.
fn matches(&self, actual: &Self::ActualT) -> MatcherResult;
/// Returns a description of `self` or a negative description if
/// `matcher_result` is `DoesNotMatch`.
///
/// The function should print a verb phrase that describes the property a
/// value matching, respectively not matching, this matcher should have.
/// The subject of the verb phrase is the value being matched.
///
/// The output appears next to `Expected` in an assertion failure message.
/// For example:
///
/// ```text
/// Value of: ...
/// Expected: is equal to 7
/// ^^^^^^^^^^^^^
/// Actual: ...
/// ```
///
/// When the matcher contains one or more inner matchers, the implementation
/// should invoke [`Self::describe`] on the inner matchers to complete the
/// description. It should place the inner description at a point where a
/// verb phrase would fit. For example, the matcher
/// [`some`][crate::matchers::some] implements `describe` as follows:
///
/// ```ignore
/// fn describe(&self, matcher_result: MatcherResult) -> Description {
/// match matcher_result {
/// MatcherResult::Matches => {
/// Description::new()
/// .text("has a value which")
/// .nested(self.inner.describe(MatcherResult::Matches))
/// // Inner matcher: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// }
/// MatcherResult::DoesNotMatch => {...} // Similar to the above
/// }
/// }
/// ```
///
/// The output expectation differs from that of
/// [`explain_match`][Self::explain_match] in that it is a verb phrase
/// (beginning with a verb like "is") rather than a relative clause
/// (beginning with "which" or "whose"). This difference is because the
/// output of `explain_match` is always used adjectivally to describe the
/// actual value, while `describe` is used in contexts where a relative
/// clause would not make sense.
fn describe(&self, matcher_result: MatcherResult) -> Description;
/// Prepares a [`String`] describing how the expected value
/// encoded in this instance matches or does not match the given value
/// `actual`.
///
/// This should be in the form of a relative clause, i.e. something starting
/// with a relative pronoun such as "which" or "whose". It will appear next
/// to the actual value in an assertion failure. For example:
///
/// ```text
/// Value of: ...
/// Expected: ...
/// Actual: ["Something"], which does not contain "Something else"
/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// ```
///
/// The default implementation relies on [`describe`][Self::describe]. Thus
/// it does not make any use of the actual value itself, but rather only
/// whether the value is matched.
///
/// Override the default implementation to provide additional context on why
/// a particular value matched or did not match. For example, the
/// [`container_eq`][crate::matchers::container_eq] matcher displays
/// information on which elements of the actual value were not present in
/// the expected value and vice versa.
///
/// This implementation should be overridden in any matcher which contains
/// one or more inner matchers. The implementation should invoke
/// `explain_match` on the inner matchers, so that the generated match
/// explanation also reflects their implementation. Without this, the match
/// explanation of the inner matchers will not be able to make use of the
/// actual value at all.
///
/// For example, the `explain_match` implementation of the matcher
/// [`points_to`][crate::matchers::points_to] defers immediately to the
/// inner matcher and appears as follows:
///
/// ```ignore
/// fn explain_match(&self, actual: &Self::ActualT) -> Description {
/// self.expected.explain_match(actual.deref())
/// }
/// ```
///
/// The matcher can also provide some additional context before deferring to
/// an inner matcher. In that case it should invoke `explain_match` on the
/// inner matcher at a point where a relative clause would fit. For example:
///
/// ```ignore
/// fn explain_match(&self, actual: &Self::ActualT) -> Description {
/// Description::new()
/// .text("which points to a value")
/// .nested(self.expected.explain_match(actual.deref()))
/// }
/// ```
fn explain_match(&self, actual: &Self::ActualT) -> Description {
format!("which {}", self.describe(self.matches(actual))).into()
}
/// Constructs a matcher that matches both `self` and `right`.
///
/// ```
/// # use googletest::prelude::*;
/// # fn should_pass() -> Result<()> {
/// verify_that!("A string", starts_with("A").and(ends_with("string")))?; // Passes
/// # Ok(())
/// # }
/// # fn should_fail_1() -> Result<()> {
/// verify_that!("A string", starts_with("Another").and(ends_with("string")))?; // Fails
/// # Ok(())
/// # }
/// # fn should_fail_2() -> Result<()> {
/// verify_that!("A string", starts_with("A").and(ends_with("non-string")))?; // Fails
/// # Ok(())
/// # }
/// # should_pass().unwrap();
/// # should_fail_1().unwrap_err();
/// # should_fail_2().unwrap_err();
/// ```
// TODO(b/264518763): Replace the return type with impl Matcher and reduce
// visibility of ConjunctionMatcher once impl in return position in trait
// methods is stable.
fn and<Right: Matcher<ActualT = Self::ActualT>>(
self,
right: Right,
) -> ConjunctionMatcher<Self, Right>
where
Self: Sized,
{
ConjunctionMatcher::new(self, right)
}
/// Constructs a matcher that matches when at least one of `self` or `right`
/// matches the input.
///
/// ```
/// # use googletest::prelude::*;
/// # fn should_pass() -> Result<()> {
/// verify_that!(10, eq(2).or(ge(5)))?; // Passes
/// verify_that!(10, eq(2).or(eq(5)).or(ge(9)))?; // Passes
/// # Ok(())
/// # }
/// # fn should_fail() -> Result<()> {
/// verify_that!(10, eq(2).or(ge(15)))?; // Fails
/// # Ok(())
/// # }
/// # should_pass().unwrap();
/// # should_fail().unwrap_err();
/// ```
// TODO(b/264518763): Replace the return type with impl Matcher and reduce
// visibility of DisjunctionMatcher once impl in return position in trait
// methods is stable.
fn or<Right: Matcher<ActualT = Self::ActualT>>(
self,
right: Right,
) -> DisjunctionMatcher<Self, Right>
where
Self: Sized,
{
DisjunctionMatcher::new(self, right)
}
}
/// Any actual value whose debug length is greater than this value will be
/// pretty-printed. Otherwise, it will have normal debug output formatting.
const PRETTY_PRINT_LENGTH_THRESHOLD: usize = 60;
/// Constructs a [`TestAssertionFailure`] reporting that the given `matcher`
/// does not match the value `actual`.
///
/// The parameter `actual_expr` contains the expression which was evaluated to
/// obtain `actual`.
pub(crate) fn create_assertion_failure<T: Debug + ?Sized>(
matcher: &impl Matcher<ActualT = T>,
actual: &T,
actual_expr: &'static str,
source_location: SourceLocation,
) -> TestAssertionFailure {
let actual_formatted = format!("{actual:?}");
let actual_formatted = if actual_formatted.len() > PRETTY_PRINT_LENGTH_THRESHOLD {
format!("{actual:#?}")
} else {
actual_formatted
};
TestAssertionFailure::create(format!(
"\
Value of: {actual_expr}
Expected: {}
Actual: {actual_formatted},
{}
{source_location}",
matcher.describe(MatcherResult::Match),
matcher.explain_match(actual).indent(),
))
}
/// The result of applying a [`Matcher`] on an actual value.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum MatcherResult {
/// The actual value matches according to the [`Matcher`] definition.
Match,
/// The actual value does not match according to the [`Matcher`] definition.
NoMatch,
}
impl From<bool> for MatcherResult {
fn from(b: bool) -> Self {
if b { MatcherResult::Match } else { MatcherResult::NoMatch }
}
}
impl From<MatcherResult> for bool {
fn from(matcher_result: MatcherResult) -> Self {
matcher_result.is_match()
}
}
impl MatcherResult {
/// Returns `true` if `self` is [`MatcherResult::Match`], otherwise
/// `false`.
pub fn is_match(self) -> bool {
matches!(self, MatcherResult::Match)
}
/// Returns `true` if `self` is [`MatcherResult::NoMatch`], otherwise
/// `false`.
pub fn is_no_match(self) -> bool {
matches!(self, MatcherResult::NoMatch)
}
}