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 use crate::description::Description;
16 use crate::matcher::{Matcher, MatcherResult};
17 use std::fmt::Debug;
18 use std::marker::PhantomData;
19 use std::ops::Deref;
20
21 /// Matches a (smart) pointer pointing to a value matched by the [`Matcher`]
22 /// `expected`.
23 ///
24 /// This allows easily matching smart pointers such as `Box`, `Rc`, and `Arc`.
25 /// For example:
26 ///
27 /// ```
28 /// # use googletest::prelude::*;
29 /// # fn should_pass() -> Result<()> {
30 /// verify_that!(Box::new(123), points_to(eq(123)))?;
31 /// # Ok(())
32 /// # }
33 /// # should_pass().unwrap();
34 /// ```
points_to<ExpectedT, MatcherT, ActualT>( expected: MatcherT, ) -> impl Matcher<ActualT = ActualT> where ExpectedT: Debug, MatcherT: Matcher<ActualT = ExpectedT>, ActualT: Deref<Target = ExpectedT> + Debug + ?Sized,35 pub fn points_to<ExpectedT, MatcherT, ActualT>(
36 expected: MatcherT,
37 ) -> impl Matcher<ActualT = ActualT>
38 where
39 ExpectedT: Debug,
40 MatcherT: Matcher<ActualT = ExpectedT>,
41 ActualT: Deref<Target = ExpectedT> + Debug + ?Sized,
42 {
43 PointsToMatcher { expected, phantom: Default::default() }
44 }
45
46 struct PointsToMatcher<ActualT: ?Sized, MatcherT> {
47 expected: MatcherT,
48 phantom: PhantomData<ActualT>,
49 }
50
51 impl<ExpectedT, MatcherT, ActualT> Matcher for PointsToMatcher<ActualT, MatcherT>
52 where
53 ExpectedT: Debug,
54 MatcherT: Matcher<ActualT = ExpectedT>,
55 ActualT: Deref<Target = ExpectedT> + Debug + ?Sized,
56 {
57 type ActualT = ActualT;
58
matches(&self, actual: &ActualT) -> MatcherResult59 fn matches(&self, actual: &ActualT) -> MatcherResult {
60 self.expected.matches(actual.deref())
61 }
62
explain_match(&self, actual: &ActualT) -> Description63 fn explain_match(&self, actual: &ActualT) -> Description {
64 self.expected.explain_match(actual.deref())
65 }
66
describe(&self, matcher_result: MatcherResult) -> Description67 fn describe(&self, matcher_result: MatcherResult) -> Description {
68 self.expected.describe(matcher_result)
69 }
70 }
71
72 #[cfg(test)]
73 mod tests {
74 use super::points_to;
75 use crate::prelude::*;
76 use indoc::indoc;
77 use std::rc::Rc;
78
79 #[test]
points_to_matches_box_of_int_with_int() -> Result<()>80 fn points_to_matches_box_of_int_with_int() -> Result<()> {
81 verify_that!(Box::new(123), points_to(eq(123)))
82 }
83
84 #[test]
points_to_matches_rc_of_int_with_int() -> Result<()>85 fn points_to_matches_rc_of_int_with_int() -> Result<()> {
86 verify_that!(Rc::new(123), points_to(eq(123)))
87 }
88
89 #[test]
points_to_matches_box_of_owned_string_with_string_reference() -> Result<()>90 fn points_to_matches_box_of_owned_string_with_string_reference() -> Result<()> {
91 verify_that!(Rc::new("A string".to_string()), points_to(eq("A string")))
92 }
93
94 #[test]
match_explanation_references_actual_value() -> Result<()>95 fn match_explanation_references_actual_value() -> Result<()> {
96 let result = verify_that!(&vec![1], points_to(container_eq([])));
97
98 verify_that!(
99 result,
100 err(displays_as(contains_substring(indoc!(
101 "
102 Actual: [1],
103 which contains the unexpected element 1
104 "
105 ))))
106 )
107 }
108 }
109