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<i32, Debuggable> = Ok(41);
399            let x = x.debug_assert_ok().map(|x| x + 1);
400
401            assert!(matches!(x, Ok(42)), "Expected Ok(42)");
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() {
410            let x: Result<i32, Debuggable> = Err(Debuggable);
411            let x = x.debug_assert_ok().map(|x| x + 1);
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        #[test]
445        #[cfg_attr(
446            all(debug_assertions, not(feature = "passthrough")),
447            should_panic = "Expected Ok(_), got Err(Debuggable)"
448        )]
449        fn it_fails_on_err() {
450            let x: Result<i32, Debuggable> = Err(Debuggable);
451            let x = x.debug_assert_ok_and(|x| x >= &20).map(|x| x);
452            //        ^-- should panic here only in debug builds
453
454            // for debug builds
455            assert!(matches!(x, Err(Debuggable)), "Expected Err(Debuggable)");
456        }
457    }
458
459    mod assert_err {
460        use super::{super::*, *};
461
462        #[test]
463        fn it_succeeds_on_err() {
464            let x: Result<Debuggable, NonDebuggable> = Err(NonDebuggable);
465            let x = x.assert_err();
466            assert!(
467                matches!(x, Err(NonDebuggable)),
468                "Expected Err(NonDebuggable)"
469            );
470        }
471
472        #[test]
473        #[should_panic(expected = "Expected Err(_), got Ok(Debuggable)")]
474        fn it_fails_on_ok() {
475            let x: Result<Debuggable, i32> = Ok(Debuggable);
476            let _ = x.assert_err().map_err(|x| x * 2);
477            //        ^-- should panic here
478        }
479    }
480
481    mod assert_err_and {
482        use super::{super::*, *};
483
484        #[test]
485        fn it_succeeds_on_err_and_condition_satisfied() {
486            let x: Result<Debuggable, i32> = Err(21);
487            let x = x.assert_err_and(|x| x == &21).map_err(|x| x * 2);
488            assert_eq!(x, Err(42), "Expected Err(42)");
489        }
490
491        #[test]
492        #[should_panic(expected = "Condition not satisfied for Err(41)")]
493        fn it_fails_on_err_but_condition_not_satisfied() {
494            let x: Result<Debuggable, i32> = Err(41);
495            let _ = x.assert_err_and(|x| x == &21).map_err(|x| x + 1);
496            //        ^-- should panic here
497        }
498
499        #[test]
500        #[should_panic(expected = "Expected Err(_), got Ok(Debuggable)")]
501        fn it_fails_on_ok() {
502            let x: Result<Debuggable, i32> = Ok(Debuggable);
503            let _ = x.assert_err_and(|x| x == &21).map_err(|x| x * 2);
504            //        ^-- should panic here
505        }
506    }
507
508    mod debug_assert_err {
509        use super::{super::*, *};
510
511        #[test]
512        fn it_succeeds_on_err() {
513            let x: Result<Debuggable, i32> = Err(41);
514            let x = x.debug_assert_err().map_err(|x| x + 1);
515            assert!(matches!(x, Err(42)), "Expected Err(42)");
516        }
517
518        #[test]
519        #[cfg_attr(
520            all(debug_assertions, not(feature = "passthrough")),
521            should_panic = "Expected Err(_), got Ok(Debuggable)"
522        )]
523
524        fn it_fails_on_ok_only_in_debug_mode() {
525            let x: Result<Debuggable, i32> = Ok(Debuggable);
526            let x = x.debug_assert_err().map_err(|x| x + 1);
527            //        ^-- panic here only in debug builds
528
529            // for debug builds
530            assert!(matches!(x, Ok(Debuggable)), "Expected Ok(Debuggable)");
531        }
532    }
533
534    mod debug_assert_err_and {
535        use super::{super::*, *};
536
537        #[test]
538        fn it_succeeds_on_satisfied_err() {
539            let x: Result<Debuggable, i32> = Err(21);
540            let x = x.debug_assert_err_and(|x| x == &21).map_err(|x| x * 2);
541
542            assert_eq!(x, Err(42), "Expected Err(42)");
543        }
544
545        #[test]
546        #[cfg_attr(
547            all(debug_assertions, not(feature = "passthrough")),
548            should_panic = "Condition not satisfied for Err(21)"
549        )]
550        fn it_fails_on_invalid_err() {
551            let x: Result<Debuggable, i32> = Err(21);
552            let x = x.debug_assert_err_and(|x| x < &21).map_err(|x| x * 2);
553            //        ^-- should panic here only in debug builds
554
555            assert_eq!(x, Err(42), "Expected Err(42)");
556        }
557
558        #[test]
559        #[cfg_attr(
560            all(debug_assertions, not(feature = "passthrough")),
561            should_panic = "Expected Err(_), got Ok(Debuggable)"
562        )]
563        fn it_fails_on_ok() {
564            let x: Result<Debuggable, i32> = Ok(Debuggable);
565            let x = x.debug_assert_err_and(|x| x >= &20).map_err(|x| x + 1);
566            //        ^-- should panic here only in debug builds
567
568            // for debug builds
569            assert!(matches!(x, Ok(Debuggable)), "Expected Ok(Debuggable)");
570        }
571    }
572}