codeprism_core/
error.rs

1//! Error types for codeprism
2
3use std::path::PathBuf;
4use thiserror::Error;
5
6/// Result type alias for codeprism operations
7pub type Result<T> = std::result::Result<T, Error>;
8
9/// Main error type for codeprism
10#[derive(Debug, Error)]
11pub enum Error {
12    /// IO error
13    #[error("IO error: {0}")]
14    Io(#[from] std::io::Error),
15
16    /// Parser error
17    #[error("Parse error in {file}: {message}")]
18    Parse {
19        /// File that failed to parse
20        file: PathBuf,
21        /// Error message
22        message: String,
23    },
24
25    /// Language not supported
26    #[error("Language not supported: {0}")]
27    UnsupportedLanguage(String),
28
29    /// Tree-sitter error
30    #[error("Tree-sitter error: {0}")]
31    TreeSitter(String),
32
33    /// Graph storage error
34    #[error("Storage error: {0}")]
35    Storage(String),
36
37    /// Serialization error
38    #[error("Serialization error: {0}")]
39    Serialization(#[from] serde_json::Error),
40
41    /// Configuration error
42    #[error("Configuration error: {0}")]
43    Config(String),
44
45    /// File watcher error
46    #[error("File watcher error: {0}")]
47    Watcher(String),
48
49    /// Indexing error
50    #[error("Indexing error: {0}")]
51    Indexing(String),
52
53    /// Invalid node ID
54    #[error("Invalid node ID: {0}")]
55    InvalidNodeId(String),
56
57    /// Node not found
58    #[error("Node not found: {0}")]
59    NodeNotFound(String),
60
61    /// Edge not found
62    #[error("Edge not found: {0}")]
63    EdgeNotFound(String),
64
65    /// Other error
66    #[error("{0}")]
67    Other(String),
68}
69
70impl Error {
71    /// Create a parse error
72    pub fn parse(file: impl Into<PathBuf>, message: impl Into<String>) -> Self {
73        Self::Parse {
74            file: file.into(),
75            message: message.into(),
76        }
77    }
78
79    /// Create a storage error
80    pub fn storage(message: impl Into<String>) -> Self {
81        Self::Storage(message.into())
82    }
83
84    /// Create a tree-sitter error
85    pub fn tree_sitter(message: impl Into<String>) -> Self {
86        Self::TreeSitter(message.into())
87    }
88
89    /// Create a watcher error
90    pub fn watcher(message: impl Into<String>) -> Self {
91        Self::Watcher(message.into())
92    }
93
94    /// Create an indexing error
95    pub fn indexing(message: impl Into<String>) -> Self {
96        Self::Indexing(message.into())
97    }
98
99    /// Create an IO error from a string message
100    pub fn io(message: impl Into<String>) -> Self {
101        Self::Io(std::io::Error::other(message.into()))
102    }
103
104    /// Create an other error
105    pub fn other(message: impl Into<String>) -> Self {
106        Self::Other(message.into())
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_parse_error_creation() {
116        let err = Error::parse("test.js", "syntax error");
117        match err {
118            Error::Parse { file, message } => {
119                assert_eq!(file, PathBuf::from("test.js"));
120                assert_eq!(message, "syntax error");
121            }
122            _ => panic!("Expected Parse error"),
123        }
124    }
125
126    #[test]
127    fn test_parse_error_display() {
128        let err = Error::parse("src/main.rs", "unexpected token");
129        let display = format!("{}", err);
130        assert!(display.contains("Parse error in src/main.rs"));
131        assert!(display.contains("unexpected token"));
132    }
133
134    #[test]
135    fn test_storage_error() {
136        let err = Error::storage("connection failed");
137        assert!(matches!(err, Error::Storage(_)));
138        assert_eq!(format!("{}", err), "Storage error: connection failed");
139    }
140
141    #[test]
142    fn test_tree_sitter_error() {
143        let err = Error::tree_sitter("grammar not found");
144        assert!(matches!(err, Error::TreeSitter(_)));
145        assert_eq!(format!("{}", err), "Tree-sitter error: grammar not found");
146    }
147
148    #[test]
149    fn test_watcher_error() {
150        let err = Error::watcher("failed to watch directory");
151        assert!(matches!(err, Error::Watcher(_)));
152        assert_eq!(
153            format!("{}", err),
154            "File watcher error: failed to watch directory"
155        );
156    }
157
158    #[test]
159    fn test_indexing_error() {
160        let err = Error::indexing("failed to index");
161        assert!(matches!(err, Error::Indexing(_)));
162        assert_eq!(format!("{}", err), "Indexing error: failed to index");
163    }
164
165    #[test]
166    fn test_other_error() {
167        let err = Error::other("generic error");
168        assert!(matches!(err, Error::Other(_)));
169        assert_eq!(format!("{}", err), "generic error");
170    }
171
172    #[test]
173    fn test_unsupported_language_error() {
174        let err = Error::UnsupportedLanguage("brainfuck".to_string());
175        assert_eq!(format!("{}", err), "Language not supported: brainfuck");
176    }
177
178    #[test]
179    fn test_config_error() {
180        let err = Error::Config("invalid TOML".to_string());
181        assert_eq!(format!("{}", err), "Configuration error: invalid TOML");
182    }
183
184    #[test]
185    fn test_node_errors() {
186        let node_err = Error::InvalidNodeId("malformed-id".to_string());
187        assert_eq!(format!("{}", node_err), "Invalid node ID: malformed-id");
188
189        let not_found_err = Error::NodeNotFound("node123".to_string());
190        assert_eq!(format!("{}", not_found_err), "Node not found: node123");
191
192        let edge_err = Error::EdgeNotFound("edge456".to_string());
193        assert_eq!(format!("{}", edge_err), "Edge not found: edge456");
194    }
195
196    #[test]
197    fn test_io_error_conversion() {
198        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
199        let err: Error = io_err.into();
200        assert!(matches!(err, Error::Io(_)));
201    }
202
203    #[test]
204    fn test_serde_error_conversion() {
205        let json_err = serde_json::from_str::<serde_json::Value>("invalid json");
206        assert!(json_err.is_err());
207        let err: Error = json_err.unwrap_err().into();
208        assert!(matches!(err, Error::Serialization(_)));
209    }
210}