Skip to main content

cargo_stitch/
error.rs

1use camino::Utf8PathBuf;
2
3#[derive(Debug)]
4pub struct IoError(pub std::io::Error);
5
6impl std::fmt::Display for IoError {
7    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8        write!(f, "{}", self.0)
9    }
10}
11
12pub struct PatchFailed {
13    pub file: Utf8PathBuf,
14    pub output: String,
15}
16
17impl std::fmt::Display for PatchFailed {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        write!(f, "failed to apply patch: {}", self.file)?;
20        if !self.output.is_empty() {
21            write!(f, "\n{}", self.output.trim_end())?;
22        }
23        Ok(())
24    }
25}
26
27pub struct AstGrepFailed {
28    pub file: Utf8PathBuf,
29    pub output: String,
30}
31
32impl std::fmt::Display for AstGrepFailed {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        write!(f, "failed to apply ast-grep rule: {}", self.file)?;
35        if !self.output.is_empty() {
36            write!(f, "\n{}", self.output.trim_end())?;
37        }
38        Ok(())
39    }
40}
41
42pub struct CargoFailed(pub i32);
43
44impl std::fmt::Display for CargoFailed {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        write!(f, "cargo exited with status {}", self.0)
47    }
48}
49
50pub struct MissingEnvVar(pub &'static str);
51
52impl std::fmt::Display for MissingEnvVar {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        write!(f, "missing environment variable: {}", self.0)
55    }
56}
57
58pub struct MissingTool(pub &'static str);
59
60impl std::fmt::Display for MissingTool {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(
63            f,
64            "required tool not found: {} (is it installed and in PATH?)",
65            self.0
66        )
67    }
68}
69
70pub struct MissingWorkspaceRoot(pub Utf8PathBuf);
71
72impl std::fmt::Display for MissingWorkspaceRoot {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        write!(
75            f,
76            "could not find workspace root from manifest directory: {}",
77            self.0
78        )
79    }
80}
81
82pub struct MissingStitchSet(pub String);
83
84impl std::fmt::Display for MissingStitchSet {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        write!(f, "stitch set not found: stitches/{}/", self.0)
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn patch_failed_display_empty_output() {
96        let err = PatchFailed {
97            file: Utf8PathBuf::from("stitches/default/crate-a/001.patch"),
98            output: String::new(),
99        };
100        assert_eq!(
101            err.to_string(),
102            "failed to apply patch: stitches/default/crate-a/001.patch"
103        );
104    }
105
106    #[test]
107    fn patch_failed_display_with_output() {
108        let err = PatchFailed {
109            file: Utf8PathBuf::from("fix.patch"),
110            output: "Hunk #1 FAILED\n".to_string(),
111        };
112        assert_eq!(
113            err.to_string(),
114            "failed to apply patch: fix.patch\nHunk #1 FAILED"
115        );
116    }
117
118    #[test]
119    fn ast_grep_failed_display_empty_output() {
120        let err = AstGrepFailed {
121            file: Utf8PathBuf::from("rule.yaml"),
122            output: String::new(),
123        };
124        assert_eq!(err.to_string(), "failed to apply ast-grep rule: rule.yaml");
125    }
126
127    #[test]
128    fn ast_grep_failed_display_with_output() {
129        let err = AstGrepFailed {
130            file: Utf8PathBuf::from("rule.yaml"),
131            output: "error details\n".to_string(),
132        };
133        assert_eq!(
134            err.to_string(),
135            "failed to apply ast-grep rule: rule.yaml\nerror details"
136        );
137    }
138
139    #[test]
140    fn cargo_failed_display() {
141        let err = CargoFailed(42);
142        assert_eq!(err.to_string(), "cargo exited with status 42");
143    }
144
145    #[test]
146    fn missing_env_var_display() {
147        let err = MissingEnvVar("CARGO_PKG_NAME");
148        assert_eq!(
149            err.to_string(),
150            "missing environment variable: CARGO_PKG_NAME"
151        );
152    }
153
154    #[test]
155    fn missing_tool_display() {
156        let err = MissingTool("patch");
157        assert_eq!(
158            err.to_string(),
159            "required tool not found: patch (is it installed and in PATH?)"
160        );
161    }
162
163    #[test]
164    fn missing_workspace_root_display() {
165        let err = MissingWorkspaceRoot(Utf8PathBuf::from("/tmp/foo"));
166        assert_eq!(
167            err.to_string(),
168            "could not find workspace root from manifest directory: /tmp/foo"
169        );
170    }
171
172    #[test]
173    fn missing_stitch_set_display() {
174        let err = MissingStitchSet("custom".to_string());
175        assert_eq!(err.to_string(), "stitch set not found: stitches/custom/");
176    }
177}