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}