chain_assertions/
result.rs

1/// An extension trait to add the assertion_ok methods.
2pub trait AssertOkExt {
3    /// Asserts the [`Result`] is [`Ok`].
4    ///
5    /// # Panics
6    ///
7    /// The method panics if it is [`Err`] and `passthrough` feature is disabled.
8    /// Otherwise, the method return self as is.
9    ///
10    /// # Examples
11    ///
12    /// ```rust
13    /// use chain_assertions::prelude::*;
14    ///
15    /// let x: Result<i32, &str> = Ok(21);
16    /// let x = x.assert_ok().map(|x| x * 2);
17    /// assert_eq!(x, Ok(42));
18    /// ```
19    ///
20    /// ```rust,should_panic
21    /// use chain_assertions::prelude::*;
22    ///
23    /// let x: Result<i32, &str> = Err("oops");
24    /// let _ = x.assert_ok().map(|x| x * 2);
25    /// //        ^-- panics here
26    /// ```
27    fn assert_ok(self) -> Self;
28
29    /// Asserts the [`Result`] is [`Ok`] but check only in debug builds.
30    ///
31    /// # Panics
32    ///
33    /// The method panics if all following conditions are satisfied:
34    ///
35    /// - It is [`Err`]
36    /// - `debug_assertions` is enabled
37    /// - `passthrough` feature is disabled
38    ///
39    /// Otherwise, the method returns self as is.
40    ///
41    /// # Examples
42    ///
43    /// ```rust
44    /// use chain_assertions::prelude::*;
45    ///
46    /// let x: Result<i32, &str> = Ok(21);
47    /// let x = x.debug_assert_ok().map(|x| x * 2);
48    /// assert_eq!(x, Ok(42));
49    /// ```
50    fn debug_assert_ok(self) -> Self;
51}
52
53/// An extension trait to add the assertion_ok_and methods.
54pub trait AssertOkAndExt<T> {
55    /// Asserts the [`Result`] is [`Ok`] and satisfies the condition.
56    ///
57    /// # Panics
58    ///
59    /// The method panics if all following conditions are satisfied:
60    ///
61    /// - It is [`Err`], or [`Ok`] but user-provided condition returns `false`
62    /// - `debug_assertions` is enabled
63    /// - `passthrough` feature is disabled
64    ///
65    /// Otherwise, the method return self as is.
66    ///
67    /// # Examples
68    /// ```rust
69    /// use chain_assertions::prelude::*;
70    ///
71    /// let x: Result<i32, &str> = Ok(21);
72    /// let x = x.assert_ok_and(|x| x == &21).map(|x| x * 2);
73    /// assert_eq!(x, Ok(42), "Expected Ok(42)");
74    /// ```
75    fn assert_ok_and(self, cond: impl FnOnce(&T) -> bool) -> Self;
76
77    /// Asserts the [`Result`] is [`Ok`] and satisfies the condition only in debug builds.
78    ///
79    /// # Panics
80    ///
81    /// The method panics if all following conditions are satisfied:
82    ///
83    /// - It is [`Err`], or [`Ok`] but user-provided condition returns `false`
84    /// - `debug_assertions` is enabled
85    /// - `passthrough` feature is disabled
86    ///
87    /// Otherwise, the method return self as is.
88    ///
89    /// # Examples
90    ///
91    /// ```rust
92    /// use chain_assertions::prelude::*;
93    ///
94    /// let x: Result<i32, &str> = Ok(21);
95    /// let x = x.debug_assert_ok_and(|x| x == &21).map(|x| x * 2);
96    /// assert_eq!(x, Ok(42), "Expected Ok(42)");
97    /// ```
98    fn debug_assert_ok_and(self, cond: impl FnOnce(&T) -> bool) -> Self;
99}
100
101/// An extension trait to add the assertion_err methods.
102pub trait AssertErrExt {
103    /// Asserts the [`Result`] is [`Err`].
104    ///
105    /// # Panics
106    ///
107    /// The method panics if it is [`Ok`] and `passthrough` feature is disabled.
108    /// Otherwise, the method return self as is.
109    ///
110    /// # Examples
111    ///
112    /// ```rust
113    /// use chain_assertions::prelude::*;
114    ///
115    /// let x: Result<&str, i32> = Err(21);
116    /// let x = x.assert_err().map_err(|x| x * 2);
117    /// assert_eq!(x, Err(42));
118    /// ```
119    ///
120    /// ```rust,should_panic
121    /// use chain_assertions::prelude::*;
122    ///
123    /// let x: Result<&str, i32> = Ok("success");
124    /// let x = x.assert_err().map_err(|x| x * 2);
125    /// //        ^-- panics here
126    /// ```
127    fn assert_err(self) -> Self;
128
129    /// Asserts the [`Result`] is [`Err`] but check only in debug builds.
130    ///
131    /// # Panics
132    ///
133    /// The method panics if all following conditions are satisfied:
134    ///
135    /// - It is [`Err`].
136    /// - `debug_assertions` is enabled.
137    /// - `passthrough` feature is disabled.
138    ///
139    /// Otherwise, the method returns self as is.
140    ///
141    /// # Examples
142    ///
143    /// ```rust
144    /// use chain_assertions::prelude::*;
145    ///
146    /// let x: Result<&str, i32> = Err(21);
147    /// let x = x.debug_assert_err().map_err(|x| x * 2);
148    /// assert_eq!(x, Err(42), "Expected Err(42)");
149    /// ```
150    ///
151    /// ```rust,should_panic,ignore
152    /// use chain_assertions::prelude::*;
153    ///
154    /// let x: Result<&str, i32> = Ok("success");
155    /// let _ = x.debug_assert_err();
156    /// //        ^-- panics here only in debug builds
157    ///
158    /// ```
159    fn debug_assert_err(self) -> Self;
160}
161
162pub trait AssertErrAndExt<T, E> {
163    /// Asserts the [`Result`] is [`Err`] and satisfies the condition.
164    ///
165    /// # Panics
166    ///
167    /// The method panics if all following conditions are satisfied:
168    ///
169    /// - It is [`Ok`], or [`Err`] but user-provided condition returns `false`
170    /// - `debug_assertions` is enabled
171    /// - `passthrough` feature is disabled
172    ///
173    /// Otherwise, the method return self as is.
174    ///
175    /// # Examples
176    /// ```rust
177    /// use chain_assertions::prelude::*;
178    ///
179    /// let x: Result<&str, i32> = Err(21);
180    /// let x = x.assert_err_and(|x| x == &21).map_err(|x| x * 2);
181    /// ```
182    ///
183    /// ```rust,should_panic
184    /// use chain_assertions::prelude::*;
185    ///
186    /// let x: Result<&str, i32> = Ok("debuggable");
187    /// let x = x.assert_err_and(|x| x == &42).map_err(|x| x + 1);
188    /// //        ^-- panics here
189    /// ```
190    fn assert_err_and(self, cond: impl FnOnce(&E) -> bool) -> Self;
191
192    /// Asserts the [`Result`] is [`Err`] and satisfies the condition only in debug builds.
193    ///
194    /// # Panics
195    ///
196    /// The method panics if all following conditions are satisfied:
197    ///
198    /// - It is [`Ok`], or [`Err`] but user-provided condition returns `false`
199    /// - `debug_assertions` is enabled
200    /// - `passthrough` feature is disabled
201    ///
202    /// Otherwise, the method return self as is.
203    ///
204    /// # Examples
205    ///
206    /// ```rust
207    /// use chain_assertions::prelude::*;
208    ///
209    /// let x: Result<&str, i32> = Err(21);
210    /// let x = x.debug_assert_err_and(|x| x == &21).map_err(|x| x * 2);
211    /// assert_eq!(x, Err(42), "Expected Err(42)");
212    /// ```
213    ///
214    /// ```rust,should_panic,ignore
215    /// use chain_assertions::prelude::*;
216    ///
217    /// let x: Result<&str, i32> = Ok("debuggable");
218    /// let x = x.debug_assert_err_and(|x| x == &42).map_err(|x| x + 1);
219    /// //        ^-- panics here only in debug builds
220    /// ```
221    fn debug_assert_err_and(self, cond: impl FnOnce(&E) -> bool) -> Self;
222}
223
224impl<T, E> AssertOkExt for Result<T, E>
225where
226    E: crate::fmt::Debug,
227{
228    #[track_caller]
229    #[inline]
230    fn assert_ok(self) -> Self {
231        if let Err(ref x) = self {
232            panic!("Expected Ok(_), got Err({:?})", x);
233        }
234        self
235    }
236
237    #[track_caller]
238    #[inline]
239    fn debug_assert_ok(self) -> Self {
240        #[cfg(all(debug_assertions, not(feature = "passthrough")))]
241        {
242            if let Err(ref x) = self {
243                panic!("Expected Ok(_), got Err({:?})", x);
244            }
245        }
246        self
247    }
248}
249
250impl<T, E> AssertOkAndExt<T> for Result<T, E>
251where
252    T: crate::fmt::Debug,
253    E: crate::fmt::Debug,
254{
255    #[track_caller]
256    #[inline]
257    fn assert_ok_and(self, cond: impl FnOnce(&T) -> bool) -> Self {
258        match self {
259            Ok(ref x) if cond(x) => { /* do nothing */ }
260            Ok(ref x) => panic!("Condition not satisfied for Ok({:?})", x),
261            Err(ref x) => panic!("Expected Ok(_), got Err({:?})", x),
262        }
263        self
264    }
265
266    #[track_caller]
267    #[inline]
268    fn debug_assert_ok_and(self, _cond: impl FnOnce(&T) -> bool) -> Self {
269        #[cfg(all(debug_assertions, not(feature = "passthrough")))]
270        {
271            match self {
272                Ok(ref x) if _cond(x) => { /* do nothing */ }
273                Ok(ref x) => panic!("Condition not satisfied for Ok({:?})", x),
274                Err(ref x) => panic!("Expected Ok(_), got Err({:?})", x),
275            }
276        }
277        self
278    }
279}
280
281impl<T, E> AssertErrExt for Result<T, E>
282where
283    T: crate::fmt::Debug,
284{
285    #[track_caller]
286    #[inline]
287    fn assert_err(self) -> Self {
288        if let Ok(ref x) = self {
289            panic!("Expected Err(_), got Ok({:?})", x);
290        }
291        self
292    }
293
294    #[track_caller]
295    #[inline]
296    fn debug_assert_err(self) -> Self {
297        #[cfg(all(debug_assertions, not(feature = "passthrough")))]
298        {
299            if let Ok(ref x) = self {
300                panic!("Expected Err(_), got Ok({:?})", x);
301            }
302        }
303        self
304    }
305}
306
307impl<T, E> AssertErrAndExt<T, E> for Result<T, E>
308where
309    T: crate::fmt::Debug,
310    E: crate::fmt::Debug,
311{
312    #[track_caller]
313    #[inline]
314    fn assert_err_and(self, cond: impl FnOnce(&E) -> bool) -> Self {
315        match self {
316            Err(ref x) if cond(x) => { /* do nothing */ }
317            Err(ref x) => panic!("Condition not satisfied for Err({:?})", x),
318            Ok(ref x) => panic!("Expected Err(_), got Ok({:?})", x),
319        }
320        self
321    }
322
323    #[track_caller]
324    #[inline]
325    fn debug_assert_err_and(self, _cond: impl FnOnce(&E) -> bool) -> Self {
326        #[cfg(all(debug_assertions, not(feature = "passthrough")))]
327        {
328            match self {
329                Err(ref x) if _cond(x) => { /* do nothing */ }
330                Err(ref x) => panic!("Condition not satisfied for Err({:?})", x),
331                Ok(ref x) => panic!("Expected Err(_), got Ok({:?})", x),
332            }
333        }
334        self
335    }
336}
337
338#[cfg(test)]
339mod tests {
340    #[derive(PartialEq)]
341    struct NonDebuggable;
342
343    #[derive(Debug, PartialEq)]
344    struct Debuggable;
345
346    mod assert_ok {
347        use super::{super::*, *};
348
349        #[test]
350        fn it_succeeds_on_ok() {
351            let x: Result<NonDebuggable, Debuggable> = Ok(NonDebuggable);
352            let x = x.assert_ok();
353
354            assert!(matches!(x, Ok(NonDebuggable)), "Expected Ok(NonDebuggable)");
355        }
356
357        #[test]
358        #[should_panic(expected = "Expected Ok(_), got Err(Debuggable)")]
359        fn it_fails_on_err() {
360            let x: Result<NonDebuggable, Debuggable> = Err(Debuggable);
361            let _ = x.assert_ok();
362            //        ^-- should panic here
363        }
364    }
365
366    mod assert_ok_and {
367        use super::{super::*, *};
368
369        #[test]
370        fn it_succeeds_on_ok_and_condition_satisfied() {
371            let x: Result<i32, Debuggable> = Ok(42);
372            let x = x.assert_ok_and(|x| x == &42);
373            assert_eq!(x, Ok(42), "Expected Ok(42)");
374        }
375
376        #[test]
377        #[should_panic(expected = "Condition not satisfied for Ok(42)")]
378        fn it_fails_on_ok_but_condition_not_satisfied() {
379            let x: Result<i32, Debuggable> = Ok(42);
380            let _ = x.assert_ok_and(|x| x == &21);
381            //        ^-- should panic here
382        }
383
384        #[test]
385        #[should_panic(expected = "Expected Ok(_), got Err(Debuggable)")]
386        fn it_fails_on_err() {
387            let x: Result<i32, Debuggable> = Err(Debuggable);
388            let _ = x.assert_ok_and(|x| x == &21).map(|x| x * 2);
389            //        ^-- should panic here
390        }
391    }
392
393    mod debug_assert_ok {
394        use super::{super::*, *};
395
396        #[test]
397        fn it_succeeds_on_ok() {
398            let x: Result<NonDebuggable, Debuggable> = Ok(NonDebuggable);
399            let x = x.debug_assert_ok();
400
401            assert!(matches!(x, Ok(NonDebuggable)), "Expected Ok(_)");
402        }
403
404        #[test]
405        #[cfg_attr(
406            all(debug_assertions, not(feature = "passthrough")),
407            should_panic = "Expected Ok(_), got Err(Debuggable)"
408        )]
409        fn it_fails_on_err_only_in_debug_mode() {
410            let x: Result<NonDebuggable, Debuggable> = Err(Debuggable);
411            let x = x.debug_assert_ok();
412            //        ^-- panic here only in debug builds
413
414            // for debug builds
415            assert!(matches!(x, Err(Debuggable)), "Expected Err(Debuggable)");
416        }
417    }
418
419    mod debug_assert_ok_and {
420        use super::{super::*, *};
421
422        #[test]
423        fn it_succeeds_on_satisfied_ok() {
424            let x: Result<i32, Debuggable> = Ok(21);
425            let x = x.debug_assert_ok_and(|x| x == &21).map(|x| x * 2);
426
427            assert_eq!(x, Ok(42), "Expected Ok(42)");
428        }
429
430        #[test]
431        #[cfg_attr(
432            all(debug_assertions, not(feature = "passthrough")),
433            should_panic = "Condition not satisfied for Ok(21)"
434        )]
435        fn it_fails_on_invalid_ok() {
436            let x: Result<i32, Debuggable> = Ok(21);
437            let x = x.debug_assert_ok_and(|_| false).map(|x| x * 2);
438            //        ^-- should panic here only in debug builds
439
440            // for debug builds
441            assert_eq!(x, Ok(42), "Expected Ok(42)");
442        }
443    }
444
445    mod assert_err {
446        use super::{super::*, *};
447
448        #[test]
449        fn it_succeeds_on_err() {
450            let x: Result<Debuggable, NonDebuggable> = Err(NonDebuggable);
451            let x = x.assert_err();
452            assert!(
453                matches!(x, Err(NonDebuggable)),
454                "Expected Err(NonDebuggable)"
455            );
456        }
457
458        #[test]
459        #[should_panic(expected = "Expected Err(_), got Ok(Debuggable)")]
460        fn it_fails_on_ok() {
461            let x: Result<Debuggable, NonDebuggable> = Ok(Debuggable);
462            let _ = x.assert_err();
463            //          ^-- should panic here
464        }
465    }
466
467    mod assert_err_and {
468        use super::{super::*, *};
469
470        #[test]
471        fn it_succeeds_on_err_and_condition_satisfied() {
472            let x: Result<Debuggable, i32> = Err(42);
473            let x = x.assert_err_and(|x| x == &42);
474            assert_eq!(x, Err(42), "Expected Err(42)");
475        }
476
477        #[test]
478        #[should_panic(expected = "Condition not satisfied for Err(42)")]
479        fn it_fails_on_err_but_condition_not_satisfied() {
480            let x: Result<Debuggable, i32> = Err(42);
481            let _ = x.assert_err_and(|x| x == &21);
482            //          ^-- should panic here
483        }
484
485        #[test]
486        #[should_panic(expected = "Expected Err(_), got Ok(Debuggable)")]
487        fn it_fails_on_ok() {
488            let x: Result<Debuggable, i32> = Ok(Debuggable);
489            let _ = x.assert_err_and(|x| x == &42).map(|x| x);
490            //          ^-- should panic here
491        }
492    }
493
494    mod debug_assert_err {
495        use super::{super::*, *};
496
497        #[test]
498        fn it_succeeds_on_err() {
499            let x: Result<Debuggable, NonDebuggable> = Err(NonDebuggable);
500            let x = x.debug_assert_err();
501            assert!(
502                matches!(x, Err(NonDebuggable)),
503                "Expected Err(NonDebuggable)"
504            );
505        }
506
507        #[test]
508        #[cfg_attr(
509            all(debug_assertions, not(feature = "passthrough")),
510            should_panic = "Expected Err(_), got Ok(Debuggable)"
511        )]
512
513        fn it_fails_on_ok_only_in_debug_mode() {
514            let x: Result<Debuggable, NonDebuggable> = Ok(Debuggable);
515            let x = x.debug_assert_err();
516            //        ^-- panic here only in debug builds
517            assert!(matches!(x, Ok(Debuggable)), "Expected Ok(Debuggable)");
518        }
519    }
520
521    mod debug_assert_err_and {
522        use super::{super::*, *};
523
524        #[test]
525        fn it_succeeds_on_satisfied_err() {
526            let x: Result<Debuggable, i32> = Err(21);
527            let x = x.debug_assert_err_and(|x| x == &21).map_err(|x| x * 2);
528
529            assert_eq!(x, Err(42), "Expected Err(42)");
530        }
531
532        #[test]
533        #[cfg_attr(
534            all(debug_assertions, not(feature = "passthrough")),
535            should_panic = "Condition not satisfied for Err(21)"
536        )]
537        fn it_fails_on_invalid_err() {
538            let x: Result<Debuggable, i32> = Err(21);
539            let x = x.debug_assert_err_and(|_| false).map_err(|x| x * 2);
540            //        ^-- should panic here only in debug builds
541
542            assert_eq!(x, Err(42), "Expected Err(42)");
543        }
544    }
545}