use std::path::PathBuf;
#[derive(Debug, thiserror::Error)]
pub enum PluginError {
#[error("Plugin manifest not found: {path}")]
ManifestNotFound { path: PathBuf },
#[error("Invalid plugin manifest at {path}: {reason}")]
InvalidManifest { path: PathBuf, reason: String },
#[error("Duplicate plugin name '{name}': first at {first}, second at {second}")]
DuplicateName {
name: String,
first: PathBuf,
second: PathBuf,
},
#[error("Invalid plugin name '{name}': {reason}")]
InvalidName { name: String, reason: String },
#[error("Failed to load resources for plugin '{plugin}': {message}")]
ResourceLoad { plugin: String, message: String },
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Json(#[from] serde_json::Error),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = PluginError::ManifestNotFound {
path: PathBuf::from("/plugins/test"),
};
assert!(err.to_string().contains("/plugins/test"));
let err = PluginError::InvalidManifest {
path: PathBuf::from("/plugins/bad"),
reason: "missing name".into(),
};
assert!(err.to_string().contains("missing name"));
let err = PluginError::DuplicateName {
name: "my-plugin".into(),
first: PathBuf::from("/plugins/first"),
second: PathBuf::from("/plugins/second"),
};
let msg = err.to_string();
assert!(msg.contains("my-plugin"));
assert!(msg.contains("first"));
assert!(msg.contains("second"));
let err = PluginError::InvalidName {
name: "bad:name".into(),
reason: "contains namespace separator".into(),
};
assert!(err.to_string().contains("bad:name"));
}
#[test]
fn test_io_error_conversion() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
let plugin_err: PluginError = io_err.into();
assert!(matches!(plugin_err, PluginError::Io(_)));
}
#[test]
fn test_json_error_conversion() {
let json_err = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
let plugin_err: PluginError = json_err.into();
assert!(matches!(plugin_err, PluginError::Json(_)));
}
}