appro-eq 0.3.1

Approximately equal traits and assertion
Documentation
#[macro_use]
extern crate appro_eq;

#[cfg(feature = "num-complex")]
use num_complex::Complex;

#[cfg(feature = "num-rational")]
use num_rational::Rational;

#[cfg(feature = "ndarray")]
use ndarray::{arr1, arr2, arr3, ArrayD, IxDyn};

use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::sync::Arc;
use std::time::{Duration, Instant, SystemTime};

macro_rules! panic_test_rel {
    ($name:ident, $($arg:tt)*) => (
        mod $name {
            #[allow(unused_imports)]
            use super::*;

            #[test]
            #[should_panic]
            fn normal() {
                assert_appro_eq_rel!($($arg)*);
            }

            #[test]
            #[cfg_attr(debug_assertions, should_panic)]
            fn debug() {
                debug_assert_appro_eq_rel!($($arg)*);
            }
        }
    )
}

macro_rules! panic_test_abs {
    ($name:ident, $($arg:tt)*) => (
        mod $name {
            #[allow(unused_imports)]
            use super::*;

            #[test]
            #[should_panic]
            fn normal() {
                assert_appro_eq_abs!($($arg)*);
            }

            #[test]
            #[cfg_attr(debug_assertions, should_panic)]
            fn debug() {
                debug_assert_appro_eq_abs!($($arg)*);
            }
        }
    )
}

macro_rules! panic_test_none {
    ($name:ident, $($arg:tt)*) => (
        mod $name {
            #[allow(unused_imports)]
            use super::*;

            #[test]
            #[should_panic]
            fn normal() {
                assert_appro_eq!($($arg)*);
            }

            #[test]
            #[cfg_attr(debug_assertions, should_panic)]
            fn debug() {
                debug_assert_appro_eq!($($arg)*);
            }
        }
    )
}

macro_rules! panic_test_all {
    ($name:ident, $($arg:tt)*) => (
        mod $name {
            #[allow(unused_imports)]
            use super::*;
            panic_test_none!(none, $($arg)*);
            panic_test_abs!(abs, $($arg)*);
            panic_test_rel!(rel, $($arg)*);
        }
    )
}

macro_rules! ok_test_rel {
    ($name:ident, $($arg:tt)*) => (
        mod $name {
            #[allow(unused_imports)]
            use super::*;

            #[test]
            fn normal() {
                assert_appro_eq_rel!($($arg)*);
            }

            #[test]
            fn debug() {
                debug_assert_appro_eq_rel!($($arg)*);
            }
        }
    )
}

macro_rules! ok_test_abs {
    ($name:ident, $($arg:tt)*) => (
        mod $name {
            #[allow(unused_imports)]
            use super::*;

            #[test]
            fn normal() {
                assert_appro_eq_abs!($($arg)*);
            }

            #[test]
            fn debug() {
                debug_assert_appro_eq_abs!($($arg)*);
            }
        }
    )
}

macro_rules! ok_test_none {
    ($name:ident, $($arg:tt)*) => (
        mod $name {
            #[allow(unused_imports)]
            use super::*;

            #[test]
            fn normal() {
                assert_appro_eq!($($arg)*);
            }

            #[test]
            fn debug() {
                debug_assert_appro_eq!($($arg)*);
            }
        }
    )
}

macro_rules! ok_test_all {
    ($name:ident, $($arg:tt)*) => (
        mod $name {
            #[allow(unused_imports)]
            use super::*;
            ok_test_none!(none, $($arg)*);
            ok_test_abs!(abs, $($arg)*);
            ok_test_rel!(rel, $($arg)*);
        }
    )
}

ok_test_all!(
    it_should_not_panic_if_values_are_appro_equal,
    8f32,
    8f32 + 1e-7
);
ok_test_all!(
    it_should_not_panic_if_values_are_appro_equal_f64,
    1e-12f64 + 1e-25,
    1e-12_f64
);
ok_test_all!(compare_with_explicit_eps, 3f64, 4f64, 2f64);

