Skip to main content

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