tests.rs (8566B)
1 use super::DecodeErr; 2 #[cfg(any( 3 target_pointer_width = "16", 4 target_pointer_width = "32", 5 target_pointer_width = "64", 6 ))] 7 use super::MAX_ENCODE_INPUT_LEN; 8 #[cfg(feature = "alloc")] 9 use alloc::{borrow::ToOwned as _, string::String, vec}; 10 use core::fmt::{self, Write}; 11 #[cfg(any( 12 target_pointer_width = "16", 13 target_pointer_width = "32", 14 target_pointer_width = "64", 15 ))] 16 use rand::{RngExt as _, rngs::SmallRng}; 17 #[expect(clippy::panic, reason = "want to crash when there is a bug")] 18 #[expect(clippy::too_many_lines, reason = "a lot to test")] 19 #[expect( 20 clippy::as_conversions, 21 clippy::cast_possible_truncation, 22 clippy::integer_division_remainder_used, 23 reason = "comment justifies correctness" 24 )] 25 #[cfg(any( 26 target_pointer_width = "16", 27 target_pointer_width = "32", 28 target_pointer_width = "64", 29 ))] 30 #[ignore = "slow"] 31 #[test] 32 fn encode_decode_len() { 33 assert_eq!(MAX_ENCODE_INPUT_LEN, 3 * (usize::MAX >> 2u8)); 34 let mut rng = rand::make_rng::<SmallRng>(); 35 for _ in 0u32..10_000_000 { 36 // `uN as usize` is fine since we `cfg` by pointer width. 37 #[cfg(target_pointer_width = "16")] 38 let len = rng.random::<u16>() as usize; 39 #[cfg(target_pointer_width = "32")] 40 let len = rng.random::<u32>() as usize; 41 #[cfg(target_pointer_width = "64")] 42 let len = rng.random::<u64>() as usize; 43 if len <= MAX_ENCODE_INPUT_LEN { 44 assert_eq!( 45 super::encode_len_checked(len).map(|l| { 46 super::decode_len(l).map(|decode_len| { 47 decode_len 48 - match len % 3 { 49 0 => 0, 50 1 => 2, 51 2 => 1, 52 _ => panic!("usize % 3 is greater than 3"), 53 } 54 }) 55 }), 56 Some(Some(len)) 57 ); 58 } else { 59 assert!(super::encode_len_checked(len).is_none()); 60 } 61 } 62 for i in 0..1025 { 63 assert_eq!( 64 super::encode_len_checked(i).map(|l| { 65 super::decode_len(l).map(|decode_len| { 66 decode_len 67 - match i % 3 { 68 0 => 0, 69 1 => 2, 70 2 => 1, 71 _ => panic!("usize % 3 is greater than 3"), 72 } 73 }) 74 }), 75 Some(Some(i)) 76 ); 77 } 78 #[cfg(target_pointer_width = "16")] 79 for i in MAX_ENCODE_INPUT_LEN + 1.. { 80 assert!(super::encode_len_checked(i).is_none()); 81 } 82 #[cfg(not(target_pointer_width = "16"))] 83 for i in MAX_ENCODE_INPUT_LEN + 1..MAX_ENCODE_INPUT_LEN + 1_000_000 { 84 assert!(super::encode_len_checked(i).is_none()); 85 } 86 assert!(super::encode_len_checked(usize::MAX).is_none()); 87 assert_eq!( 88 super::encode_len_checked(MAX_ENCODE_INPUT_LEN), 89 Some(usize::MAX - 3) 90 ); 91 for _ in 0u32..10_000_000 { 92 #[cfg(target_pointer_width = "16")] 93 let len = rng.random::<u16>() as usize; 94 #[cfg(target_pointer_width = "32")] 95 let len = rng.random::<u32>() as usize; 96 #[cfg(target_pointer_width = "64")] 97 let len = rng.random::<u64>() as usize; 98 if len.trailing_zeros() > 1 { 99 assert_eq!( 100 super::decode_len(len).map(super::encode_len_checked), 101 Some(Some(len)) 102 ); 103 } else { 104 assert!(super::decode_len(len).is_none()); 105 } 106 } 107 for i in 0usize..1025 { 108 if i.trailing_zeros() > 1 { 109 assert_eq!( 110 super::decode_len(i).map(super::encode_len_checked), 111 Some(Some(i)) 112 ); 113 } else { 114 assert!(super::decode_len(i).is_none()); 115 } 116 } 117 #[cfg(target_pointer_width = "16")] 118 for i in 0..=usize::MAX { 119 if i & 3 == 1 { 120 assert!(super::decode_len(i).is_none()); 121 } else { 122 assert_eq!( 123 super::decode_len(i).map(super::encode_len_checked), 124 Some(Some(i)) 125 ); 126 } 127 } 128 #[cfg(not(target_pointer_width = "16"))] 129 for i in usize::MAX - 1_000_000..=usize::MAX { 130 if i.trailing_zeros() > 1 { 131 assert_eq!( 132 super::decode_len(i).map(super::encode_len_checked), 133 Some(Some(i)) 134 ); 135 } else { 136 assert!(super::decode_len(i).is_none()); 137 } 138 } 139 assert_eq!( 140 super::decode_len(usize::MAX - 3), 141 Some(MAX_ENCODE_INPUT_LEN) 142 ); 143 } 144 #[expect(clippy::indexing_slicing, reason = "comments justify correctness")] 145 #[cfg(feature = "alloc")] 146 #[test] 147 fn encode_write() { 148 let input = [9; 8192]; 149 let mut buffer = String::with_capacity(super::encode_len(input.len())); 150 let cap = buffer.capacity(); 151 let mut write_len; 152 for len in 0..input.len() { 153 write_len = super::encode_len(len); 154 match write_len.checked_add(buffer.len()) { 155 None => { 156 buffer.clear(); 157 // Indexing is fine since `len <= input.len()`. 158 assert_eq!(super::encode_write(&input[..len], &mut buffer), Ok(())); 159 assert_eq!(buffer.len(), write_len); 160 } 161 Some(l) => { 162 if l > cap { 163 buffer.clear(); 164 // Indexing is fine since `len <= input.len()`. 165 assert_eq!(super::encode_write(&input[..len], &mut buffer), Ok(())); 166 assert_eq!(buffer.len(), write_len); 167 } else { 168 // Indexing is fine since `len <= input.len()`. 169 assert_eq!(super::encode_write(&input[..len], &mut buffer), Ok(())); 170 assert_eq!(buffer.len(), l); 171 } 172 } 173 } 174 assert!( 175 buffer 176 .as_bytes() 177 .iter() 178 .all(|b| { matches!(*b, b'C' | b'J' | b'Q' | b'k' | b'=') }) 179 ); 180 } 181 } 182 #[cfg(feature = "alloc")] 183 #[test] 184 fn try_encode() { 185 assert_eq!(super::try_encode(&[0]), Ok("AA==".to_owned())); 186 } 187 #[cfg(feature = "alloc")] 188 #[test] 189 fn encode() { 190 assert_eq!(super::encode(&[0]), "AA==".to_owned()); 191 } 192 #[cfg(feature = "alloc")] 193 #[test] 194 fn try_encode_append() { 195 let mut val = "Hi".to_owned(); 196 assert_eq!( 197 super::try_encode_append(&[0], &mut val), 198 Ok("AA==".to_owned().as_mut_str()) 199 ); 200 assert_eq!(val, "HiAA=="); 201 } 202 #[cfg(feature = "alloc")] 203 #[test] 204 fn encode_append() { 205 let mut val = "Hi".to_owned(); 206 assert_eq!( 207 super::encode_append(&[0], &mut val), 208 "AA==".to_owned().as_mut_str() 209 ); 210 assert_eq!(val, "HiAA=="); 211 } 212 #[cfg(feature = "alloc")] 213 #[test] 214 fn try_encode_append_only() { 215 let mut val = "Hi".to_owned(); 216 assert_eq!(super::try_encode_append_only(&[0], &mut val), Ok(())); 217 assert_eq!(val, "HiAA=="); 218 } 219 #[cfg(feature = "alloc")] 220 #[test] 221 fn encode_append_only() { 222 let mut val = "Hi".to_owned(); 223 super::encode_append_only(&[0], &mut val); 224 assert_eq!(val, "HiAA=="); 225 } 226 #[test] 227 fn decode_buffer() { 228 assert_eq!( 229 super::decode_buffer(b"AA==", &mut [0]), 230 Ok([0].as_mut_slice()) 231 ); 232 assert_eq!( 233 super::decode_buffer(b"AA==", &mut []), 234 Err(DecodeErr::BufferLen) 235 ); 236 } 237 #[cfg(feature = "alloc")] 238 #[test] 239 fn decode() { 240 assert_eq!(super::decode(b"AA=="), Ok(vec![0])); 241 } 242 #[test] 243 fn validate_encoded_data() { 244 assert_eq!(super::validate_encoded_data(b"AA=="), Ok(())); 245 } 246 #[test] 247 fn encode_buffer_exact() { 248 let mut output = [0; 4]; 249 super::encode_buffer_exact(&[0], &mut output); 250 assert_eq!(output, *b"AA=="); 251 } 252 #[test] 253 fn decode_buffer_exact() { 254 let mut output = [1]; 255 assert_eq!(super::decode_buffer_exact(b"AA==", &mut output), Ok(())); 256 assert_eq!(output, [0]); 257 } 258 #[test] 259 fn encode_write_core() { 260 struct Writer<'a>(&'a mut [u8]); 261 impl Write for Writer<'_> { 262 fn write_str(&mut self, s: &str) -> fmt::Result { 263 self.0.get_mut(..s.len()).ok_or(fmt::Error).map(|bytes| { 264 bytes.copy_from_slice(s.as_bytes()); 265 }) 266 } 267 } 268 let mut writer = Writer(&mut [0, 0, 0, 0, 1]); 269 assert_eq!(super::encode_write(&[0], &mut writer), Ok(())); 270 assert_eq!(writer.0, b"AA==\x01"); 271 assert_eq!( 272 super::encode_write(&[0, 0, 0, 0], &mut writer), 273 Err(fmt::Error) 274 ); 275 }