Skip to main content

claude_agent/plugins/
error.rs

1use std::path::PathBuf;
2
3#[derive(Debug, thiserror::Error)]
4pub enum PluginError {
5    #[error("Plugin manifest not found: {path}")]
6    ManifestNotFound { path: PathBuf },
7
8    #[error("Invalid plugin manifest at {path}: {reason}")]
9    InvalidManifest { path: PathBuf, reason: String },
10
11    #[error("Duplicate plugin name '{name}': first at {first}, second at {second}")]
12    DuplicateName {
13        name: String,
14        first: PathBuf,
15        second: PathBuf,
16    },
17
18    #[error("Invalid plugin name '{name}': {reason}")]
19    InvalidName { name: String, reason: String },
20
21    #[error("Failed to load resources for plugin '{plugin}': {message}")]
22    ResourceLoad { plugin: String, message: String },
23
24    #[error(transparent)]
25    Io(#[from] std::io::Error),
26
27    #[error(transparent)]
28    Json(#[from] serde_json::Error),
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34
35    #[test]
36    fn test_error_display() {
37        let err = PluginError::ManifestNotFound {
38            path: PathBuf::from("/plugins/test"),
39        };
40        assert!(err.to_string().contains("/plugins/test"));
41
42        let err = PluginError::InvalidManifest {
43            path: PathBuf::from("/plugins/bad"),
44            reason: "missing name".into(),
45        };
46        assert!(err.to_string().contains("missing name"));
47
48        let err = PluginError::DuplicateName {
49            name: "my-plugin".into(),
50            first: PathBuf::from("/plugins/first"),
51            second: PathBuf::from("/plugins/second"),
52        };
53        let msg = err.to_string();
54        assert!(msg.contains("my-plugin"));
55        assert!(msg.contains("first"));
56        assert!(msg.contains("second"));
57
58        let err = PluginError::InvalidName {
59            name: "bad:name".into(),
60            reason: "contains namespace separator".into(),
61        };
62        assert!(err.to_string().contains("bad:name"));
63    }
64
65    #[test]
66    fn test_io_error_conversion() {
67        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
68        let plugin_err: PluginError = io_err.into();
69        assert!(matches!(plugin_err, PluginError::Io(_)));
70    }
71
72    #[test]
73    fn test_json_error_conversion() {
74        let json_err = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
75        let plugin_err: PluginError = json_err.into();
76        assert!(matches!(plugin_err, PluginError::Json(_)));
77    }
78}