use super::error::CnpjError;
#[inline]
fn is_formatting_char(c: char) -> bool {
matches!(c, '.' | '/' | '-' | ' ')
}
pub(super) fn normalize(input: &str) -> Result<[u8; 14], CnpjError> {
if input.is_empty() {
return Err(CnpjError::Empty);
}
let meaningful = input.chars().filter(|&c| !is_formatting_char(c));
let found = meaningful.clone().count();
if found != 14 {
return Err(CnpjError::InvalidLength { found });
}
let mut buf = [0u8; 14];
for (i, ch) in meaningful.enumerate() {
if !ch.is_ascii() {
return Err(CnpjError::InvalidCharacter {
character: ch,
position: (i + 1) as u8,
expected: super::error::CharacterClass::AlphanumericUppercase,
});
}
buf[i] = ch.to_ascii_uppercase() as u8;
}
Ok(buf)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rejects_empty() {
assert_eq!(normalize(""), Err(CnpjError::Empty));
}
#[test]
fn strips_conventional_punctuation() {
assert_eq!(normalize("12.345.678/0001-95"), normalize("12345678000195"),);
}
#[test]
fn uppercases_letters() {
assert_eq!(normalize("12abc34501de35").unwrap(), *b"12ABC34501DE35",);
}
#[test]
fn rejects_wrong_length() {
assert_eq!(
normalize("1234"),
Err(CnpjError::InvalidLength { found: 4 })
);
}
#[test]
fn rejects_non_ascii() {
let err = normalize("12ç45678000195").unwrap_err();
assert!(matches!(
err,
CnpjError::InvalidCharacter {
character: 'ç', ..
}
));
}
}