1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use crate::internal::fmt::MaybeDebug;
use crate::internal::{ArgumentMatcher, MaybeDebugWrapper};
use nameof::name_of;
use nearly_eq::NearlyEq;
use std::fmt::{self, Debug};

/// Creates a new `ArgumentMatcher` that matches against values using [`NearlyEq`]
pub fn nearly_eq<T, U>(value: T) -> NearlyEqArgumentMatcher<T, U>
where
    T: NearlyEq<T, U> + MaybeDebug,
    U: MaybeDebug,
{
    NearlyEqArgumentMatcher {
        value,
        accuracy: T::eps(),
    }
}

/// Creates a new `ArgumentMatcher` that matches against values using [`NearlyEq`]
pub fn nearly_eq_with_accuracy<T, U>(value: T, accuracy: U) -> NearlyEqArgumentMatcher<T, U>
where
    T: NearlyEq<T, U> + MaybeDebug,
    U: MaybeDebug,
{
    NearlyEqArgumentMatcher { value, accuracy }
}

pub struct NearlyEqArgumentMatcher<T, U>
where
    T: NearlyEq<T, U> + MaybeDebug,
    U: MaybeDebug,
{
    value: T,
    accuracy: U,
}

impl<T, U> Debug for NearlyEqArgumentMatcher<T, U>
where
    T: NearlyEq<T, U> + MaybeDebug,
    U: MaybeDebug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct(name_of!(type NearlyEqArgumentMatcher<T, U>))
            .field(
                name_of!(value in NearlyEqArgumentMatcher<T, U>),
                &MaybeDebugWrapper(&self.value),
            )
            .field(
                name_of!(accuracy in NearlyEqArgumentMatcher<T, U>),
                &MaybeDebugWrapper(&self.accuracy),
            )
            .finish()
    }
}

impl<T, U> ArgumentMatcher<T> for NearlyEqArgumentMatcher<T, U>
where
    T: NearlyEq<T, U> + MaybeDebug,
    U: MaybeDebug,
{
    fn matches_argument(&self, input: &T) -> bool {
        NearlyEq::eq(&self.value, input, &self.accuracy)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn float_is_not_nearly_equivalent_to_different_float() {
        let first_value = 3.0;
        let second_value = first_value + 1.0;

        assert!(!nearly_eq(first_value).matches_argument(&second_value));
    }

    #[test]
    fn float_is_nearly_equivalent_to_slightly_different_float() {
        let first_value = 3.0;
        let second_value = first_value + 0.000_000_000_000_1;

        assert!(nearly_eq(first_value).matches_argument(&second_value));
    }

    #[test]
    fn float_is_nearly_equal_to_itself() {
        let first_value = 3.0;
        let second_value = first_value;

        assert!(nearly_eq(first_value).matches_argument(&second_value));
    }

    #[test]
    fn float_is_not_nearly_equal_to_different_float_with_no_accuracy() {
        let first_value = 3.0;
        let second_value = first_value + 1.0;
        let accuracy = 0.0;

        assert!(!nearly_eq_with_accuracy(first_value, accuracy).matches_argument(&second_value));
    }

    #[test]
    fn float_is_not_nearly_equal_to_different_float_with_same_accuracy_as_difference() {
        let first_value = 3.0;
        let second_value = first_value + 0.1;
        let accuracy = 0.1;

        assert!(!nearly_eq_with_accuracy(first_value, accuracy).matches_argument(&second_value));
    }

    #[test]
    fn float_is_nearly_equal_to_different_float_low_accuracy() {
        let first_value = 3.0;
        let second_value = first_value + 0.01;
        let accuracy = 0.1;

        assert!(nearly_eq_with_accuracy(first_value, accuracy).matches_argument(&second_value));
    }

    #[test]
    fn float_is_not_nearly_equal_to_different_float_with_highest_accuracy() {
        let first_value = 3.0;
        let second_value = first_value + 0.1;
        let accuracy = 0.0;

        assert!(!nearly_eq_with_accuracy(first_value, accuracy).matches_argument(&second_value));
    }

    #[test]
    fn float_is_nearly_equal_to_itself_with_highest_accuracy() {
        let first_value = 3.0;
        let second_value = first_value;
        let accuracy = 0.0;

        assert!(nearly_eq_with_accuracy(first_value, accuracy).matches_argument(&second_value));
    }
}