fluent_asserter/
number_approx_asserter.rs1use super::*;
2use num::traits::Pow;
3
4pub trait IsApproxEqual<T> {
5 fn is_approx_equal(&self, expected_value: T, delta: T);
6}
7
8macro_rules! abs_diff_unsigned_eq {
9 ($x:expr, $y:expr, $d:expr) => {
10 if (if $x > $y { $x - $y } else { $y - $x }) > $d {
11 panic!("AssertionError: not equal within delta"); }
13 };
14}
15
16macro_rules! abs_diff_signed_eq {
17 ($x:expr, $y:expr, $d:expr) => {
18 if (($x - $y).abs() > $d) {
19 panic!("AssertionError: not equal within delta"); }
21 };
22}
23
24macro_rules! abs_diff {
25 ($x:expr, $y:expr) => {
26 ($x - $y).abs()
27 };
28}
29
30macro_rules! generate_is_approx_equal_impl_for_signed {
31 ($TStructType:ident) => {
32 impl IsApproxEqual<$TStructType> for Asserter<$TStructType> {
33 fn is_approx_equal(&self, expected: $TStructType, delta: $TStructType) {
34 abs_diff_signed_eq!(self.value, expected, delta);
35 }
36 }
37 };
38}
39
40generate_is_approx_equal_impl_for_signed!(i8);
41generate_is_approx_equal_impl_for_signed!(i16);
42generate_is_approx_equal_impl_for_signed!(i32);
43generate_is_approx_equal_impl_for_signed!(i64);
44generate_is_approx_equal_impl_for_signed!(i128);
45
46macro_rules! generate_is_approx_equal_impl_for_unsigned {
47 ($TStructType:ident) => {
48 impl IsApproxEqual<$TStructType> for Asserter<$TStructType> {
49 fn is_approx_equal(&self, expected: $TStructType, delta: $TStructType) {
50 abs_diff_unsigned_eq!(self.value, expected, delta);
51 }
52 }
53 };
54}
55
56generate_is_approx_equal_impl_for_unsigned!(u8);
57generate_is_approx_equal_impl_for_unsigned!(u16);
58generate_is_approx_equal_impl_for_unsigned!(u32);
59generate_is_approx_equal_impl_for_unsigned!(u64);
60generate_is_approx_equal_impl_for_unsigned!(u128);
61
62macro_rules! get_length_of_rounder {
63 ($delta:expr) => {
64 $delta
65 .to_string()
66 .split('.')
67 .last()
68 .unwrap()
69 .len()
70 .to_string()
71 .parse()
72 .unwrap()
73 };
74}
75
76macro_rules! round {
77 ($TStructType:ident, $diff:expr,$rounder:expr) => {{
78 let number: $TStructType = format!("{}", $diff).parse().unwrap();
79 let number: $TStructType = (number * $rounder).round() / $rounder;
80
81 return number;
82 }};
83}
84
85impl IsApproxEqual<f64> for Asserter<f64> {
86 fn is_approx_equal(&self, expected_value: f64, delta: f64) {
87 let rounder = 10f64.pow(get_length_of_rounder_f64(delta));
88
89 let diff = abs_diff!(self.value, expected_value);
90
91 let diff_f64 = round_f64(diff, rounder);
92 let delta_f64 = round_f64(delta, rounder);
93
94 if diff_f64 > delta_f64 {
95 panic!(
96 "The number '{}' is not approximately equal to '{}' within delta '{}'",
97 self.name, expected_value, delta
98 )
99 }
100 }
101}
102
103impl IsApproxEqual<f32> for Asserter<f32> {
104 fn is_approx_equal(&self, expected_value: f32, delta: f32) {
105 let rounder = 10f32.pow(get_length_of_rounder_f32(delta));
106
107 let diff = abs_diff!(self.value, expected_value);
108
109 let diff_f32 = round_f32(diff, rounder);
110 let delta_f32 = round_f32(delta, rounder);
111
112 if diff_f32 > delta_f32 {
113 panic!(
114 "The number '{}' is not approximately equal to '{}' within delta '{}'",
115 self.name, expected_value, delta
116 )
117 }
118 }
119}
120
121fn get_length_of_rounder_f64<T>(delta: T) -> f64
122where
123 T: ToString,
124{
125 return get_length_of_rounder!(delta);
126}
127
128fn get_length_of_rounder_f32<T>(delta: T) -> f32
129where
130 T: ToString,
131{
132 return get_length_of_rounder!(delta);
133}
134
135fn round_f64<T>(diff: T, rounder: f64) -> f64
136where
137 T: std::fmt::Display,
138{
139 round!(f64, diff, rounder)
140}
141
142fn round_f32<T>(diff: T, rounder: f32) -> f32
143where
144 T: std::fmt::Display,
145{
146 round!(f32, diff, rounder)
147}