2

I have a test assertion that looks like this

assert_eq!(-0.000031989493, res);

which works for the test. But when I run Clippy on my test it complains.

error: strict comparison of `f32` or `f64`
   --> src/main.rs:351:9
    |
351 |         assert_eq!(-0.000031989493, res);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

I've looked at the provided link https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp and rewrote it like this instead.

assert_eq!(
    true,
    (res - -0.000031989493).abs() < f32::EPSILON
);

But that makes the test less readable and if the test fails I can't see the result of what I'm testing in the output.

How should I write my f32 comparison assertions so that Clippy is happy and so that the tests still output the values in the terminal if it fails?

Or should I just not run Clippy on my tests?

Thanks!

mottosson
  • 3,283
  • 4
  • 35
  • 73
  • 1
    Make your own macro or function, say `assert_almost_eq!` or look for already made by somebody – Alexey S. Larionov Jan 24 '21 at 18:11
  • 1
    Nobody can answer this for you because the definition of what's "close enough" to compare equal varies according to what, specifically, you're doing. Sometimes "equal" means within a certain range; sometimes it means within a certain percentage of a target value; sometimes it means just this exact value, nothing different. Epsilons are there to help with *some* of those cases but there is no one way to compare using epsilon either. You must decide whether Clippy's suggestion is right or not based on what your program is doing. – trent Jan 25 '21 at 12:50
  • (Note that you can allow certain things in Clippy on a lint-by-lint basis; you don't have to go all the way to "don't run clippy at all") – trent Jan 25 '21 at 12:50

1 Answers1

0

Ok so I've copied and altered the assert_eq macro a bit

macro_rules! assert_almost_eq {
    ($left:expr, $right:expr, $prec:expr) => {{
        match (&$left, &$right) {
            (left_val, right_val) => {
                let diff = (left_val - right_val).abs();

                if diff > $prec {
                    panic!(
                        "assertion failed: `(left == right)`\n      left: `{:?}`,\n     right: `{:?}`",
                        &*left_val, &*right_val
                    )
                }
            }
        }
    }};
}

I don't really understand everything, like the reason for the match, but it seems to solve my problem.

mottosson
  • 3,283
  • 4
  • 35
  • 73
  • 2
    You don't need to rewrite macro, you can add custom panic message like this : `assert!((actual - expected).abs() < f32::EPSILON, "left: {:?} not equal right: {:?}", actual, expected)` – Ömer Erden Jan 24 '21 at 19:16
  • Thanks, that's really good to know. But in this case it would bloat my tests a bit since I compare a bunch of values in every test. – mottosson Jan 24 '21 at 21:07