use std::collections::HashMap;
use crate::error::InvalidArgumentError;
type Args = HashMap<String, String>;
type ValidationResult = Result<(), InvalidArgumentError>;
pub trait ServiceArgValidator {
fn validate(&self, args: &Args) -> ValidationResult;
}
impl ServiceArgValidator for Box<dyn ServiceArgValidator> {
fn validate(&self, args: &Args) -> ValidationResult {
(**self).validate(args)
}
}
#[cfg(test)]
mod test {
use super::*;
struct ContainsFoo;
impl ServiceArgValidator for ContainsFoo {
fn validate(&self, args: &Args) -> ValidationResult {
if !args.contains_key("foo") {
return Err(InvalidArgumentError::new(
"foo".into(),
r#""foo" is missing"#.into(),
));
}
Ok(())
}
}
struct BarNotEmpty;
impl ServiceArgValidator for BarNotEmpty {
fn validate(&self, args: &Args) -> ValidationResult {
if args.get("bar").map(|v| v.is_empty()).unwrap_or(true) {
return Err(InvalidArgumentError::new(
"bar".into(),
r#""bar" is missing or empty"#.into(),
));
}
Ok(())
}
}
#[test]
fn test_valid() {
let validators: Vec<Box<dyn ServiceArgValidator>> =
vec![Box::new(ContainsFoo), Box::new(BarNotEmpty)];
let mut args: Args = HashMap::new();
args.insert("foo".into(), "one".into());
args.insert("bar".into(), "yes".into());
assert!(validators
.iter()
.map(|v| v.validate(&args))
.all(|r| r.is_ok()))
}
#[test]
fn test_fail_contains_validation() {
let validators: Vec<Box<dyn ServiceArgValidator>> =
vec![Box::new(ContainsFoo), Box::new(BarNotEmpty)];
let mut args: Args = HashMap::new();
args.insert("bar".into(), "yes".into());
let _expected_result: Option<Result<(), InvalidArgumentError>> = Some(Err(
InvalidArgumentError::new("foo".into(), "argument is missing".into()),
));
assert!(matches!(
validators
.iter()
.map(|v| v.validate(&args))
.find(|r| r.is_err()),
_expected_result,
));
}
#[test]
fn test_fail_not_empty_validation() {
let validators: Vec<Box<dyn ServiceArgValidator>> =
vec![Box::new(ContainsFoo), Box::new(BarNotEmpty)];
let mut args: Args = HashMap::new();
args.insert("foo".into(), "one".into());
args.insert("bar".into(), "".into());
let _expected_result: Option<Result<(), InvalidArgumentError>> = Some(Err(
InvalidArgumentError::new("bar".into(), "missing or empty".into()),
));
assert!(matches!(
validators
.iter()
.map(|v| v.validate(&args))
.find(|r| r.is_err()),
_expected_result
));
}
}