1use std::{io::Error, path::Path};
8
9use rand::Rng;
10use tokio::{
11 fs::File,
12 io::{AsyncReadExt, AsyncWriteExt},
13};
14
15pub async fn read_large_file(path: impl AsRef<Path>) -> Result<Vec<u8>, Error> {
19 let mut file = File::open(path).await?;
20 let mut buffer = Vec::new();
21 file.read_to_end(&mut buffer).await?;
22 Ok(buffer)
23}
24
25pub async fn generate_random_file(path: impl AsRef<Path>, size_mb: usize) -> Result<(), Error> {
30 let mut file = File::create(path).await?;
31 let mut rng = rand::thread_rng();
32 let chunk_size = 1024 * 1024;
33 let total_chunks = size_mb;
34
35 for _ in 0..total_chunks {
36 let mut chunk = vec![0u8; chunk_size];
37 rng.fill(&mut chunk[..]);
38 AsyncWriteExt::write_all(&mut file, &chunk).await?;
39 }
40
41 file.flush().await?;
42 Ok(())
43}
44
45pub async fn generate_random_bytes(size: usize) -> Result<Vec<u8>, Error> {
50 let mut rng = rand::thread_rng();
51 let mut bytes = vec![0u8; size];
52 rng.fill(&mut bytes[..]);
53 Ok(bytes)
54}
55
56#[cfg(test)]
57mod tests {
58 use tempfile::TempDir;
59
60 use super::*;
61
62 #[tokio::test]
63 async fn test_read_large_file_success() {
64 let temp_dir = TempDir::new().unwrap();
65 let file_path = temp_dir.path().join("test.txt");
66 tokio::fs::write(&file_path, b"Hello, World!")
67 .await
68 .unwrap();
69
70 let content = read_large_file(&file_path).await.unwrap();
71 assert_eq!(content, b"Hello, World!");
72 }
73
74 #[tokio::test]
75 async fn test_read_large_file_empty() {
76 let temp_dir = TempDir::new().unwrap();
77 let file_path = temp_dir.path().join("empty.txt");
78 tokio::fs::write(&file_path, b"").await.unwrap();
79
80 let content = read_large_file(&file_path).await.unwrap();
81 assert!(content.is_empty());
82 }
83
84 #[tokio::test]
85 async fn test_read_large_file_not_found() {
86 let result = read_large_file("/nonexistent/path/file.txt").await;
87 assert!(result.is_err());
88 }
89
90 #[tokio::test]
91 async fn test_generate_random_file_creates_file() {
92 let temp_dir = TempDir::new().unwrap();
93 let file_path = temp_dir.path().join("random.bin");
94
95 generate_random_file(&file_path, 1).await.unwrap();
96
97 let content = tokio::fs::read(&file_path).await.unwrap();
98 assert_eq!(content.len(), 1024 * 1024);
99 }
100
101 #[tokio::test]
102 async fn test_generate_random_file_zero_size() {
103 let temp_dir = TempDir::new().unwrap();
104 let file_path = temp_dir.path().join("empty_random.bin");
105
106 generate_random_file(&file_path, 0).await.unwrap();
107
108 let content = tokio::fs::read(&file_path).await.unwrap();
109 assert!(content.is_empty());
110 }
111
112 #[tokio::test]
113 async fn test_generate_random_bytes_size() {
114 let bytes = generate_random_bytes(256).await.unwrap();
115 assert_eq!(bytes.len(), 256);
116 }
117
118 #[tokio::test]
119 async fn test_generate_random_bytes_zero_size() {
120 let bytes = generate_random_bytes(0).await.unwrap();
121 assert!(bytes.is_empty());
122 }
123
124 #[tokio::test]
125 async fn test_generate_random_bytes_not_all_zeros() {
126 let bytes = generate_random_bytes(1024).await.unwrap();
127 assert!(bytes.iter().any(|&byte| byte != 0));
128 }
129
130 #[tokio::test]
131 async fn test_read_large_file_roundtrip() {
132 let temp_dir = TempDir::new().unwrap();
133 let file_path = temp_dir.path().join("roundtrip.bin");
134
135 generate_random_file(&file_path, 1).await.unwrap();
136 let content = read_large_file(&file_path).await.unwrap();
137 assert_eq!(content.len(), 1024 * 1024);
138 }
139}