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}