assertr/assertions/core/
fn.rs1use crate::actual::Actual;
2use crate::mode::Mode;
3use crate::prelude::ResultAssertions;
4use crate::tracking::AssertionTracking;
5use crate::{AssertThat, PanicValue};
6use core::fmt::{Debug, Write};
7use indoc::writedoc;
8
9pub trait FnOnceAssertions<'t, R, M: Mode> {
10 #[cfg(feature = "std")]
11 fn panics(self) -> AssertThat<'t, PanicValue, M>;
12
13 #[cfg(feature = "std")]
14 fn does_not_panic(self) -> AssertThat<'t, R, M>
15 where
16 R: Debug;
17}
18
19impl<'t, R, F: FnOnce() -> R, M: Mode> FnOnceAssertions<'t, R, M> for AssertThat<'t, F, M> {
20 #[track_caller]
21 fn panics(self) -> AssertThat<'t, PanicValue, M> {
22 self.track_assertion();
23
24 let this = self.map(|it| match it {
25 Actual::Borrowed(_) => panic!("panics() can only be called on an owned FnOnce!"),
26 Actual::Owned(f) => Actual::Owned(std::panic::catch_unwind(
27 core::panic::AssertUnwindSafe(move || {
28 f();
29 }),
30 )),
31 });
32
33 if this.actual().is_ok() {
34 this.fail(|w: &mut String| {
35 writedoc! {w, r#"
36 Expected: Function to panic when called.
37
38 Actual: No panic occurred!
39 "#}
40 });
41 }
42
43 this.is_err()
44 .with_detail_message("Function did not panic as expected!")
45 .map(|it| {
46 let boxed_any = it.unwrap_owned();
47 PanicValue(boxed_any).into()
48 })
49 }
50
51 #[track_caller]
52 fn does_not_panic(self) -> AssertThat<'t, R, M>
53 where
54 R: Debug,
55 {
56 self.track_assertion();
57
58 let this = self.map(|it| match it {
59 Actual::Borrowed(_) => panic!("panics() can only be called on an owned FnOnce!"),
60 Actual::Owned(f) => {
61 Actual::Owned(std::panic::catch_unwind(core::panic::AssertUnwindSafe(f)))
62 }
63 });
64
65 if this.actual().is_err() {
66 this.fail(|w: &mut String| {
67 writedoc! {w, r#"
68 Expected: Function to not panic when called.
69
70 Actual: Function panicked unexpectedly!
71 "#}
72 });
73 }
74
75 this.is_ok()
76 .with_detail_message("Function panicked unexpectedly!")
77 .map(|it| it.unwrap_owned().into())
78 }
79}
80
81#[cfg(test)]
82mod tests {
83
84 mod panics {
85 use crate::prelude::*;
86 use indoc::formatdoc;
87
88 #[test]
89 fn succeeds_when_panic_occurs() {
90 assert_that(|| unimplemented!())
91 .panics()
92 .has_type::<&str>()
93 .is_equal_to("not implemented");
94 }
95
96 #[test]
97 fn panics_when_no_panic_occurs() {
98 assert_that_panic_by(|| assert_that(|| 42).with_location(false).panics())
99 .has_type::<String>()
100 .is_equal_to(formatdoc! {r#"
101 -------- assertr --------
102 Expected: Function to panic when called.
103
104 Actual: No panic occurred!
105 -------- assertr --------
106 "#});
107 }
108 }
109
110 mod does_not_panic {
111 use crate::prelude::*;
112 use indoc::formatdoc;
113
114 #[test]
115 fn succeeds_when_no_panic_occurs() {
116 assert_that(|| 42).does_not_panic();
117 }
118
119 #[test]
120 fn fails_when_panic_occurs() {
121 assert_that_panic_by(|| {
122 assert_that(|| unimplemented!())
123 .with_location(false)
124 .does_not_panic()
125 })
126 .has_type::<String>()
127 .is_equal_to(formatdoc! {r#"
128 -------- assertr --------
129 Expected: Function to not panic when called.
130
131 Actual: Function panicked unexpectedly!
132 -------- assertr --------
133 "#});
134 }
135 }
136}