ftracker_identifiers/cnpj/
arbitrary.rs1use arbitrary::{Arbitrary, Unstructured};
2
3use super::Cnpj;
4use super::validation::{BASE_LEN, avoid_all_repeated, compute_valid_check_digits};
5
6const ALPHABET: &[u8; 36] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
7
8impl<'a> Arbitrary<'a> for Cnpj {
9 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
10 let mut base = [0u8; BASE_LEN];
11 for slot in base.iter_mut() {
12 let idx = u32::from(u.arbitrary::<u8>()?) as usize % ALPHABET.len();
13 *slot = ALPHABET[idx];
14 }
15
16 avoid_all_repeated(&mut base);
18
19 let (dv1, dv2) = compute_valid_check_digits(&base);
20 let mut bytes = [0u8; 14];
21 bytes[..BASE_LEN].copy_from_slice(&base);
22 bytes[BASE_LEN] = dv1 + b'0';
23 bytes[BASE_LEN + 1] = dv2 + b'0';
24
25 Cnpj::from_bytes(bytes).map_err(|_| arbitrary::Error::IncorrectFormat)
26 }
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32
33 #[test]
34 fn always_produces_valid_cnpjs() {
35 for seed in 0u32..256 {
36 let data = seed.to_le_bytes().repeat(8);
37 let mut u = Unstructured::new(&data);
38 let cnpj = Cnpj::arbitrary(&mut u).expect("arbitrary should always succeed");
39 assert!(Cnpj::parse(cnpj.as_str()).is_ok());
42 }
43 }
44}