1use std::fmt;
4
5#[derive(Debug)]
7pub enum CliError {
8 FileNotFound(String),
10 InvalidPattern(String),
12 ConfigError(String),
14 ProcessingError(String),
16}
17
18impl fmt::Display for CliError {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 match self {
21 CliError::FileNotFound(path) => write!(f, "File not found: {path}"),
22 CliError::InvalidPattern(pattern) => write!(f, "Invalid file pattern: {pattern}"),
23 CliError::ConfigError(msg) => write!(f, "Configuration error: {msg}"),
24 CliError::ProcessingError(msg) => write!(f, "Processing error: {msg}"),
25 }
26 }
27}
28
29impl std::error::Error for CliError {}
30
31pub type CliResult<T> = Result<T, anyhow::Error>;
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn test_file_not_found_error_display() {
40 let error = CliError::FileNotFound("test.txt".to_string());
41 assert_eq!(error.to_string(), "File not found: test.txt");
42 }
43
44 #[test]
45 fn test_invalid_pattern_error_display() {
46 let error = CliError::InvalidPattern("[invalid".to_string());
47 assert_eq!(error.to_string(), "Invalid file pattern: [invalid");
48 }
49
50 #[test]
51 fn test_config_error_display() {
52 let error = CliError::ConfigError("invalid format".to_string());
53 assert_eq!(error.to_string(), "Configuration error: invalid format");
54 }
55
56 #[test]
57 fn test_processing_error_display() {
58 let error = CliError::ProcessingError("parse failed".to_string());
59 assert_eq!(error.to_string(), "Processing error: parse failed");
60 }
61
62 #[test]
63 fn test_error_trait_implementation() {
64 let error = CliError::FileNotFound("test.txt".to_string());
65 let _: &dyn std::error::Error = &error;
67
68 let debug_str = format!("{:?}", error);
70 assert!(debug_str.contains("FileNotFound"));
71 assert!(debug_str.contains("test.txt"));
72 }
73
74 #[test]
75 fn test_cli_result_type_alias() {
76 let success: CliResult<String> = Ok("test".to_string());
78 assert!(success.is_ok());
79 assert_eq!(success.as_ref().unwrap(), "test");
80
81 let failure: CliResult<String> = Err(anyhow::anyhow!("test error"));
83 assert!(failure.is_err());
84 assert!(failure
85 .as_ref()
86 .unwrap_err()
87 .to_string()
88 .contains("test error"));
89 }
90
91 #[test]
92 fn test_all_error_variants_creation() {
93 let file_error = CliError::FileNotFound("/path/to/file.txt".to_string());
95 let pattern_error = CliError::InvalidPattern("*.{".to_string());
96 let config_error = CliError::ConfigError("missing field 'language'".to_string());
97 let processing_error = CliError::ProcessingError("segmentation fault".to_string());
98
99 assert!(file_error.to_string().starts_with("File not found:"));
101 assert!(pattern_error
102 .to_string()
103 .starts_with("Invalid file pattern:"));
104 assert!(config_error.to_string().starts_with("Configuration error:"));
105 assert!(processing_error
106 .to_string()
107 .starts_with("Processing error:"));
108 }
109
110 #[test]
111 fn test_error_with_special_characters() {
112 let error = CliError::FileNotFound("ファイル/test 文件.txt".to_string());
114 assert_eq!(error.to_string(), "File not found: ファイル/test 文件.txt");
115
116 let pattern_error = CliError::InvalidPattern("**[!@#$%^&*()".to_string());
117 assert_eq!(
118 pattern_error.to_string(),
119 "Invalid file pattern: **[!@#$%^&*()"
120 );
121 }
122}