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` according to the supplied matching
48    /// sense: a positive description if `sense` is `Match`, and a negative
49    /// description if it's `NoMatch`.
50    ///
51    /// The function should print a verb phrase that describes the property a
52    /// value matching, respectively not matching, this matcher should have.
53    /// The subject of the verb phrase is the value being matched.
54    ///
55    /// The output appears next to `Expected` in an assertion failure message.
56    /// For example:
57    ///
58    /// ```text
59    /// Value of: ...
60    /// Expected: is equal to 7
61    ///           ^^^^^^^^^^^^^
62    /// Actual: ...
63    /// ```
64    ///
65    /// When the matcher contains one or more inner matchers, the implementation
66    /// should invoke [`Self::describe`] on the inner matchers to complete the
67    /// description. It should place the inner description at a point where a
68    /// verb phrase would fit. For example, the matcher
69    /// [`some`][crate::matchers::some] implements `describe` as follows:
70    ///
71    /// ```ignore
72    /// fn describe(&self, sense: MatcherResult) -> Description {
73    ///     match sense {
74    ///         MatcherResult::Match => {
75    ///             Description::new()
76    ///                 .text("has a value which")
77    ///                 .nested(self.inner.describe(MatcherResult::Match))
78    ///       // Inner matcher: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
79    ///         }
80    ///         MatcherResult::NoMatch => {
81    ///             Description::new()
82    ///                 .text("is None or has a value which")
83    ///                 .nested(self.inner.describe(MatcherResult::NoMatch))
84    ///         }
85    ///     }
86    /// }
87    /// ```
88    ///
89    /// The output expectation differs from that of
90    /// [`explain_match`][Self::explain_match] in that it is a verb phrase
91    /// (beginning with a verb like "is") rather than a relative clause
92    /// (beginning with "which" or "whose"). This difference is because the
93    /// output of `explain_match` is always used adjectivally to describe the
94    /// actual value, while `describe` is used in contexts where a relative
95    /// clause would not make sense.
96    fn describe(&self, sense: MatcherResult) -> Description;
97
98    /// Prepares a [`String`] describing how the expected value
99    /// encoded in this instance matches or does not match the given value
100    /// `actual`.
101    ///
102    /// This should be in the form of a relative clause, i.e. something starting
103    /// with a relative pronoun such as "which" or "whose". It will appear next
104    /// to the actual value in an assertion failure. For example:
105    ///
106    /// ```text
107    /// Value of: ...
108    /// Expected: ...
109    /// Actual: ["Something"], which does not contain "Something else"
110    ///                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
111    /// ```
112    ///
113    /// The default implementation relies on [`describe`][Self::describe]. Thus
114    /// it does not make any use of the actual value itself, but rather only
115    /// whether the value is matched.
116    ///
117    /// Override the default implementation to provide additional context on why
118    /// a particular value matched or did not match. For example, the
119    /// [`container_eq`][crate::matchers::container_eq] matcher displays
120    /// information on which elements of the actual value were not present in
121    /// the expected value and vice versa.
122    ///
123    /// This implementation should be overridden in any matcher which contains
124    /// one or more inner matchers. The implementation should invoke
125    /// `explain_match` on the inner matchers, so that the generated match
126    /// explanation also reflects their implementation. Without this, the match
127    /// explanation of the inner matchers will not be able to make use of the
128    /// actual value at all.
129    ///
130    /// For example, the `explain_match` implementation of the matcher
131    /// [`points_to`][crate::matchers::points_to] defers immediately to the
132    /// inner matcher and appears as follows:
133    ///
134    /// ```ignore
135    /// fn explain_match(&self, actual: &ActualT) -> Description {
136    ///     self.expected.explain_match(*actual)
137    /// }
138    /// ```
139    ///
140    /// The matcher can also provide some additional context before deferring to
141    /// an inner matcher. In that case it should invoke `explain_match` on the
142    /// inner matcher at a point where a relative clause would fit. For example:
143    ///
144    /// ```ignore
145    /// fn explain_match(&self, actual: ActualT) -> Description {
146    ///     Description::new()
147    ///         .text("which points to a value")
148    ///         .nested(self.expected.explain_match(*actual))
149    /// }
150    /// ```
151    fn explain_match(&self, actual: ActualT) -> Description {
152        format!("which {}", self.describe(self.matches(actual))).into()
153    }
154}
155
156/// Base trait for matchers. Any type implementing `Matcher` must implement
157/// `MatcherBase`, but that should be done through the `#[derive(MatcherBase)]`
158/// macro.
159// The `and` and `or` functions cannot be part of the `Matcher` trait since it
160// can be implemented multiple times for a given matcher type. Consider that
161// `and` and `or` are part of the `Matcher` trait and `MyMatcher` implements
162// both `Matcher<A>` and `Matcher<B>`. Then `MyMatcher{...}.and(...)` can be
163// either:
164//   * `Matcher::<A>::and(MyMatcher{...}, ...)` or
165//   * `Matcher::<B>::and(MyMatcher{...}, ...)`.
166// Moving the `and` and `or` functions in a non-generic trait removes this
167// confusion by making `and` and `or` unique for a given type.
168pub trait MatcherBase {
169    /// Constructs a matcher that matches both `self` and `right`.
170    ///
171    /// ```
172    /// # use googletest::prelude::*;
173    /// # fn should_pass() -> Result<()> {
174    /// verify_that!("A string", starts_with("A").and(ends_with("string")))?; // Passes
175    /// #     Ok(())
176    /// # }
177    /// # fn should_fail_1() -> Result<()> {
178    /// verify_that!("A string", starts_with("Another").and(ends_with("string")))?; // Fails
179    /// #     Ok(())
180    /// # }
181    /// # fn should_fail_2() -> Result<()> {
182    /// verify_that!("A string", starts_with("A").and(ends_with("non-string")))?; // Fails
183    /// #     Ok(())
184    /// # }
185    /// # should_pass().unwrap();
186    /// # should_fail_1().unwrap_err();
187    /// # should_fail_2().unwrap_err();
188    /// ```
189    // TODO(b/264518763): Replace the return type with impl Matcher and reduce
190    // visibility of ConjunctionMatcher once impl in return position in trait
191    // methods is stable.
192    fn and<Right>(self, right: Right) -> ConjunctionMatcher<Self, Right>
193    where
194        Self: Sized,
195    {
196        ConjunctionMatcher::new(self, right)
197    }
198
199    /// Constructs a matcher that matches when at least one of `self` or `right`
200    /// matches the input.
201    ///
202    /// ```
203    /// # use googletest::prelude::*;
204    /// # fn should_pass() -> Result<()> {
205    /// verify_that!(10, eq(2).or(ge(5)))?;  // Passes
206    /// verify_that!(10, eq(2).or(eq(5)).or(ge(9)))?;  // Passes
207    /// #     Ok(())
208    /// # }
209    /// # fn should_fail() -> Result<()> {
210    /// verify_that!(10, eq(2).or(ge(15)))?; // Fails
211    /// #     Ok(())
212    /// # }
213    /// # should_pass().unwrap();
214    /// # should_fail().unwrap_err();
215    /// ```
216    // TODO(b/264518763): Replace the return type with impl Matcher and reduce
217    // visibility of DisjunctionMatcher once impl in return position in trait
218    // methods is stable.
219    fn or<Right>(self, right: Right) -> DisjunctionMatcher<Self, Right>
220    where
221        Self: Sized,
222    {
223        DisjunctionMatcher::new(self, right)
224    }
225}
226
227/// Any actual value whose debug length is greater than this value will be
228/// pretty-printed. Otherwise, it will have normal debug output formatting.
229const PRETTY_PRINT_LENGTH_THRESHOLD: usize = 60;
230
231/// Constructs a [`TestAssertionFailure`] reporting that the given `matcher`
232/// does not match the value `actual`.
233///
234/// The parameter `actual_expr` contains the expression which was evaluated to
235/// obtain `actual`.
236#[track_caller]
237pub(crate) fn create_assertion_failure<T: Debug + Copy>(
238    matcher: &impl Matcher<T>,
239    actual: T,
240    actual_expr: &'static str,
241) -> TestAssertionFailure {
242    let actual_formatted = format!("{actual:?}");
243    let actual_formatted = if actual_formatted.len() > PRETTY_PRINT_LENGTH_THRESHOLD {
244        format!("{actual:#?}")
245    } else {
246        actual_formatted
247    };
248    TestAssertionFailure::create(format!(
249        "\
250Value of: {actual_expr}
251Expected: {}
252Actual: {actual_formatted},
253{}",
254        matcher.describe(MatcherResult::Match),
255        matcher.explain_match(actual).indent(),
256    ))
257}
258
259/// The result of applying a [`Matcher`] on an actual value.
260#[derive(Debug, PartialEq, Clone, Copy)]
261pub enum MatcherResult {
262    /// The actual value matches according to the [`Matcher`] definition.
263    Match,
264    /// The actual value does not match according to the [`Matcher`] definition.
265    NoMatch,
266}
267
268impl From<bool> for MatcherResult {
269    fn from(b: bool) -> Self {
270        if b {
271            MatcherResult::Match
272        } else {
273            MatcherResult::NoMatch
274        }
275    }
276}
277
278impl From<MatcherResult> for bool {
279    fn from(matcher_result: MatcherResult) -> Self {
280        matcher_result.is_match()
281    }
282}
283
284impl MatcherResult {
285    /// Returns `true` if `self` is [`MatcherResult::Match`], otherwise
286    /// `false`.
287    pub fn is_match(self) -> bool {
288        matches!(self, MatcherResult::Match)
289    }
290
291    /// Returns `true` if `self` is [`MatcherResult::NoMatch`], otherwise
292    /// `false`.
293    pub fn is_no_match(self) -> bool {
294        matches!(self, MatcherResult::NoMatch)
295    }
296}
297
298impl<M: ?Sized + MatcherBase> MatcherBase for &M {}
299
300impl<T: Debug + Copy, M: Matcher<T>> Matcher<T> for &M {
301    fn matches(&self, actual: T) -> MatcherResult {
302        (*self).matches(actual)
303    }
304
305    fn describe(&self, matcher_result: MatcherResult) -> Description {
306        (*self).describe(matcher_result)
307    }
308
309    fn explain_match(&self, actual: T) -> Description {
310        (*self).explain_match(actual)
311    }
312}
313
314#[cfg(test)]
315mod tests {
316    use crate::prelude::*;
317    use crate::Result;
318
319    #[test]
320    fn ref_matchers_can_be_reused() -> Result<()> {
321        let matcher = eq(1);
322
323        verify_that!(1, &matcher)?;
324        verify_that!(1, &matcher)
325    }
326
327    #[test]
328    fn ref_matchers_as_inner_matcher() -> Result<()> {
329        let matcher = gt(1);
330
331        verify_that!([2, 3, 4, 5], [&matcher, &matcher, &matcher, &matcher])
332    }
333}