Skip to main content

googletest/matchers/
err_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
15use crate::{
16    description::Description,
17    matcher::{Matcher, MatcherBase, MatcherResult},
18};
19use std::fmt::Debug;
20
21/// Matches a `Result` containing `Err` with a value matched by `inner`.
22///
23/// ```
24/// # use googletest::prelude::*;
25/// # fn should_pass() -> googletest::Result<()> {
26/// verify_that!(Err::<(), _>("Some error"), err(eq("Some error")))?;  // Passes
27/// #     Ok(())
28/// # }
29/// # fn should_fail_1() -> googletest::Result<()> {
30/// verify_that!(Ok::<_, &str>("A value"), err(eq("A value")))?;   // Fails
31/// #     Ok(())
32/// # }
33/// # fn should_fail_2() -> googletest::Result<()> {
34/// verify_that!(Err::<(), _>("Some error"), err(eq("Some other error")))?;   // Fails
35/// #     Ok(())
36/// # }
37/// # should_pass().unwrap();
38/// # should_fail_1().unwrap_err();
39/// # should_fail_2().unwrap_err();
40/// ```
41pub fn err<Inner>(inner: Inner) -> ErrMatcher<Inner> {
42    ErrMatcher { inner }
43}
44
45#[derive(MatcherBase)]
46pub struct ErrMatcher<InnerMatcherT> {
47    inner: InnerMatcherT,
48}
49
50impl<T: Debug + Copy, E: Debug + Copy, InnerMatcherT: Matcher<E>> Matcher<std::result::Result<T, E>>
51    for ErrMatcher<InnerMatcherT>
52{
53    fn matches(&self, actual: std::result::Result<T, E>) -> MatcherResult {
54        actual.err().map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
55    }
56
57    fn explain_match(&self, actual: std::result::Result<T, E>) -> Description {
58        match actual {
59            Err(e) => {
60                Description::new().text("which is an error").nested(self.inner.explain_match(e))
61            }
62            Ok(_) => "which is a success".into(),
63        }
64    }
65
66    fn describe(&self, matcher_result: MatcherResult) -> Description {
67        match matcher_result {
68            MatcherResult::Match => {
69                format!("is an error which {}", self.inner.describe(MatcherResult::Match)).into()
70            }
71            MatcherResult::NoMatch => format!(
72                "is a success or is an error containing a value which {}",
73                self.inner.describe(MatcherResult::NoMatch)
74            )
75            .into(),
76        }
77    }
78}
79
80impl<'a, T: Debug, E: Debug, InnerMatcherT: Matcher<&'a E>> Matcher<&'a std::result::Result<T, E>>
81    for ErrMatcher<InnerMatcherT>
82{
83    fn matches(&self, actual: &'a std::result::Result<T, E>) -> MatcherResult {
84        actual.as_ref().err().map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
85    }
86
87    fn explain_match(&self, actual: &'a std::result::Result<T, E>) -> Description {
88        match actual {
89            Err(e) => {
90                Description::new().text("which is an error").nested(self.inner.explain_match(e))
91            }
92            Ok(_) => "which is a success".into(),
93        }
94    }
95
96    fn describe(&self, matcher_result: MatcherResult) -> Description {
97        match matcher_result {
98            MatcherResult::Match => {
99                format!("is an error which {}", self.inner.describe(MatcherResult::Match)).into()
100            }
101            MatcherResult::NoMatch => format!(
102                "is a success or is an error containing a value which {}",
103                self.inner.describe(MatcherResult::NoMatch)
104            )
105            .into(),
106        }
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use crate::matcher::MatcherResult;
113    use crate::prelude::*;
114    use crate::Result;
115    use indoc::indoc;
116
117    #[test]
118    fn err_matches_result_with_err_value() -> Result<()> {
119        let matcher = err(eq(1));
120        let value: std::result::Result<i32, i32> = Err(1);
121
122        let result = matcher.matches(value);
123
124        verify_that!(result, eq(MatcherResult::Match))
125    }
126
127    #[test]
128    fn err_does_not_match_result_with_wrong_err_value() -> Result<()> {
129        let matcher = err(eq(1));
130        let value: std::result::Result<i32, i32> = Err(0);
131
132        let result = matcher.matches(value);
133
134        verify_that!(result, eq(MatcherResult::NoMatch))
135    }
136
137    #[test]
138    fn err_does_not_match_result_with_ok() -> Result<()> {
139        let matcher = err(eq(1));
140        let value: std::result::Result<i32, i32> = Ok(1);
141
142        let result = matcher.matches(value);
143
144        verify_that!(result, eq(MatcherResult::NoMatch))
145    }
146
147    #[test]
148    fn err_matches_result_with_err_value_by_ref() -> Result<()> {
149        let value: std::result::Result<String, String> = Err("123".to_string());
150        verify_that!(value, err(eq("123")))
151    }
152
153    #[test]
154    fn err_does_not_match_result_with_wrong_err_value_by_ref() -> Result<()> {
155        let value: std::result::Result<String, String> = Err("321".to_string());
156        verify_that!(value, not(err(eq("123"))))
157    }
158
159    #[test]
160    fn err_does_not_match_result_with_ok_by_ref() -> Result<()> {
161        let value: std::result::Result<String, String> = Ok("123".to_string());
162        verify_that!(value, not(err(eq("123"))))
163    }
164
165    #[test]
166    fn err_full_error_message() -> Result<()> {
167        let result = verify_that!(Err::<i32, i32>(1), err(eq(2)));
168
169        verify_that!(
170            result,
171            err(displays_as(contains_substring(indoc!(
172                "
173                    Value of: Err::<i32, i32>(1)
174                    Expected: is an error which is equal to 2
175                    Actual: Err(1),
176                      which is an error
177                        which isn't equal to 2
178                "
179            ))))
180        )
181    }
182
183    #[test]
184    fn err_describe_match() -> Result<()> {
185        let matcher = err(eq(1));
186        verify_that!(
187            Matcher::<std::result::Result<i32, i32>>::describe(&matcher, MatcherResult::Match),
188            displays_as(eq("is an error which is equal to 1"))
189        )
190    }
191
192    #[test]
193    fn err_describe_no_match() -> Result<()> {
194        let matcher = err(eq(1));
195        verify_that!(
196            Matcher::<std::result::Result<i32, i32>>::describe(&matcher, MatcherResult::NoMatch),
197            displays_as(eq(
198                "is a success or is an error containing a value which isn't equal to 1"
199            ))
200        )
201    }
202
203    #[test]
204    fn err_describe_match_by_ref() -> Result<()> {
205        let matcher = err(eq("123"));
206        verify_that!(
207            Matcher::<&std::result::Result<String, String>>::describe(
208                &matcher,
209                MatcherResult::Match
210            ),
211            displays_as(eq("is an error which is equal to \"123\""))
212        )
213    }
214
215    #[test]
216    fn err_describe_no_match_by_ref() -> Result<()> {
217        let matcher = err(eq("123"));
218        verify_that!(
219            Matcher::<&std::result::Result<String, String>>::describe(
220                &matcher,
221                MatcherResult::NoMatch
222            ),
223            displays_as(eq(
224                "is a success or is an error containing a value which isn't equal to \"123\""
225            ))
226        )
227    }
228
229    #[test]
230    fn err_explain_match_success() -> Result<()> {
231        let actual: std::result::Result<i32, i32> = Err(1);
232        let matcher = err(eq(1));
233        verify_that!(
234            matcher.explain_match(actual),
235            displays_as(eq("which is an error\n  which is equal to 1"))
236        )
237    }
238
239    #[test]
240    fn err_explain_match_fail() -> Result<()> {
241        let actual: std::result::Result<i32, i32> = Err(2);
242        let matcher = err(eq(1));
243        verify_that!(
244            matcher.explain_match(actual),
245            displays_as(eq("which is an error\n  which isn't equal to 1"))
246        )
247    }
248
249    #[test]
250    fn err_explain_match_ok() -> Result<()> {
251        let actual: std::result::Result<i32, i32> = Ok(1);
252        let matcher = err(eq(1));
253        verify_that!(matcher.explain_match(actual), displays_as(eq("which is a success")))
254    }
255
256    #[test]
257    fn err_explain_match_success_by_ref() -> Result<()> {
258        let actual: std::result::Result<String, String> = Err("123".to_string());
259        let matcher = err(eq("123"));
260        verify_that!(
261            matcher.explain_match(&actual),
262            displays_as(eq("which is an error\n  which is equal to \"123\""))
263        )
264    }
265
266    #[test]
267    fn err_explain_match_fail_by_ref() -> Result<()> {
268        let actual: std::result::Result<String, String> = Err("321".to_string());
269        let matcher = err(eq("123"));
270        verify_that!(
271            matcher.explain_match(&actual),
272            displays_as(eq("which is an error\n  which isn't equal to \"123\""))
273        )
274    }
275
276    #[test]
277    fn err_explain_match_ok_by_ref() -> Result<()> {
278        let actual: std::result::Result<String, String> = Ok("123".to_string());
279        let matcher = err(eq("123"));
280        verify_that!(matcher.explain_match(&actual), displays_as(eq("which is a success")))
281    }
282}