assertables/assert_some/assert_some.rs
1//!Assert expression is Some.
2//!
3//! Pseudocode:<br>
4//! a is Some
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! let a: Option<i8> = Option::Some(1);
12//! assert_some!(a);
13//! ```
14//!
15//! # Module macros
16//!
17//! * [`assert_some`](macro@crate::assert_some)
18//! * [`assert_some_as_result`](macro@crate::assert_some_as_result)
19//! * [`debug_assert_some`](macro@crate::debug_assert_some)
20
21/// Assert an expression.is_some() is true.
22///
23/// Pseudocode:<br>
24/// a is Some(a1)
25///
26/// * If true, return Result `Ok(a1)`.
27///
28/// * Otherwise, return Result `Err(message)`.
29///
30/// This macro is useful for runtime checks, such as checking parameters,
31/// or sanitizing inputs, or handling different results in different ways.
32///
33/// # Module macros
34///
35/// * [`assert_some`](macro@crate::assert_some)
36/// * [`assert_some_as_result`](macro@crate::assert_some_as_result)
37/// * [`debug_assert_some`](macro@crate::debug_assert_some)
38///
39#[macro_export]
40macro_rules! assert_some_as_result {
41 ($a:expr $(,)?) => {
42 match ($a) {
43 Some(a1) => Ok(a1),
44 _ => Err(format!(
45 concat!(
46 "assertion failed: `assert_some!(a)`\n",
47 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_some.html\n",
48 " option label: `{}`,\n",
49 " option debug: `{:?}`",
50 ),
51 stringify!($a),
52 $a
53 )),
54 }
55 };
56}
57
58#[cfg(test)]
59mod test_assert_some_as_result {
60 use std::sync::Once;
61
62 #[test]
63 fn success() {
64 let a: Option<i8> = Option::Some(1);
65 for _ in 0..1 {
66 let actual = assert_some_as_result!(a);
67 assert_eq!(actual.unwrap(), 1);
68 }
69 }
70
71 #[test]
72 fn success_once() {
73 static A: Once = Once::new();
74 fn a() -> Option<i8> {
75 if A.is_completed() {
76 panic!("A.is_completed()")
77 } else {
78 A.call_once(|| {})
79 }
80 Option::Some(1)
81 }
82
83 assert_eq!(A.is_completed(), false);
84 let result = assert_some_as_result!(a());
85 assert!(result.is_ok());
86 assert_eq!(A.is_completed(), true);
87 }
88
89 #[test]
90 fn failure() {
91 let a: Option<i8> = Option::None;
92 let actual = assert_some_as_result!(a);
93 let message = concat!(
94 "assertion failed: `assert_some!(a)`\n",
95 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_some.html\n",
96 " option label: `a`,\n",
97 " option debug: `None`",
98 );
99 assert_eq!(actual.unwrap_err(), message);
100 }
101}
102
103/// Assert expression is Some.
104///
105/// Pseudocode:<br>
106/// a is Some(a1)
107///
108/// * If true, return `a1`.
109///
110/// * Otherwise, call [`panic!`] with a message and the values of the
111/// expressions with their debug representations.
112///
113/// # Examples
114///
115/// ```rust
116/// use assertables::*;
117/// # use std::panic;
118///
119/// # fn main() {
120/// let a: Option<i8> = Option::Some(1);
121/// assert_some!(a);
122///
123/// # let result = panic::catch_unwind(|| {
124/// // This will panic
125/// let a: Option<i8> = Option::None;
126/// assert_some!(a);
127/// # });
128/// // assertion failed: `assert_some!(a)`
129/// // https://docs.rs/assertables/…/assertables/macro.assert_some.html
130/// // option label: `a`,
131/// // option debug: `None`
132/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
133/// # let message = concat!(
134/// # "assertion failed: `assert_some!(a)`\n",
135/// # "https://docs.rs/assertables/9.8.3/assertables/macro.assert_some.html\n",
136/// # " option label: `a`,\n",
137/// # " option debug: `None`",
138/// # );
139/// # assert_eq!(actual, message);
140/// # }
141/// ```
142///
143/// # Module macros
144///
145/// * [`assert_some`](macro@crate::assert_some)
146/// * [`assert_some_as_result`](macro@crate::assert_some_as_result)
147/// * [`debug_assert_some`](macro@crate::debug_assert_some)
148///
149#[macro_export]
150macro_rules! assert_some {
151 ($a:expr $(,)?) => {
152 match $crate::assert_some_as_result!($a) {
153 Ok(x) => x,
154 Err(err) => panic!("{}", err),
155 }
156 };
157 ($a:expr, $($message:tt)+) => {
158 match $crate::assert_some_as_result!($a) {
159 Ok(x) => x,
160 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
161 }
162 };
163}
164
165#[cfg(test)]
166mod test_assert_some {
167 use std::panic;
168
169 #[test]
170 fn success() {
171 let a: Option<i8> = Option::Some(1);
172 for _ in 0..1 {
173 let actual = assert_some!(a);
174 assert_eq!(actual, 1);
175 }
176 }
177
178 #[test]
179 fn failure() {
180 let a: Option<i8> = Option::None;
181 let result = panic::catch_unwind(|| {
182 let _actual = assert_some!(a);
183 });
184 let message = concat!(
185 "assertion failed: `assert_some!(a)`\n",
186 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_some.html\n",
187 " option label: `a`,\n",
188 " option debug: `None`",
189 );
190 assert_eq!(
191 result
192 .unwrap_err()
193 .downcast::<String>()
194 .unwrap()
195 .to_string(),
196 message
197 );
198 }
199}
200
201/// Assert expression is Some.
202///
203/// Pseudocode:<br>
204/// a is Some
205///
206/// This macro provides the same statements as [`assert_some`](macro.assert_some.html),
207/// except this macro's statements are only enabled in non-optimized
208/// builds by default. An optimized build will not execute this macro's
209/// statements unless `-C debug-assertions` is passed to the compiler.
210///
211/// This macro is useful for checks that are too expensive to be present
212/// in a release build but may be helpful during development.
213///
214/// The result of expanding this macro is always type checked.
215///
216/// An unchecked assertion allows a program in an inconsistent state to
217/// keep running, which might have unexpected consequences but does not
218/// introduce unsafety as long as this only happens in safe code. The
219/// performance cost of assertions, however, is not measurable in general.
220/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
221/// after thorough profiling, and more importantly, only in safe code!
222///
223/// This macro is intended to work in a similar way to
224/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
225///
226/// # Module macros
227///
228/// * [`assert_some`](macro@crate::assert_some)
229/// * [`assert_some`](macro@crate::assert_some)
230/// * [`debug_assert_some`](macro@crate::debug_assert_some)
231///
232#[macro_export]
233macro_rules! debug_assert_some {
234 ($($arg:tt)*) => {
235 if $crate::cfg!(debug_assertions) {
236 $crate::assert_some!($($arg)*);
237 }
238 };
239}