directory_indexer/
error.rs1use thiserror::Error;
2
3pub type Result<T> = std::result::Result<T, IndexerError>;
4
5#[derive(Error, Debug)]
6pub enum IndexerError {
7 #[error("IO error: {0}")]
8 Io(#[from] std::io::Error),
9
10 #[error("Database error: {0}")]
11 Database(#[from] rusqlite::Error),
12
13 #[error("HTTP request error: {0}")]
14 Http(#[from] reqwest::Error),
15
16 #[error("JSON serialization error: {0}")]
17 Json(#[from] serde_json::Error),
18
19 #[error("Configuration error: {0}")]
20 Config(#[from] config::ConfigError),
21
22 #[error("Embedding provider error: {message}")]
23 Embedding { message: String },
24
25 #[error("Vector store error: {message}")]
26 VectorStore { message: String },
27
28 #[error("File processing error: {message}")]
29 FileProcessing { message: String },
30
31 #[error("Invalid input: {message}")]
32 InvalidInput { message: String },
33
34 #[error("Resource not found: {message}")]
35 NotFound { message: String },
36
37 #[error("MCP protocol error: {message}")]
38 Mcp { message: String },
39
40 #[error("Environment setup required: {message}")]
41 EnvironmentSetup { message: String },
42}
43
44impl IndexerError {
45 pub fn embedding<S: Into<String>>(message: S) -> Self {
46 Self::Embedding {
47 message: message.into(),
48 }
49 }
50
51 pub fn vector_store<S: Into<String>>(message: S) -> Self {
52 Self::VectorStore {
53 message: message.into(),
54 }
55 }
56
57 pub fn file_processing<S: Into<String>>(message: S) -> Self {
58 Self::FileProcessing {
59 message: message.into(),
60 }
61 }
62
63 pub fn invalid_input<S: Into<String>>(message: S) -> Self {
64 Self::InvalidInput {
65 message: message.into(),
66 }
67 }
68
69 pub fn not_found<S: Into<String>>(message: S) -> Self {
70 Self::NotFound {
71 message: message.into(),
72 }
73 }
74
75 pub fn mcp<S: Into<String>>(message: S) -> Self {
76 Self::Mcp {
77 message: message.into(),
78 }
79 }
80
81 pub fn environment_setup<S: Into<String>>(message: S) -> Self {
82 Self::EnvironmentSetup {
83 message: message.into(),
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use std::io;
92
93 #[test]
94 fn test_error_display_messages() {
95 let io_error = IndexerError::Io(io::Error::new(io::ErrorKind::NotFound, "test io error"));
96 assert!(io_error.to_string().contains("IO error"));
97 assert!(io_error.to_string().contains("test io error"));
98
99 let embedding_error = IndexerError::embedding("embedding failed");
100 assert_eq!(
101 embedding_error.to_string(),
102 "Embedding provider error: embedding failed"
103 );
104
105 let vector_error = IndexerError::vector_store("qdrant unavailable");
106 assert_eq!(
107 vector_error.to_string(),
108 "Vector store error: qdrant unavailable"
109 );
110
111 let file_error = IndexerError::file_processing("cannot read file");
112 assert_eq!(
113 file_error.to_string(),
114 "File processing error: cannot read file"
115 );
116
117 let input_error = IndexerError::invalid_input("invalid path");
118 assert_eq!(input_error.to_string(), "Invalid input: invalid path");
119
120 let not_found_error = IndexerError::not_found("file not found");
121 assert_eq!(
122 not_found_error.to_string(),
123 "Resource not found: file not found"
124 );
125
126 let mcp_error = IndexerError::mcp("protocol error");
127 assert_eq!(mcp_error.to_string(), "MCP protocol error: protocol error");
128
129 let env_error = IndexerError::environment_setup("qdrant not running");
130 assert_eq!(
131 env_error.to_string(),
132 "Environment setup required: qdrant not running"
133 );
134 }
135
136 #[test]
137 fn test_error_constructor_functions() {
138 let embedding_error = IndexerError::embedding("test message");
139 match embedding_error {
140 IndexerError::Embedding { message } => assert_eq!(message, "test message"),
141 _ => panic!("Expected Embedding error"),
142 }
143
144 let vector_error = IndexerError::vector_store("qdrant error");
145 match vector_error {
146 IndexerError::VectorStore { message } => assert_eq!(message, "qdrant error"),
147 _ => panic!("Expected VectorStore error"),
148 }
149
150 let file_error = IndexerError::file_processing("read failed");
151 match file_error {
152 IndexerError::FileProcessing { message } => assert_eq!(message, "read failed"),
153 _ => panic!("Expected FileProcessing error"),
154 }
155
156 let input_error = IndexerError::invalid_input("bad input");
157 match input_error {
158 IndexerError::InvalidInput { message } => assert_eq!(message, "bad input"),
159 _ => panic!("Expected InvalidInput error"),
160 }
161
162 let not_found_error = IndexerError::not_found("missing");
163 match not_found_error {
164 IndexerError::NotFound { message } => assert_eq!(message, "missing"),
165 _ => panic!("Expected NotFound error"),
166 }
167
168 let mcp_error = IndexerError::mcp("rpc error");
169 match mcp_error {
170 IndexerError::Mcp { message } => assert_eq!(message, "rpc error"),
171 _ => panic!("Expected Mcp error"),
172 }
173
174 let env_error = IndexerError::environment_setup("setup needed");
175 match env_error {
176 IndexerError::EnvironmentSetup { message } => assert_eq!(message, "setup needed"),
177 _ => panic!("Expected EnvironmentSetup error"),
178 }
179 }
180
181 #[test]
182 fn test_error_from_conversions() {
183 let io_error = io::Error::new(io::ErrorKind::PermissionDenied, "access denied");
184 let indexer_error: IndexerError = io_error.into();
185 match indexer_error {
186 IndexerError::Io(_) => {}
187 _ => panic!("Expected Io error from conversion"),
188 }
189
190 let json_error = serde_json::from_str::<i32>("invalid json").unwrap_err();
191 let indexer_error: IndexerError = json_error.into();
192 match indexer_error {
193 IndexerError::Json(_) => {}
194 _ => panic!("Expected Json error from conversion"),
195 }
196 }
197
198 #[test]
199 fn test_error_debug_format() {
200 let error = IndexerError::embedding("debug test");
201 let debug_str = format!("{:?}", error);
202 assert!(debug_str.contains("Embedding"));
203 assert!(debug_str.contains("debug test"));
204 }
205
206 #[test]
207 fn test_error_string_conversion() {
208 let error1 = IndexerError::embedding(String::from("owned string"));
209 let error2 = IndexerError::embedding("borrowed string");
210
211 match (&error1, &error2) {
212 (
213 IndexerError::Embedding { message: msg1 },
214 IndexerError::Embedding { message: msg2 },
215 ) => {
216 assert_eq!(msg1, "owned string");
217 assert_eq!(msg2, "borrowed string");
218 }
219 _ => panic!("Expected Embedding errors"),
220 }
221 }
222
223 #[test]
224 fn test_result_type_alias() {
225 fn returns_result() -> Result<i32> {
226 Ok(42)
227 }
228
229 fn returns_error() -> Result<i32> {
230 Err(IndexerError::invalid_input("test error"))
231 }
232
233 assert_eq!(returns_result().unwrap(), 42);
234 assert!(returns_error().is_err());
235 }
236}