assertables/assert_abs_diff/assert_abs_diff_ne_x.rs
1//! Assert an absolute difference is not equal to an expression.
2//!
3//! Pseudocode:<br>
4//! |Δ| ≠ x
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! let a = 10;
12//! let b = 13;
13//! let x = 2;
14//! assert_abs_diff_ne_x!(a, b, x);
15//! ```
16//!
17//! # Module macros
18//!
19//! * [`assert_abs_diff_ne_x`](macro@crate::assert_abs_diff_ne_x)
20//! * [`assert_abs_diff_ne_x_as_result`](macro@crate::assert_abs_diff_ne_x_as_result)
21//! * [`debug_assert_abs_diff_ne_x`](macro@crate::debug_assert_abs_diff_ne_x)
22
23/// Assert an absolute difference is not equal to an expression.
24///
25/// Pseudocode:<br>
26/// |Δ| ≠ x
27///
28/// * If true, return `Ok((lhs, rhs))`.
29///
30/// * Otherwise, return [`Err`] with a message and the values of the
31/// expressions with their debug representations.
32///
33/// This macro is useful for runtime checks, such as checking parameters,
34/// or sanitizing inputs, or handling different results in different ways.
35///
36/// # Module macros
37///
38/// * [`assert_abs_diff_ne_x`](macro@crate::assert_abs_diff_ne_x)
39/// * [`assert_abs_diff_ne_x_as_result`](macro@crate::assert_abs_diff_ne_x_as_result)
40/// * [`debug_assert_abs_diff_ne_x`](macro@crate::debug_assert_abs_diff_ne_x)
41///
42#[macro_export]
43macro_rules! assert_abs_diff_ne_x_as_result {
44 ($a:expr, $b:expr, $x:expr $(,)?) => {
45 match (&$a, &$b, &$x) {
46 (a, b, x) => {
47 match ::std::panic::catch_unwind(|| if (a >= b) { a - b } else { b - a }) {
48 Ok(abs_diff) => {
49 if abs_diff != *x {
50 Ok((abs_diff, *x))
51 } else {
52 Err(format!(
53 concat!(
54 "assertion failed: `assert_abs_diff_ne_x!(a, b, x)`\n",
55 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_abs_diff_ne_x.html\n",
56 " a label: `{}`,\n",
57 " a debug: `{:?}`,\n",
58 " b label: `{}`,\n",
59 " b debug: `{:?}`,\n",
60 " x label: `{}`,\n",
61 " x debug: `{:?}`,\n",
62 " |Δ|: `{:?}`,\n",
63 " |Δ| ≠ x: {}"
64 ),
65 stringify!($a),
66 a,
67 stringify!($b),
68 b,
69 stringify!($x),
70 x,
71 abs_diff,
72 false
73 ))
74 }
75 }
76 Err(_err) => {
77 Err(format!(
78 concat!(
79 "assertion failed: `assert_abs_diff_ne_x!(a, b, x)`\n",
80 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_abs_diff_ne_x.html\n",
81 " a label: `{}`,\n",
82 " a debug: `{:?}`,\n",
83 " b label: `{}`,\n",
84 " b debug: `{:?}`,\n",
85 " x label: `{}`,\n",
86 " x debug: `{:?}`,\n",
87 " |Δ|: panic", //TODO add the panic message
88 ),
89 stringify!($a),
90 a,
91 stringify!($b),
92 b,
93 stringify!($x),
94 x
95 ))
96 }
97 }
98 }
99 }
100 };
101}
102
103#[cfg(test)]
104mod test_assert_abs_diff_ne_x_as_result {
105 use std::sync::Once;
106
107 #[test]
108 fn lt() {
109 let a = 10;
110 let b = 13;
111 let x = 4;
112 for _ in 0..1 {
113 let actual = assert_abs_diff_ne_x_as_result!(a, b, x);
114 let expect = (3, 4);
115 assert_eq!(actual.unwrap(), expect);
116 }
117 }
118
119 #[test]
120 fn lt_once() {
121 static A: Once = Once::new();
122 fn a() -> i32 {
123 if A.is_completed() {
124 panic!("A.is_completed()")
125 } else {
126 A.call_once(|| {})
127 }
128 10
129 }
130
131 static B: Once = Once::new();
132 fn b() -> i32 {
133 if B.is_completed() {
134 panic!("B.is_completed()")
135 } else {
136 B.call_once(|| {})
137 }
138 13
139 }
140
141 static X: Once = Once::new();
142 fn x() -> i32 {
143 if X.is_completed() {
144 panic!("X.is_completed()")
145 } else {
146 X.call_once(|| {})
147 }
148 4
149 }
150
151 assert_eq!(A.is_completed(), false);
152 assert_eq!(B.is_completed(), false);
153 assert_eq!(X.is_completed(), false);
154 let result = assert_abs_diff_ne_x_as_result!(a(), b(), x());
155 assert!(result.is_ok());
156 assert_eq!(A.is_completed(), true);
157 assert_eq!(B.is_completed(), true);
158 assert_eq!(X.is_completed(), true);
159 }
160
161 #[test]
162 fn gt() {
163 let a = 10;
164 let b = 13;
165 let x = 2;
166 for _ in 0..1 {
167 let actual = assert_abs_diff_ne_x_as_result!(a, b, x);
168 let expect = (3, 2);
169 assert_eq!(actual.unwrap(), expect);
170 }
171 }
172
173 #[test]
174 fn gt_once() {
175 static A: Once = Once::new();
176 fn a() -> i32 {
177 if A.is_completed() {
178 panic!("A.is_completed()")
179 } else {
180 A.call_once(|| {})
181 }
182 10
183 }
184
185 static B: Once = Once::new();
186 fn b() -> i32 {
187 if B.is_completed() {
188 panic!("B.is_completed()")
189 } else {
190 B.call_once(|| {})
191 }
192 13
193 }
194
195 static X: Once = Once::new();
196 fn x() -> i32 {
197 if X.is_completed() {
198 panic!("X.is_completed()")
199 } else {
200 X.call_once(|| {})
201 }
202 2
203 }
204
205 assert_eq!(A.is_completed(), false);
206 assert_eq!(B.is_completed(), false);
207 assert_eq!(X.is_completed(), false);
208 let result = assert_abs_diff_ne_x_as_result!(a(), b(), x());
209 assert!(result.is_ok());
210 assert_eq!(A.is_completed(), true);
211 assert_eq!(B.is_completed(), true);
212 assert_eq!(X.is_completed(), true);
213 }
214
215 #[test]
216 fn eq() {
217 let a = 10;
218 let b = 13;
219 let x = 3;
220 let actual = assert_abs_diff_ne_x_as_result!(a, b, x);
221 let message = concat!(
222 "assertion failed: `assert_abs_diff_ne_x!(a, b, x)`\n",
223 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_abs_diff_ne_x.html\n",
224 " a label: `a`,\n",
225 " a debug: `10`,\n",
226 " b label: `b`,\n",
227 " b debug: `13`,\n",
228 " x label: `x`,\n",
229 " x debug: `3`,\n",
230 " |Δ|: `3`,\n",
231 " |Δ| ≠ x: false"
232 );
233 assert_eq!(actual.unwrap_err(), message);
234 }
235
236 #[test]
237 fn overflow() {
238 let a: i8 = i8::MAX;
239 let b: i8 = i8::MIN;
240 let x: i8 = 0;
241 let actual = assert_abs_diff_ne_x_as_result!(a, b, x);
242 let message = format!(
243 concat!(
244 "assertion failed: `assert_abs_diff_ne_x!(a, b, x)`\n",
245 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_abs_diff_ne_x.html\n",
246 " a label: `a`,\n",
247 " a debug: `{}`,\n",
248 " b label: `b`,\n",
249 " b debug: `{}`,\n",
250 " x label: `x`,\n",
251 " x debug: `{}`,\n",
252 " |Δ|: panic"
253 ),
254 a, b, x
255 );
256 assert_eq!(actual.unwrap_err(), message);
257 }
258}
259
260/// Assert an absolute difference is not equal to an expression.
261///
262/// Pseudocode:<br>
263/// |Δ| ≠ x
264///
265/// * If true, return `(lhs, rhs)`.
266///
267/// * Otherwise, call [`panic!`] with a message and the values of the
268/// expressions with their debug representations.
269///
270/// # Examples
271///
272/// ```rust
273/// use assertables::*;
274/// # use std::panic;
275///
276/// # fn main() {
277/// let a = 10;
278/// let b = 13;
279/// let x = 2;
280/// assert_abs_diff_ne_x!(a, b, x);
281///
282/// # let result = panic::catch_unwind(|| {
283/// // This will panic
284/// let a = 10;
285/// let b = 13;
286/// let x = 3;
287/// assert_abs_diff_ne_x!(a, b, x);
288/// # });
289/// // assertion failed: `assert_abs_diff_ne_x!(a, b)`
290/// // https://docs.rs/assertables/…/assertables/macro.assert_abs_diff_ne_x.html
291/// // a label: `a`,
292/// // a debug: `10`,
293/// // b label: `b`,
294/// // b debug: `13`,
295/// // x label: `x`,
296/// // x debug: `2`,
297/// // |Δ|: `3`,
298/// // |Δ| ≠ x: false
299/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
300/// # let message = concat!(
301/// # "assertion failed: `assert_abs_diff_ne_x!(a, b, x)`\n",
302/// # "https://docs.rs/assertables/9.8.6/assertables/macro.assert_abs_diff_ne_x.html\n",
303/// # " a label: `a`,\n",
304/// # " a debug: `10`,\n",
305/// # " b label: `b`,\n",
306/// # " b debug: `13`,\n",
307/// # " x label: `x`,\n",
308/// # " x debug: `3`,\n",
309/// # " |Δ|: `3`,\n",
310/// # " |Δ| ≠ x: false"
311/// # );
312/// # assert_eq!(actual, message);
313/// # }
314/// ```
315///
316/// # Module macros
317///
318/// * [`assert_abs_diff_ne_x`](macro@crate::assert_abs_diff_ne_x)
319/// * [`assert_abs_diff_ne_x_as_result`](macro@crate::assert_abs_diff_ne_x_as_result)
320/// * [`debug_assert_abs_diff_ne_x`](macro@crate::debug_assert_abs_diff_ne_x)
321///
322#[macro_export]
323macro_rules! assert_abs_diff_ne_x {
324 ($a:expr, $b:expr, $x:expr $(,)?) => {
325 match $crate::assert_abs_diff_ne_x_as_result!($a, $b, $x) {
326 Ok(x) => x,
327 Err(err) => panic!("{}", err),
328 }
329 };
330 ($a:expr, $b:expr, $x:expr, $($message:tt)+) => {
331 match $crate::assert_abs_diff_ne_x_as_result!($a, $b, $x) {
332 Ok(x) => x,
333 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
334 }
335 };
336}
337
338#[cfg(test)]
339mod test_assert_abs_diff_ne_x {
340 use std::panic;
341
342 #[test]
343 fn lt() {
344 let a = 10;
345 let b = 13;
346 let x = 4;
347 for _ in 0..1 {
348 let actual = assert_abs_diff_ne_x!(a, b, x);
349 let expect = (3, 4);
350 assert_eq!(actual, expect);
351 }
352 }
353
354 #[test]
355 fn gt() {
356 let a = 10;
357 let b = 13;
358 let x = 2;
359 for _ in 0..1 {
360 let actual = assert_abs_diff_ne_x!(a, b, x);
361 let expect = (3, 2);
362 assert_eq!(actual, expect);
363 }
364 }
365
366 #[test]
367 fn eq() {
368 let result = panic::catch_unwind(|| {
369 let a = 10;
370 let b = 13;
371 let x = 3;
372 let _result = assert_abs_diff_ne_x!(a, b, x);
373 });
374 let message = concat!(
375 "assertion failed: `assert_abs_diff_ne_x!(a, b, x)`\n",
376 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_abs_diff_ne_x.html\n",
377 " a label: `a`,\n",
378 " a debug: `10`,\n",
379 " b label: `b`,\n",
380 " b debug: `13`,\n",
381 " x label: `x`,\n",
382 " x debug: `3`,\n",
383 " |Δ|: `3`,\n",
384 " |Δ| ≠ x: false"
385 );
386 assert_eq!(
387 result
388 .unwrap_err()
389 .downcast::<String>()
390 .unwrap()
391 .to_string(),
392 message
393 );
394 }
395
396 #[test]
397 fn overflow() {
398 let a: i8 = i8::MAX;
399 let b: i8 = i8::MIN;
400 let x: i8 = 0;
401 let result = panic::catch_unwind(|| {
402 let _actual = assert_abs_diff_ne_x!(a, b, x);
403 });
404 let message = format!(
405 concat!(
406 "assertion failed: `assert_abs_diff_ne_x!(a, b, x)`\n",
407 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_abs_diff_ne_x.html\n",
408 " a label: `a`,\n",
409 " a debug: `{}`,\n",
410 " b label: `b`,\n",
411 " b debug: `{}`,\n",
412 " x label: `x`,\n",
413 " x debug: `{}`,\n",
414 " |Δ|: panic"
415 ),
416 a, b, x
417 );
418 assert_eq!(
419 result
420 .unwrap_err()
421 .downcast::<String>()
422 .unwrap()
423 .to_string(),
424 message
425 );
426 }
427}
428
429/// Assert an absolute difference is not equal to an expression.
430///
431/// Pseudocode:<br>
432/// |Δ| ≠ c
433///
434/// This macro provides the same statements as [`assert_abs_diff_ne_x`](macro.assert_abs_diff_ne_x.html),
435/// except this macro's statements are only enabled in non-optimized
436/// builds by default. An optimized build will not execute this macro's
437/// statements unless `-x debug-assertions` is passed to the compiler.
438///
439/// This macro is useful for checks that are too expensive to be present
440/// in a release build but may be helpful during development.
441///
442/// The result of expanding this macro is always type checked.
443///
444/// An unchecked assertion allows a program in an inconsistent state to
445/// keep running, which might have unexpected consequences but does not
446/// introduce unsafety as long as this only happens in safe code. The
447/// performance cost of assertions, however, is not measurable in general.
448/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
449/// after thorough profiling, and more importantly, only in safe code!
450///
451/// This macro is intended to work in a similar way to
452/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
453///
454/// # Module macros
455///
456/// * [`assert_abs_diff_ne_x`](macro@crate::assert_abs_diff_ne_x)
457/// * [`assert_abs_diff_ne_x`](macro@crate::assert_abs_diff_ne_x)
458/// * [`debug_assert_abs_diff_ne_x`](macro@crate::debug_assert_abs_diff_ne_x)
459///
460#[macro_export]
461macro_rules! debug_assert_abs_diff_ne_x {
462 ($($arg:tt)*) => {
463 if cfg!(debug_assertions) {
464 $crate::assert_abs_diff_ne_x!($($arg)*);
465 }
466 };
467}
468
469#[cfg(test)]
470mod test_debug_assert_abs_diff_ne_x {
471 use std::panic;
472
473 #[test]
474 fn lt() {
475 let a = 10;
476 let b = 13;
477 let x = 4;
478 for _ in 0..1 {
479 let _actual = debug_assert_abs_diff_ne_x!(a, b, x);
480 let _expect = (3, 4);
481 // assert_eq!(actual, expect);
482 }
483 }
484
485 #[test]
486 fn gt() {
487 let a = 10;
488 let b = 13;
489 let x = 2;
490 for _ in 0..1 {
491 let _actual = debug_assert_abs_diff_ne_x!(a, b, x);
492 let _expect = (3, 2);
493 // assert_eq!(actual, expect);
494 }
495 }
496
497 #[test]
498 fn eq() {
499 let result = panic::catch_unwind(|| {
500 let a = 10;
501 let b = 13;
502 let x = 3;
503 let _result = debug_assert_abs_diff_ne_x!(a, b, x);
504 });
505 let message = concat!(
506 "assertion failed: `assert_abs_diff_ne_x!(a, b, x)`\n",
507 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_abs_diff_ne_x.html\n",
508 " a label: `a`,\n",
509 " a debug: `10`,\n",
510 " b label: `b`,\n",
511 " b debug: `13`,\n",
512 " x label: `x`,\n",
513 " x debug: `3`,\n",
514 " |Δ|: `3`,\n",
515 " |Δ| ≠ x: false"
516 );
517 assert_eq!(
518 result
519 .unwrap_err()
520 .downcast::<String>()
521 .unwrap()
522 .to_string(),
523 message
524 );
525 }
526
527 #[test]
528 fn overflow() {
529 let a: i8 = i8::MAX;
530 let b: i8 = i8::MIN;
531 let x: i8 = 0;
532 let result = panic::catch_unwind(|| {
533 let _actual = debug_assert_abs_diff_ne_x!(a, b, x);
534 });
535 let message = format!(
536 concat!(
537 "assertion failed: `assert_abs_diff_ne_x!(a, b, x)`\n",
538 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_abs_diff_ne_x.html\n",
539 " a label: `a`,\n",
540 " a debug: `{}`,\n",
541 " b label: `b`,\n",
542 " b debug: `{}`,\n",
543 " x label: `x`,\n",
544 " x debug: `{}`,\n",
545 " |Δ|: panic"
546 ),
547 a, b, x
548 );
549 assert_eq!(
550 result
551 .unwrap_err()
552 .downcast::<String>()
553 .unwrap()
554 .to_string(),
555 message
556 );
557 }
558}