1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::{
16     description::Description,
17     matcher::{Matcher, MatcherResult},
18 };
19 use num_traits::{Float, FloatConst};
20 use std::fmt::Debug;
21 
22 /// Matches a value equal within `max_abs_error` of `expected`.
23 ///
24 /// The type `T` of the actual, `expected`, and `max_abs_error` values must
25 /// implement [`Float`].
26 ///
27 /// The values `expected` and `max_abs_error` may not be NaN. The value
28 /// `max_abs_error` must be non-negative. The matcher panics on construction
29 /// otherwise.
30 ///
31 /// ```
32 /// # use googletest::prelude::*;
33 /// # fn should_pass_1() -> Result<()> {
34 /// verify_that!(1.0, near(1.0, 0.1))?; // Passes
35 /// verify_that!(1.01, near(1.0, 0.1))?; // Passes
36 /// verify_that!(1.25, near(1.0, 0.25))?; // Passes
37 /// verify_that!(0.75, near(1.0, 0.25))?; // Passes
38 /// #     Ok(())
39 /// # }
40 /// # fn should_fail_1() -> Result<()> {
41 /// verify_that!(1.101, near(1.0, 0.1))?; // Fails
42 /// #     Ok(())
43 /// # }
44 /// # fn should_fail_2() -> Result<()> {
45 /// verify_that!(0.899, near(1.0, 0.1))?; // Fails
46 /// #     Ok(())
47 /// # }
48 /// # fn should_pass_2() -> Result<()> {
49 /// verify_that!(100.25, near(100.0, 0.25))?; // Passes
50 /// #     Ok(())
51 /// # }
52 /// # should_pass_1().unwrap();
53 /// # should_fail_1().unwrap_err();
54 /// # should_fail_2().unwrap_err();
55 /// # should_pass_2().unwrap();
56 /// ```
57 ///
58 /// The default behaviour for special values is consistent with the IEEE
59 /// floating point standard. Thus infinity is infinitely far away from any
60 /// floating point value:
61 ///
62 /// ```
63 /// # use googletest::prelude::*;
64 /// # fn should_fail_1() -> Result<()> {
65 /// verify_that!(f64::INFINITY, near(0.0, f64::MAX))?; // Fails
66 /// #     Ok(())
67 /// # }
68 /// # fn should_fail_2() -> Result<()> {
69 /// verify_that!(0.0, near(f64::INFINITY, f64::MAX))?; // Fails
70 /// #     Ok(())
71 /// # }
72 /// # fn should_fail_3() -> Result<()> {
73 /// verify_that!(f64::INFINITY, near(f64::INFINITY, f64::MAX))?; // Fails
74 /// #     Ok(())
75 /// # }
76 /// # should_fail_1().unwrap_err();
77 /// # should_fail_2().unwrap_err();
78 /// # should_fail_3().unwrap_err();
79 /// ```
80 ///
81 /// Similarly, by default, `NaN` is infinitely far away from any value:
82 ///
83 /// ```
84 /// # use googletest::prelude::*;
85 /// # fn should_fail_1() -> Result<()> {
86 /// verify_that!(f64::NAN, near(0.0, f64::MAX))?; // Fails
87 /// #     Ok(())
88 /// # }
89 /// # fn should_fail_2() -> Result<()> {
90 /// verify_that!(0.0, near(f64::NAN, f64::MAX))?; // Fails
91 /// #     Ok(())
92 /// # }
93 /// # fn should_fail_3() -> Result<()> {
94 /// verify_that!(f64::NAN, near(f64::NAN, f64::MAX))?; // Fails
95 /// #     Ok(())
96 /// # }
97 /// # should_fail_1().unwrap_err();
98 /// # should_fail_2().unwrap_err();
99 /// # should_fail_3().unwrap_err();
100 /// ```
101 ///
102 /// To treat two `NaN` values as equal, use the method
103 /// [`NearMatcher::nans_are_equal`].
104 ///
105 /// ```
106 /// # use googletest::prelude::*;
107 /// # fn should_pass() -> Result<()> {
108 /// verify_that!(f64::NAN, near(f64::NAN, f64::MAX).nans_are_equal())?; // Passes
109 /// #     Ok(())
110 /// # }
111 /// # should_pass().unwrap();
112 /// ```
near<T: Debug + Float + Copy>(expected: T, max_abs_error: T) -> NearMatcher<T>113 pub fn near<T: Debug + Float + Copy>(expected: T, max_abs_error: T) -> NearMatcher<T> {
114     if max_abs_error.is_nan() {
115         panic!("max_abs_error must not be NaN");
116     }
117     if max_abs_error < T::zero() {
118         panic!("max_abs_error must be non-negative");
119     }
120     NearMatcher { expected, max_abs_error, nans_are_equal: false }
121 }
122 
123 /// Matches a value approximately equal to `expected`.
124 ///
125 /// This automatically computes a tolerance from the magnitude of `expected` and
126 /// matches any actual value within this tolerance of the expected value. The
127 /// tolerance is chosen to account for the inaccuracies in most ordinary
128 /// floating point calculations.
129 ///
130 /// Otherwise this works analogously to [`near`]; see its documentation for
131 /// further notes.
approx_eq<T: Debug + Float + FloatConst + Copy>(expected: T) -> NearMatcher<T>132 pub fn approx_eq<T: Debug + Float + FloatConst + Copy>(expected: T) -> NearMatcher<T> {
133     // The FloatConst trait doesn't offer 2 as a constant but does offer 1.
134     let five_bits_of_mantissa = (T::one() + T::one()).powi(5);
135     let abs_tolerance = five_bits_of_mantissa * T::epsilon();
136     let max_abs_error = T::max(expected.abs() * abs_tolerance, abs_tolerance);
137     NearMatcher { expected, max_abs_error, nans_are_equal: false }
138 }
139 
140 /// A matcher which matches floating-point numbers approximately equal to its
141 /// expected value.
142 pub struct NearMatcher<T: Debug> {
143     expected: T,
144     max_abs_error: T,
145     nans_are_equal: bool,
146 }
147 
148 impl<T: Debug> NearMatcher<T> {
149     /// Configures this instance to treat two NaNs as equal.
150     ///
151     /// This behaviour differs from the IEEE standad for floating point which
152     /// treats two NaNs as infinitely far apart.
nans_are_equal(mut self) -> Self153     pub fn nans_are_equal(mut self) -> Self {
154         self.nans_are_equal = true;
155         self
156     }
157 
158     /// Configures this instance to treat two NaNs as not equal.
159     ///
160     /// This behaviour complies with the IEEE standad for floating point. It is
161     /// the default behaviour for this matcher, so invoking this method is
162     /// usually redunant.
nans_are_not_equal(mut self) -> Self163     pub fn nans_are_not_equal(mut self) -> Self {
164         self.nans_are_equal = false;
165         self
166     }
167 }
168 
169 impl<T: Debug + Float> Matcher for NearMatcher<T> {
170     type ActualT = T;
171 
matches(&self, actual: &T) -> MatcherResult172     fn matches(&self, actual: &T) -> MatcherResult {
173         if self.nans_are_equal && self.expected.is_nan() && actual.is_nan() {
174             return MatcherResult::Match;
175         }
176 
177         let delta = *actual - self.expected;
178         if delta >= -self.max_abs_error && delta <= self.max_abs_error {
179             MatcherResult::Match
180         } else {
181             MatcherResult::NoMatch
182         }
183     }
184 
describe(&self, matcher_result: MatcherResult) -> Description185     fn describe(&self, matcher_result: MatcherResult) -> Description {
186         match matcher_result {
187             MatcherResult::Match => {
188                 format!("is within {:?} of {:?}", self.max_abs_error, self.expected).into()
189             }
190             MatcherResult::NoMatch => {
191                 format!("isn't within {:?} of {:?}", self.max_abs_error, self.expected).into()
192             }
193         }
194     }
195 }
196 
197 #[cfg(test)]
198 mod tests {
199     use super::{approx_eq, near};
200     use crate::matcher::{Matcher, MatcherResult};
201     use crate::prelude::*;
202 
203     #[test]
matches_value_inside_range() -> Result<()>204     fn matches_value_inside_range() -> Result<()> {
205         let matcher = near(1.0f64, 0.1f64);
206 
207         let result = matcher.matches(&1.0f64);
208 
209         verify_that!(result, eq(MatcherResult::Match))
210     }
211 
212     #[test]
matches_value_at_low_end_of_range() -> Result<()>213     fn matches_value_at_low_end_of_range() -> Result<()> {
214         let matcher = near(1.0f64, 0.1f64);
215 
216         let result = matcher.matches(&0.9f64);
217 
218         verify_that!(result, eq(MatcherResult::Match))
219     }
220 
221     #[test]
matches_value_at_high_end_of_range() -> Result<()>222     fn matches_value_at_high_end_of_range() -> Result<()> {
223         let matcher = near(1.0f64, 0.25f64);
224 
225         let result = matcher.matches(&1.25f64);
226 
227         verify_that!(result, eq(MatcherResult::Match))
228     }
229 
230     #[test]
does_not_match_value_below_low_end_of_range() -> Result<()>231     fn does_not_match_value_below_low_end_of_range() -> Result<()> {
232         let matcher = near(1.0f64, 0.1f64);
233 
234         let result = matcher.matches(&0.899999f64);
235 
236         verify_that!(result, eq(MatcherResult::NoMatch))
237     }
238 
239     #[test]
does_not_match_value_above_high_end_of_range() -> Result<()>240     fn does_not_match_value_above_high_end_of_range() -> Result<()> {
241         let matcher = near(1.0f64, 0.1f64);
242 
243         let result = matcher.matches(&1.100001f64);
244 
245         verify_that!(result, eq(MatcherResult::NoMatch))
246     }
247 
248     #[test]
nan_is_not_near_a_number() -> Result<()>249     fn nan_is_not_near_a_number() -> Result<()> {
250         let matcher = near(0.0f64, f64::MAX);
251 
252         let result = matcher.matches(&f64::NAN);
253 
254         verify_that!(result, eq(MatcherResult::NoMatch))
255     }
256 
257     #[test]
nan_is_not_near_nan_by_default() -> Result<()>258     fn nan_is_not_near_nan_by_default() -> Result<()> {
259         verify_that!(f64::NAN, not(near(f64::NAN, f64::MAX)))
260     }
261 
262     #[test]
nan_is_not_near_nan_when_explicitly_configured() -> Result<()>263     fn nan_is_not_near_nan_when_explicitly_configured() -> Result<()> {
264         verify_that!(f64::NAN, not(near(f64::NAN, f64::MAX).nans_are_not_equal()))
265     }
266 
267     #[test]
nan_is_near_nan_if_nans_are_equal() -> Result<()>268     fn nan_is_near_nan_if_nans_are_equal() -> Result<()> {
269         verify_that!(f64::NAN, near(f64::NAN, f64::MAX).nans_are_equal())
270     }
271 
272     #[test]
nan_is_not_near_number_when_nans_are_equal() -> Result<()>273     fn nan_is_not_near_number_when_nans_are_equal() -> Result<()> {
274         verify_that!(f64::NAN, not(near(0.0, f64::MAX).nans_are_equal()))
275     }
276 
277     #[test]
number_is_not_near_nan_when_nans_are_equal() -> Result<()>278     fn number_is_not_near_nan_when_nans_are_equal() -> Result<()> {
279         verify_that!(0.0, not(near(f64::NAN, f64::MAX).nans_are_equal()))
280     }
281 
282     #[test]
inf_is_not_near_inf() -> Result<()>283     fn inf_is_not_near_inf() -> Result<()> {
284         let matcher = near(f64::INFINITY, f64::MAX);
285 
286         let result = matcher.matches(&f64::INFINITY);
287 
288         verify_that!(result, eq(MatcherResult::NoMatch))
289     }
290 
291     #[test]
inf_is_not_near_a_number() -> Result<()>292     fn inf_is_not_near_a_number() -> Result<()> {
293         let matcher = near(f64::INFINITY, f64::MAX);
294 
295         let result = matcher.matches(&f64::MIN);
296 
297         verify_that!(result, eq(MatcherResult::NoMatch))
298     }
299 
300     #[test]
any_two_numbers_are_within_inf_of_each_other() -> Result<()>301     fn any_two_numbers_are_within_inf_of_each_other() -> Result<()> {
302         let matcher = near(f64::MIN, f64::INFINITY);
303 
304         let result = matcher.matches(&f64::MAX);
305 
306         verify_that!(result, eq(MatcherResult::Match))
307     }
308 
309     #[::core::prelude::v1::test]
310     #[should_panic]
panics_if_max_abs_error_is_nan()311     fn panics_if_max_abs_error_is_nan() {
312         near(0.0, f64::NAN);
313     }
314 
315     #[::core::prelude::v1::test]
316     #[should_panic]
panics_if_tolerance_is_negative()317     fn panics_if_tolerance_is_negative() {
318         near(0.0, -1.0);
319     }
320 
321     #[test]
approx_eq_matches_equal_number() -> Result<()>322     fn approx_eq_matches_equal_number() -> Result<()> {
323         verify_that!(1.0f64, approx_eq(1.0f64))
324     }
325 
326     #[test]
approx_eq_matches_really_close_f64_number() -> Result<()>327     fn approx_eq_matches_really_close_f64_number() -> Result<()> {
328         verify_that!(1.0f64, approx_eq(1.0 + 16.0 * f64::EPSILON))
329     }
330 
331     #[test]
approx_eq_matches_really_close_f64_number_to_large_number() -> Result<()>332     fn approx_eq_matches_really_close_f64_number_to_large_number() -> Result<()> {
333         verify_that!(1000f64, approx_eq(1000.0 + 16000.0 * f64::EPSILON))
334     }
335 
336     #[test]
approx_eq_matches_really_close_f64_number_to_zero() -> Result<()>337     fn approx_eq_matches_really_close_f64_number_to_zero() -> Result<()> {
338         verify_that!(16.0 * f64::EPSILON, approx_eq(0.0))
339     }
340 
341     #[test]
approx_eq_matches_really_close_f32_number() -> Result<()>342     fn approx_eq_matches_really_close_f32_number() -> Result<()> {
343         verify_that!(1.0f32, approx_eq(1.0 + 16.0 * f32::EPSILON))
344     }
345 
346     #[test]
approx_eq_does_not_match_distant_number() -> Result<()>347     fn approx_eq_does_not_match_distant_number() -> Result<()> {
348         verify_that!(0.0f64, not(approx_eq(1.0f64)))
349     }
350 }
351