assertables/assert_some/assert_some_ne_x.rs
1//! Assert an expression is Some and its value is not equal to an expression.
2//!
3//! Pseudocode:<br>
4//! (a ⇒ Some(a1) ⇒ a1) ≠ b
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! let a: Option<i8> = Option::Some(1);
12//! let b: i8 = 2;
13//! assert_some_ne_x!(a, b);
14//! ```
15//!
16//! # Module macros
17//!
18//! * [`assert_some_ne_x`](macro@crate::assert_some_ne_x)
19//! * [`assert_some_ne_x_as_result`](macro@crate::assert_some_ne_x_as_result)
20//! * [`debug_assert_some_ne_x`](macro@crate::debug_assert_some_ne_x)
21
22/// Assert a.is_some() and a.unwrap() are equal to another.
23///
24/// Pseudocode:<br>
25/// (a ⇒ Some(a1) ⇒ a1) ≠ b
26///
27/// * If true, return Result `Ok(a1)`.
28///
29/// * Otherwise, return Result `Err(message)`.
30///
31/// This macro provides the same statements as [`assert_some_ne_x`](macro.assert_some_ne_x.html),
32/// except this macro returns a Option, rather than doing a panic.
33///
34/// This macro is useful for runtime checks, such as checking parameters,
35/// or sanitizing inputs, or handling different results in different ways.
36///
37/// # Module macros
38///
39/// * [`assert_some_ne_x`](macro@crate::assert_some_ne_x)
40/// * [`assert_some_ne_x_as_result`](macro@crate::assert_some_ne_x_as_result)
41/// * [`debug_assert_some_ne_x`](macro@crate::debug_assert_some_ne_x)
42///
43#[macro_export]
44macro_rules! assert_some_ne_x_as_result {
45 ($a:expr, $b:expr $(,)?) => {
46 match ($a) {
47 Some(a1) => {
48 if a1 != $b {
49 Ok(a1)
50 } else {
51 Err(format!(
52 concat!(
53 "assertion failed: `assert_some_ne_x!(a, b)`\n",
54 "https://docs.rs/assertables/",
55 env!("CARGO_PKG_VERSION"),
56 "/assertables/macro.assert_some_ne_x.html\n",
57 " a label: `{}`,\n",
58 " a debug: `{:?}`,\n",
59 " a inner: `{:?}`,\n",
60 " b label: `{}`,\n",
61 " b debug: `{:?}`"
62 ),
63 stringify!($a),
64 $a,
65 a1,
66 stringify!($b),
67 $b
68 ))
69 }
70 }
71 _ => Err(format!(
72 concat!(
73 "assertion failed: `assert_some_ne_x!(a, b)`\n",
74 "https://docs.rs/assertables/",
75 env!("CARGO_PKG_VERSION"),
76 "/assertables/macro.assert_some_ne_x.html\n",
77 " a label: `{}`,\n",
78 " a debug: `{:?}`,\n",
79 " b label: `{}`,\n",
80 " b debug: `{:?}`",
81 ),
82 stringify!($a),
83 $a,
84 stringify!($b),
85 $b,
86 )),
87 }
88 };
89}
90
91#[cfg(test)]
92mod test_assert_some_ne_x_as_result {
93 use std::sync::Once;
94
95 #[test]
96 fn lt() {
97 let a: Option<i8> = Option::Some(1);
98 let b: i8 = 2;
99 for _ in 0..1 {
100 let actual = assert_some_ne_x_as_result!(a, b);
101 assert_eq!(actual.unwrap(), 1);
102 }
103 }
104
105 #[test]
106 fn lt_once() {
107 static A: Once = Once::new();
108 fn a() -> Option<i8> {
109 if A.is_completed() {
110 panic!("A.is_completed()")
111 } else {
112 A.call_once(|| {})
113 }
114 Option::Some(1)
115 }
116
117 static B: Once = Once::new();
118 fn b() -> i8 {
119 if B.is_completed() {
120 panic!("B.is_completed()")
121 } else {
122 B.call_once(|| {})
123 }
124 2
125 }
126
127 assert_eq!(A.is_completed(), false);
128 assert_eq!(B.is_completed(), false);
129 let result = assert_some_ne_x_as_result!(a(), b());
130 assert!(result.is_ok());
131 assert_eq!(A.is_completed(), true);
132 assert_eq!(B.is_completed(), true);
133 }
134
135 #[test]
136 fn gt() {
137 let a: Option<i8> = Option::Some(2);
138 let b: i8 = 1;
139 for _ in 0..1 {
140 let actual = assert_some_ne_x_as_result!(a, b);
141 assert_eq!(actual.unwrap(), 2);
142 }
143 }
144
145 #[test]
146 fn gt_once() {
147 static A: Once = Once::new();
148 fn a() -> Option<i8> {
149 if A.is_completed() {
150 panic!("A.is_completed()")
151 } else {
152 A.call_once(|| {})
153 }
154 Option::Some(2)
155 }
156
157 static B: Once = Once::new();
158 fn b() -> i8 {
159 if B.is_completed() {
160 panic!("B.is_completed()")
161 } else {
162 B.call_once(|| {})
163 }
164 1
165 }
166
167 assert_eq!(A.is_completed(), false);
168 assert_eq!(B.is_completed(), false);
169 let result = assert_some_ne_x_as_result!(a(), b());
170 assert!(result.is_ok());
171 assert_eq!(A.is_completed(), true);
172 assert_eq!(B.is_completed(), true);
173 }
174
175 #[test]
176 fn eq() {
177 let a: Option<i8> = Option::Some(1);
178 let b: i8 = 1;
179 let actual = assert_some_ne_x_as_result!(a, b);
180 let message = concat!(
181 "assertion failed: `assert_some_ne_x!(a, b)`\n",
182 "https://docs.rs/assertables/",
183 env!("CARGO_PKG_VERSION"),
184 "/assertables/macro.assert_some_ne_x.html\n",
185 " a label: `a`,\n",
186 " a debug: `Some(1)`,\n",
187 " a inner: `1`,\n",
188 " b label: `b`,\n",
189 " b debug: `1`"
190 );
191 assert_eq!(actual.unwrap_err(), message);
192 }
193
194 #[test]
195 fn not_some() {
196 let a: Option<i8> = Option::None;
197 let b: i8 = 1;
198 let actual = assert_some_ne_x_as_result!(a, b);
199 let message = concat!(
200 "assertion failed: `assert_some_ne_x!(a, b)`\n",
201 "https://docs.rs/assertables/",
202 env!("CARGO_PKG_VERSION"),
203 "/assertables/macro.assert_some_ne_x.html\n",
204 " a label: `a`,\n",
205 " a debug: `None`,\n",
206 " b label: `b`,\n",
207 " b debug: `1`",
208 );
209 assert_eq!(actual.unwrap_err(), message);
210 }
211}
212
213/// Assert an expression is Some and its value is not equal to an expression.
214///
215/// Pseudocode:<br>
216/// (a ⇒ Some(a1) ⇒ a1) ≠ b
217///
218/// * If true, return `a1`.
219///
220/// * Otherwise, call [`panic!`] with a message and the values of the
221/// expressions with their debug representations.
222///
223/// # Examples
224///
225/// ```rust
226/// use assertables::*;
227/// # use std::panic;
228///
229/// # fn main() {
230/// let a: Option<i8> = Option::Some(1);
231/// let b: i8 = 2;
232/// assert_some_ne_x!(a, b);
233///
234/// # let result = panic::catch_unwind(|| {
235/// // This will panic
236/// let a: Option<i8> = Option::Some(1);
237/// let b: i8 = 1;
238/// assert_some_ne_x!(a, b);
239/// # });
240/// // assertion failed: `assert_some_ne_x!(a, b)`
241/// // https://docs.rs/assertables/9.7.0/assertables/macro.assert_some_ne_x.html
242/// // a label: `a`,
243/// // a debug: `Some(1)`,
244/// // a inner: `1`,
245/// // b label: `b`,
246/// // b debug: `1`
247/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
248/// # let message = concat!(
249/// # "assertion failed: `assert_some_ne_x!(a, b)`\n",
250/// # "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_some_ne_x.html\n",
251/// # " a label: `a`,\n",
252/// # " a debug: `Some(1)`,\n",
253/// # " a inner: `1`,\n",
254/// # " b label: `b`,\n",
255/// # " b debug: `1`",
256/// # );
257/// # assert_eq!(actual, message);
258/// # }
259/// ```
260///
261/// # Module macros
262///
263/// * [`assert_some_ne_x`](macro@crate::assert_some_ne_x)
264/// * [`assert_some_ne_x_as_result`](macro@crate::assert_some_ne_x_as_result)
265/// * [`debug_assert_some_ne_x`](macro@crate::debug_assert_some_ne_x)
266///
267#[macro_export]
268macro_rules! assert_some_ne_x {
269 ($a:expr, $b:expr $(,)?) => {
270 match $crate::assert_some_ne_x_as_result!($a, $b) {
271 Ok(x) => x,
272 Err(err) => panic!("{}", err),
273 }
274 };
275 ($a:expr, $b:expr, $($message:tt)+) => {
276 match $crate::assert_some_ne_x_as_result!($a, $b) {
277 Ok(x) => x,
278 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
279 }
280 };
281}
282
283#[cfg(test)]
284mod test_assert_some_ne_x {
285 use std::panic;
286
287 #[test]
288 fn ne() {
289 let a: Option<i8> = Option::Some(1);
290 let b: i8 = 2;
291 for _ in 0..1 {
292 let actual = assert_some_ne_x!(a, b);
293 assert_eq!(actual, 1);
294 }
295 }
296
297 #[test]
298 fn eq() {
299 let a: Option<i8> = Option::Some(1);
300 let b: i8 = 1;
301 let result = panic::catch_unwind(|| {
302 let _actual = assert_some_ne_x!(a, b);
303 });
304 let message = concat!(
305 "assertion failed: `assert_some_ne_x!(a, b)`\n",
306 "https://docs.rs/assertables/",
307 env!("CARGO_PKG_VERSION"),
308 "/assertables/macro.assert_some_ne_x.html\n",
309 " a label: `a`,\n",
310 " a debug: `Some(1)`,\n",
311 " a inner: `1`,\n",
312 " b label: `b`,\n",
313 " b debug: `1`"
314 );
315 assert_eq!(
316 result
317 .unwrap_err()
318 .downcast::<String>()
319 .unwrap()
320 .to_string(),
321 message
322 );
323 }
324
325 #[test]
326 fn not_some() {
327 let a: Option<i8> = Option::None;
328 let b: i8 = 1;
329 let result = panic::catch_unwind(|| {
330 let _actual = assert_some_ne_x!(a, b);
331 });
332 let message = concat!(
333 "assertion failed: `assert_some_ne_x!(a, b)`\n",
334 "https://docs.rs/assertables/",
335 env!("CARGO_PKG_VERSION"),
336 "/assertables/macro.assert_some_ne_x.html\n",
337 " a label: `a`,\n",
338 " a debug: `None`,\n",
339 " b label: `b`,\n",
340 " b debug: `1`",
341 );
342 assert_eq!(
343 result
344 .unwrap_err()
345 .downcast::<String>()
346 .unwrap()
347 .to_string(),
348 message
349 );
350 }
351}
352
353/// Assert an expression is Some and its value is not equal to an expression.
354///
355/// Pseudocode:<br>
356/// (a ⇒ Some(a1) ⇒ a1) ≠ b
357///
358/// This macro provides the same statements as [`assert_some_ne_x`](macro.assert_some_ne_x.html),
359/// except this macro's statements are only enabled in non-optimized
360/// builds by default. An optimized build will not execute this macro's
361/// statements unless `-C debug-assertions` is passed to the compiler.
362///
363/// This macro is useful for checks that are too expensive to be present
364/// in a release build but may be helpful during development.
365///
366/// The result of expanding this macro is always type checked.
367///
368/// An unchecked assertion allows a program in an inconsistent state to
369/// keep running, which might have unexpected consequences but does not
370/// introduce unsafety as long as this only happens in safe code. The
371/// performance cost of assertions, however, is not measurable in general.
372/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
373/// after thorough profiling, and more importantly, only in safe code!
374///
375/// This macro is intended to work in a similar way to
376/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
377///
378/// # Module macros
379///
380/// * [`assert_some_ne_x`](macro@crate::assert_some_ne_x)
381/// * [`assert_some_ne_x`](macro@crate::assert_some_ne_x)
382/// * [`debug_assert_some_ne_x`](macro@crate::debug_assert_some_ne_x)
383///
384#[macro_export]
385macro_rules! debug_assert_some_ne_x {
386 ($($arg:tt)*) => {
387 if $crate::cfg!(debug_assertions) {
388 $crate::assert_some_ne_x!($($arg)*);
389 }
390 };
391}