assertables/assert_approx/
assert_approx_ne.rs

1//! Assert a number is approximately not equal to another.
2//!
3//! Pseudocode:<br>
4//! | a - b | > 1e-6
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! let a: f32 = 1.0000001;
12//! let b: f32 = 1.0000012;
13//! assert_approx_ne!(a, b);
14//! ```
15//!
16//!
17//! ## Comparisons
18//!
19//! This crate provides macro groups that test approximations and nearness:
20//!
21//! * [`assert_approx_eq`](macro@crate::assert_approx_eq) and
22//!   [`assert_approx_ne`](macro@crate::assert_approx_ne) test the approximate
23//!   equality within 1e-6. The macro name and the approximate value are chosen
24//!   to be similar to the longtime popular rust crate `assert_approx_eq`.
25//!
26//! * [`assert_in_delta`](macro@crate::assert_in_delta) tests the absolute error
27//!   (i.e. delta). This is the magnitude of the difference between the exact
28//!   value and the approximation.
29//!
30//! * [`assert_in_epsilon`](macro@crate::assert_in_epsilon) tests the relative
31//!   error (i.e. epsilon). This is the absolute error divided by the magnitude
32//!   of the exact value. This can be used to compare approximations of numbers
33//!   of wildly differing size.
34//!
35//! Examples:
36//!
37//! * Approximating the number 100 and 103 has an absolute error (approx) of 3
38//!   and a relative error (epsilon) of 0.03.
39//!
40//! * Approximating the number 1,000,000 and 1,000,003 has an absolute error
41//!   (approx) of 3, and a relative error (epsilon) of 0.000003.
42//!
43//! * For many kinds of applications, the relative error is more important than
44//!   the absolute error.
45//!
46//!
47//! ## Thanks
48//!
49//! * Thanks to [Ashley Williams](https://github.com/ashleygwilliams) for
50//!   creating and maintaining the `assert_approx_eq` crate.
51//!
52//! * Thanks to [Ryan Davis](https://github.com/zenspider) and Ruby minitest for
53//!   creating and maintaining `assert_in_approx` and `assert_in_epsilon` code.
54//!
55//!
56//! # Module macros
57//!
58//! * [`assert_approx_ne`](macro@crate::assert_approx_ne)
59//! * [`assert_approx_ne_as_result`](macro@crate::assert_approx_ne_as_result)
60//! * [`debug_assert_approx_ne`](macro@crate::debug_assert_approx_ne)
61
62/// Assert a number is approximately not equal to another.
63///
64/// Pseudocode:<br>
65/// | a - b | > 1e-6
66///
67/// * If true, return Result `Ok(abs_diff, approx)`.
68///
69/// * When false, return [`Err`] with a message and the values of the
70///   expressions with their debug representations.
71///
72/// This macro provides the same statements as [`assert_`](macro.assert_.html), except this macro
73/// returns a Result, rather than doing a panic.
74///
75/// This macro is useful for runtime checks, such as checking parameters, or
76/// sanitizing inputs, or handling different results in different ways.
77///
78/// # Module macros
79///
80/// * [`assert_approx_ne`](macro@crate::assert_approx_ne)
81/// * [`assert_approx_ne_as_result`](macro@crate::assert_approx_ne_as_result)
82/// * [`debug_assert_approx_ne`](macro@crate::debug_assert_approx_ne)
83///
84#[macro_export]
85macro_rules! assert_approx_ne_as_result {
86    ($a:expr, $b:expr $(,)?) => {
87        match (&$a, &$b) {
88            (a, b) => {
89                let approx = 1e-6;
90                let abs_diff = if (a >= b) { a - b } else { b - a };
91                if abs_diff > approx {
92                    Ok((abs_diff, approx))
93                } else {
94                    Err(
95                        format!(
96                            concat!(
97                                "assertion failed: `assert_approx_ne!(a, b)`\n",
98                                "https://docs.rs/assertables/9.5.1/assertables/macro.assert_approx_ne.html\n",
99                                "            a label: `{}`,\n",
100                                "            a debug: `{:?}`,\n",
101                                "            b label: `{}`,\n",
102                                "            b debug: `{:?}`,\n",
103                                "          | a - b |: `{:?}`,\n",
104                                "             approx: `{:?}`,\n",
105                                " | a - b | > approx: false"
106                            ),
107                            stringify!($a),
108                            a,
109                            stringify!($b),
110                            b,
111                            abs_diff,
112                            approx
113                        )
114                    )
115                }
116            }
117        }
118    };
119}
120
121#[cfg(test)]
122mod test_assert_approx_ne_as_result {
123
124    #[test]
125    fn ne() {
126        let a: f32 = 1.0000001;
127        let b: f32 = 1.0000012;
128        let actual = assert_approx_ne_as_result!(a, b);
129        assert_eq!(actual.unwrap(), (1.0728836e-6, 1e-6));
130    }
131
132    #[test]
133    fn eq() {
134        let a: f32 = 1.0000001;
135        let b: f32 = 1.0000011;
136        let actual = assert_approx_ne_as_result!(a, b);
137        let message = concat!(
138            "assertion failed: `assert_approx_ne!(a, b)`\n",
139            "https://docs.rs/assertables/9.5.1/assertables/macro.assert_approx_ne.html\n",
140            "            a label: `a`,\n",
141            "            a debug: `1.0000001`,\n",
142            "            b label: `b`,\n",
143            "            b debug: `1.0000011`,\n",
144            "          | a - b |: `9.536743e-7`,\n",
145            "             approx: `1e-6`,\n",
146            " | a - b | > approx: false"
147        );
148        assert_eq!(actual.unwrap_err(), message);
149    }
150}
151
152/// Assert a number is approximately not equal to another.
153///
154/// Pseudocode:<br>
155/// | a - b | > 1e-6
156///
157/// * If true, return `(diff, approx)`.
158///
159/// * Otherwise, call [`panic!`] with a message and the values of the
160///   expressions with their debug representations.
161///
162/// # Examples
163///
164/// ```rust
165/// use assertables::*;
166/// # use std::panic;
167///
168/// # fn main() {
169/// let a: f32 = 1.0000001;
170/// let b: f32 = 1.0000012;
171/// assert_approx_ne!(a, b);
172///
173/// # let result = panic::catch_unwind(|| {
174/// // This will panic
175/// let a: f32 = 1.0000001;
176/// let b: f32 = 1.0000011;
177/// assert_approx_ne!(a, b);
178/// # });
179/// // assertion failed: `assert_approx_ne!(a, b)`
180/// // https://docs.rs/assertables/9.5.1/assertables/macro.assert_approx_ne.html
181/// //             a label: `a`,
182/// //             a debug: `1.0000001`,
183/// //             b label: `b`,
184/// //             b debug: `1.0000011`,
185/// //           | a - b |: `9.536743e-7`,
186/// //              approx: `1e-6`,
187/// //  | a - b | > approx: false
188/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
189/// # let message = concat!(
190/// #     "assertion failed: `assert_approx_ne!(a, b)`\n",
191/// #     "https://docs.rs/assertables/9.5.1/assertables/macro.assert_approx_ne.html\n",
192/// #     "            a label: `a`,\n",
193/// #     "            a debug: `1.0000001`,\n",
194/// #     "            b label: `b`,\n",
195/// #     "            b debug: `1.0000011`,\n",
196/// #     "          | a - b |: `9.536743e-7`,\n",
197/// #     "             approx: `1e-6`,\n",
198/// #     " | a - b | > approx: false",
199/// # );
200/// # assert_eq!(actual, message);
201/// # }
202/// ```
203///
204/// The macros `assert_approx_ne` and `assert_in_epsilon` can test
205/// approximations:
206///
207/// * For an approximation, the absolute error (i.e. approx) is the magnitude of
208///   the difference between the exact value and the approximation. For this,
209///  use the macro
210///
211/// * For an approximation, the relative error (i.e. epsilon) is the absolute
212///   error divided by the magnitude of the exact value. This can be used to
213///   compare approximations of numbers of wildly differing size.
214///
215/// * For example, approximating the number 1,000 with an absolute error of 3
216///   is, in most applications, much worse than approximating the number
217///   1,000,000 with an absolute error of 3; in the first case the relative
218///   error is 0.003 and in the second it is only 0.000003.
219///
220/// * Thanks to Ruby minitest for the example and documentation.
221///
222/// # Module macros
223///
224/// * [`assert_approx_ne`](macro@crate::assert_approx_ne)
225/// * [`assert_approx_ne_as_result`](macro@crate::assert_approx_ne_as_result)
226/// * [`debug_assert_approx_ne`](macro@crate::debug_assert_approx_ne)
227///
228#[macro_export]
229macro_rules! assert_approx_ne {
230    ($a:expr, $b:expr $(,)?) => {{
231        match $crate::assert_approx_ne_as_result!($a, $b) {
232            Ok(x) => x,
233            Err(err) => panic!("{}", err),
234        }
235    }};
236    ($a:expr, $b:expr, $($message:tt)+) => {{
237        match $crate::assert_approx_ne_as_result!($a, $b) {
238            Ok(x) => x,
239            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
240        }
241    }};
242}
243
244#[cfg(test)]
245mod test_assert_approx_ne {
246    use std::panic;
247
248    #[test]
249    fn ne() {
250        let a: f32 = 1.0000001;
251        let b: f32 = 1.0000012;
252        let actual = assert_approx_ne!(a, b);
253        assert_eq!(actual, (1.0728836e-6, 1e-6));
254    }
255
256    #[test]
257    fn eq() {
258        let result = panic::catch_unwind(|| {
259            let a: f32 = 1.0000001;
260            let b: f32 = 1.0000011;
261            let _actual = assert_approx_ne!(a, b);
262        });
263        let message = concat!(
264            "assertion failed: `assert_approx_ne!(a, b)`\n",
265            "https://docs.rs/assertables/9.5.1/assertables/macro.assert_approx_ne.html\n",
266            "            a label: `a`,\n",
267            "            a debug: `1.0000001`,\n",
268            "            b label: `b`,\n",
269            "            b debug: `1.0000011`,\n",
270            "          | a - b |: `9.536743e-7`,\n",
271            "             approx: `1e-6`,\n",
272            " | a - b | > approx: false"
273        );
274        assert_eq!(
275            result
276                .unwrap_err()
277                .downcast::<String>()
278                .unwrap()
279                .to_string(),
280            message
281        );
282    }
283}
284
285/// Assert a number is approximately not equal to another.
286///
287/// Pseudocode:<br>
288/// | a - b | > 1e-6
289///
290/// This macro provides the same statements as [`assert_approx_ne`](macro.assert_approx_ne.html),
291/// except this macro's statements are only enabled in non-optimized
292/// builds by default. An optimized build will not execute this macro's
293/// statements unless `-C debug-assertions` is passed to the compiler.
294///
295/// This macro is useful for checks that are too expensive to be present
296/// in a release build but may be helpful during development.
297///
298/// The result of expanding this macro is always type checked.
299///
300/// An unchecked assertion allows a program in an inconsistent state to
301/// keep running, which might have unexpected consequences but does not
302/// introduce unsafety as long as this only happens in safe code. The
303/// performance cost of assertions, however, is not measurable in general.
304/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
305/// after thorough profiling, and more importantly, only in safe code!
306///
307/// This macro is intended to work in a similar way to
308/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
309///
310/// # Module macros
311///
312/// * [`assert_approx_ne`](macro@crate::assert_approx_ne)
313/// * [`assert_approx_ne`](macro@crate::assert_approx_ne)
314/// * [`debug_assert_approx_ne`](macro@crate::debug_assert_approx_ne)
315///
316#[macro_export]
317macro_rules! debug_assert_approx_ne {
318    ($($arg:tt)*) => {
319        if $crate::cfg!(debug_assertions) {
320            $crate::assert_approx_ne!($($arg)*);
321        }
322    };
323}