assertables/assert_abs_diff/
assert_abs_diff_eq_x.rs

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