Skip to main content

forgekit_core/
error.rs

1//! Error types for ForgeKit.
2
3use crate::types::Span;
4use std::path::PathBuf;
5
6/// Main error type for ForgeKit.
7///
8/// All Forge operations return `Result<T> = std::result::Result<T, ForgeError>`.
9#[derive(thiserror::Error, Debug)]
10pub enum ForgeError {
11    /// Database operation failed.
12    #[error("Database error: {0}")]
13    DatabaseError(String),
14
15    /// Symbol could not be found.
16    #[error("Symbol not found: {0}")]
17    SymbolNotFound(String),
18
19    /// Invalid query syntax or parameters.
20    #[error("Invalid query: {0}")]
21    InvalidQuery(String),
22
23    /// Edit conflict detected.
24    #[error("Edit conflict in {file:?} at {span:?}")]
25    EditConflict {
26        /// File containing the conflict
27        file: PathBuf,
28        /// Conflicting span
29        span: Span,
30    },
31
32    /// Pre-commit verification failed.
33    #[error("Verification failed: {0}")]
34    VerificationFailed(String),
35
36    /// Policy constraint violated.
37    #[error("Policy violation: {0}")]
38    PolicyViolation(String),
39
40    /// Requested backend is not available.
41    #[error("Backend not available: {0}")]
42    BackendNotAvailable(String),
43
44    /// CFG not available for the requested function.
45    #[error("CFG not available for symbol: {0:?}")]
46    CfgNotAvailable(crate::types::SymbolId),
47
48    /// Path enumeration overflow (too many paths).
49    #[error("Path overflow for symbol: {0:?}")]
50    PathOverflow(crate::types::SymbolId),
51
52    /// I/O error.
53    #[error("I/O error: {0}")]
54    Io(#[from] std::io::Error),
55
56    /// Serialization/deserialization error.
57    #[error("JSON error: {0}")]
58    Json(#[from] serde_json::Error),
59
60    /// Error from underlying sqlitegraph.
61    #[error("Graph error: {0}")]
62    Graph(#[from] anyhow::Error),
63
64    /// External tool execution error (Magellan, LLMGrep, etc.).
65    #[error("Tool error: {0}")]
66    ToolError(String),
67
68    /// Path is not allowed (outside codebase or absolute).
69    #[error("Path not allowed: {0}")]
70    PathNotAllowed(PathBuf),
71
72    /// File already exists.
73    #[error("File already exists: {0}")]
74    FileAlreadyExists(PathBuf),
75}
76
77/// Type alias for Result with ForgeError.
78pub type Result<T> = std::result::Result<T, ForgeError>;
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn test_error_display() {
86        let err = ForgeError::SymbolNotFound("test".to_string());
87        assert_eq!(err.to_string(), "Symbol not found: test");
88    }
89
90    #[test]
91    fn test_span_is_empty() {
92        let span = Span { start: 10, end: 10 };
93        assert!(span.is_empty());
94    }
95
96    #[test]
97    fn test_span_contains() {
98        let span = Span { start: 10, end: 20 };
99        assert!(span.contains(15));
100        assert!(!span.contains(20));
101        assert!(!span.contains(5));
102    }
103}