use std::collections::HashMap;
use std::error;
use std::fmt;
#[derive(Debug, PartialEq)]
pub struct ServiceArgValidationError(pub String);
impl error::Error for ServiceArgValidationError {}
impl fmt::Display for ServiceArgValidationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Invalid service arguments: {}", self.0)
}
}
type Args = HashMap<String, String>;
type ValidationResult = Result<(), ServiceArgValidationError>;
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(ServiceArgValidationError(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(ServiceArgValidationError(
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());
assert_eq!(
Some(Err(ServiceArgValidationError(r#""foo" is missing"#.into()))),
validators
.iter()
.map(|v| v.validate(&args))
.find(|r| r.is_err())
);
}
#[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());
assert_eq!(
Some(Err(ServiceArgValidationError(
r#""bar" is missing or empty"#.into()
))),
validators
.iter()
.map(|v| v.validate(&args))
.find(|r| r.is_err())
);
}
}