use crate::error::common::OperationErrorKind;
use crate::error::metrics::MetricsError;
use crate::error::{GraphError, GreeksError, InterpolationError, OptionsError, PositionError};
use std::error::Error;
use std::fmt;
impl Error for CurveError {}
#[derive(Debug)]
pub enum CurveError {
Point2DError {
reason: &'static str,
},
OperationError(
OperationErrorKind,
),
StdError {
reason: String,
},
InterpolationError(
String,
),
ConstructionError(
String,
),
AnalysisError(
String,
),
MetricsError(
String,
),
}
impl CurveError {
pub fn operation_not_supported(operation: &str, reason: &str) -> Self {
CurveError::OperationError(OperationErrorKind::NotSupported {
operation: operation.to_string(),
reason: reason.to_string(),
})
}
pub fn invalid_parameters(operation: &str, reason: &str) -> Self {
CurveError::OperationError(OperationErrorKind::InvalidParameters {
operation: operation.to_string(),
reason: reason.to_string(),
})
}
}
impl fmt::Display for CurveError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CurveError::OperationError(err) => write!(f, "Operation error: {err}"),
CurveError::StdError { reason } => write!(f, "Error: {reason}"),
CurveError::Point2DError { reason } => write!(f, "Error: {reason}"),
CurveError::ConstructionError(reason) => write!(f, "Construction error: {reason}"),
CurveError::AnalysisError(reason) => write!(f, "Analysis error: {reason}"),
CurveError::MetricsError(reason) => write!(f, "Metrics error: {reason}"),
CurveError::InterpolationError(reason) => write!(f, "Interpolation error: {reason}"),
}
}
}
pub type CurvesResult<T> = Result<T, CurveError>;
impl From<PositionError> for CurveError {
fn from(err: PositionError) -> Self {
CurveError::OperationError(OperationErrorKind::InvalidParameters {
operation: "Position".to_string(),
reason: err.to_string(),
})
}
}
impl From<OptionsError> for CurveError {
fn from(err: OptionsError) -> Self {
CurveError::OperationError(OperationErrorKind::InvalidParameters {
operation: "Option".to_string(),
reason: err.to_string(),
})
}
}
impl From<GreeksError> for CurveError {
fn from(err: GreeksError) -> Self {
CurveError::OperationError(OperationErrorKind::InvalidParameters {
operation: "Greeks".to_string(),
reason: err.to_string(),
})
}
}
impl From<InterpolationError> for CurveError {
fn from(err: InterpolationError) -> Self {
CurveError::StdError {
reason: err.to_string(),
}
}
}
impl From<MetricsError> for CurveError {
fn from(err: MetricsError) -> Self {
CurveError::MetricsError(err.to_string())
}
}
impl From<Box<dyn Error>> for CurveError {
fn from(err: Box<dyn Error>) -> Self {
CurveError::StdError {
reason: err.to_string(),
}
}
}
impl From<GraphError> for CurveError {
fn from(err: GraphError) -> Self {
CurveError::StdError {
reason: 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::StdError {
reason: "Standard error".to_string(),
};
assert_eq!(error.to_string(), "Error: Standard error");
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_box_dyn_error() {
let boxed_error: Box<dyn Error> = Box::new(std::io::Error::other("io error"));
let curves_error = CurveError::from(boxed_error);
match curves_error {
CurveError::StdError { reason } => assert_eq!(reason, "io error"),
_ => panic!("Wrong error variant"),
}
}
#[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::OperationError(OperationErrorKind::InvalidParameters {
operation,
reason,
}) => {
assert_eq!(operation, "Position");
assert!(reason.contains("test_op"));
}
_ => panic!("Wrong error variant"),
}
}
#[test]
fn test_debug_implementation() {
let error = CurveError::Point2DError {
reason: "test debug",
};
assert!(format!("{error:?}").contains("test debug"));
let error = CurveError::StdError {
reason: "test debug".to_string(),
};
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"
);
}
}