assertr/assertions/core/
option.rs1use crate::{AssertThat, Mode, actual::Actual, mode::Panic, tracking::AssertionTracking};
2use alloc::string::String;
3use core::fmt::{Debug, Write};
4use core::option::Option;
5use indoc::writedoc;
6
7#[cfg_attr(feature = "fluent", assertr_derive::fluent_aliases)]
9pub trait OptionExtractAssertions<'t, T> {
10 fn is_some(self) -> AssertThat<'t, T, Panic>
18 where
19 T: Debug;
20}
21
22impl<'t, T> OptionExtractAssertions<'t, T> for AssertThat<'t, Option<T>, Panic> {
23 #[track_caller]
24 fn is_some(self) -> AssertThat<'t, T, Panic>
25 where
26 T: Debug,
27 {
28 self.track_assertion();
29
30 if !self.actual().is_some() {
31 let actual = self.actual();
32 self.fail(|w: &mut String| {
33 writedoc! {w, r"
34 Actual: {actual:#?}
35
36 is not of expected variant: Option::Some
37 "}
38 });
39 }
40
41 self.map(|actual| match actual {
42 Actual::Owned(o) => Actual::Owned(o.unwrap()),
43 Actual::Borrowed(b) => Actual::Borrowed(b.as_ref().unwrap()),
44 })
45 }
46}
47
48#[allow(clippy::return_self_not_must_use)]
51#[cfg_attr(feature = "fluent", assertr_derive::fluent_aliases)]
52pub trait OptionAssertions<'t, T, M: Mode> {
53 fn is_some_satisfying<A>(self, assertions: A) -> Self
55 where
56 T: Debug,
57 A: for<'a> FnOnce(AssertThat<'a, &'a T, M>);
58
59 fn is_none(self) -> AssertThat<'t, (), M>
63 where
64 T: Debug;
65}
66
67impl<'t, T, M: Mode> OptionAssertions<'t, T, M> for AssertThat<'t, Option<T>, M> {
68 #[track_caller]
69 fn is_some_satisfying<A>(self, assertions: A) -> Self
70 where
71 T: Debug,
72 A: for<'a> FnOnce(AssertThat<'a, &'a T, M>),
73 {
74 self.track_assertion();
75
76 if self.actual().is_some() {
77 self.satisfies_ref(|it| it.as_ref().unwrap(), assertions)
78 } else {
79 let actual = self.actual();
80 self.fail(|w: &mut String| {
81 writedoc! {w, r"
82 Actual: {actual:#?}
83
84 is not of expected variant: Option::Some
85 "}
86 });
87 self
88 }
89 }
90
91 #[track_caller]
92 fn is_none(self) -> AssertThat<'t, (), M>
93 where
94 T: Debug,
95 {
96 self.track_assertion();
97
98 if !self.actual().is_none() {
99 let actual = self.actual();
100 self.fail(|w: &mut String| {
101 writedoc! {w, r"
102 Actual: {actual:#?}
103
104 is not of expected variant: Option::None
105 "}
106 });
107 }
108
109 self.map(|_actual| Actual::Owned(()))
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 mod is_some {
116 use crate::prelude::*;
117 use indoc::formatdoc;
118
119 #[test]
120 fn succeeds_when_some() {
121 assert_that!(Option::<i32>::Some(42))
122 .is_some()
123 .is_equal_to(42);
124 }
125
126 #[test]
127 fn panics_when_none() {
128 assert_that_panic_by(|| {
129 assert_that!(Option::<i32>::None)
130 .with_location(false)
131 .is_some()
132 })
133 .has_type::<String>()
134 .is_equal_to(formatdoc! {"
135 -------- assertr --------
136 Actual: None
137
138 is not of expected variant: Option::Some
139 -------- assertr --------
140 "});
141 }
142 }
143
144 mod is_some_satisfying {
145 use crate::prelude::*;
146 use indoc::formatdoc;
147
148 #[test]
149 fn succeeds_when_some_and_assertions_pass() {
150 assert_that!(Option::<i32>::Some(42)).is_some_satisfying(|some| {
151 some.is_equal_to(&42);
152 });
153 }
154
155 #[test]
156 fn captures_inner_failure_when_some_and_assertion_fails() {
157 let failures = assert_that!(Option::<i32>::Some(42))
158 .with_capture()
159 .with_location(false)
160 .is_some_satisfying(|some| {
161 some.is_greater_than(&9000);
162 })
163 .capture_failures();
164
165 assert_that!(failures).contains_exactly::<String>([formatdoc! {"
166 -------- assertr --------
167 Actual: 42
168
169 is not greater than
170
171 Expected: 9000
172 -------- assertr --------
173 "}]);
174 }
175
176 #[test]
177 fn captures_variant_failure_when_none() {
178 let failures = assert_that!(Option::<i32>::None)
179 .with_capture()
180 .with_location(false)
181 .is_some_satisfying(|_| panic!("assertions should not run"))
182 .capture_failures();
183
184 assert_that!(failures).contains_exactly::<String>([formatdoc! {"
185 -------- assertr --------
186 Actual: None
187
188 is not of expected variant: Option::Some
189 -------- assertr --------
190 "}]);
191 }
192
193 #[test]
194 fn panics_when_none() {
195 assert_that_panic_by(|| {
196 assert_that!(Option::<i32>::None)
197 .with_location(false)
198 .is_some_satisfying(|_| panic!("assertions should not run"))
199 })
200 .has_type::<String>()
201 .is_equal_to(formatdoc! {"
202 -------- assertr --------
203 Actual: None
204
205 is not of expected variant: Option::Some
206 -------- assertr --------
207 "});
208 }
209 }
210
211 mod is_none {
212 use crate::prelude::*;
213 use alloc::string::String;
214 use indoc::formatdoc;
215
216 #[test]
217 fn succeeds_when_none() {
218 assert_that!(Option::<i32>::None).is_none();
219 }
220
221 #[test]
222 fn panics_when_some() {
223 assert_that_panic_by(|| {
224 assert_that!(Option::<i32>::Some(42))
225 .with_location(false)
226 .is_none()
227 })
228 .has_type::<String>()
229 .is_equal_to(formatdoc! {"
230 -------- assertr --------
231 Actual: Some(
232 42,
233 )
234
235 is not of expected variant: Option::None
236 -------- assertr --------
237 "});
238 }
239 }
240}