Skip to main content

googletest/
matcher.rs

1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! The components required to implement matchers.
16
17use crate::description::Description;
18use crate::internal::test_outcome::TestAssertionFailure;
19use crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher;
20use crate::matchers::__internal_unstable_do_not_depend_on_these::DisjunctionMatcher;
21pub use googletest_macro::MatcherBase;
22use std::fmt::Debug;
23
24/// An interface for checking an arbitrary condition on a datum.
25///
26/// This trait is automatically implemented for a reference of any type
27/// implementing `Matcher`. This simplifies reusing a matcher in different
28/// assertions.
29///
30/// It is also implemented for tuple of `Matcher`. If `MatcherT: Matcher<T>` and
31/// `MatcherU: Matcher<U>`, then `(MatcherT, MatcherU): Matcher<(T, U)>`, and so
32/// on, up to 12 elements. Tuples longer than that do not automatically inherit
33/// the `Debug` trait from their members, so are generally not well-supported;
34/// see [Rust by Example](https://doc.rust-lang.org/rust-by-example/primitives/tuples.html#tuples).
35// `ActualT` requires `Copy` so that `actual` could be passed to `matches` and
36// if it fails passed to `explain_match`. We can relax this constraint later by
37// requiring only `Clone`.
38pub trait Matcher<ActualT: Debug + Copy>: MatcherBase {
39    /// Returns whether the condition matches the datum `actual`.
40    ///
41    /// The trait implementation defines what it means to "match". Often the
42    /// matching condition is based on data stored in the matcher. For example,
43    /// `eq` matches when its stored expected value is equal (in the sense of
44    /// the `==` operator) to the value `actual`.
45    fn matches(&self, actual: ActualT) -> MatcherResult;
46
47    /// Returns a description of `self` or a negative description if
48    /// `matcher_result` is `DoesNotMatch`.
49    ///
50    /// The function should print a verb phrase that describes the property a
51    /// value matching, respectively not matching, this matcher should have.
52    /// The subject of the verb phrase is the value being matched.
53    ///
54    /// The output appears next to `Expected` in an assertion failure message.
55    /// For example:
56    ///
57    /// ```text
58    /// Value of: ...
59    /// Expected: is equal to 7
60    ///           ^^^^^^^^^^^^^
61    /// Actual: ...
62    /// ```
63    ///
64    /// When the matcher contains one or more inner matchers, the implementation
65    /// should invoke [`Self::describe`] on the inner matchers to complete the
66    /// description. It should place the inner description at a point where a
67    /// verb phrase would fit. For example, the matcher
68    /// [`some`][crate::matchers::some] implements `describe` as follows:
69    ///
70    /// ```ignore
71    /// fn describe(&self, matcher_result: MatcherResult) -> Description {
72    ///     match matcher_result {
73    ///         MatcherResult::Matches => {
74    ///             Description::new()
75    ///                 .text("has a value which")
76    ///                 .nested(self.inner.describe(MatcherResult::Matches))
77    ///       // Inner matcher: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
78    ///         }
79    ///         MatcherResult::DoesNotMatch => {...} // Similar to the above
80    ///     }
81    /// }
82    /// ```
83    ///
84    /// The output expectation differs from that of
85    /// [`explain_match`][Self::explain_match] in that it is a verb phrase
86    /// (beginning with a verb like "is") rather than a relative clause
87    /// (beginning with "which" or "whose"). This difference is because the
88    /// output of `explain_match` is always used adjectivally to describe the
89    /// actual value, while `describe` is used in contexts where a relative
90    /// clause would not make sense.
91    fn describe(&self, matcher_result: MatcherResult) -> Description;
92
93    /// Prepares a [`String`] describing how the expected value
94    /// encoded in this instance matches or does not match the given value
95    /// `actual`.
96    ///
97    /// This should be in the form of a relative clause, i.e. something starting
98    /// with a relative pronoun such as "which" or "whose". It will appear next
99    /// to the actual value in an assertion failure. For example:
100    ///
101    /// ```text
102    /// Value of: ...
103    /// Expected: ...
104    /// Actual: ["Something"], which does not contain "Something else"
105    ///                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
106    /// ```
107    ///
108    /// The default implementation relies on [`describe`][Self::describe]. Thus
109    /// it does not make any use of the actual value itself, but rather only
110    /// whether the value is matched.
111    ///
112    /// Override the default implementation to provide additional context on why
113    /// a particular value matched or did not match. For example, the
114    /// [`container_eq`][crate::matchers::container_eq] matcher displays
115    /// information on which elements of the actual value were not present in
116    /// the expected value and vice versa.
117    ///
118    /// This implementation should be overridden in any matcher which contains
119    /// one or more inner matchers. The implementation should invoke
120    /// `explain_match` on the inner matchers, so that the generated match
121    /// explanation also reflects their implementation. Without this, the match
122    /// explanation of the inner matchers will not be able to make use of the
123    /// actual value at all.
124    ///
125    /// For example, the `explain_match` implementation of the matcher
126    /// [`points_to`][crate::matchers::points_to] defers immediately to the
127    /// inner matcher and appears as follows:
128    ///
129    /// ```ignore
130    /// fn explain_match(&self, actual: &ActualT) -> Description {
131    ///     self.expected.explain_match(*actual)
132    /// }
133    /// ```
134    ///
135    /// The matcher can also provide some additional context before deferring to
136    /// an inner matcher. In that case it should invoke `explain_match` on the
137    /// inner matcher at a point where a relative clause would fit. For example:
138    ///
139    /// ```ignore
140    /// fn explain_match(&self, actual: ActualT) -> Description {
141    ///     Description::new()
142    ///         .text("which points to a value")
143    ///         .nested(self.expected.explain_match(*actual))
144    /// }
145    /// ```
146    fn explain_match(&self, actual: ActualT) -> Description {
147        format!("which {}", self.describe(self.matches(actual))).into()
148    }
149}
150
151/// Base trait for matchers. Any type implementing `Matcher` must implement
152/// `MatcherBase`, but that should be done through the `#[derive(MatcherBase)]`
153/// macro.
154// The `and` and `or` functions cannot be part of the `Matcher` trait since it
155// can be implemented multiple times for a given matcher type. Consider that
156// `and` and `or` are part of the `Matcher` trait and `MyMatcher` implements
157// both `Matcher<A>` and `Matcher<B>`. Then `MyMatcher{...}.and(...)` can be
158// either:
159//   * `Matcher::<A>::and(MyMatcher{...}, ...)` or
160//   * `Matcher::<B>::and(MyMatcher{...}, ...)`.
161// Moving the `and` and `or` functions in a non-generic trait removes this
162// confusion by making `and` and `or` unique for a given type.
163pub trait MatcherBase {
164    /// Constructs a matcher that matches both `self` and `right`.
165    ///
166    /// ```
167    /// # use googletest::prelude::*;
168    /// # fn should_pass() -> Result<()> {
169    /// verify_that!("A string", starts_with("A").and(ends_with("string")))?; // Passes
170    /// #     Ok(())
171    /// # }
172    /// # fn should_fail_1() -> Result<()> {
173    /// verify_that!("A string", starts_with("Another").and(ends_with("string")))?; // Fails
174    /// #     Ok(())
175    /// # }
176    /// # fn should_fail_2() -> Result<()> {
177    /// verify_that!("A string", starts_with("A").and(ends_with("non-string")))?; // Fails
178    /// #     Ok(())
179    /// # }
180    /// # should_pass().unwrap();
181    /// # should_fail_1().unwrap_err();
182    /// # should_fail_2().unwrap_err();
183    /// ```
184    // TODO(b/264518763): Replace the return type with impl Matcher and reduce
185    // visibility of ConjunctionMatcher once impl in return position in trait
186    // methods is stable.
187    fn and<Right>(self, right: Right) -> ConjunctionMatcher<Self, Right>
188    where
189        Self: Sized,
190    {
191        ConjunctionMatcher::new(self, right)
192    }
193
194    /// Constructs a matcher that matches when at least one of `self` or `right`
195    /// matches the input.
196    ///
197    /// ```
198    /// # use googletest::prelude::*;
199    /// # fn should_pass() -> Result<()> {
200    /// verify_that!(10, eq(2).or(ge(5)))?;  // Passes
201    /// verify_that!(10, eq(2).or(eq(5)).or(ge(9)))?;  // Passes
202    /// #     Ok(())
203    /// # }
204    /// # fn should_fail() -> Result<()> {
205    /// verify_that!(10, eq(2).or(ge(15)))?; // Fails
206    /// #     Ok(())
207    /// # }
208    /// # should_pass().unwrap();
209    /// # should_fail().unwrap_err();
210    /// ```
211    // TODO(b/264518763): Replace the return type with impl Matcher and reduce
212    // visibility of DisjunctionMatcher once impl in return position in trait
213    // methods is stable.
214    fn or<Right>(self, right: Right) -> DisjunctionMatcher<Self, Right>
215    where
216        Self: Sized,
217    {
218        DisjunctionMatcher::new(self, right)
219    }
220}
221
222/// Any actual value whose debug length is greater than this value will be
223/// pretty-printed. Otherwise, it will have normal debug output formatting.
224const PRETTY_PRINT_LENGTH_THRESHOLD: usize = 60;
225
226/// Constructs a [`TestAssertionFailure`] reporting that the given `matcher`
227/// does not match the value `actual`.
228///
229/// The parameter `actual_expr` contains the expression which was evaluated to
230/// obtain `actual`.
231#[track_caller]
232pub(crate) fn create_assertion_failure<T: Debug + Copy>(
233    matcher: &impl Matcher<T>,
234    actual: T,
235    actual_expr: &'static str,
236) -> TestAssertionFailure {
237    let actual_formatted = format!("{actual:?}");
238    let actual_formatted = if actual_formatted.len() > PRETTY_PRINT_LENGTH_THRESHOLD {
239        format!("{actual:#?}")
240    } else {
241        actual_formatted
242    };
243    TestAssertionFailure::create(format!(
244        "\
245Value of: {actual_expr}
246Expected: {}
247Actual: {actual_formatted},
248{}",
249        matcher.describe(MatcherResult::Match),
250        matcher.explain_match(actual).indent(),
251    ))
252}
253
254/// The result of applying a [`Matcher`] on an actual value.
255#[derive(Debug, PartialEq, Clone, Copy)]
256pub enum MatcherResult {
257    /// The actual value matches according to the [`Matcher`] definition.
258    Match,
259    /// The actual value does not match according to the [`Matcher`] definition.
260    NoMatch,
261}
262
263impl From<bool> for MatcherResult {
264    fn from(b: bool) -> Self {
265        if b {
266            MatcherResult::Match
267        } else {
268            MatcherResult::NoMatch
269        }
270    }
271}
272
273impl From<MatcherResult> for bool {
274    fn from(matcher_result: MatcherResult) -> Self {
275        matcher_result.is_match()
276    }
277}
278
279impl MatcherResult {
280    /// Returns `true` if `self` is [`MatcherResult::Match`], otherwise
281    /// `false`.
282    pub fn is_match(self) -> bool {
283        matches!(self, MatcherResult::Match)
284    }
285
286    /// Returns `true` if `self` is [`MatcherResult::NoMatch`], otherwise
287    /// `false`.
288    pub fn is_no_match(self) -> bool {
289        matches!(self, MatcherResult::NoMatch)
290    }
291}
292
293impl<M: ?Sized + MatcherBase> MatcherBase for &M {}
294
295impl<T: Debug + Copy, M: Matcher<T>> Matcher<T> for &M {
296    fn matches(&self, actual: T) -> MatcherResult {
297        (*self).matches(actual)
298    }
299
300    fn describe(&self, matcher_result: MatcherResult) -> Description {
301        (*self).describe(matcher_result)
302    }
303
304    fn explain_match(&self, actual: T) -> Description {
305        (*self).explain_match(actual)
306    }
307}
308
309#[cfg(test)]
310mod tests {
311    use crate::prelude::*;
312    use crate::Result;
313
314    #[test]
315    fn ref_matchers_can_be_reused() -> Result<()> {
316        let matcher = eq(1);
317
318        verify_that!(1, &matcher)?;
319        verify_that!(1, &matcher)
320    }
321
322    #[test]
323    fn ref_matchers_as_inner_matcher() -> Result<()> {
324        let matcher = gt(1);
325
326        verify_that!([2, 3, 4, 5], [&matcher, &matcher, &matcher, &matcher])
327    }
328}