tailwind_rs_core/
error.rs

1//! Error types for tailwind-rs-core
2
3use thiserror::Error;
4
5/// Result type alias for tailwind-rs operations
6pub type Result<T> = std::result::Result<T, TailwindError>;
7
8/// Main error type for tailwind-rs operations
9#[derive(Error, Debug)]
10pub enum TailwindError {
11    /// Configuration errors
12    #[error("Configuration error: {message}")]
13    Config { message: String },
14
15    /// Theme-related errors
16    #[error("Theme error: {message}")]
17    Theme { message: String },
18
19    /// Class generation errors
20    #[error("Class generation error: {message}")]
21    ClassGeneration { message: String },
22
23    /// Build process errors
24    #[error("Build error: {message}")]
25    Build { message: String },
26
27    /// Validation errors
28    #[error("Validation error: {message}")]
29    Validation { message: String },
30
31    /// File I/O errors
32    #[error("File I/O error: {0}")]
33    Io(#[from] std::io::Error),
34
35    /// JSON serialization/deserialization errors
36    #[error("JSON error: {0}")]
37    Json(#[from] serde_json::Error),
38
39    /// Generic error wrapper
40    #[error("Generic error: {0}")]
41    Generic(#[from] anyhow::Error),
42}
43
44impl TailwindError {
45    /// Create a new configuration error
46    pub fn config(message: impl Into<String>) -> Self {
47        Self::Config {
48            message: message.into(),
49        }
50    }
51
52    /// Create a new theme error
53    pub fn theme(message: impl Into<String>) -> Self {
54        Self::Theme {
55            message: message.into(),
56        }
57    }
58
59    /// Create a new class generation error
60    pub fn class_generation(message: impl Into<String>) -> Self {
61        Self::ClassGeneration {
62            message: message.into(),
63        }
64    }
65
66    /// Create a new build error
67    pub fn build(message: impl Into<String>) -> Self {
68        Self::Build {
69            message: message.into(),
70        }
71    }
72
73    /// Create a new validation error
74    pub fn validation(message: impl Into<String>) -> Self {
75        Self::Validation {
76            message: message.into(),
77        }
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn test_config_error() {
87        let error = TailwindError::config("Invalid configuration");
88        assert!(matches!(error, TailwindError::Config { .. }));
89        assert!(error.to_string().contains("Invalid configuration"));
90    }
91
92    #[test]
93    fn test_theme_error() {
94        let error = TailwindError::theme("Theme not found");
95        assert!(matches!(error, TailwindError::Theme { .. }));
96        assert!(error.to_string().contains("Theme not found"));
97    }
98
99    #[test]
100    fn test_class_generation_error() {
101        let error = TailwindError::class_generation("Invalid class name");
102        assert!(matches!(error, TailwindError::ClassGeneration { .. }));
103        assert!(error.to_string().contains("Invalid class name"));
104    }
105
106    #[test]
107    fn test_build_error() {
108        let error = TailwindError::build("Build failed");
109        assert!(matches!(error, TailwindError::Build { .. }));
110        assert!(error.to_string().contains("Build failed"));
111    }
112
113    #[test]
114    fn test_io_error_conversion() {
115        let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "File not found");
116        let tailwind_error: TailwindError = io_error.into();
117        assert!(matches!(tailwind_error, TailwindError::Io(_)));
118    }
119
120    #[test]
121    fn test_json_error_conversion() {
122        let json_error = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
123        let tailwind_error: TailwindError = json_error.into();
124        assert!(matches!(tailwind_error, TailwindError::Json(_)));
125    }
126
127    #[test]
128    fn test_generic_error_conversion() {
129        let anyhow_error = anyhow::anyhow!("Generic error");
130        let tailwind_error: TailwindError = anyhow_error.into();
131        assert!(matches!(tailwind_error, TailwindError::Generic(_)));
132    }
133    
134    /// Test that all Week 17 error handling features are implemented
135    #[test]
136    fn test_week17_error_handling() {
137        // Test comprehensive error types
138        let config_error = TailwindError::config("Invalid configuration");
139        assert!(matches!(config_error, TailwindError::Config { .. }));
140        assert!(config_error.to_string().contains("Configuration error"));
141        
142        let theme_error = TailwindError::theme("Theme not found");
143        assert!(matches!(theme_error, TailwindError::Theme { .. }));
144        assert!(theme_error.to_string().contains("Theme error"));
145        
146        let class_error = TailwindError::class_generation("Invalid class name");
147        assert!(matches!(class_error, TailwindError::ClassGeneration { .. }));
148        assert!(class_error.to_string().contains("Class generation error"));
149        
150        let build_error = TailwindError::build("Build failed");
151        assert!(matches!(build_error, TailwindError::Build { .. }));
152        assert!(build_error.to_string().contains("Build error"));
153        
154        let validation_error = TailwindError::validation("Invalid input");
155        assert!(matches!(validation_error, TailwindError::Validation { .. }));
156        assert!(validation_error.to_string().contains("Validation error"));
157        
158        // Test error recovery - errors can be converted back to Result types
159        let result: Result<()> = Err(config_error);
160        assert!(result.is_err());
161        
162        // Test error reporting - all errors implement Display and Debug
163        let error = TailwindError::config("Test error");
164        let error_string = format!("{}", error);
165        let debug_string = format!("{:?}", error);
166        assert!(!error_string.is_empty());
167        assert!(!debug_string.is_empty());
168        
169        // Test error documentation - errors provide meaningful messages
170        assert!(error_string.contains("Configuration error"));
171        assert!(error_string.contains("Test error"));
172        
173        // Test error conversion from standard library errors
174        let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "File not found");
175        let converted_error: TailwindError = io_error.into();
176        assert!(matches!(converted_error, TailwindError::Io(_)));
177        
178        // Test JSON error conversion
179        let json_error = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
180        let json_tailwind_error: TailwindError = json_error.into();
181        assert!(matches!(json_tailwind_error, TailwindError::Json(_)));
182        
183        // Test anyhow error conversion
184        let anyhow_error = anyhow::anyhow!("Generic error");
185        let anyhow_tailwind_error: TailwindError = anyhow_error.into();
186        assert!(matches!(anyhow_tailwind_error, TailwindError::Generic(_)));
187    }
188}