Skip to main content

verdure_core/error/
component.rs

1//! Component-specific error types and implementations
2//!
3//! This module defines error types specifically related to component operations,
4//! including dependency resolution, instantiation, and lifecycle management.
5
6use crate::error::container::{ContainerError, ContainerErrorKind};
7use std::fmt;
8
9/// Error types specific to component operations
10///
11/// `ComponentError` represents various failure conditions that can occur during
12/// component creation, dependency injection, and component lifecycle management.
13///
14/// # Examples
15///
16/// ```rust
17/// use verdure_core::error::component::ComponentError;
18///
19/// let error = ComponentError::DependencyNotFound("DatabaseService".to_string());
20/// println!("{}", error); // Prints: "Dependency 'DatabaseService' not found"
21/// ```
22#[derive(Debug)]
23pub enum ComponentError {
24    /// A required dependency was not found in the container
25    DependencyNotFound(String),
26    /// Failed to downcast a dependency to the expected type
27    DowncastFailed(String),
28    /// A circular dependency was detected between components
29    CircularDependency(String),
30    /// A configuration error occurred during component setup
31    ConfigurationError(String),
32    /// Component creation failed for some reason
33    CreationError(String),
34    /// The requested component was not found
35    NotFound(String),
36}
37
38impl fmt::Display for ComponentError {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            ComponentError::DependencyNotFound(s) => write!(f, "Dependency '{}' not found", s),
42            ComponentError::DowncastFailed(s) => write!(f, "Failed to downcast dependency '{}'", s),
43            ComponentError::CircularDependency(s) => {
44                write!(f, "Circular dependency detected: {}", s)
45            }
46            ComponentError::ConfigurationError(s) => write!(f, "Configuration error: {}", s),
47            ComponentError::CreationError(s) => write!(f, "Component creation error: {}", s),
48            ComponentError::NotFound(s) => write!(f, "Component not found: {}", s),
49        }
50    }
51}
52
53impl From<ContainerError> for ComponentError {
54    fn from(err: ContainerError) -> Self {
55        match err.kind {
56            ContainerErrorKind::NotFound => ComponentError::NotFound(err.message),
57            ContainerErrorKind::CircularDependency => {
58                ComponentError::CircularDependency(err.message)
59            }
60            ContainerErrorKind::CreationFailed => ComponentError::CreationError(err.message),
61            ContainerErrorKind::TypeCastFailed => ComponentError::DowncastFailed(err.message),
62            ContainerErrorKind::Configuration => ComponentError::ConfigurationError(err.message),
63            ContainerErrorKind::Other => ComponentError::CreationError(err.message),
64        }
65    }
66}
67
68impl From<ComponentError> for ContainerError {
69    fn from(err: ComponentError) -> Self {
70        match err {
71            ComponentError::NotFound(msg) => ContainerError::not_found(msg),
72            ComponentError::CircularDependency(msg) => ContainerError::circular_dependency(msg),
73            ComponentError::CreationError(msg) => ContainerError::creation_failed(msg),
74            ComponentError::DowncastFailed(msg) => ContainerError::type_cast_failed(msg),
75            ComponentError::ConfigurationError(msg) => ContainerError::configuration(msg),
76            ComponentError::DependencyNotFound(msg) => {
77                ContainerError::not_found(format!("Dependency: {}", msg))
78            }
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_component_error_display() {
89        let errors = vec![
90            ComponentError::DependencyNotFound("TestDep".to_string()),
91            ComponentError::DowncastFailed("TestComponent".to_string()),
92            ComponentError::CircularDependency("A -> B -> A".to_string()),
93            ComponentError::ConfigurationError("Invalid config".to_string()),
94            ComponentError::CreationError("Failed to create".to_string()),
95            ComponentError::NotFound("ComponentX".to_string()),
96        ];
97
98        let expected_messages = vec![
99            "Dependency 'TestDep' not found",
100            "Failed to downcast dependency 'TestComponent'",
101            "Circular dependency detected: A -> B -> A",
102            "Configuration error: Invalid config",
103            "Component creation error: Failed to create",
104            "Component not found: ComponentX",
105        ];
106
107        for (error, expected) in errors.iter().zip(expected_messages.iter()) {
108            assert_eq!(error.to_string(), *expected);
109        }
110    }
111
112    #[test]
113    fn test_from_container_error() {
114        let container_errors = vec![
115            ContainerError::not_found("test component"),
116            ContainerError::circular_dependency("A -> B -> A"),
117            ContainerError::creation_failed("creation failed"),
118            ContainerError::type_cast_failed("cast failed"),
119            ContainerError::configuration("config error"),
120            ContainerError::other("other error"),
121        ];
122
123        let component_errors: Vec<ComponentError> = container_errors
124            .into_iter()
125            .map(ComponentError::from)
126            .collect();
127
128        assert!(matches!(component_errors[0], ComponentError::NotFound(_)));
129        assert!(matches!(
130            component_errors[1],
131            ComponentError::CircularDependency(_)
132        ));
133        assert!(matches!(
134            component_errors[2],
135            ComponentError::CreationError(_)
136        ));
137        assert!(matches!(
138            component_errors[3],
139            ComponentError::DowncastFailed(_)
140        ));
141        assert!(matches!(
142            component_errors[4],
143            ComponentError::ConfigurationError(_)
144        ));
145        assert!(matches!(
146            component_errors[5],
147            ComponentError::CreationError(_)
148        ));
149    }
150
151    #[test]
152    fn test_to_container_error() {
153        let component_errors = vec![
154            ComponentError::NotFound("test".to_string()),
155            ComponentError::CircularDependency("A -> B -> A".to_string()),
156            ComponentError::CreationError("create failed".to_string()),
157            ComponentError::DowncastFailed("cast failed".to_string()),
158            ComponentError::ConfigurationError("config error".to_string()),
159            ComponentError::DependencyNotFound("dependency".to_string()),
160        ];
161
162        let container_errors: Vec<ContainerError> = component_errors
163            .into_iter()
164            .map(ContainerError::from)
165            .collect();
166
167        assert_eq!(container_errors[0].kind, ContainerErrorKind::NotFound);
168        assert_eq!(
169            container_errors[1].kind,
170            ContainerErrorKind::CircularDependency
171        );
172        assert_eq!(container_errors[2].kind, ContainerErrorKind::CreationFailed);
173        assert_eq!(container_errors[3].kind, ContainerErrorKind::TypeCastFailed);
174        assert_eq!(container_errors[4].kind, ContainerErrorKind::Configuration);
175        assert_eq!(container_errors[5].kind, ContainerErrorKind::NotFound);
176        assert!(
177            container_errors[5]
178                .message
179                .contains("Dependency: dependency")
180        );
181    }
182
183    #[test]
184    fn test_error_roundup_conversion() {
185        let original_container_error = ContainerError::circular_dependency("A -> B -> A");
186        let component_error: ComponentError = original_container_error.into();
187        let back_to_container: ContainerError = component_error.into();
188
189        assert_eq!(
190            back_to_container.kind,
191            ContainerErrorKind::CircularDependency
192        );
193        assert_eq!(back_to_container.message, "A -> B -> A");
194    }
195}