vkteams_bot_cli/
errors.rs1use std::fmt;
2use vkteams_bot::error::BotError;
3
4pub static FILE_NOT_FOUND: &str = "File not found: ";
6pub static DIR_NOT_FOUND: &str = "Directory not found: ";
7pub static NOT_A_FILE: &str = "Path is not a file: ";
8pub static NOT_A_DIR: &str = "Path is not a directory: ";
9pub static WRITE_ERROR: &str = "Failed to write file: ";
10pub static READ_ERROR: &str = "Failed to read file: ";
11pub static DOWNLOAD_ERROR: &str = "Failed to download file: ";
12pub static API_ERROR: &str = "API Error: ";
13pub static INPUT_ERROR: &str = "Input Error: ";
14pub static UNEXPECTED_ERROR: &str = "Unexpected Error: ";
15
16#[derive(Debug)]
18pub enum CliError {
19 ApiError(BotError),
21 FileError(String),
23 InputError(String),
25 UnexpectedError(String),
27 Storage(String),
29 Config(String),
31 DaemonAlreadyRunning,
33 DaemonNotRunning,
35 System(String),
37}
38
39pub type Result<T> = std::result::Result<T, CliError>;
41
42impl From<BotError> for CliError {
43 fn from(error: BotError) -> Self {
44 CliError::ApiError(error)
45 }
46}
47
48impl From<std::io::Error> for CliError {
49 fn from(error: std::io::Error) -> Self {
50 CliError::FileError(error.to_string())
51 }
52}
53
54impl From<serde_json::Error> for CliError {
55 fn from(error: serde_json::Error) -> Self {
56 CliError::UnexpectedError(format!("JSON error: {error}"))
57 }
58}
59
60impl fmt::Display for CliError {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 match self {
63 CliError::ApiError(err) => write!(f, "{API_ERROR}{err}"),
64 CliError::FileError(err) => write!(f, "File Error: {err}"),
65 CliError::InputError(err) => write!(f, "{INPUT_ERROR}{err}"),
66 CliError::UnexpectedError(err) => write!(f, "{UNEXPECTED_ERROR}{err}"),
67 CliError::Storage(err) => write!(f, "Storage Error: {err}"),
68 CliError::Config(err) => write!(f, "Configuration Error: {err}"),
69 CliError::DaemonAlreadyRunning => write!(f, "Daemon is already running"),
70 CliError::DaemonNotRunning => write!(f, "Daemon is not running"),
71 CliError::System(err) => write!(f, "System Error: {err}"),
72 }
73 }
74}
75
76impl std::error::Error for CliError {}
77
78impl CliError {
79 #[must_use]
81 pub fn exit_code(&self) -> i32 {
82 match self {
83 CliError::ApiError(_) => exitcode::UNAVAILABLE,
84 CliError::FileError(_) => exitcode::IOERR,
85 CliError::InputError(_) => exitcode::USAGE,
86 CliError::UnexpectedError(_) => exitcode::SOFTWARE,
87 CliError::Storage(_) => exitcode::IOERR,
88 CliError::Config(_) => exitcode::CONFIG,
89 CliError::DaemonAlreadyRunning => exitcode::TEMPFAIL,
90 CliError::DaemonNotRunning => exitcode::TEMPFAIL,
91 CliError::System(_) => exitcode::OSERR,
92 }
93 }
94
95 }
110
111pub mod prelude {
113 pub use super::{
114 API_ERROR, DIR_NOT_FOUND, DOWNLOAD_ERROR, FILE_NOT_FOUND, INPUT_ERROR, NOT_A_DIR,
115 NOT_A_FILE, READ_ERROR, UNEXPECTED_ERROR, WRITE_ERROR,
116 };
117 pub use super::{CliError, Result};
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use serde_json;
124 use std::io;
125 use vkteams_bot::error::BotError;
126
127 #[test]
128 fn test_cli_error_display_and_exit_code() {
129 let api_err = CliError::ApiError(BotError::Api(vkteams_bot::error::ApiError {
130 description: "api fail".to_string(),
131 }));
132 assert!(format!("{api_err}").contains("API Error:"));
133 assert_eq!(api_err.exit_code(), exitcode::UNAVAILABLE);
134
135 let file_err = CliError::FileError("file fail".to_string());
136 assert!(format!("{file_err}").contains("File Error:"));
137 assert_eq!(file_err.exit_code(), exitcode::IOERR);
138
139 let input_err = CliError::InputError("bad arg".to_string());
140 assert!(format!("{input_err}").contains("Input Error:"));
141 assert_eq!(input_err.exit_code(), exitcode::USAGE);
142
143 let unexp_err = CliError::UnexpectedError("boom".to_string());
144 assert!(format!("{unexp_err}").contains("Unexpected Error:"));
145 assert_eq!(unexp_err.exit_code(), exitcode::SOFTWARE);
146 }
147
148 #[test]
149 fn test_from_bot_error() {
150 let bot_err = BotError::Api(vkteams_bot::error::ApiError {
151 description: "api fail".to_string(),
152 });
153 let cli_err: CliError = bot_err.into();
154 match cli_err {
155 CliError::ApiError(_) => {}
156 _ => panic!("Expected ApiError variant"),
157 }
158 }
159
160 #[test]
161 fn test_from_io_error() {
162 let io_err = io::Error::other("io fail");
163 let cli_err: CliError = io_err.into();
164 match cli_err {
165 CliError::FileError(msg) => assert!(msg.contains("io fail")),
166 _ => panic!("Expected FileError variant"),
167 }
168 }
169
170 #[test]
171 fn test_from_serde_json_error() {
172 let json_err = serde_json::from_str::<u32>("not a number").unwrap_err();
173 let cli_err: CliError = json_err.into();
174 match cli_err {
175 CliError::UnexpectedError(msg) => assert!(msg.contains("JSON error")),
176 _ => panic!("Expected UnexpectedError variant"),
177 }
178 }
179}