assertables/assert_abs_diff/assert_abs_diff_gt_x.rs
1//! Assert an absolute difference is greater than 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_gt_x!(a, b, x);
15//! ```
16//!
17//! # Module macros
18//!
19//! * [`assert_abs_diff_gt_x`](macro@crate::assert_abs_diff_gt_x)
20//! * [`assert_abs_diff_gt_x_as_result`](macro@crate::assert_abs_diff_gt_x_as_result)
21//! * [`debug_assert_abs_diff_gt_x`](macro@crate::debug_assert_abs_diff_gt_x)
22
23/// Assert an absolute difference is greater than 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_gt_x`](macro@crate::assert_abs_diff_gt_x)
39/// * [`assert_abs_diff_gt_x_as_result`](macro@crate::assert_abs_diff_gt_x_as_result)
40/// * [`debug_assert_abs_diff_gt_x`](macro@crate::debug_assert_abs_diff_gt_x)
41///
42#[macro_export]
43macro_rules! assert_abs_diff_gt_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_gt_x!(a, b, x)`\n",
55 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_abs_diff_gt_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_gt_x!(a, b, x)`\n",
80 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_abs_diff_gt_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_gt_x_as_result {
105 use std::sync::Once;
106
107 #[test]
108 fn gt() {
109 let a: i8 = 10;
110 let b: i8 = 13;
111 let x: i8 = 2;
112 for _ in 0..1 {
113 let actual = assert_abs_diff_gt_x_as_result!(a, b, x);
114 assert_eq!(actual.unwrap(), (3, 2));
115 }
116 }
117
118 #[test]
119 fn gt_once() {
120 static A: Once = Once::new();
121 fn a() -> i8 {
122 if A.is_completed() {
123 panic!("A.is_completed()")
124 } else {
125 A.call_once(|| {})
126 }
127 10
128 }
129
130 static B: Once = Once::new();
131 fn b() -> i8 {
132 if B.is_completed() {
133 panic!("B.is_completed()")
134 } else {
135 B.call_once(|| {})
136 }
137 13
138 }
139
140 static X: Once = Once::new();
141 fn x() -> i8 {
142 if X.is_completed() {
143 panic!("X.is_completed()")
144 } else {
145 X.call_once(|| {})
146 }
147 2
148 }
149
150 assert_eq!(A.is_completed(), false);
151 assert_eq!(B.is_completed(), false);
152 assert_eq!(X.is_completed(), false);
153 let result = assert_abs_diff_gt_x_as_result!(a(), b(), x());
154 assert!(result.is_ok());
155 assert_eq!(A.is_completed(), true);
156 assert_eq!(B.is_completed(), true);
157 assert_eq!(X.is_completed(), true);
158 }
159
160 #[test]
161 fn eq() {
162 let a: i8 = 10;
163 let b: i8 = 13;
164 let x: i8 = 3;
165 let actual = assert_abs_diff_gt_x_as_result!(a, b, x);
166 let message = concat!(
167 "assertion failed: `assert_abs_diff_gt_x!(a, b, x)`\n",
168 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_abs_diff_gt_x.html\n",
169 " a label: `a`,\n",
170 " a debug: `10`,\n",
171 " b label: `b`,\n",
172 " b debug: `13`,\n",
173 " x label: `x`,\n",
174 " x debug: `3`,\n",
175 " |Δ|: `3`,\n",
176 " |Δ| > x: false"
177 );
178 assert_eq!(actual.unwrap_err(), message);
179 }
180
181 #[test]
182 fn lt() {
183 let a: i8 = 10;
184 let b: i8 = 13;
185 let x: i8 = 4;
186 let actual = assert_abs_diff_gt_x_as_result!(a, b, x);
187 let message = concat!(
188 "assertion failed: `assert_abs_diff_gt_x!(a, b, x)`\n",
189 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_abs_diff_gt_x.html\n",
190 " a label: `a`,\n",
191 " a debug: `10`,\n",
192 " b label: `b`,\n",
193 " b debug: `13`,\n",
194 " x label: `x`,\n",
195 " x debug: `4`,\n",
196 " |Δ|: `3`,\n",
197 " |Δ| > x: false"
198 );
199 assert_eq!(actual.unwrap_err(), message);
200 }
201
202 #[test]
203 fn overflow() {
204 let a: i8 = i8::MAX;
205 let b: i8 = i8::MIN;
206 let x: i8 = 0;
207 let actual = assert_abs_diff_gt_x_as_result!(a, b, x);
208 let message = format!(
209 concat!(
210 "assertion failed: `assert_abs_diff_gt_x!(a, b, x)`\n",
211 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_abs_diff_gt_x.html\n",
212 " a label: `a`,\n",
213 " a debug: `{}`,\n",
214 " b label: `b`,\n",
215 " b debug: `{}`,\n",
216 " x label: `x`,\n",
217 " x debug: `{}`,\n",
218 " |Δ|: panic"
219 ),
220 a, b, x
221 );
222 assert_eq!(actual.unwrap_err(), message);
223 }
224}
225
226/// Assert an absolute difference is greater than an expression.
227///
228/// Pseudocode:<br>
229/// |Δ| > x
230///
231/// * If true, return `(lhs, rhs)`.
232///
233/// * Otherwise, call [`panic!`] with a message and the values of the
234/// expressions with their debug representations.
235///
236/// # Examples
237///
238/// ```rust
239/// use assertables::*;
240/// # use std::panic;
241///
242/// # fn main() {
243/// let a = 10;
244/// let b = 13;
245/// let x = 2;
246/// assert_abs_diff_gt_x!(a, b, x);
247///
248/// # let result = panic::catch_unwind(|| {
249/// // This will panic
250/// let a = 10;
251/// let b = 13;
252/// let x = 4;
253/// assert_abs_diff_gt_x!(a, b, x);
254/// # });
255/// // assertion failed: `assert_abs_diff_gt_x!(a, b)`
256/// // https://docs.rs/assertables/…/assertables/macro.assert_abs_diff_gt_x.html
257/// // a label: `a`,
258/// // a debug: `10`,
259/// // b label: `b`,
260/// // b debug: `13`,
261/// // x label: `x`,
262/// // x debug: `4`,
263/// // |Δ|: `3`,
264/// // |Δ| > x: false
265/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
266/// # let message = concat!(
267/// # "assertion failed: `assert_abs_diff_gt_x!(a, b, x)`\n",
268/// # "https://docs.rs/assertables/9.8.2/assertables/macro.assert_abs_diff_gt_x.html\n",
269/// # " a label: `a`,\n",
270/// # " a debug: `10`,\n",
271/// # " b label: `b`,\n",
272/// # " b debug: `13`,\n",
273/// # " x label: `x`,\n",
274/// # " x debug: `4`,\n",
275/// # " |Δ|: `3`,\n",
276/// # " |Δ| > x: false"
277/// # );
278/// # assert_eq!(actual, message);
279/// # }
280/// ```
281///
282/// # Module macros
283///
284/// * [`assert_abs_diff_gt_x`](macro@crate::assert_abs_diff_gt_x)
285/// * [`assert_abs_diff_gt_x_as_result`](macro@crate::assert_abs_diff_gt_x_as_result)
286/// * [`debug_assert_abs_diff_gt_x`](macro@crate::debug_assert_abs_diff_gt_x)
287///
288#[macro_export]
289macro_rules! assert_abs_diff_gt_x {
290 ($a:expr, $b:expr, $x:expr $(,)?) => {
291 match $crate::assert_abs_diff_gt_x_as_result!($a, $b, $x) {
292 Ok(x) => x,
293 Err(err) => panic!("{}", err),
294 }
295 };
296 ($a:expr, $b:expr, $x:expr, $($message:tt)+) => {
297 match $crate::assert_abs_diff_gt_x_as_result!($a, $b, $x) {
298 Ok(x) => x,
299 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
300 }
301 };
302}
303
304#[cfg(test)]
305mod assert_abs_diff_gt_x {
306 use std::panic;
307
308 #[test]
309 fn gt() {
310 let a = 10;
311 let b = 13;
312 let x = 2;
313 for _ in 0..1 {
314 let actual = assert_abs_diff_gt_x!(a, b, x);
315 assert_eq!(actual, (3, 2));
316 }
317 }
318
319 #[test]
320 fn eq() {
321 let result = panic::catch_unwind(|| {
322 let a = 10;
323 let b = 13;
324 let x = 3;
325 let _actual = assert_abs_diff_gt_x!(a, b, x);
326 });
327 let message = concat!(
328 "assertion failed: `assert_abs_diff_gt_x!(a, b, x)`\n",
329 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_abs_diff_gt_x.html\n",
330 " a label: `a`,\n",
331 " a debug: `10`,\n",
332 " b label: `b`,\n",
333 " b debug: `13`,\n",
334 " x label: `x`,\n",
335 " x debug: `3`,\n",
336 " |Δ|: `3`,\n",
337 " |Δ| > x: false"
338 );
339 assert_eq!(
340 result
341 .unwrap_err()
342 .downcast::<String>()
343 .unwrap()
344 .to_string(),
345 message
346 );
347 }
348
349 #[test]
350 fn lt() {
351 let result = panic::catch_unwind(|| {
352 let a = 10;
353 let b = 13;
354 let x = 4;
355 let _actual = assert_abs_diff_gt_x!(a, b, x);
356 });
357 let message = concat!(
358 "assertion failed: `assert_abs_diff_gt_x!(a, b, x)`\n",
359 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_abs_diff_gt_x.html\n",
360 " a label: `a`,\n",
361 " a debug: `10`,\n",
362 " b label: `b`,\n",
363 " b debug: `13`,\n",
364 " x label: `x`,\n",
365 " x debug: `4`,\n",
366 " |Δ|: `3`,\n",
367 " |Δ| > x: false"
368 );
369 assert_eq!(
370 result
371 .unwrap_err()
372 .downcast::<String>()
373 .unwrap()
374 .to_string(),
375 message
376 );
377 }
378
379 #[test]
380 fn overflow() {
381 let a: i8 = i8::MAX;
382 let b: i8 = i8::MIN;
383 let x: i8 = 0;
384 let result = panic::catch_unwind(|| {
385 let _actual = assert_abs_diff_gt_x!(a, b, x);
386 });
387 let message = format!(
388 concat!(
389 "assertion failed: `assert_abs_diff_gt_x!(a, b, x)`\n",
390 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_abs_diff_gt_x.html\n",
391 " a label: `a`,\n",
392 " a debug: `{}`,\n",
393 " b label: `b`,\n",
394 " b debug: `{}`,\n",
395 " x label: `x`,\n",
396 " x debug: `{}`,\n",
397 " |Δ|: panic"
398 ),
399 a, b, x
400 );
401 assert_eq!(
402 result
403 .unwrap_err()
404 .downcast::<String>()
405 .unwrap()
406 .to_string(),
407 message
408 );
409 }
410}
411
412/// Assert an absolute difference is greater than an expression.
413///
414/// Pseudocode:<br>
415/// |Δ| > c
416///
417/// This macro provides the same statements as [`assert_abs_diff_gt_x`](macro.assert_abs_diff_gt_x.html),
418/// except this macro's statements are only enabled in non-optimized
419/// builds by default. An optimized build will not execute this macro's
420/// statements unless `-x debug-assertions` is passed to the compiler.
421///
422/// This macro is useful for checks that are too expensive to be present
423/// in a release build but may be helpful during development.
424///
425/// The result of expanding this macro is always type checked.
426///
427/// An unchecked assertion allows a program in an inconsistent state to
428/// keep running, which might have unexpected consequences but does not
429/// introduce unsafety as long as this only happens in safe code. The
430/// performance cost of assertions, however, is not measurable in general.
431/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
432/// after thorough profiling, and more importantly, only in safe code!
433///
434/// This macro is intended to work in a similar way to
435/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
436///
437/// # Module macros
438///
439/// * [`assert_abs_diff_gt_x`](macro@crate::assert_abs_diff_gt_x)
440/// * [`assert_abs_diff_gt_x`](macro@crate::assert_abs_diff_gt_x)
441/// * [`debug_assert_abs_diff_gt_x`](macro@crate::debug_assert_abs_diff_gt_x)
442///
443#[macro_export]
444macro_rules! debug_assert_abs_diff_gt_x {
445 ($($arg:tt)*) => {
446 if $crate::cfg!(debug_assertions) {
447 $crate::assert_abs_diff_gt_x!($($arg)*);
448 }
449 };
450}