use crate::error::{CacheError, Result};
#[derive(Debug, Clone, Copy)]
pub struct ConfigValidation;
impl ConfigValidation {
pub const MAX_CAPACITY: u64 = 1_000_000_000;
pub const MAX_TTL_SECS: u64 = 30 * 24 * 60 * 60;
pub const MAX_TTI_SECS: u64 = 30 * 24 * 60 * 60;
pub const MAX_CUSTOM_NAME_LENGTH: usize = 256;
pub const VALID_NAME_CHARS: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-";
pub fn validate_custom_name(name: &str) -> Result<String> {
if name.is_empty() {
return Err(CacheError::InvalidInput(
"Custom backend name cannot be empty".to_string(),
));
}
if name.len() > Self::MAX_CUSTOM_NAME_LENGTH {
return Err(CacheError::InvalidInput(format!(
"Custom backend name exceeds maximum length of {} characters",
Self::MAX_CUSTOM_NAME_LENGTH
)));
}
for ch in name.chars() {
if !Self::VALID_NAME_CHARS.contains(ch) {
return Err(CacheError::InvalidInput(format!(
"Custom backend name contains invalid character '{}'. Allowed characters: {}",
ch,
Self::VALID_NAME_CHARS
)));
}
}
Ok(name.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_custom_name_valid() {
assert_eq!(
ConfigValidation::validate_custom_name("my_backend").unwrap(),
"my_backend"
);
assert_eq!(
ConfigValidation::validate_custom_name("backend-1").unwrap(),
"backend-1"
);
assert_eq!(ConfigValidation::validate_custom_name("app.v2").unwrap(), "app.v2");
assert_eq!(ConfigValidation::validate_custom_name("ABC123").unwrap(), "ABC123");
assert_eq!(ConfigValidation::validate_custom_name("a").unwrap(), "a");
}
#[test]
fn test_validate_custom_name_empty() {
let result = ConfigValidation::validate_custom_name("");
assert!(result.is_err());
match result.unwrap_err() {
CacheError::InvalidInput(msg) => assert!(msg.contains("cannot be empty")),
_ => panic!("Expected InvalidInput error"),
}
}
#[test]
fn test_validate_custom_name_too_long() {
let long_name = "a".repeat(ConfigValidation::MAX_CUSTOM_NAME_LENGTH + 1);
let result = ConfigValidation::validate_custom_name(&long_name);
assert!(result.is_err());
match result.unwrap_err() {
CacheError::InvalidInput(msg) => assert!(msg.contains("maximum length")),
_ => panic!("Expected InvalidInput error"),
}
}
#[test]
fn test_validate_custom_name_exactly_max_length() {
let name = "a".repeat(ConfigValidation::MAX_CUSTOM_NAME_LENGTH);
assert!(ConfigValidation::validate_custom_name(&name).is_ok());
}
#[test]
fn test_validate_custom_name_invalid_chars() {
assert!(ConfigValidation::validate_custom_name("name with space").is_err());
assert!(ConfigValidation::validate_custom_name("name:colon").is_err());
assert!(ConfigValidation::validate_custom_name("name/slash").is_err());
assert!(ConfigValidation::validate_custom_name("name@at").is_err());
assert!(ConfigValidation::validate_custom_name("name#hash").is_err());
assert!(ConfigValidation::validate_custom_name("name$dollar").is_err());
}
#[test]
fn test_validate_custom_name_all_valid_chars() {
let name: String = ConfigValidation::VALID_NAME_CHARS.chars().collect();
assert!(ConfigValidation::validate_custom_name(&name).is_ok());
}
#[test]
fn test_config_validation_constants() {
assert_eq!(ConfigValidation::MAX_CUSTOM_NAME_LENGTH, 256);
assert!(ConfigValidation::VALID_NAME_CHARS.contains('a'));
assert!(ConfigValidation::VALID_NAME_CHARS.contains('Z'));
assert!(ConfigValidation::VALID_NAME_CHARS.contains('0'));
assert!(ConfigValidation::VALID_NAME_CHARS.contains('_'));
assert!(ConfigValidation::VALID_NAME_CHARS.contains('-'));
assert!(ConfigValidation::VALID_NAME_CHARS.contains('.'));
assert!(!ConfigValidation::VALID_NAME_CHARS.contains(':'));
assert!(!ConfigValidation::VALID_NAME_CHARS.contains('/'));
assert!(!ConfigValidation::VALID_NAME_CHARS.contains(' '));
}
}