expectest/matchers/
floats.rs

1use crate::core::{Join, Matcher};
2use num_traits::{self, Float};
3use std::fmt;
4
5/// A matcher for `be_close_to` assertions for float numbers.
6pub struct BeCloseTo<E> {
7    expected: E,
8    delta: E,
9}
10
11/// Returns a new `BeCloseTo` matcher with default `delta` equal to `0.001`.
12pub fn be_close_to<E>(expected: E) -> BeCloseTo<E>
13where
14    E: Float,
15{
16    BeCloseTo {
17        expected: expected,
18        delta: num_traits::cast(0.001).unwrap(),
19    }
20}
21
22impl<E> BeCloseTo<E> {
23    /// Sets new `delta` value.
24    pub fn delta(mut self, v: E) -> BeCloseTo<E> {
25        self.delta = v;
26        self
27    }
28}
29
30impl<E> Matcher<E, E> for BeCloseTo<E>
31where
32    E: Float + fmt::Debug,
33{
34    fn failure_message(&self, join: Join, actual: &E) -> String {
35        format!(
36            "expected {} be close to <{:?}> ±{:?}, got <{:?}>",
37            join, self.expected, self.delta, actual
38        )
39    }
40
41    fn matches(&self, actual: &E) -> bool {
42        if *actual == self.expected {
43            true
44        } else {
45            (self.expected - *actual).abs() - self.delta <= E::zero()
46        }
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::be_close_to;
53    use crate::core::expect;
54
55    #[test]
56    fn close_to_one_and_half_failure_message() {
57        expect(0.5)
58            .to(be_close_to(1.5))
59            .assert_eq_message("expected to be close to <1.5> ±0.001, got <0.5>");
60    }
61
62    #[test]
63    fn to_not_be_close_to_one_and_half_failure_message() {
64        expect(1.4991)
65            .not_to(be_close_to(1.5))
66            .assert_eq_message("expected not to be close to <1.5> ±0.001, got <1.4991>");
67    }
68
69    #[test]
70    fn close_to_one_and_half_delta_failure_message() {
71        expect(0.5)
72            .to(be_close_to(1.5).delta(0.1))
73            .assert_eq_message("expected to be close to <1.5> ±0.1, got <0.5>");
74    }
75}