Skip to main content

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