panic_test_all!(
    it_should_panic_if_values_are_not_appro_equal,
    8f32,
    8f32 - 1e-5
);
panic_test_all!(bad_compare_with_explicit_eps, 3f64, 4f64, 1e-3f64);
panic_test_rel!(bad_compare_with_rel_div_zero_f32, 3f32, 0f32);
panic_test_rel!(bad_compare_with_rel_div_zero_f64, 3f64, 0f64);

ok_test_all!(
    it_should_not_panic_if_values_are_appro_equal_f32_f64,
    8f32,
    8f64 + 1e-7
);
panic_test_all!(
    it_should_panic_if_values_are_not_appro_equal_f32_f64,
    8f32,
    8f64 - 1e-5
);
panic_test_all!(bad_compare_with_explicit_eps_f32_f64, 3f32, 4f64, 1e-3f32);

ok_test_all!(
    it_should_not_panic_if_values_are_appro_equal_f64_f32,
    8f64,
    8f32 + 1e-7
);
panic_test_all!(
    it_should_panic_if_values_are_not_appro_equal_f64_f32,
    8f64,
    8f32 - 1e-5
);
panic_test_all!(bad_compare_with_explicit_eps_f64_f32, 3f64, 4f32, 1e-3f32);

ok_test_all!(
    compare_with_vector,
    vec![
        1f32,
        2.0,
        3.0,
        4.0,
        5.0,
        6.0,
        7.0 + 1e-8,
        8.0,
        9.0 - 1e-7,
        10.0,
    ],
    vec![1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 - 1e-9, 9.0, 10.0]
);

