Skip to main content

cc_audit/
error.rs

1use crate::hooks::HookError;
2use crate::malware_db::MalwareDbError;
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum AuditError {
7    #[error("File not found: {0}")]
8    FileNotFound(String),
9
10    #[error("Failed to read file: {path}")]
11    ReadError {
12        path: String,
13        #[source]
14        source: std::io::Error,
15    },
16
17    #[error("Failed to parse YAML frontmatter: {path}")]
18    YamlParseError {
19        path: String,
20        #[source]
21        source: serde_yaml::Error,
22    },
23
24    #[error("Invalid SKILL.md format: {0}")]
25    InvalidSkillFormat(String),
26
27    #[error("Regex compilation error: {0}")]
28    RegexError(#[from] regex::Error),
29
30    #[error("Path is not a directory: {0}")]
31    NotADirectory(String),
32
33    #[error("JSON serialization error: {0}")]
34    JsonError(#[from] serde_json::Error),
35
36    #[error("Failed to parse file: {path} - {message}")]
37    ParseError { path: String, message: String },
38
39    #[error("Hook operation failed: {0}")]
40    Hook(#[from] HookError),
41
42    #[error("Malware database error: {0}")]
43    MalwareDb(#[from] MalwareDbError),
44
45    #[error("File watch error: {0}")]
46    Watch(#[from] notify::Error),
47
48    #[error("Configuration error: {0}")]
49    Config(String),
50}
51
52pub type Result<T> = std::result::Result<T, AuditError>;
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_error_display_file_not_found() {
60        let err = AuditError::FileNotFound("/path/to/file".to_string());
61        assert_eq!(err.to_string(), "File not found: /path/to/file");
62    }
63
64    #[test]
65    fn test_error_display_read_error() {
66        let err = AuditError::ReadError {
67            path: "/path/to/file".to_string(),
68            source: std::io::Error::new(std::io::ErrorKind::NotFound, "not found"),
69        };
70        assert_eq!(err.to_string(), "Failed to read file: /path/to/file");
71    }
72
73    #[test]
74    fn test_error_display_invalid_skill_format() {
75        let err = AuditError::InvalidSkillFormat("missing frontmatter".to_string());
76        assert_eq!(
77            err.to_string(),
78            "Invalid SKILL.md format: missing frontmatter"
79        );
80    }
81
82    #[test]
83    fn test_error_display_not_a_directory() {
84        let err = AuditError::NotADirectory("/path/to/file".to_string());
85        assert_eq!(err.to_string(), "Path is not a directory: /path/to/file");
86    }
87
88    #[test]
89    fn test_error_display_parse_error() {
90        let err = AuditError::ParseError {
91            path: "/path/to/file".to_string(),
92            message: "invalid JSON".to_string(),
93        };
94        assert_eq!(
95            err.to_string(),
96            "Failed to parse file: /path/to/file - invalid JSON"
97        );
98    }
99
100    #[test]
101    fn test_error_from_hook_error() {
102        let hook_error = HookError::NotAGitRepository;
103        let err: AuditError = hook_error.into();
104        assert!(err.to_string().contains("Hook operation failed"));
105    }
106
107    #[test]
108    fn test_error_from_malware_db_error() {
109        let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "not found");
110        let malware_error = MalwareDbError::ReadFile(io_error);
111        let err: AuditError = malware_error.into();
112        assert!(err.to_string().contains("Malware database error"));
113    }
114
115    #[test]
116    fn test_error_display_config() {
117        let err = AuditError::Config("invalid value".to_string());
118        assert_eq!(err.to_string(), "Configuration error: invalid value");
119    }
120}