use crate::error::InterpolationError;
use optionstratlib_core::error::OperationErrorKind;
use optionstratlib_core::error::{OptionsError, PositionError};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum CurveError {
#[error("Error: {reason}")]
Point2DError {
reason: &'static str,
},
#[error("Operation error: {0}")]
OperationError(
OperationErrorKind,
),
#[error("parametric generator failed: {0}")]
Generator(#[source] Box<dyn std::error::Error + Send + Sync>),
#[error("Interpolation error: {0}")]
InterpolationError(
String,
),
#[error("Construction error: {0}")]
ConstructionError(
String,
),
#[error("Analysis error: {0}")]
AnalysisError(
String,
),
#[error("Metrics error: {0}")]
MetricsError(
String,
),
#[error(transparent)]
Position(#[from] PositionError),
#[error(transparent)]
Options(#[from] OptionsError),
#[error("Interpolation error: {0}")]
InterpolationOp(String),
}
impl CurveError {
#[must_use]
#[cold]
#[inline(never)]
pub fn operation_not_supported(operation: &str, reason: &str) -> Self {
CurveError::OperationError(OperationErrorKind::NotSupported {
operation: operation.to_string(),
reason: reason.to_string(),
})
}
#[must_use]
#[cold]
#[inline(never)]
pub fn invalid_parameters(operation: &str, reason: &str) -> Self {
CurveError::OperationError(OperationErrorKind::InvalidParameters {
operation: operation.to_string(),
reason: reason.to_string(),
})
}
}
pub type CurvesResult<T> = Result<T, CurveError>;
impl CurveError {
#[cold]
#[must_use]
pub fn generator<E>(error: E) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
CurveError::Generator(Box::new(error))
}
}
impl From<InterpolationError> for CurveError {
fn from(err: InterpolationError) -> Self {
CurveError::InterpolationOp(err.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error;
#[test]
fn test_curves_error_display() {
let error = CurveError::Point2DError {
reason: "Invalid coordinates",
};
assert_eq!(error.to_string(), "Error: Invalid coordinates");
let error = CurveError::operation_not_supported("calculate", "Strategy");
assert_eq!(
error.to_string(),
"Operation error: Operation 'calculate' is not supported for strategy 'Strategy'"
);
}
#[test]
fn test_operation_not_supported() {
let error = CurveError::operation_not_supported("test_op", "TestStrat");
match error {
CurveError::OperationError(OperationErrorKind::NotSupported {
operation,
reason: strategy_type,
}) => {
assert_eq!(operation, "test_op");
assert_eq!(strategy_type, "TestStrat");
}
_ => panic!("Wrong error variant"),
}
}
#[test]
fn test_invalid_parameters() {
let error = CurveError::invalid_parameters("test_op", "invalid input");
match error {
CurveError::OperationError(OperationErrorKind::InvalidParameters {
operation,
reason,
}) => {
assert_eq!(operation, "test_op");
assert_eq!(reason, "invalid input");
}
_ => panic!("Wrong error variant"),
}
}
#[test]
fn test_error_trait_implementation() {
let error = CurveError::Point2DError {
reason: "test error",
};
let error_ref: &dyn Error = &error;
assert_eq!(error_ref.to_string(), "Error: test error");
}
#[test]
fn test_from_position_error() {
let position_error = PositionError::unsupported_operation("TestStruct", "test_op");
let curves_error = CurveError::from(position_error);
match curves_error {
CurveError::Position(_) => {
}
_ => panic!("Wrong error variant"),
}
}
#[test]
fn test_debug_implementation() {
let error = CurveError::Point2DError {
reason: "test debug",
};
assert!(format!("{error:?}").contains("test debug"));
}
}
#[cfg(test)]
mod tests_extended {
use super::*;
#[test]
fn test_curves_error_construction_error() {
let error =
CurveError::ConstructionError("Invalid curve construction parameters".to_string());
assert_eq!(
format!("{error}"),
"Construction error: Invalid curve construction parameters"
);
}
#[test]
fn test_curves_error_analysis_error() {
let error =
CurveError::AnalysisError("Analysis failed due to insufficient data".to_string());
assert_eq!(
format!("{error}"),
"Analysis error: Analysis failed due to insufficient data"
);
}
}