panic_test_all!(
    bad_compare_with_vector,
    vec![1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.01],
    vec![1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
);
panic_test_all!(
    bad_len_compare_with_vector,
    vec![1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
    vec![1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
);

ok_test_all!(
    compare_with_slice,
    &[
        1f32,
        2.0,
        3.0,
        4.0,
        5.0,
        6.0,
        7.0 + 1e-8,
        8.0,
        9.0 - 1e-7,
        10.0
    ] as &[f32],
    &[1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 - 1e-9, 9.0, 10.0] as &[f32]
);

panic_test_all!(
    bad_compare_with_slice,
    &[1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.01] as &[f32],
    &[1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0] as &[f32]
);
panic_test_all!(
    bad_len_compare_with_slice,
    &[1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] as &[f32],
    &[1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0] as &[f32]
);

ok_test_all!(
    compare_with_array,
    [
        1f32,
        2.0,
        3.0,
        4.0,
        5.0,
        6.0,
        7.0 + 1e-8,
        8.0,
        9.0 - 1e-7,
        10.0
    ],
    [1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 - 1e-9, 9.0, 10.0]
);

panic_test_all!(
    bad_compare_with_array,
    [1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.01],
    [1f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
);

#[cfg(feature = "num-complex")]
ok_test_all!(
    compare_with_complex,
    Complex::new(1.0f64, 0.0),
    Complex::new(1.0f64, 1e-12)
);

#[cfg(feature = "num-complex")]
panic_test_all!(
    bad_compare_with_complex,
    Complex::new(1.0f64, 0.0),
    Complex::new(1.0f64, 1e-8)
);

macro_rules! type_unsigned_impls {
    ($($T:ident)+) => {
        $(
            mod $T {
                use core::$T;
                ok_test_all!(it_should_not_panic_if_values_are_appro_equal, $T::from(1_u8), $T::from(1_u8));
                panic_test_all!(it_should_panic_if_values_are_not_appro_equal, $T::from(0_u8), $T::from(1_u8));
                panic_test_rel!(it_should_panic_if_values_are_rel_div_zero, $T::from(1_u8), $T::from(0_u8));
            }
        )+
    }
}

macro_rules! type_signed_impls {
    ($($T:ident)+) => {
        $(
            mod $T {
                use core::$T;
                ok_test_all!(it_should_not_panic_if_values_are_appro_equal, $T::from(1_i8), $T::from(1_i8));
                panic_test_all!(it_should_panic_if_values_are_not_appro_equal, $T::from(0_i8), $T::from(1_i8));
                panic_test_rel!(it_should_panic_if_values_are_rel_div_zero, $T::from(1_i8), $T::from(0_i8));
            }
        )+
    }
}

type_signed_impls! { i8 i16 i32 i64 i128 }
type_unsigned_impls! { u8 u16 u32 u64 u128 }

ok_test_all!(
    compare_with_option_both_some,
    Some(1f64),
    Some(1.0 + 1e-12)
);

ok_test_all!(
    compare_with_option_both_none,
    Option::<f64>::None,
    Option::<f64>::None
);

panic_test_all!(
    bad_compare_with_option_both_some,
    Some(2f64),
    Some(1f64)
);
panic_test_all!(
    bad_compare_with_option_left_some,
    Some(2f64),
    Option::<f64>::None
);
panic_test_all!(
    bad_compare_with_option_right_some,
    Option::<f64>::None,
    Some(1f64)
);

#[cfg(feature = "num-rational")]
ok_test_all!(
    compare_with_ratio_mindiff,
    Rational::new(1001, 1000),
    Rational::new(1002, 1001),
    Rational::new(1, 10000)
);

#[cfg(feature = "num-rational")]
ok_test_all!(
    compare_with_ratio_equal,
    Rational::new(1, 1000),
    Rational::new(1, 1000)
);

#[cfg(feature = "num-rational")]
panic_test_all!(
    bad_compare_with_ratio,
    Rational::new(1, 1000),
    Rational::new(1, 1001),
    Rational::new(1, 1000000000)
);

ok_test_all!(compare_with_rc, Rc::new(1.0), Rc::new(1.0));
panic_test_all!(bad_compare_with_rc, Rc::new(1.0), Rc::new(1.00001));

ok_test_all!(compare_with_arc, Arc::new(1.0), Arc::new(1.0));
panic_test_all!(bad_compare_with_arc, Arc::new(1.0), Arc::new(1.00001));

ok_test_all!(
    compare_with_weak,
    Rc::downgrade(&Rc::new(1.0)),
    Rc::downgrade(&Rc::new(1.0))
);
panic_test_all!(
    bad_compare_with_weak,
    Rc::downgrade(&Rc::new(1.0)),
    Rc::downgrade(&Rc::new(1.00001))
);

ok_test_all!(compare_with_cell, Cell::new(1.0), Cell::new(1.0));
panic_test_all!(bad_compare_with_cell, Cell::new(1.0), Cell::new(1.00001));

ok_test_all!(compare_with_refcell, RefCell::new(1.0), RefCell::new(1.0));
panic_test_all!(
    bad_compare_with_refcell,
    RefCell::new(1.0),
    RefCell::new(1.00001)
);

#[cfg(feature = "ndarray")]
ok_test_all!(
    compare_with_ndarray1d,
    arr1(&[1f64, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]),
    arr1(&[1f64, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
);

#[cfg(feature = "ndarray")]
ok_test_all!(
    compare_with_ndarray2d,
    arr2(&[[1f64, 2.0, 3.0, 4.0, 5.0], [6.0, 7.0, 8.0, 9.0, 10.0]]),
    arr2(&[[1f64, 2.0, 3.0, 4.0, 5.0], [6.0, 7.0, 8.0, 9.0, 10.0]])
);

#[cfg(feature = "ndarray")]
ok_test_all!(
    compare_with_ndarray3d,
    arr3(&[[[1f64, 2.0], [4.0, 5.0]], [[6.0, 7.0], [9.0, 10.0]]]),
    arr3(&[[[1f64, 2.0], [4.0, 5.0]], [[6.0, 7.0], [9.0, 10.0]]])
);

#[cfg(feature = "ndarray")]
ok_test_abs!(
    compare_with_ndarraynd,
    ArrayD::<f64>::zeros(IxDyn(&[2, 3, 4, 5, 6, 7])),
    ArrayD::<f64>::zeros(IxDyn(&[2, 3, 4, 5, 6, 7]))
);

#[cfg(feature = "ndarray")]
panic_test_all!(
    bad_compare_with_ndarray1d,
    arr1(&[1f64, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0001]),
    arr1(&[1f64, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
);

#[cfg(feature = "ndarray")]
panic_test_all!(
    bad_compare_with_ndarray2d_val,
    arr2(&[[1f64, 2.0, 3.0, 4.0, 5.0], [6.0, 7.0, 8.0, 9.0, 10.0001]]),
    arr2(&[[1f64, 2.0, 3.0, 4.0, 5.0], [6.0, 7.0, 8.0, 9.0, 10.0]])
);

#[cfg(feature = "ndarray")]
panic_test_all!(
    bad_compare_with_ndarray2d_len,
    arr2(&[[1f64, 2.0, 3.0, 4.0, 5.0], [6.0, 7.0, 8.0, 9.0, 10.0]]),
    arr2(&[[1f64, 2.0], [3.0, 4.0], [5.0, 6.0], [7.0, 8.0], [9.0, 10.0]])
);

#[cfg(feature = "ndarray")]
panic_test_all!(
    bad_compare_with_ndarray3d,
    arr3(&[[[1f64, 2.0], [4.0, 5.0]], [[6.0, 7.0], [9.0, 10.0001]]]),
    arr3(&[[[1f64, 2.0], [4.0, 5.0]], [[6.0, 7.0], [9.0, 10.0]]])
);

#[cfg(feature = "ndarray")]
panic_test_all!(
    bad_compare_with_ndarraynd,
    ArrayD::<f64>::zeros(IxDyn(&[2, 3, 4, 5, 6, 7])),
    ArrayD::<f64>::zeros(IxDyn(&[2, 3, 4, 5, 6]))
);

#[cfg(feature = "ndarray")]
panic_test_rel!(
    compare_with_ndarraynd_rel,
    ArrayD::<f64>::zeros(IxDyn(&[2, 3, 4, 5, 6, 7])),
    ArrayD::<f64>::zeros(IxDyn(&[2, 3, 4, 5, 6, 7]))
);

#[cfg(feature = "ndarray")]
panic_test_all!(
    bad_compare_with_ndarray3d_f32_f64,
    arr3(&[[[1f32, 2.0], [4.0, 5.0]], [[6.0, 7.0], [9.0, 10.001]]]),
    arr3(&[[[1f64, 2.0], [4.0, 5.0]], [[6.0, 7.0], [9.0, 10.0]]])
);

ok_test_none!(
    compare_with_systemtime_none,
    SystemTime::now(),
    SystemTime::now()
);

ok_test_abs!(
    compare_with_systemtime_abs,
    SystemTime::now(),
    SystemTime::now()
);

panic_test_none!(
    bad_compare_with_systemtime_none,
    SystemTime::now() - Duration::new(10, 0),
    SystemTime::now()
);

panic_test_abs!(
    bad_compare_with_systemtime_abs,
    SystemTime::now() - Duration::new(10, 0),
    SystemTime::now()
);

ok_test_abs!(compare_with_instant_abs, Instant::now(), Instant::now());

ok_test_none!(compare_with_instant_none, Instant::now(), Instant::now());

panic_test_abs!(
    bad_compare_with_instant_abs,
    Instant::now() - Duration::new(10, 0),
    Instant::now()
);

panic_test_none!(
    bad_compare_with_instant_none,
    Instant::now() - Duration::new(10, 0),
    Instant::now()
);

ok_test_all!(
    compare_with_duration,
    Duration::new(10, 0),
    Duration::new(10, 1)
);

panic_test_all!(
    bad_compare_with_duration,
    Duration::new(9, 0),
    Duration::new(10, 1)
);