Skip to main content

depyler_knowledge/
error.rs

1//! Error types for the Sovereign Type Database.
2
3use thiserror::Error;
4
5/// Result type alias for knowledge operations.
6pub type Result<T> = std::result::Result<T, KnowledgeError>;
7
8/// Errors that can occur during type extraction and database operations.
9#[derive(Error, Debug)]
10pub enum KnowledgeError {
11    /// Failed to execute uv command
12    #[error("uv command failed: {0}")]
13    UvCommandFailed(String),
14
15    /// Package not found or installation failed
16    #[error("package not found: {0}")]
17    PackageNotFound(String),
18
19    /// Failed to parse Python stub file
20    #[error("stub parse error in {file}: {message}")]
21    StubParseError { file: String, message: String },
22
23    /// Failed to read/write Parquet database
24    #[error("database error: {0}")]
25    DatabaseError(String),
26
27    /// Invalid TypeFactKind string
28    #[error("invalid type fact kind: {0}")]
29    InvalidKind(String),
30
31    /// Query returned no results
32    #[error("symbol not found: {module}.{symbol}")]
33    SymbolNotFound { module: String, symbol: String },
34
35    /// IO error
36    #[error("IO error: {0}")]
37    Io(#[from] std::io::Error),
38
39    /// Arrow/Parquet error (when parquet-storage feature is enabled)
40    #[error("storage error: {0}")]
41    Storage(String),
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    #[test]
49    fn test_uv_command_failed_display() {
50        let err = KnowledgeError::UvCommandFailed("connection timeout".to_string());
51        assert_eq!(err.to_string(), "uv command failed: connection timeout");
52    }
53
54    #[test]
55    fn test_package_not_found_display() {
56        let err = KnowledgeError::PackageNotFound("nonexistent-pkg".to_string());
57        assert_eq!(err.to_string(), "package not found: nonexistent-pkg");
58    }
59
60    #[test]
61    fn test_stub_parse_error_display() {
62        let err = KnowledgeError::StubParseError {
63            file: "mod.pyi".to_string(),
64            message: "syntax error".to_string(),
65        };
66        assert_eq!(
67            err.to_string(),
68            "stub parse error in mod.pyi: syntax error"
69        );
70    }
71
72    #[test]
73    fn test_database_error_display() {
74        let err = KnowledgeError::DatabaseError("corrupt file".to_string());
75        assert_eq!(err.to_string(), "database error: corrupt file");
76    }
77
78    #[test]
79    fn test_invalid_kind_display() {
80        let err = KnowledgeError::InvalidKind("foobar".to_string());
81        assert_eq!(err.to_string(), "invalid type fact kind: foobar");
82    }
83
84    #[test]
85    fn test_symbol_not_found_display() {
86        let err = KnowledgeError::SymbolNotFound {
87            module: "os".to_string(),
88            symbol: "missing".to_string(),
89        };
90        assert_eq!(err.to_string(), "symbol not found: os.missing");
91    }
92
93    #[test]
94    fn test_io_error_from() {
95        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
96        let knowledge_err = KnowledgeError::from(io_err);
97        assert!(matches!(knowledge_err, KnowledgeError::Io(_)));
98        assert!(knowledge_err.to_string().contains("file not found"));
99    }
100
101    #[test]
102    fn test_storage_error_display() {
103        let err = KnowledgeError::Storage("parquet write failed".to_string());
104        assert_eq!(err.to_string(), "storage error: parquet write failed");
105    }
106
107    #[test]
108    fn test_error_is_debug() {
109        let err = KnowledgeError::InvalidKind("test".to_string());
110        let debug_str = format!("{err:?}");
111        assert!(debug_str.contains("InvalidKind"));
112    }
113
114    #[test]
115    fn test_result_type_alias_ok() {
116        let result: Result<i32> = Ok(42);
117        assert!(result.is_ok());
118        assert_eq!(*result.as_ref().unwrap(), 42);
119    }
120
121    #[test]
122    fn test_result_type_alias_err() {
123        let result: Result<i32> = Err(KnowledgeError::DatabaseError("fail".to_string()));
124        assert!(result.is_err());
125    }
126
127    // ========================================================================
128    // S9B7: Coverage tests for error types
129    // ========================================================================
130
131    #[test]
132    fn test_s9b7_uv_command_failed_debug() {
133        let err = KnowledgeError::UvCommandFailed("timeout".to_string());
134        let debug = format!("{err:?}");
135        assert!(debug.contains("UvCommandFailed"));
136        assert!(debug.contains("timeout"));
137    }
138
139    #[test]
140    fn test_s9b7_package_not_found_debug() {
141        let err = KnowledgeError::PackageNotFound("fake-pkg".to_string());
142        let debug = format!("{err:?}");
143        assert!(debug.contains("PackageNotFound"));
144    }
145
146    #[test]
147    fn test_s9b7_stub_parse_error_fields() {
148        let err = KnowledgeError::StubParseError {
149            file: "test.pyi".to_string(),
150            message: "unexpected token".to_string(),
151        };
152        let display = err.to_string();
153        assert!(display.contains("test.pyi"));
154        assert!(display.contains("unexpected token"));
155    }
156
157    #[test]
158    fn test_s9b7_symbol_not_found_fields() {
159        let err = KnowledgeError::SymbolNotFound {
160            module: "collections".to_string(),
161            symbol: "OrderedDict".to_string(),
162        };
163        assert_eq!(err.to_string(), "symbol not found: collections.OrderedDict");
164    }
165
166    #[test]
167    fn test_s9b7_storage_error_debug() {
168        let err = KnowledgeError::Storage("corruption detected".to_string());
169        let debug = format!("{err:?}");
170        assert!(debug.contains("Storage"));
171        assert!(debug.contains("corruption detected"));
172    }
173
174    #[test]
175    fn test_s9b7_io_error_kind_preserved() {
176        let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "access denied");
177        let knowledge_err = KnowledgeError::from(io_err);
178        match knowledge_err {
179            KnowledgeError::Io(ref e) => {
180                assert_eq!(e.kind(), std::io::ErrorKind::PermissionDenied);
181            }
182            _ => panic!("expected Io variant"),
183        }
184    }
185
186    #[test]
187    fn test_s9b7_result_type_with_complex_value() {
188        let result: Result<Vec<String>> = Ok(vec!["a".to_string(), "b".to_string()]);
189        assert_eq!(result.as_ref().unwrap().len(), 2);
190    }
191
192    #[test]
193    fn test_s9b7_error_is_std_error() {
194        let err: Box<dyn std::error::Error> =
195            Box::new(KnowledgeError::InvalidKind("bad".to_string()));
196        assert!(err.to_string().contains("bad"));
197    }
198}