cli_testing_specialist/utils/
io_optimized.rs1use crate::error::Result;
7use serde::{Deserialize, Serialize};
8use std::fs::File;
9use std::io::{BufReader, BufWriter, Read, Write};
10use std::path::Path;
11
12const BUFFER_SIZE: usize = 64 * 1024; pub fn write_json_optimized<T, P>(data: &T, path: P) -> Result<()>
45where
46 T: Serialize,
47 P: AsRef<Path>,
48{
49 let file = File::create(path)?;
50 let mut writer = BufWriter::with_capacity(BUFFER_SIZE, file);
51
52 serde_json::to_writer_pretty(&mut writer, data)?;
54
55 writer.flush()?;
57
58 Ok(())
59}
60
61pub fn write_json_compact_optimized<T, P>(data: &T, path: P) -> Result<()>
82where
83 T: Serialize,
84 P: AsRef<Path>,
85{
86 let file = File::create(path)?;
87 let mut writer = BufWriter::with_capacity(BUFFER_SIZE, file);
88
89 serde_json::to_writer(&mut writer, data)?;
91
92 writer.flush()?;
94
95 Ok(())
96}
97
98pub fn read_json_optimized<T, P>(path: P) -> Result<T>
124where
125 T: for<'de> Deserialize<'de>,
126 P: AsRef<Path>,
127{
128 let file = File::open(path)?;
129 let mut reader = BufReader::with_capacity(BUFFER_SIZE, file);
130
131 let data = serde_json::from_reader(&mut reader)?;
133
134 Ok(data)
135}
136
137pub fn read_json_string_optimized<P>(path: P) -> Result<String>
151where
152 P: AsRef<Path>,
153{
154 let file = File::open(path)?;
155 let mut reader = BufReader::with_capacity(BUFFER_SIZE, file);
156
157 let mut contents = String::new();
158 reader.read_to_string(&mut contents)?;
159
160 Ok(contents)
161}
162
163#[doc(hidden)]
167pub fn write_json_naive<T, P>(data: &T, path: P) -> Result<()>
168where
169 T: Serialize,
170 P: AsRef<Path>,
171{
172 let json = serde_json::to_string_pretty(data)?;
173 std::fs::write(path, json)?;
174 Ok(())
175}
176
177#[doc(hidden)]
181pub fn read_json_naive<T, P>(path: P) -> Result<T>
182where
183 T: for<'de> Deserialize<'de>,
184 P: AsRef<Path>,
185{
186 let json = std::fs::read_to_string(path)?;
187 let data = serde_json::from_str(&json)?;
188 Ok(data)
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194 use serde::{Deserialize, Serialize};
195 use tempfile::NamedTempFile;
196
197 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
198 struct TestData {
199 name: String,
200 value: i32,
201 items: Vec<String>,
202 }
203
204 fn create_test_data() -> TestData {
205 TestData {
206 name: "test".to_string(),
207 value: 42,
208 items: vec![
209 "item1".to_string(),
210 "item2".to_string(),
211 "item3".to_string(),
212 ],
213 }
214 }
215
216 #[test]
217 fn test_write_json_optimized() {
218 let data = create_test_data();
219 let temp_file = NamedTempFile::new().unwrap();
220
221 write_json_optimized(&data, temp_file.path()).unwrap();
222
223 let content = std::fs::read_to_string(temp_file.path()).unwrap();
225 let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
226
227 assert_eq!(parsed["name"], "test");
228 assert_eq!(parsed["value"], 42);
229 assert_eq!(parsed["items"].as_array().unwrap().len(), 3);
230 }
231
232 #[test]
233 fn test_write_json_compact_optimized() {
234 let data = create_test_data();
235 let temp_file = NamedTempFile::new().unwrap();
236
237 write_json_compact_optimized(&data, temp_file.path()).unwrap();
238
239 let content = std::fs::read_to_string(temp_file.path()).unwrap();
241 assert!(!content.contains(" ")); let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
244 assert_eq!(parsed["name"], "test");
245 }
246
247 #[test]
248 fn test_read_json_optimized() {
249 let data = create_test_data();
250 let temp_file = NamedTempFile::new().unwrap();
251
252 write_json_optimized(&data, temp_file.path()).unwrap();
254
255 let read_data: TestData = read_json_optimized(temp_file.path()).unwrap();
257
258 assert_eq!(read_data, data);
259 }
260
261 #[test]
262 fn test_read_json_string_optimized() {
263 let data = create_test_data();
264 let temp_file = NamedTempFile::new().unwrap();
265
266 write_json_optimized(&data, temp_file.path()).unwrap();
268
269 let json_string = read_json_string_optimized(temp_file.path()).unwrap();
271
272 assert!(json_string.contains("\"name\": \"test\""));
274 assert!(json_string.contains("\"value\": 42"));
275
276 let parsed: TestData = serde_json::from_str(&json_string).unwrap();
278 assert_eq!(parsed, data);
279 }
280
281 #[test]
282 fn test_roundtrip_optimized() {
283 let original = create_test_data();
284 let temp_file = NamedTempFile::new().unwrap();
285
286 write_json_optimized(&original, temp_file.path()).unwrap();
288 let roundtrip: TestData = read_json_optimized(temp_file.path()).unwrap();
289
290 assert_eq!(roundtrip, original);
291 }
292
293 #[test]
294 fn test_naive_vs_optimized_correctness() {
295 let data = create_test_data();
296 let temp_optimized = NamedTempFile::new().unwrap();
297 let temp_naive = NamedTempFile::new().unwrap();
298
299 write_json_optimized(&data, temp_optimized.path()).unwrap();
301 write_json_naive(&data, temp_naive.path()).unwrap();
302
303 let optimized: TestData = read_json_optimized(temp_optimized.path()).unwrap();
305 let naive: TestData = read_json_naive(temp_naive.path()).unwrap();
306
307 assert_eq!(optimized, naive);
309 assert_eq!(optimized, data);
310 }
311
312 #[test]
313 #[cfg_attr(
314 all(target_os = "linux", not(target_env = "musl")),
315 ignore = "Requires >20MB memory allocation, fails in CI environments"
316 )]
317 fn test_large_data_handling() {
318 #[derive(Serialize, Deserialize, PartialEq, Debug)]
320 struct LargeData {
321 items: Vec<TestData>,
322 }
323
324 let large_data = LargeData {
325 items: (0..1000)
326 .map(|i| TestData {
327 name: format!("item-{}", i),
328 value: i,
329 items: vec![format!("sub-{}", i); 10],
330 })
331 .collect(),
332 };
333
334 let temp_file = NamedTempFile::new().unwrap();
335
336 write_json_optimized(&large_data, temp_file.path()).unwrap();
338 let read_data: LargeData = read_json_optimized(temp_file.path()).unwrap();
339
340 assert_eq!(read_data.items.len(), 1000);
341 assert_eq!(read_data.items[0].name, "item-0");
342 assert_eq!(read_data.items[999].name, "item-999");
343 }
344}