use std::{path::PathBuf, sync::Arc};
use thiserror::Error;
use crate::{diagnostic::LimitKind, ir::Address};
#[derive(Debug, Clone, Error, PartialEq, Eq)]
#[non_exhaustive]
pub enum EvalError {
#[error("cycle in locals: {participants:?}")]
Cycle {
participants: Vec<Address>,
},
#[error("evaluator limit ({kind:?}): observed {observed} > {limit}")]
Limit {
kind: LimitKind,
observed: u64,
limit: u64,
},
#[error("function `{name}` failed: {message}")]
Func {
name: Arc<str>,
message: Arc<str>,
},
#[error("path escape in `{func}`: `{path}`")]
PathEscape {
func: &'static str,
path: PathBuf,
},
}
#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::indexing_slicing
)]
mod tests {
use super::*;
#[test]
fn test_should_render_cycle_with_participants() {
let e = EvalError::Cycle {
participants: vec![
Address::new("local.a").expect("addr"),
Address::new("local.b").expect("addr"),
],
};
let s = format!("{e}");
assert!(s.contains("local.a"));
assert!(s.contains("local.b"));
}
#[test]
fn test_should_render_limit_with_kind_and_values() {
let e = EvalError::Limit {
kind: LimitKind::EvalIterations,
observed: 10,
limit: 5,
};
let s = format!("{e}");
assert!(s.contains("10"));
assert!(s.contains('5'));
}
#[test]
fn test_should_render_path_escape_with_func_and_path() {
let e = EvalError::PathEscape {
func: "file",
path: PathBuf::from("../../etc/passwd"),
};
let s = format!("{e}");
assert!(s.contains("file"));
assert!(s.contains("etc/passwd"));
}
}