use crate::stat_id::StatId;
use thiserror::Error;
fn format_cycle_path(path: &[StatId]) -> String {
if path.is_empty() {
return String::from("(empty cycle)");
}
path.iter()
.map(|id| id.as_str())
.collect::<Vec<_>>()
.join(" -> ")
}
#[derive(Debug, Error, Clone, PartialEq)]
pub enum StatError {
#[error("Cycle detected: {}", format_cycle_path(.path))]
Cycle { path: Vec<StatId> },
#[error("Missing dependency: {0}")]
MissingDependency(StatId),
#[error("Missing source for stat: {0}")]
MissingSource(StatId),
#[error("Invalid transform for stat {0}: {1}")]
InvalidTransform(StatId, String),
#[error("VM error: {0}")]
VmError(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = StatError::MissingSource(StatId::from("HP"));
assert!(err.to_string().contains("HP"));
}
#[test]
fn test_cycle_error_display() {
let a = StatId::from("A");
let b = StatId::from("B");
let c = StatId::from("C");
let err = StatError::Cycle {
path: vec![a.clone(), b.clone(), c.clone(), a.clone()],
};
let display = err.to_string();
assert!(display.contains("Cycle detected"));
assert!(display.contains("A"));
assert!(display.contains("B"));
assert!(display.contains("C"));
assert!(display.contains(" -> "));
}
}