chrome_cli/chrome/
error.rs1use std::fmt;
2
3#[derive(Debug)]
5pub enum ChromeError {
6 NotFound(String),
8
9 LaunchFailed(String),
11
12 StartupTimeout {
14 port: u16,
16 },
17
18 HttpError(String),
20
21 ParseError(String),
23
24 NoActivePort,
26
27 NotRunning(String),
29
30 Io(std::io::Error),
32}
33
34impl fmt::Display for ChromeError {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 match self {
37 Self::NotFound(msg) => write!(f, "Chrome not found: {msg}"),
38 Self::LaunchFailed(msg) => write!(f, "Chrome launch failed: {msg}"),
39 Self::StartupTimeout { port } => {
40 write!(
41 f,
42 "Chrome startup timed out on port {port}. Try --timeout to increase the wait time, or --headless for headless mode"
43 )
44 }
45 Self::HttpError(msg) => write!(f, "Chrome HTTP error: {msg}"),
46 Self::ParseError(msg) => write!(f, "Chrome parse error: {msg}"),
47 Self::NoActivePort => write!(f, "DevToolsActivePort file not found"),
48 Self::NotRunning(detail) => {
49 write!(
50 f,
51 "no running Chrome instance found with remote debugging: {detail}"
52 )
53 }
54 Self::Io(e) => write!(f, "Chrome I/O error: {e}"),
55 }
56 }
57}
58
59impl std::error::Error for ChromeError {
60 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
61 match self {
62 Self::Io(e) => Some(e),
63 _ => None,
64 }
65 }
66}
67
68impl From<std::io::Error> for ChromeError {
69 fn from(e: std::io::Error) -> Self {
70 Self::Io(e)
71 }
72}
73
74impl From<ChromeError> for crate::error::AppError {
75 fn from(e: ChromeError) -> Self {
76 use crate::error::ExitCode;
77 let code = match &e {
78 ChromeError::NotFound(_) | ChromeError::ParseError(_) | ChromeError::Io(_) => {
79 ExitCode::GeneralError
80 }
81 ChromeError::LaunchFailed(_)
82 | ChromeError::HttpError(_)
83 | ChromeError::NotRunning(_)
84 | ChromeError::NoActivePort => ExitCode::ConnectionError,
85 ChromeError::StartupTimeout { .. } => ExitCode::TimeoutError,
86 };
87 Self {
88 message: e.to_string(),
89 code,
90 custom_json: None,
91 }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn display_not_found() {
101 let err = ChromeError::NotFound("try --chrome-path".into());
102 assert_eq!(err.to_string(), "Chrome not found: try --chrome-path");
103 }
104
105 #[test]
106 fn display_launch_failed() {
107 let err = ChromeError::LaunchFailed("permission denied".into());
108 assert_eq!(err.to_string(), "Chrome launch failed: permission denied");
109 }
110
111 #[test]
112 fn display_startup_timeout() {
113 let err = ChromeError::StartupTimeout { port: 9222 };
114 assert_eq!(
115 err.to_string(),
116 "Chrome startup timed out on port 9222. Try --timeout to increase the wait time, or --headless for headless mode"
117 );
118 }
119
120 #[test]
121 fn display_http_error() {
122 let err = ChromeError::HttpError("connection refused".into());
123 assert_eq!(err.to_string(), "Chrome HTTP error: connection refused");
124 }
125
126 #[test]
127 fn display_parse_error() {
128 let err = ChromeError::ParseError("invalid JSON".into());
129 assert_eq!(err.to_string(), "Chrome parse error: invalid JSON");
130 }
131
132 #[test]
133 fn display_no_active_port() {
134 let err = ChromeError::NoActivePort;
135 assert_eq!(err.to_string(), "DevToolsActivePort file not found");
136 }
137
138 #[test]
139 fn display_not_running() {
140 let err = ChromeError::NotRunning("port 9222 refused".into());
141 assert_eq!(
142 err.to_string(),
143 "no running Chrome instance found with remote debugging: port 9222 refused"
144 );
145 }
146
147 #[test]
148 fn display_io() {
149 let err = ChromeError::Io(std::io::Error::new(
150 std::io::ErrorKind::NotFound,
151 "file gone",
152 ));
153 assert_eq!(err.to_string(), "Chrome I/O error: file gone");
154 }
155
156 #[test]
157 fn error_source_is_none_for_non_io() {
158 let err: &dyn std::error::Error = &ChromeError::NotRunning("no instance".into());
159 assert!(err.source().is_none());
160 }
161
162 #[test]
163 fn error_source_returns_io_error() {
164 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file gone");
165 let err: &dyn std::error::Error = &ChromeError::Io(io_err);
166 assert!(err.source().is_some());
167 }
168}