use std::fs;
use std::io;
use std::path::Path;
pub fn oversized_zeros(path: &Path, size_bytes: u64) -> io::Result<()> {
let buf = vec![0u8; size_bytes as usize];
fs::write(path, buf)
}
pub fn oversized_sparse(path: &Path, size_bytes: u64) -> io::Result<()> {
let f = fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(path)?;
f.set_len(size_bytes)?;
Ok(())
}
pub fn malformed_utf8(path: &Path) -> io::Result<()> {
let mut bytes = b"valid ascii prefix\n".to_vec();
bytes.extend_from_slice(&[0xFF, 0xFE, 0xFD, 0xFC]);
bytes.extend_from_slice(b"more after the bad bytes\n");
fs::write(path, bytes)
}
pub fn random_bytes(path: &Path, n: usize, seed: u64) -> io::Result<()> {
let mut state = seed;
let mut bytes = Vec::with_capacity(n);
while bytes.len() < n {
state = state.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = state;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^= z >> 31;
let chunk = z.to_le_bytes();
for b in chunk {
if bytes.len() < n {
bytes.push(b);
}
}
}
fs::write(path, bytes)
}
pub fn unusual_names(count: usize) -> Vec<String> {
let pool = vec![
".hidden_file".to_string(),
"with space.txt".to_string(),
"with-many-dashes-in-name.txt".to_string(),
"résumé.tex".to_string(),
"файл.txt".to_string(),
"ファイル.txt".to_string(),
"emoji-✅-name.txt".to_string(),
format!("{}{}", "long_name_", "x".repeat(120)),
"trailing.dot.".to_string(),
"no_extension".to_string(),
];
pool.into_iter().take(count).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn oversized_zeros_writes_exact_size() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("big.bin");
oversized_zeros(&path, 1024).unwrap();
let bytes = fs::read(&path).unwrap();
assert_eq!(bytes.len(), 1024);
assert!(bytes.iter().all(|&b| b == 0));
}
#[test]
fn oversized_sparse_reports_exact_size() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("sparse.bin");
oversized_sparse(&path, 4096).unwrap();
let meta = fs::metadata(&path).unwrap();
assert_eq!(meta.len(), 4096);
}
#[test]
fn malformed_utf8_is_not_valid_utf8() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("bad.txt");
malformed_utf8(&path).unwrap();
let bytes = fs::read(&path).unwrap();
assert!(std::str::from_utf8(&bytes).is_err());
}
#[test]
fn random_bytes_are_deterministic_from_seed() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("rand.bin");
random_bytes(&path, 64, 7).unwrap();
let a = fs::read(&path).unwrap();
random_bytes(&path, 64, 7).unwrap();
let b = fs::read(&path).unwrap();
assert_eq!(a, b);
assert_eq!(a.len(), 64);
}
#[test]
fn random_bytes_differ_with_seed() {
let dir = tempfile::tempdir().unwrap();
let path_a = dir.path().join("a.bin");
let path_b = dir.path().join("b.bin");
random_bytes(&path_a, 64, 1).unwrap();
random_bytes(&path_b, 64, 2).unwrap();
let a = fs::read(&path_a).unwrap();
let b = fs::read(&path_b).unwrap();
assert_ne!(a, b);
}
#[test]
fn unusual_names_returns_requested_count() {
let names = unusual_names(3);
assert_eq!(names.len(), 3);
let big = unusual_names(100);
assert!(big.len() <= 10);
}
}