apollo_redaction/strategy/
last4.rs1use crate::RedactionStrategy;
2use std::fmt;
3
4#[derive(Default, Clone)]
25pub struct Last4Redactor;
26
27impl<T: AsRef<str>> RedactionStrategy<T> for Last4Redactor {
28 fn display(&self, value: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 let s = value.as_ref();
30 let len = s.chars().count();
31
32 if len <= 4 {
33 write!(f, "****")
34 } else {
35 let redacted_count = (len - 4).max(4);
37 for _ in 0..redacted_count {
38 write!(f, "*")?;
39 }
40 for c in s.chars().skip(len - 4) {
41 write!(f, "{c}")?;
42 }
43 Ok(())
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use crate::Redacted;
52
53 fn last4(input: &str) -> String {
54 Redacted::<_, Last4Redactor>::new(input).to_string()
55 }
56
57 #[test]
58 fn test_last4() {
59 assert_eq!(last4("1234567890"), "******7890");
60 assert_eq!(last4("4242424242424242"), "************4242");
61 }
62
63 #[test]
64 fn test_short_input() {
65 assert_eq!(last4("abc"), "****");
66 assert_eq!(last4("abcd"), "****");
67 assert_eq!(last4("a"), "****");
68 assert_eq!(last4(""), "****");
69 }
70
71 #[test]
72 fn test_exactly_5_chars() {
73 assert_eq!(last4("12345"), "****2345");
74 }
75
76 #[test]
77 fn test_unicode() {
78 assert_eq!(last4("안녕하세요한글"), "****세요한글");
79 }
80}