use thiserror::Error;
#[derive(Error, Debug, Clone)]
#[error("Invalid status '{status}'. Allowed: {allowed:?}")]
pub struct StatusError {
pub status: String,
pub allowed: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ValidationMode {
#[default]
Strict,
None,
}
pub trait StatusValidator {
const VALIDATION_MODE: ValidationMode;
fn default_statuses() -> Vec<String>;
fn validate_status(status: &str, allowed: &[String]) -> Result<(), StatusError> {
match Self::VALIDATION_MODE {
ValidationMode::Strict => validate_strict(status, allowed),
ValidationMode::None => Ok(()),
}
}
}
pub fn validate_strict(status: &str, allowed: &[String]) -> Result<(), StatusError> {
if allowed.iter().any(|s| s.eq_ignore_ascii_case(status)) {
Ok(())
} else {
Err(StatusError {
status: status.to_string(),
allowed: allowed.to_vec(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strict_validation_valid() {
let allowed = vec!["open".to_string(), "closed".to_string()];
assert!(validate_strict("open", &allowed).is_ok());
assert!(validate_strict("OPEN", &allowed).is_ok()); }
#[test]
fn test_strict_validation_invalid() {
let allowed = vec!["open".to_string(), "closed".to_string()];
let result = validate_strict("invalid", &allowed);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.status, "invalid");
assert_eq!(err.allowed, allowed);
}
}