Skip to main content

oparry_core/
error.rs

1//! Core error types for Parry
2
3use std::path::PathBuf;
4
5/// Result type alias
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// Core error type
9#[derive(Debug, thiserror::Error)]
10pub enum Error {
11    /// Configuration error
12    #[error("Configuration error: {0}")]
13    Config(String),
14
15    /// File I/O error
16    #[error("File error: {path} - {source}")]
17    File {
18        path: PathBuf,
19        #[source]
20        source: std::io::Error,
21    },
22
23    /// Parsing error
24    #[error("Parse error in {file}:{line}:{column}: {message}")]
25    Parse {
26        file: String,
27        line: usize,
28        column: usize,
29        message: String,
30    },
31
32    /// Validation error
33    #[error("Validation error: {0}")]
34    Validation(String),
35
36    /// Watcher error
37    #[error("Watcher error: {0}")]
38    Watcher(String),
39
40    /// Wrapper error
41    #[error("Wrapper error: {0}")]
42    Wrapper(String),
43
44    /// JSON error
45    #[error("JSON error: {0}")]
46    Json(#[from] serde_json::Error),
47
48    /// TOML error
49    #[error("TOML error: {0}")]
50    Toml(#[from] toml::de::Error),
51
52    /// Regex error
53    #[error("Regex error: {0}")]
54    Regex(#[from] regex::Error),
55
56    /// Generic error
57    #[error("{0}")]
58    Other(String),
59}
60
61impl Error {
62    /// Create a file error
63    pub fn file(path: impl Into<PathBuf>, source: std::io::Error) -> Self {
64        Self::File {
65            path: path.into(),
66            source,
67        }
68    }
69
70    /// Create a parse error
71    pub fn parse(file: impl Into<String>, line: usize, column: usize, message: impl Into<String>) -> Self {
72        Self::Parse {
73            file: file.into(),
74            line,
75            column,
76            message: message.into(),
77        }
78    }
79
80    /// Create a validation error
81    pub fn validation(msg: impl Into<String>) -> Self {
82        Self::Validation(msg.into())
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_error_display() {
92        let err = Error::validation("test error");
93        assert_eq!(err.to_string(), "Validation error: test error");
94    }
95
96    #[test]
97    fn test_error_config() {
98        let err = Error::Config("invalid config".to_string());
99        assert_eq!(err.to_string(), "Configuration error: invalid config");
100    }
101
102    #[test]
103    fn test_error_file() {
104        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
105        let err = Error::file("/path/to/file", io_err);
106        assert!(err.to_string().contains("File error"));
107        assert!(err.to_string().contains("/path/to/file"));
108    }
109
110    #[test]
111    fn test_error_parse() {
112        let err = Error::parse("test.js", 10, 5, "unexpected token");
113        assert_eq!(err.to_string(), "Parse error in test.js:10:5: unexpected token");
114    }
115
116    #[test]
117    fn test_error_validation() {
118        let err = Error::validation("invalid input");
119        assert_eq!(err.to_string(), "Validation error: invalid input");
120    }
121
122    #[test]
123    fn test_error_watcher() {
124        let err = Error::Watcher("watcher failed".to_string());
125        assert_eq!(err.to_string(), "Watcher error: watcher failed");
126    }
127
128    #[test]
129    fn test_error_wrapper() {
130        let err = Error::Wrapper("wrap failed".to_string());
131        assert_eq!(err.to_string(), "Wrapper error: wrap failed");
132    }
133
134    #[test]
135    fn test_error_other() {
136        let err = Error::Other("something happened".to_string());
137        assert_eq!(err.to_string(), "something happened");
138    }
139
140    #[test]
141    fn test_error_static_creation() {
142        assert!(matches!(Error::validation("test"), Error::Validation(_)));
143        assert!(matches!(Error::parse("", 0, 0, ""), Error::Parse { .. }));
144    }
145}