1use std::path::PathBuf;
4use thiserror::Error;
5
6pub type Result<T> = std::result::Result<T, Error>;
8
9#[derive(Debug, Error)]
11pub enum Error {
12 #[error("IO error: {0}")]
14 Io(#[from] std::io::Error),
15
16 #[error("Parse error in {file}: {message}")]
18 Parse {
19 file: PathBuf,
21 message: String,
23 },
24
25 #[error("Language not supported: {0}")]
27 UnsupportedLanguage(String),
28
29 #[error("Tree-sitter error: {0}")]
31 TreeSitter(String),
32
33 #[error("Storage error: {0}")]
35 Storage(String),
36
37 #[error("Serialization error: {0}")]
39 Serialization(#[from] serde_json::Error),
40
41 #[error("Configuration error: {0}")]
43 Config(String),
44
45 #[error("File watcher error: {0}")]
47 Watcher(String),
48
49 #[error("Indexing error: {0}")]
51 Indexing(String),
52
53 #[error("Invalid node ID: {0}")]
55 InvalidNodeId(String),
56
57 #[error("Node not found: {0}")]
59 NodeNotFound(String),
60
61 #[error("Edge not found: {0}")]
63 EdgeNotFound(String),
64
65 #[error("{0}")]
67 Other(String),
68}
69
70impl Error {
71 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 pub fn storage(message: impl Into<String>) -> Self {
81 Self::Storage(message.into())
82 }
83
84 pub fn tree_sitter(message: impl Into<String>) -> Self {
86 Self::TreeSitter(message.into())
87 }
88
89 pub fn watcher(message: impl Into<String>) -> Self {
91 Self::Watcher(message.into())
92 }
93
94 pub fn indexing(message: impl Into<String>) -> Self {
96 Self::Indexing(message.into())
97 }
98
99 pub fn io(message: impl Into<String>) -> Self {
101 Self::Io(std::io::Error::other(message.into()))
102 }
103
104 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}