use rand::Rng;
pub fn remove_symbols(license_plate: &str) -> String {
license_plate.replace("-", "")
}
pub fn format_license_plate(license_plate: &str) -> Option<String> {
let license_plate = license_plate.to_uppercase();
if is_valid_old_format(&license_plate) {
return Some(format!("{}-{}", &license_plate[0..3], &license_plate[3..]));
} else if is_valid_mercosul(&license_plate) {
return Some(license_plate);
}
None
}
fn is_valid_old_format(license_plate: &str) -> bool {
let plate = license_plate.trim().to_uppercase();
if plate.len() != 7 {
return false;
}
let chars: Vec<char> = plate.chars().collect();
if !chars[0..3].iter().all(|c| c.is_ascii_alphabetic()) {
return false;
}
chars[3..7].iter().all(|c| c.is_ascii_digit())
}
fn is_valid_mercosul(license_plate: &str) -> bool {
let plate = license_plate.trim().to_uppercase();
if plate.len() != 7 {
return false;
}
let chars: Vec<char> = plate.chars().collect();
if !chars[0..3].iter().all(|c| c.is_ascii_alphabetic()) {
return false;
}
if !chars[3].is_ascii_digit() {
return false;
}
if !chars[4].is_ascii_alphabetic() {
return false;
}
chars[5..7].iter().all(|c| c.is_ascii_digit())
}
pub fn is_valid(license_plate: &str, format: Option<&str>) -> bool {
match format {
Some("old_format") => is_valid_old_format(license_plate),
Some("mercosul") => is_valid_mercosul(license_plate),
_ => is_valid_old_format(license_plate) || is_valid_mercosul(license_plate),
}
}
pub fn get_format(license_plate: &str) -> Option<String> {
if is_valid_old_format(license_plate) {
return Some("LLLNNNN".to_string());
}
if is_valid_mercosul(license_plate) {
return Some("LLLNLNN".to_string());
}
None
}
pub fn convert_to_mercosul(license_plate: &str) -> Option<String> {
if !is_valid_old_format(license_plate) {
return None;
}
let mut chars: Vec<char> = license_plate.to_uppercase().chars().collect();
if let Some(digit) = chars[4].to_digit(10) {
chars[4] = char::from_u32('A' as u32 + digit).unwrap();
}
Some(chars.into_iter().collect())
}
pub fn generate(format: Option<&str>) -> Option<String> {
let format = format.unwrap_or("LLLNLNN").to_uppercase();
if format != "LLLNLNN" && format != "LLLNNNN" {
return None;
}
let mut rng = rand::thread_rng();
let mut result = String::new();
for ch in format.chars() {
if ch == 'L' {
let letter = char::from_u32('A' as u32 + rng.gen_range(0..26)).unwrap();
result.push(letter);
} else if ch == 'N' {
let digit = rng.gen_range(0..10);
result.push_str(&digit.to_string());
}
}
Some(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_remove_symbols() {
assert_eq!(remove_symbols("ABC-1234"), "ABC1234");
assert_eq!(remove_symbols("abc123"), "abc123");
assert_eq!(remove_symbols("ABCD123"), "ABCD123");
assert_eq!(remove_symbols("ABC-1D23"), "ABC1D23");
}
#[test]
fn test_format_license_plate_old() {
assert_eq!(
format_license_plate("ABC1234"),
Some("ABC-1234".to_string())
);
assert_eq!(
format_license_plate("abc1234"),
Some("ABC-1234".to_string())
);
assert_eq!(
format_license_plate("XYZ9876"),
Some("XYZ-9876".to_string())
);
}
#[test]
fn test_format_license_plate_mercosul() {
assert_eq!(format_license_plate("ABC1D23"), Some("ABC1D23".to_string()));
assert_eq!(format_license_plate("abc1e34"), Some("ABC1E34".to_string()));
}
#[test]
fn test_format_license_plate_invalid() {
assert_eq!(format_license_plate("ABC123"), None);
assert_eq!(format_license_plate("ABCD1234"), None);
assert_eq!(format_license_plate("AB1234"), None);
assert_eq!(format_license_plate(""), None);
}
#[test]
fn test_is_valid_old_format() {
assert!(is_valid("ABC1234", Some("old_format")));
assert!(is_valid("XYZ9876", Some("old_format")));
assert!(is_valid("abc1234", Some("old_format")));
assert!(!is_valid("ABC1D23", Some("old_format")));
assert!(!is_valid("ABC123", Some("old_format")));
assert!(!is_valid("ABCD1234", Some("old_format")));
}
#[test]
fn test_is_valid_mercosul() {
assert!(is_valid("ABC1D23", Some("mercosul")));
assert!(is_valid("XYZ9A99", Some("mercosul")));
assert!(is_valid("abc1e34", Some("mercosul")));
assert!(!is_valid("ABC1234", Some("mercosul")));
assert!(!is_valid("ABC12D3", Some("mercosul")));
assert!(!is_valid("ABCD123", Some("mercosul")));
}
#[test]
fn test_is_valid_any_format() {
assert!(is_valid("ABC1234", None));
assert!(is_valid("ABC1D23", None));
assert!(is_valid("xyz9876", None));
assert!(is_valid("abc1e34", None));
assert!(!is_valid("ABC123", None));
assert!(!is_valid("ABCD1234", None));
assert!(!is_valid("", None));
}
#[test]
fn test_get_format() {
assert_eq!(get_format("ABC1234"), Some("LLLNNNN".to_string()));
assert_eq!(get_format("abc1234"), Some("LLLNNNN".to_string()));
assert_eq!(get_format("ABC1D23"), Some("LLLNLNN".to_string()));
assert_eq!(get_format("abc1e34"), Some("LLLNLNN".to_string()));
assert_eq!(get_format("ABC123"), None);
assert_eq!(get_format("ABCD1234"), None);
}
#[test]
fn test_convert_to_mercosul() {
assert_eq!(convert_to_mercosul("ABC1234"), Some("ABC1C34".to_string()));
assert_eq!(convert_to_mercosul("ABC4567"), Some("ABC4F67".to_string()));
assert_eq!(convert_to_mercosul("ABC0000"), Some("ABC0A00".to_string()));
assert_eq!(convert_to_mercosul("ABC9999"), Some("ABC9J99".to_string()));
assert_eq!(convert_to_mercosul("abc1234"), Some("ABC1C34".to_string()));
}
#[test]
fn test_convert_to_mercosul_invalid() {
assert_eq!(convert_to_mercosul("ABC4*67"), None);
assert_eq!(convert_to_mercosul("ABC123"), None);
assert_eq!(convert_to_mercosul("ABC1D23"), None);
assert_eq!(convert_to_mercosul("ABCD1234"), None);
}
#[test]
fn test_generate_mercosul() {
let plate = generate(None);
assert!(plate.is_some());
let plate = plate.unwrap();
assert_eq!(plate.len(), 7);
assert!(is_valid(&plate, Some("mercosul")));
}
#[test]
fn test_generate_old_format() {
let plate = generate(Some("LLLNNNN"));
assert!(plate.is_some());
let plate = plate.unwrap();
assert_eq!(plate.len(), 7);
assert!(is_valid(&plate, Some("old_format")));
}
#[test]
fn test_generate_invalid_format() {
assert_eq!(generate(Some("invalid")), None);
assert_eq!(generate(Some("LLLLNNN")), None);
assert_eq!(generate(Some("")), None);
}
#[test]
fn test_generate_uniqueness() {
let plate1 = generate(None).unwrap();
let plate2 = generate(None).unwrap();
let plate3 = generate(None).unwrap();
assert!(plate1 != plate2 || plate2 != plate3);
}
}