Skip to main content

test_helpers/api/
evaluate_vector.rs

1// evaluate_vector.rs : src/api
2
3use crate::{
4    traits::{
5        ApproximateEqualityEvaluator,
6        TestableAsF64,
7    },
8    ComparisonResult,
9    VectorComparisonResult,
10};
11
12use super::evaluate_scalar_eq_approx;
13
14use std::{
15    convert as std_convert,
16    fmt as std_fmt,
17};
18
19
20// API functions
21
22/// Compares two vectors element-wise using `evaluator` without asserting.
23///
24/// `expected` and `actual` may be slices, arrays, or [`Vec`]; each element
25/// pair is compared via [`evaluate_scalar_eq_approx`].
26///
27/// Used by [`assert_vector_eq_approx!`] and
28/// [`assert_vector_ne_approx!`]; may also be used when building custom
29/// vector assertion macros.
30///
31/// # Returns
32///
33/// A tuple of:
34///
35/// * [`VectorComparisonResult`];
36/// * `margin_factor` from the first inexact element match, if any;
37/// * `multiplier_factor` from the first inexact element match, if any;
38///
39/// When lengths differ, returns
40/// [`VectorComparisonResult::DifferentLengths`]
41/// with `(None, None)` factors.
42///
43/// # Examples
44///
45/// ```
46/// use test_helpers::{
47///     evaluate_vector_eq_approx,
48///     multiplier,
49///     VectorComparisonResult,
50/// };
51///
52/// let expected = &[3.0, -40404.0, 1.23456];
53/// let actual = vec![3.0, -40410.0, 1.234567];
54/// let (result, _, _) =
55///     evaluate_vector_eq_approx(&expected, &actual, &multiplier(0.00015));
56/// assert!(matches!(result, VectorComparisonResult::ApproximatelyEqual));
57/// ```
58pub fn evaluate_vector_eq_approx<T_expected, T_actual, T_expectedElement, T_actualElement>(
59    expected : &T_expected,
60    actual : &T_actual,
61    evaluator : &dyn ApproximateEqualityEvaluator,
62) -> (
63    VectorComparisonResult, // comparison_result
64    Option<f64>,            // margin_factor
65    Option<f64>,            // multiplier_factor
66)
67where
68    T_expected : std_convert::AsRef<[T_expectedElement]>,
69    T_actual : std_convert::AsRef<[T_actualElement]>,
70    T_expectedElement : TestableAsF64 + std_fmt::Debug,
71    T_actualElement : TestableAsF64 + std_fmt::Debug,
72{
73    let expected = expected.as_ref();
74    let actual = actual.as_ref();
75
76    let expected_length = expected.len();
77    let actual_length = actual.len();
78
79    if expected_length != actual_length {
80        (
81            VectorComparisonResult::DifferentLengths {
82                expected_length,
83                actual_length,
84            },
85            None,
86            None,
87        )
88    } else {
89        let mut any_inexact = false;
90        let mut margin_factor = None;
91        let mut multiplier_factor = None;
92
93        for ix in 0..expected_length {
94            let expected_element = &expected[ix];
95            let actual_element = &actual[ix];
96
97            let (scalar_comparison_result, scalar_margin_factor, scalar_multiplier_factor) =
98                evaluate_scalar_eq_approx(expected_element, actual_element, evaluator);
99
100            match scalar_comparison_result {
101                ComparisonResult::ExactlyEqual => (),
102                ComparisonResult::ApproximatelyEqual => {
103                    if !any_inexact {
104                        any_inexact = true;
105                        margin_factor = scalar_margin_factor;
106                        multiplier_factor = scalar_multiplier_factor;
107                    }
108                },
109                ComparisonResult::Unequal => {
110                    let (expected_value_of_first_unequal_element, actual_value_of_first_unequal_element) = {
111                        let expected : &dyn TestableAsF64 = &expected[ix];
112                        let actual : &dyn TestableAsF64 = &actual[ix];
113
114                        let expected = expected.testable_as_f64();
115                        let actual = actual.testable_as_f64();
116
117                        (expected, actual)
118                    };
119
120                    return (
121                        VectorComparisonResult::UnequalElements {
122                            index_of_first_unequal_element : ix,
123                            expected_value_of_first_unequal_element,
124                            actual_value_of_first_unequal_element,
125                        },
126                        scalar_margin_factor,
127                        scalar_multiplier_factor,
128                    );
129                },
130            };
131        }
132
133        (
134            if any_inexact {
135                VectorComparisonResult::ApproximatelyEqual
136            } else {
137                VectorComparisonResult::ExactlyEqual
138            },
139            margin_factor,
140            multiplier_factor,
141        )
142    }
143}
144
145
146// ///////////////////////////// end of file //////////////////////////// //