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}