optionstratlib_math/error/
interpolation.rs1use crate::error::{CurveError, SurfaceError};
9use optionstratlib_core::error::PositionError;
10use thiserror::Error;
11
12#[derive(Error, Debug)]
22pub enum InterpolationError {
23 #[error("Linear interpolation error: {0}")]
28 Linear(String),
29
30 #[error("Bilinear interpolation error: {0}")]
44 Bilinear(String),
45
46 #[error("Cubic interpolation error: {0}")]
51 Cubic(String),
52
53 #[error("Spline interpolation error: {0}")]
58 Spline(String),
59
60 #[error(transparent)]
62 Position(#[from] PositionError),
63
64 #[error(transparent)]
66 Curve(CurveError),
67
68 #[error(transparent)]
70 Surface(#[from] SurfaceError),
71
72 #[error("interpolation input has no data points")]
74 EmptyData,
75
76 #[error("interpolation target {target} is outside the supported range")]
78 OutOfRange {
79 target: String,
81 },
82
83 #[error("interpolation interval is degenerate: knots collapse to a single point")]
85 DegenerateInterval,
86}
87
88impl From<CurveError> for InterpolationError {
89 fn from(err: CurveError) -> Self {
90 InterpolationError::Curve(err)
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 use optionstratlib_core::error::position::PositionValidationErrorKind;
98 use std::error::Error as StdError;
99 use std::fmt;
100
101 #[derive(Debug)]
103 struct MockPositionError;
104
105 impl fmt::Display for MockPositionError {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 write!(f, "Mock position error")
108 }
109 }
110
111 impl StdError for MockPositionError {}
112
113 #[derive(Debug)]
114 struct MockCurveError;
115
116 impl fmt::Display for MockCurveError {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 write!(f, "Mock curve error")
119 }
120 }
121
122 impl StdError for MockCurveError {}
123
124 #[derive(Debug)]
125 struct MockSurfaceError;
126
127 impl fmt::Display for MockSurfaceError {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 write!(f, "Mock surface error")
130 }
131 }
132
133 impl StdError for MockSurfaceError {}
134
135 impl From<MockSurfaceError> for SurfaceError {
136 fn from(err: MockSurfaceError) -> Self {
137 SurfaceError::AnalysisError(err.to_string())
138 }
139 }
140
141 impl From<MockCurveError> for CurveError {
143 fn from(err: MockCurveError) -> Self {
144 CurveError::AnalysisError(err.to_string())
146 }
147 }
148
149 impl From<MockPositionError> for PositionError {
151 fn from(err: MockPositionError) -> Self {
152 PositionError::ValidationError(PositionValidationErrorKind::InvalidPosition {
154 reason: err.to_string(),
155 })
156 }
157 }
158
159 #[test]
160 fn test_create_interpolation_errors() {
161 let linear_err = InterpolationError::Linear("insufficient data points".to_string());
163 let bilinear_err = InterpolationError::Bilinear("out of grid boundary".to_string());
164 let cubic_err = InterpolationError::Cubic("numerical instability".to_string());
165 let spline_err = InterpolationError::Spline("invalid knot placement".to_string());
166 let empty_err = InterpolationError::EmptyData;
167 let out_of_range = InterpolationError::OutOfRange {
168 target: "1.23".to_string(),
169 };
170 let degenerate = InterpolationError::DegenerateInterval;
171
172 match linear_err {
174 InterpolationError::Linear(msg) => assert_eq!(msg, "insufficient data points"),
175 _ => panic!("Expected Linear variant"),
176 }
177
178 match bilinear_err {
179 InterpolationError::Bilinear(msg) => assert_eq!(msg, "out of grid boundary"),
180 _ => panic!("Expected Bilinear variant"),
181 }
182
183 match cubic_err {
184 InterpolationError::Cubic(msg) => assert_eq!(msg, "numerical instability"),
185 _ => panic!("Expected Cubic variant"),
186 }
187
188 match spline_err {
189 InterpolationError::Spline(msg) => assert_eq!(msg, "invalid knot placement"),
190 _ => panic!("Expected Spline variant"),
191 }
192
193 assert!(matches!(empty_err, InterpolationError::EmptyData));
194 assert!(matches!(
195 out_of_range,
196 InterpolationError::OutOfRange { .. }
197 ));
198 assert!(matches!(degenerate, InterpolationError::DegenerateInterval));
199 }
200
201 #[test]
202 fn test_display_implementation() {
203 let linear_err = InterpolationError::Linear("test error".to_string());
205 let bilinear_err = InterpolationError::Bilinear("test error".to_string());
206 let cubic_err = InterpolationError::Cubic("test error".to_string());
207 let spline_err = InterpolationError::Spline("test error".to_string());
208 let empty_err = InterpolationError::EmptyData;
209
210 assert_eq!(
211 format!("{linear_err}"),
212 "Linear interpolation error: test error"
213 );
214 assert_eq!(
215 format!("{bilinear_err}"),
216 "Bilinear interpolation error: test error"
217 );
218 assert_eq!(
219 format!("{cubic_err}"),
220 "Cubic interpolation error: test error"
221 );
222 assert_eq!(
223 format!("{spline_err}"),
224 "Spline interpolation error: test error"
225 );
226 assert_eq!(
227 format!("{empty_err}"),
228 "interpolation input has no data points"
229 );
230 }
231
232 #[test]
233 fn test_conversion_from_position_error() {
234 let position_err = MockPositionError;
235 let position_err = PositionError::from(position_err);
236 let interpolation_err = InterpolationError::from(position_err);
237
238 match interpolation_err {
239 InterpolationError::Position(_) => {
240 }
242 _ => panic!("Expected Position variant"),
243 }
244 }
245
246 #[test]
247 fn test_conversion_from_curve_error() {
248 let curve_err = MockCurveError;
249 let curve_err = CurveError::from(curve_err);
250 let interpolation_err = InterpolationError::from(curve_err);
251 match interpolation_err {
252 InterpolationError::Curve(_) => {
253 }
255 _ => panic!("Expected Curve variant"),
256 }
257 }
258
259 #[test]
260 fn test_conversion_from_surface_error() {
261 let surface_err = MockSurfaceError;
262 let surface_err = SurfaceError::from(surface_err);
263 let interpolation_err = InterpolationError::from(surface_err);
264
265 match interpolation_err {
266 InterpolationError::Surface(_) => {
267 }
269 _ => panic!("Expected Surface variant"),
270 }
271 }
272
273 #[test]
274 fn test_debug_implementation() {
275 let err = InterpolationError::Linear("test debug".to_string());
276 let debug_str = format!("{err:?}");
277 assert!(
278 debug_str.contains("Linear"),
279 "Debug representation should include the variant"
280 );
281 assert!(
282 debug_str.contains("test debug"),
283 "Debug representation should include the error message"
284 );
285 }
286}