use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum TreadleError {
#[error("State store error: {0}")]
StateStore(String),
#[error("Stage execution error: {0}")]
StageExecution(String),
#[error("Invalid workflow: {0}")]
InvalidWorkflow(String),
#[error("Work item not found: {0}")]
WorkItemNotFound(String),
#[error("Stage not found: {0}")]
StageNotFound(String),
#[error("Duplicate stage name: {0}")]
DuplicateStage(String),
#[error("Cycle detected in workflow DAG")]
DagCycle,
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[cfg(feature = "sqlite")]
#[error("Database error: {0}")]
Database(String),
}
pub type Result<T> = std::result::Result<T, TreadleError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display_state_store() {
let error = TreadleError::StateStore("connection failed".to_string());
assert_eq!(error.to_string(), "State store error: connection failed");
}
#[test]
fn test_error_display_stage_execution() {
let error = TreadleError::StageExecution("timeout".to_string());
assert_eq!(error.to_string(), "Stage execution error: timeout");
}
#[test]
fn test_error_display_invalid_workflow() {
let error = TreadleError::InvalidWorkflow("cycle detected".to_string());
assert_eq!(error.to_string(), "Invalid workflow: cycle detected");
}
#[test]
fn test_error_display_work_item_not_found() {
let error = TreadleError::WorkItemNotFound("item-123".to_string());
assert_eq!(error.to_string(), "Work item not found: item-123");
}
#[test]
fn test_error_display_stage_not_found() {
let error = TreadleError::StageNotFound("scan".to_string());
assert_eq!(error.to_string(), "Stage not found: scan");
}
#[test]
fn test_error_display_duplicate_stage() {
let error = TreadleError::DuplicateStage("scan".to_string());
assert_eq!(error.to_string(), "Duplicate stage name: scan");
}
#[test]
fn test_error_display_dag_cycle() {
let error = TreadleError::DagCycle;
assert_eq!(error.to_string(), "Cycle detected in workflow DAG");
}
#[test]
fn test_error_from_serde_json() {
let json_error = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
let treadle_error: TreadleError = json_error.into();
assert!(treadle_error.to_string().contains("Serialization error"));
}
#[test]
fn test_error_from_io() {
let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let treadle_error: TreadleError = io_error.into();
assert!(treadle_error.to_string().contains("I/O error"));
}
#[test]
fn test_result_ok() {
let result: Result<i32> = Ok(42);
assert!(result.is_ok());
assert_eq!(result.ok(), Some(42));
}
#[test]
fn test_result_err() {
let result: Result<i32> = Err(TreadleError::StateStore("test".to_string()));
assert!(result.is_err());
}
#[test]
fn test_error_debug_format() {
let error = TreadleError::StateStore("debug test".to_string());
let debug_output = format!("{:?}", error);
assert!(debug_output.contains("StateStore"));
assert!(debug_output.contains("debug test"));
}
}