use crate::error::{CurveError, PositionError, SurfaceError};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum InterpolationError {
#[error("Linear interpolation error: {0}")]
Linear(String),
#[error("Bilinear interpolation error: {0}")]
Bilinear(String),
#[error("Cubic interpolation error: {0}")]
Cubic(String),
#[error("Spline interpolation error: {0}")]
Spline(String),
#[error(transparent)]
Position(#[from] PositionError),
#[error(transparent)]
Curve(CurveError),
#[error(transparent)]
Surface(#[from] SurfaceError),
#[error("interpolation input has no data points")]
EmptyData,
#[error("interpolation target {target} is outside the supported range")]
OutOfRange {
target: String,
},
#[error("interpolation interval is degenerate: knots collapse to a single point")]
DegenerateInterval,
}
impl From<CurveError> for InterpolationError {
fn from(err: CurveError) -> Self {
InterpolationError::Curve(err)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::position::PositionValidationErrorKind;
use std::error::Error as StdError;
use std::fmt;
#[derive(Debug)]
struct MockPositionError;
impl fmt::Display for MockPositionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Mock position error")
}
}
impl StdError for MockPositionError {}
#[derive(Debug)]
struct MockCurveError;
impl fmt::Display for MockCurveError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Mock curve error")
}
}
impl StdError for MockCurveError {}
#[derive(Debug)]
struct MockSurfaceError;
impl fmt::Display for MockSurfaceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Mock surface error")
}
}
impl StdError for MockSurfaceError {}
impl From<MockSurfaceError> for SurfaceError {
fn from(err: MockSurfaceError) -> Self {
SurfaceError::AnalysisError(err.to_string())
}
}
impl From<MockCurveError> for CurveError {
fn from(err: MockCurveError) -> Self {
CurveError::AnalysisError(err.to_string())
}
}
impl From<MockPositionError> for PositionError {
fn from(err: MockPositionError) -> Self {
PositionError::ValidationError(PositionValidationErrorKind::InvalidPosition {
reason: err.to_string(),
})
}
}
#[test]
fn test_create_interpolation_errors() {
let linear_err = InterpolationError::Linear("insufficient data points".to_string());
let bilinear_err = InterpolationError::Bilinear("out of grid boundary".to_string());
let cubic_err = InterpolationError::Cubic("numerical instability".to_string());
let spline_err = InterpolationError::Spline("invalid knot placement".to_string());
let empty_err = InterpolationError::EmptyData;
let out_of_range = InterpolationError::OutOfRange {
target: "1.23".to_string(),
};
let degenerate = InterpolationError::DegenerateInterval;
match linear_err {
InterpolationError::Linear(msg) => assert_eq!(msg, "insufficient data points"),
_ => panic!("Expected Linear variant"),
}
match bilinear_err {
InterpolationError::Bilinear(msg) => assert_eq!(msg, "out of grid boundary"),
_ => panic!("Expected Bilinear variant"),
}
match cubic_err {
InterpolationError::Cubic(msg) => assert_eq!(msg, "numerical instability"),
_ => panic!("Expected Cubic variant"),
}
match spline_err {
InterpolationError::Spline(msg) => assert_eq!(msg, "invalid knot placement"),
_ => panic!("Expected Spline variant"),
}
assert!(matches!(empty_err, InterpolationError::EmptyData));
assert!(matches!(
out_of_range,
InterpolationError::OutOfRange { .. }
));
assert!(matches!(degenerate, InterpolationError::DegenerateInterval));
}
#[test]
fn test_display_implementation() {
let linear_err = InterpolationError::Linear("test error".to_string());
let bilinear_err = InterpolationError::Bilinear("test error".to_string());
let cubic_err = InterpolationError::Cubic("test error".to_string());
let spline_err = InterpolationError::Spline("test error".to_string());
let empty_err = InterpolationError::EmptyData;
assert_eq!(
format!("{linear_err}"),
"Linear interpolation error: test error"
);
assert_eq!(
format!("{bilinear_err}"),
"Bilinear interpolation error: test error"
);
assert_eq!(
format!("{cubic_err}"),
"Cubic interpolation error: test error"
);
assert_eq!(
format!("{spline_err}"),
"Spline interpolation error: test error"
);
assert_eq!(
format!("{empty_err}"),
"interpolation input has no data points"
);
}
#[test]
fn test_conversion_from_position_error() {
let position_err = MockPositionError;
let position_err = PositionError::from(position_err);
let interpolation_err = InterpolationError::from(position_err);
match interpolation_err {
InterpolationError::Position(_) => {
}
_ => panic!("Expected Position variant"),
}
}
#[test]
fn test_conversion_from_curve_error() {
let curve_err = MockCurveError;
let curve_err = CurveError::from(curve_err);
let interpolation_err = InterpolationError::from(curve_err);
match interpolation_err {
InterpolationError::Curve(_) => {
}
_ => panic!("Expected Curve variant"),
}
}
#[test]
fn test_conversion_from_surface_error() {
let surface_err = MockSurfaceError;
let surface_err = SurfaceError::from(surface_err);
let interpolation_err = InterpolationError::from(surface_err);
match interpolation_err {
InterpolationError::Surface(_) => {
}
_ => panic!("Expected Surface variant"),
}
}
#[test]
fn test_debug_implementation() {
let err = InterpolationError::Linear("test debug".to_string());
let debug_str = format!("{err:?}");
assert!(
debug_str.contains("Linear"),
"Debug representation should include the variant"
);
assert!(
debug_str.contains("test debug"),
"Debug representation should include the error message"
);
}
}