use common::character::MAX_NAME_LENGTH; use std::fmt::{self, Display}; #[derive(Debug, Default)] pub struct AliasValidator { banned_substrings: Vec, } impl AliasValidator { pub fn new(banned_substrings: Vec) -> Self { let banned_substrings = banned_substrings .iter() .map(|string| string.to_lowercase()) .collect(); AliasValidator { banned_substrings } } pub fn validate(&self, alias: &str) -> Result<(), ValidatorError> { if alias.len() > MAX_NAME_LENGTH { return Err(ValidatorError::TooLong(alias.to_owned(), alias.len())); } let lowercase_alias = alias.to_lowercase(); for banned_word in self.banned_substrings.iter() { if lowercase_alias.contains(banned_word) { return Err(ValidatorError::Forbidden( alias.to_owned(), banned_word.to_owned(), )); } } Ok(()) } } #[derive(Debug, PartialEq)] pub enum ValidatorError { Forbidden(String, String), TooLong(String, usize), } impl Display for ValidatorError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Forbidden(name, _) => write!( formatter, "Character name \"{}\" contains a banned word", name ), Self::TooLong(name, _) => write!(formatter, "Character name \"{}\" too long", name), } } } #[cfg(test)] mod tests { use super::*; #[test] fn multiple_matches() { let banned_substrings = vec!["bad".to_owned(), "worse".to_owned()]; let validator = AliasValidator::new(banned_substrings); let bad_alias = "BadplayerMcWorseFace"; let result = validator.validate(bad_alias); assert_eq!( result, Err(ValidatorError::Forbidden( bad_alias.to_owned(), "bad".to_owned() )) ); } #[test] fn single_lowercase_match() { let banned_substrings = vec!["blue".to_owned()]; let validator = AliasValidator::new(banned_substrings); let bad_alias = "blueName"; let result = validator.validate(bad_alias); assert_eq!( result, Err(ValidatorError::Forbidden( bad_alias.to_owned(), "blue".to_owned() )) ); } #[test] fn single_case_insensitive_match() { let banned_substrings = vec!["GrEEn".to_owned()]; let validator = AliasValidator::new(banned_substrings); let bad_alias = "gReenName"; let result = validator.validate(bad_alias); assert_eq!( result, Err(ValidatorError::Forbidden( bad_alias.to_owned(), "green".to_owned() )) ); } #[test] fn mp_matches() { let banned_substrings = vec!["orange".to_owned()]; let validator = AliasValidator::new(banned_substrings); let good_alias = "ReasonableName"; let result = validator.validate(good_alias); assert_eq!(result, Ok(())); } #[test] fn too_long() { let banned_substrings = vec!["orange".to_owned()]; let validator = AliasValidator::new(banned_substrings); let bad_alias = "Thisnameistoolong Muchtoolong MuchTooLongByFar"; let result = validator.validate(bad_alias); assert_eq!( result, Err(ValidatorError::TooLong( bad_alias.to_owned(), bad_alias.chars().count() )) ); } }