1#[derive(Debug, thiserror::Error)]
6pub enum GitError {
7 #[error("{command}: {stderr}")]
9 CommandFailed {
10 command: String,
12 stderr: String,
14 },
15
16 #[error("{0}")]
18 OutputParse(String),
19
20 #[error("{0}")]
22 Io(#[from] std::io::Error),
23
24 #[error("Join error: {0}")]
26 Join(#[from] tokio::task::JoinError),
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32
33 #[test]
34 fn command_failed_display_includes_command_and_stderr() {
35 let error = GitError::CommandFailed {
37 command: "git push origin main".to_string(),
38 stderr: "fatal: could not read Username".to_string(),
39 };
40
41 let display = error.to_string();
43
44 assert!(matches!(
46 error,
47 GitError::CommandFailed {
48 ref command,
49 ref stderr,
50 } if command == "git push origin main" && stderr == "fatal: could not read Username"
51 ));
52 assert_eq!(
53 display,
54 "git push origin main: fatal: could not read Username"
55 );
56 }
57
58 #[test]
59 fn output_parse_display_shows_message() {
60 let error = GitError::OutputParse("unexpected rev-parse output".to_string());
62
63 assert!(
65 matches!(error, GitError::OutputParse(ref message) if message == "unexpected rev-parse output")
66 );
67 assert_eq!(error.to_string(), "unexpected rev-parse output");
68 }
69
70 #[test]
71 fn io_error_converts_via_from() {
72 let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
74
75 let error = GitError::from(io_error);
77
78 assert!(matches!(error, GitError::Io(_)));
80 assert!(error.to_string().contains("file missing"));
81 }
82}