use crate::RedactionStrategy;
use std::fmt;
#[derive(Default, Clone)]
pub struct Last4Redactor;
impl<T: AsRef<str>> RedactionStrategy<T> for Last4Redactor {
fn display(&self, value: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = value.as_ref();
let len = s.chars().count();
if len <= 4 {
write!(f, "****")
} else {
let redacted_count = (len - 4).max(4);
for _ in 0..redacted_count {
write!(f, "*")?;
}
for c in s.chars().skip(len - 4) {
write!(f, "{c}")?;
}
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Redacted;
fn last4(input: &str) -> String {
Redacted::<_, Last4Redactor>::new(input).to_string()
}
#[test]
fn test_last4() {
assert_eq!(last4("1234567890"), "******7890");
assert_eq!(last4("4242424242424242"), "************4242");
}
#[test]
fn test_short_input() {
assert_eq!(last4("abc"), "****");
assert_eq!(last4("abcd"), "****");
assert_eq!(last4("a"), "****");
assert_eq!(last4(""), "****");
}
#[test]
fn test_exactly_5_chars() {
assert_eq!(last4("12345"), "****2345");
}
#[test]
fn test_unicode() {
assert_eq!(last4("안녕하세요한글"), "****세요한글");
}
}