use std::fs;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TestDataPattern {
Zeros,
Ones,
Sequential,
Random,
Compressible,
Text,
}
pub fn create_test_data(size_mb: usize, pattern: TestDataPattern) -> Vec<u8> {
let size_bytes = size_mb * 1024 * 1024;
match pattern {
TestDataPattern::Zeros => vec![0u8; size_bytes],
TestDataPattern::Ones => vec![0xFF; size_bytes],
TestDataPattern::Sequential => (0..size_bytes).map(|i| (i % 256) as u8).collect(),
TestDataPattern::Random => {
(0..size_bytes)
.map(|i| ((i.wrapping_mul(2654435761)) % 256) as u8)
.collect()
}
TestDataPattern::Compressible => {
let pattern = b"The quick brown fox jumps over the lazy dog. ";
(0..size_bytes)
.map(|i| pattern[i % pattern.len()])
.collect()
}
TestDataPattern::Text => {
let chars = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \n";
(0..size_bytes).map(|i| chars[i % chars.len()]).collect()
}
}
}
pub fn verify_data_sampled(data: &[u8], expected_pattern: TestDataPattern, sample_points: usize) {
let len = data.len();
let stride = len / sample_points;
for i in 0..sample_points {
let pos = i * stride;
if pos >= len {
break;
}
let expected = match expected_pattern {
TestDataPattern::Zeros => 0u8,
TestDataPattern::Ones => 0xFF,
TestDataPattern::Sequential => (pos % 256) as u8,
TestDataPattern::Random => ((pos.wrapping_mul(2654435761)) % 256) as u8,
TestDataPattern::Compressible => {
let pattern = b"The quick brown fox jumps over the lazy dog. ";
pattern[pos % pattern.len()]
}
TestDataPattern::Text => {
let chars = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \n";
chars[pos % chars.len()]
}
};
assert_eq!(
data[pos], expected,
"Mismatch at position {} (sample {}): expected {}, got {}",
pos, i, expected, data[pos]
);
}
}
pub fn create_test_dataset(base_path: &Path, size_mb: usize, pattern: TestDataPattern) -> usize {
fs::create_dir_all(base_path).expect("Failed to create dataset directory");
let target_bytes = size_mb * 1024 * 1024;
let mut written = 0;
let mut file_count = 0;
while written < target_bytes {
let file_size = match file_count % 5 {
0 => 1024, 1 => 10 * 1024, 2 => 100 * 1024, 3 => 500 * 1024, _ => 1024 * 1024, };
let actual_size = file_size.min(target_bytes - written);
let filename = format!("file_{:04}.bin", file_count);
let filepath = base_path.join(&filename);
let data = create_test_data_bytes(actual_size, pattern);
fs::write(&filepath, data).expect("Failed to write test file");
written += actual_size;
file_count += 1;
}
file_count
}
fn create_test_data_bytes(size_bytes: usize, pattern: TestDataPattern) -> Vec<u8> {
match pattern {
TestDataPattern::Zeros => vec![0u8; size_bytes],
TestDataPattern::Ones => vec![0xFF; size_bytes],
TestDataPattern::Sequential => (0..size_bytes).map(|i| (i % 256) as u8).collect(),
TestDataPattern::Random => (0..size_bytes)
.map(|i| ((i.wrapping_mul(2654435761)) % 256) as u8)
.collect(),
TestDataPattern::Compressible => {
let pattern = b"The quick brown fox jumps over the lazy dog. ";
(0..size_bytes)
.map(|i| pattern[i % pattern.len()])
.collect()
}
TestDataPattern::Text => {
let chars = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \n";
(0..size_bytes).map(|i| chars[i % chars.len()]).collect()
}
}
}
pub fn write_file_of_size(
path: &Path,
size_bytes: usize,
pattern: TestDataPattern,
) -> std::io::Result<()> {
let data = create_test_data_bytes(size_bytes, pattern);
fs::write(path, data)
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_create_test_data() {
let data = create_test_data(1, TestDataPattern::Zeros);
assert_eq!(data.len(), 1024 * 1024);
assert!(data.iter().all(|&b| b == 0));
let data = create_test_data(1, TestDataPattern::Ones);
assert!(data.iter().all(|&b| b == 0xFF));
}
#[test]
fn test_sequential_pattern() {
let data = create_test_data_bytes(512, TestDataPattern::Sequential);
assert_eq!(data.len(), 512);
for (i, &byte) in data.iter().enumerate().take(256) {
assert_eq!(byte, i as u8);
}
for (i, &byte) in data.iter().enumerate().take(512).skip(256) {
assert_eq!(byte, (i % 256) as u8);
}
}
#[test]
fn test_compressible_pattern() {
let data = create_test_data_bytes(100, TestDataPattern::Compressible);
let pattern = b"The quick brown fox jumps over the lazy dog. ";
assert_eq!(&data[0..pattern.len()], pattern);
}
#[test]
fn test_verify_data_sampled() {
let data = create_test_data_bytes(10000, TestDataPattern::Sequential);
verify_data_sampled(&data, TestDataPattern::Sequential, 100);
}
#[test]
#[should_panic(expected = "Mismatch at position")]
fn test_verify_data_sampled_mismatch() {
let mut data = create_test_data_bytes(1000, TestDataPattern::Sequential);
data[500] = 0xFF; verify_data_sampled(&data, TestDataPattern::Sequential, 100);
}
#[test]
fn test_create_test_dataset() {
let temp_dir = TempDir::new().unwrap();
let dataset_path = temp_dir.path().join("dataset");
let file_count = create_test_dataset(&dataset_path, 5, TestDataPattern::Random);
assert!(file_count > 0);
assert!(dataset_path.exists());
let mut total_size = 0;
for entry in fs::read_dir(&dataset_path).unwrap() {
let entry = entry.unwrap();
let metadata = entry.metadata().unwrap();
total_size += metadata.len();
}
let expected_size = 5 * 1024 * 1024;
assert!(total_size >= expected_size - 1024 * 1024); assert!(total_size <= expected_size + 1024 * 1024);
}
#[test]
fn test_write_file_of_size() {
let temp_dir = TempDir::new().unwrap();
let filepath = temp_dir.path().join("test.bin");
write_file_of_size(&filepath, 4096, TestDataPattern::Random).unwrap();
assert!(filepath.exists());
let metadata = fs::metadata(&filepath).unwrap();
assert_eq!(metadata.len(), 4096);
}
}