verdure_core/error/
container.rs1use std::fmt;
7
8#[derive(Debug)]
22pub struct ContainerError {
23 pub kind: ContainerErrorKind,
25 pub message: String,
27 pub source: Option<Box<dyn std::error::Error + Send + Sync>>,
29}
30
31#[derive(Debug, PartialEq, Eq)]
37pub enum ContainerErrorKind {
38 NotFound,
40 CircularDependency,
42 CreationFailed,
44 TypeCastFailed,
46 Configuration,
48 Other,
50}
51
52impl fmt::Display for ContainerErrorKind {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 ContainerErrorKind::NotFound => write!(f, "Component not found"),
56 ContainerErrorKind::CircularDependency => write!(f, "Circular dependency detected"),
57 ContainerErrorKind::CreationFailed => write!(f, "Component creation failed"),
58 ContainerErrorKind::TypeCastFailed => write!(f, "Type cast failed"),
59 ContainerErrorKind::Configuration => write!(f, "Configuration error"),
60 ContainerErrorKind::Other => write!(f, "Other error"),
61 }
62 }
63}
64
65impl fmt::Display for ContainerError {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(f, "{}: {}", self.kind, self.message)
68 }
69}
70
71impl std::error::Error for ContainerError {
72 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
73 self.source
74 .as_ref()
75 .map(|e| e.as_ref() as &(dyn std::error::Error + 'static))
76 }
77}
78
79impl ContainerError {
80 pub fn new<M: Into<String>>(kind: ContainerErrorKind, message: M) -> Self {
95 Self {
96 kind,
97 message: message.into(),
98 source: None,
99 }
100 }
101
102 pub fn with_source<E>(mut self, err: E) -> Self
121 where
122 E: std::error::Error + Send + Sync + 'static,
123 {
124 self.source = Some(Box::new(err));
125 self
126 }
127
128 pub fn not_found<M: Into<String>>(message: M) -> Self {
134 Self::new(ContainerErrorKind::NotFound, message)
135 }
136
137 pub fn circular_dependency<M: Into<String>>(message: M) -> Self {
143 Self::new(ContainerErrorKind::CircularDependency, message)
144 }
145
146 pub fn creation_failed<M: Into<String>>(message: M) -> Self {
152 Self::new(ContainerErrorKind::CreationFailed, message)
153 }
154
155 pub fn type_cast_failed<M: Into<String>>(message: M) -> Self {
161 Self::new(ContainerErrorKind::TypeCastFailed, message)
162 }
163
164 pub fn configuration<M: Into<String>>(message: M) -> Self {
170 Self::new(ContainerErrorKind::Configuration, message)
171 }
172
173 pub fn other<M: Into<String>>(message: M) -> Self {
179 Self::new(ContainerErrorKind::Other, message)
180 }
181}
182
183impl From<&str> for ContainerError {
184 fn from(msg: &str) -> Self {
185 ContainerError::new(ContainerErrorKind::Other, msg)
186 }
187}
188
189impl From<String> for ContainerError {
190 fn from(msg: String) -> Self {
191 ContainerError::new(ContainerErrorKind::Other, msg)
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_container_error_creation() {
201 let error = ContainerError::not_found("test component");
202 assert_eq!(error.kind, ContainerErrorKind::NotFound);
203 assert_eq!(error.message, "test component");
204 assert!(error.source.is_none());
205 }
206
207 #[test]
208 fn test_container_error_display() {
209 let error = ContainerError::circular_dependency("ComponentA -> ComponentB -> ComponentA");
210 assert_eq!(
211 error.to_string(),
212 "Circular dependency detected: ComponentA -> ComponentB -> ComponentA"
213 );
214 }
215
216 #[test]
217 fn test_container_error_with_source() {
218 let source_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
219 let error =
220 ContainerError::creation_failed("Failed to create component").with_source(source_error);
221
222 assert_eq!(error.kind, ContainerErrorKind::CreationFailed);
223 assert!(error.source.is_some());
224 }
225
226 #[test]
227 fn test_container_error_from_string() {
228 let error: ContainerError = "test error message".into();
229 assert_eq!(error.kind, ContainerErrorKind::Other);
230 assert_eq!(error.message, "test error message");
231 }
232
233 #[test]
234 fn test_container_error_from_owned_string() {
235 let msg = String::from("test error message");
236 let error: ContainerError = msg.into();
237 assert_eq!(error.kind, ContainerErrorKind::Other);
238 assert_eq!(error.message, "test error message");
239 }
240
241 #[test]
242 fn test_all_error_kinds() {
243 let errors = vec![
244 ContainerError::not_found("not found"),
245 ContainerError::circular_dependency("circular"),
246 ContainerError::creation_failed("creation failed"),
247 ContainerError::type_cast_failed("cast failed"),
248 ContainerError::configuration("config error"),
249 ContainerError::other("other error"),
250 ];
251
252 let expected_kinds = vec![
253 ContainerErrorKind::NotFound,
254 ContainerErrorKind::CircularDependency,
255 ContainerErrorKind::CreationFailed,
256 ContainerErrorKind::TypeCastFailed,
257 ContainerErrorKind::Configuration,
258 ContainerErrorKind::Other,
259 ];
260
261 for (error, expected_kind) in errors.iter().zip(expected_kinds.iter()) {
262 assert_eq!(&error.kind, expected_kind);
263 }
264 }
265
266 #[test]
267 fn test_error_kind_display() {
268 assert_eq!(
269 ContainerErrorKind::NotFound.to_string(),
270 "Component not found"
271 );
272 assert_eq!(
273 ContainerErrorKind::CircularDependency.to_string(),
274 "Circular dependency detected"
275 );
276 assert_eq!(
277 ContainerErrorKind::CreationFailed.to_string(),
278 "Component creation failed"
279 );
280 assert_eq!(
281 ContainerErrorKind::TypeCastFailed.to_string(),
282 "Type cast failed"
283 );
284 assert_eq!(
285 ContainerErrorKind::Configuration.to_string(),
286 "Configuration error"
287 );
288 assert_eq!(ContainerErrorKind::Other.to_string(), "Other error");
289 }
290}