use super::validator::Validator;
pub struct LookupValidator {
valid_values: Vec<String>,
case_sensitive: bool,
}
impl LookupValidator {
pub fn new(valid_values: Vec<String>) -> Self {
Self {
valid_values,
case_sensitive: true,
}
}
pub fn new_case_insensitive(valid_values: Vec<String>) -> Self {
Self {
valid_values,
case_sensitive: false,
}
}
pub fn set_case_sensitive(&mut self, case_sensitive: bool) {
self.case_sensitive = case_sensitive;
}
pub fn valid_values(&self) -> &[String] {
&self.valid_values
}
pub fn add_value(&mut self, value: String) {
self.valid_values.push(value);
}
pub fn remove_value(&mut self, value: &str) -> bool {
if let Some(pos) = self.find_value(value) {
self.valid_values.remove(pos);
true
} else {
false
}
}
fn find_value(&self, value: &str) -> Option<usize> {
self.valid_values.iter().position(|v| {
if self.case_sensitive {
v == value
} else {
v.eq_ignore_ascii_case(value)
}
})
}
pub fn contains(&self, value: &str) -> bool {
self.find_value(value).is_some()
}
}
impl Validator for LookupValidator {
fn is_valid(&self, input: &str) -> bool {
if input.is_empty() {
return true;
}
self.contains(input)
}
fn is_valid_input(&self, _input: &str, _append: bool) -> bool {
true
}
fn error(&self) {
}
}
pub struct LookupValidatorBuilder {
valid_values: Vec<String>,
case_sensitive: bool,
}
impl LookupValidatorBuilder {
pub fn new() -> Self {
Self {
valid_values: Vec::new(),
case_sensitive: true,
}
}
#[must_use]
pub fn values(mut self, valid_values: Vec<String>) -> Self {
self.valid_values = valid_values;
self
}
#[must_use]
pub fn add_value(mut self, value: impl Into<String>) -> Self {
self.valid_values.push(value.into());
self
}
#[must_use]
pub fn case_sensitive(mut self, case_sensitive: bool) -> Self {
self.case_sensitive = case_sensitive;
self
}
pub fn build(self) -> LookupValidator {
if self.valid_values.is_empty() {
panic!("LookupValidator must have at least one valid value");
}
LookupValidator {
valid_values: self.valid_values,
case_sensitive: self.case_sensitive,
}
}
}
impl Default for LookupValidatorBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lookup_validator_case_sensitive() {
let validator = LookupValidator::new(vec![
"Red".to_string(),
"Green".to_string(),
"Blue".to_string(),
]);
assert!(validator.is_valid("Red"));
assert!(validator.is_valid("Green"));
assert!(validator.is_valid("Blue"));
assert!(!validator.is_valid("red"));
assert!(!validator.is_valid("RED"));
assert!(!validator.is_valid("Yellow"));
assert!(validator.is_valid(""));
}
#[test]
fn test_lookup_validator_case_insensitive() {
let validator = LookupValidator::new_case_insensitive(vec![
"Red".to_string(),
"Green".to_string(),
"Blue".to_string(),
]);
assert!(validator.is_valid("Red"));
assert!(validator.is_valid("red"));
assert!(validator.is_valid("RED"));
assert!(validator.is_valid("Green"));
assert!(validator.is_valid("green"));
assert!(validator.is_valid("BLUE"));
assert!(!validator.is_valid("Yellow"));
assert!(!validator.is_valid("yellow"));
assert!(validator.is_valid(""));
}
#[test]
fn test_lookup_validator_add_remove() {
let mut validator = LookupValidator::new(vec!["Apple".to_string(), "Banana".to_string()]);
assert!(validator.is_valid("Apple"));
assert!(!validator.is_valid("Orange"));
validator.add_value("Orange".to_string());
assert!(validator.is_valid("Orange"));
assert!(validator.remove_value("Banana"));
assert!(!validator.is_valid("Banana"));
assert!(!validator.remove_value("NonExistent"));
}
#[test]
fn test_lookup_validator_contains() {
let validator = LookupValidator::new(vec![
"One".to_string(),
"Two".to_string(),
"Three".to_string(),
]);
assert!(validator.contains("One"));
assert!(validator.contains("Two"));
assert!(validator.contains("Three"));
assert!(!validator.contains("Four"));
assert!(!validator.contains("one")); }
#[test]
fn test_lookup_validator_contains_case_insensitive() {
let validator = LookupValidator::new_case_insensitive(vec![
"One".to_string(),
"Two".to_string(),
"Three".to_string(),
]);
assert!(validator.contains("One"));
assert!(validator.contains("one"));
assert!(validator.contains("ONE"));
assert!(validator.contains("Two"));
assert!(validator.contains("two"));
assert!(!validator.contains("Four"));
}
#[test]
fn test_lookup_validator_set_case_sensitive() {
let mut validator = LookupValidator::new(vec!["Test".to_string()]);
assert!(validator.is_valid("Test"));
assert!(!validator.is_valid("test"));
validator.set_case_sensitive(false);
assert!(validator.is_valid("Test"));
assert!(validator.is_valid("test"));
assert!(validator.is_valid("TEST"));
validator.set_case_sensitive(true);
assert!(validator.is_valid("Test"));
assert!(!validator.is_valid("test"));
}
#[test]
fn test_lookup_validator_valid_values() {
let validator =
LookupValidator::new(vec!["A".to_string(), "B".to_string(), "C".to_string()]);
let values = validator.valid_values();
assert_eq!(values.len(), 3);
assert_eq!(values[0], "A");
assert_eq!(values[1], "B");
assert_eq!(values[2], "C");
}
#[test]
fn test_lookup_validator_is_valid_input() {
let validator = LookupValidator::new(vec!["Test".to_string()]);
assert!(validator.is_valid_input("a", true));
assert!(validator.is_valid_input("Z", true));
assert!(validator.is_valid_input("0", true));
assert!(validator.is_valid_input(" ", true));
assert!(validator.is_valid_input("!", true));
}
#[test]
fn test_lookup_validator_builder() {
let validator = LookupValidatorBuilder::new()
.add_value("Red")
.add_value("Green")
.add_value("Blue")
.build();
assert!(validator.is_valid("Red"));
assert!(validator.is_valid("Green"));
assert!(validator.is_valid("Blue"));
assert!(!validator.is_valid("Yellow"));
}
#[test]
fn test_lookup_validator_builder_case_insensitive() {
let validator = LookupValidatorBuilder::new()
.values(vec!["One".to_string(), "Two".to_string()])
.case_sensitive(false)
.build();
assert!(validator.is_valid("One"));
assert!(validator.is_valid("one"));
assert!(validator.is_valid("TWO"));
}
#[test]
#[should_panic(expected = "must have at least one valid value")]
fn test_lookup_validator_builder_empty() {
LookupValidatorBuilder::new().build();
}
}