use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Error)]
pub enum Error {
#[error("Playbook parse error: {0}")]
PlaybookParseError(String),
#[error("Command failed: {command} (exit code: {exit_code})")]
CommandFailed {
command: String,
exit_code: i32,
stderr: String,
},
#[error("Command timed out after {timeout_ms}ms: {command}")]
Timeout {
command: String,
timeout_ms: u64,
},
#[error("Gateway check failed: {gate}")]
GatewayFailed {
gate: String,
reason: String,
},
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
#[error("IO error: {0}")]
Io(std::io::Error),
#[error("Execution error: {0}")]
Execution(String),
#[error("Execution failed: {command} - {reason}")]
ExecutionFailed {
command: String,
reason: String,
},
#[error("Serialization error: {0}")]
SerializationError(#[from] serde_json::Error),
#[error("YAML error: {0}")]
YamlError(#[from] serde_yaml::Error),
#[error("Generator error: {0}")]
GeneratorError(#[from] apr_qa_gen::Error),
#[error("Provenance error: {0}")]
Provenance(#[from] crate::provenance::ProvenanceError),
#[error("Validation error: {0}")]
Validation(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = Error::CommandFailed {
command: "apr run".to_string(),
exit_code: 1,
stderr: "error".to_string(),
};
assert!(err.to_string().contains("apr run"));
assert!(err.to_string().contains("exit code: 1"));
}
#[test]
fn test_timeout_error() {
let err = Error::Timeout {
command: "apr serve".to_string(),
timeout_ms: 30000,
};
assert!(err.to_string().contains("30000ms"));
}
#[test]
fn test_validation_error() {
let err = Error::Validation("Invalid playbook name".to_string());
assert!(err.to_string().contains("Validation error"));
assert!(err.to_string().contains("Invalid playbook name"));
}
}