use crate::{hkid_check_digit::calculate_check_digit, hkid_prefix::HKIDPrefix};
pub fn validate_hkid(hkid_full: &str, must_exist_in_enum: bool) -> Result<bool, String> {
let cleaned: String = hkid_full
.chars()
.filter(|&c| c != '(' && c != ')')
.collect();
if !(8..=9).contains(&cleaned.len()) {
return Err("Invalid HKID format: incorrect length.".to_string());
}
let (hkid_body, provided_digit) = cleaned.split_at(cleaned.len() - 1);
let prefix_len = cleaned.len() - 7;
let prefix = &hkid_body[..prefix_len];
if must_exist_in_enum {
let parsed_prefix = HKIDPrefix::parse(prefix);
if !parsed_prefix.is_known() {
return Err(format!("Prefix '{prefix}' is not recognized."));
}
}
let calculated_digit = calculate_check_digit(hkid_body);
Ok(calculated_digit == provided_digit.chars().next().unwrap())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_hkid_correct() {
let valid_hkid = "A123456(3)";
let result = validate_hkid(valid_hkid, false);
assert!(result.is_ok());
assert_eq!(result.unwrap(), true);
}
#[test]
fn test_validate_hkid_incorrect_digit() {
let invalid_hkid = "A123456(9)";
let result = validate_hkid(invalid_hkid, false);
assert!(result.is_ok());
assert_eq!(result.unwrap(), false);
}
#[test]
fn test_validate_hkid_invalid_format() {
let invalid_hkid_format = "A12345"; let result = validate_hkid(invalid_hkid_format, false);
assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
"Invalid HKID format: incorrect length."
);
}
#[test]
fn test_validate_hkid_unknown_prefix_with_must_exist() {
let hkid = "XX123456(1)";
let result = validate_hkid(hkid, true);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Prefix 'XX' is not recognized.");
}
}