assertr/assertions/core/
result.rs

1use crate::{AssertThat, actual::Actual, mode::Mode, tracking::AssertionTracking};
2use core::fmt::Debug;
3
4pub trait ResultAssertions<'t, M: Mode, T, E> {
5    fn is_ok(self) -> AssertThat<'t, T, M>
6    where
7        T: Debug,
8        E: Debug;
9
10    fn is_err(self) -> AssertThat<'t, E, M>
11    where
12        T: Debug,
13        E: Debug;
14
15    fn is_ok_satisfying<A>(self, assertions: A) -> Self
16    where
17        T: Debug,
18        E: Debug,
19        A: for<'a> FnOnce(AssertThat<'a, &'a T, M>);
20
21    fn is_err_satisfying<A>(self, assertions: A) -> Self
22    where
23        T: Debug,
24        E: Debug,
25        A: for<'a> FnOnce(AssertThat<'a, &'a E, M>);
26}
27
28// Assertions for generic result values.
29impl<'t, M: Mode, T, E> ResultAssertions<'t, M, T, E> for AssertThat<'t, Result<T, E>, M> {
30    /// This is a terminal operation on the contained `Result`,
31    /// as there is little meaningful to do with the result if its variant was ensured.
32    /// This allows you to chain additional expectations on the contained success value.
33    #[track_caller]
34    fn is_ok(self) -> AssertThat<'t, T, M>
35    where
36        T: Debug,
37        E: Debug,
38    {
39        self.track_assertion();
40
41        if self.actual().is_err() {
42            self.fail(format_args!(
43                "Actual: {actual:#?}\n\nis not of expected variant: Result:Ok\n",
44                actual = self.actual()
45            ));
46        }
47
48        // Calling `unwrap` is safe here, as we would have seen a panic when the error is not present!
49        self.map(|it| match it {
50            Actual::Owned(o) => Actual::Owned(o.unwrap()),
51            Actual::Borrowed(b) => Actual::Borrowed(b.as_ref().unwrap()),
52        })
53    }
54
55    /// This is a terminal operation on the contained `Result`,
56    /// as there is little meaningful to do with the result if its variant was ensured.
57    /// This allows you to chain additional expectations on the contained error value.
58    #[track_caller]
59    fn is_err(self) -> AssertThat<'t, E, M>
60    where
61        T: Debug,
62        E: Debug,
63    {
64        self.track_assertion();
65
66        if self.actual().is_ok() {
67            self.fail(format_args!(
68                "Actual: {actual:#?}\n\nis not of expected variant: Result:Err\n",
69                actual = self.actual()
70            ));
71        }
72
73        // Calling `unwrap_err` is safe here, as we would have seen a panic when the error is not present!
74        self.map(|it| match it {
75            Actual::Owned(o) => Actual::Owned(o.unwrap_err()),
76            Actual::Borrowed(b) => Actual::Borrowed(b.as_ref().unwrap_err()),
77        })
78    }
79
80    #[track_caller]
81    fn is_ok_satisfying<A>(self, assertions: A) -> Self
82    where
83        T: Debug,
84        E: Debug,
85        A: for<'a> FnOnce(AssertThat<'a, &'a T, M>),
86    {
87        self.track_assertion();
88
89        if self.actual().is_ok() {
90            self.satisfies_ref(|it| it.as_ref().unwrap(), assertions)
91        } else {
92            self.fail(format_args!(
93                "Actual: {actual:#?}\n\nis not of expected variant: Result:Ok\n",
94                actual = self.actual()
95            ));
96            self
97        }
98    }
99
100    #[track_caller]
101    fn is_err_satisfying<A>(self, assertions: A) -> Self
102    where
103        T: Debug,
104        E: Debug,
105        A: for<'a> FnOnce(AssertThat<'a, &'a E, M>),
106    {
107        self.track_assertion();
108
109        if self.actual().is_err() {
110            self.satisfies_ref(|it| it.as_ref().unwrap_err(), assertions)
111        } else {
112            self.fail(format_args!(
113                "Actual: {actual:#?}\n\nis not of expected variant: Result:Err\n",
114                actual = self.actual()
115            ));
116            self
117        }
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use indoc::formatdoc;
124
125    use crate::prelude::*;
126
127    #[test]
128    fn is_ok_succeeds_when_ok() {
129        assert_that(Result::<(), ()>::Ok(())).is_ok();
130    }
131
132    #[test]
133    fn is_ok_panics_when_error() {
134        assert_that_panic_by(|| {
135            assert_that(Result::<i32, String>::Err("someError".to_owned()))
136                .with_location(false)
137                .is_ok();
138        })
139        .has_type::<String>()
140        .is_equal_to(formatdoc! {r#"
141                -------- assertr --------
142                Actual: Err(
143                    "someError",
144                )
145
146                is not of expected variant: Result:Ok
147                -------- assertr --------
148            "#});
149    }
150
151    #[test]
152    fn is_err_succeeds_when_error() {
153        assert_that(Result::<(), ()>::Err(())).is_err();
154    }
155
156    #[test]
157    fn is_err_panics_when_ok() {
158        assert_that_panic_by(|| {
159            assert_that(Result::<i32, String>::Ok(42))
160                .with_location(false)
161                .is_err();
162        })
163        .has_type::<String>()
164        .is_equal_to(formatdoc! {r#"
165                -------- assertr --------
166                Actual: Ok(
167                    42,
168                )
169
170                is not of expected variant: Result:Err
171                -------- assertr --------
172            "#});
173    }
174
175    #[test]
176    fn is_ok_satisfying_succeeds_when_ok() {
177        assert_that(Result::<i32, ()>::Ok(42))
178            .with_location(false)
179            .with_capture()
180            .is_ok_satisfying(|ok_value| {
181                ok_value.is_greater_than(&9000);
182            })
183            .capture_failures()
184            .assert_that_it()
185            .contains_exactly::<String>([formatdoc! {"
186                -------- assertr --------
187                Actual: 42
188
189                is not greater than
190
191                Expected: 9000
192                -------- assertr --------
193            "}]);
194    }
195}