use crate::error::{Error, Result};
use std::fs;
use std::path::Path;
pub fn read_file(path: &Path, operation: &str) -> Result<String> {
fs::read_to_string(path)
.map_err(|e| Error::internal_io(e.to_string(), Some(operation.to_string())))
}
pub fn write_file(path: &Path, content: &str, operation: &str) -> Result<()> {
fs::write(path, content)
.map_err(|e| Error::internal_io(e.to_string(), Some(operation.to_string())))
}
pub fn write_file_atomic(path: &Path, content: &str, operation: &str) -> Result<()> {
let parent = path.parent().ok_or_else(|| {
Error::internal_io(
format!("Invalid path: {}", path.display()),
Some(operation.to_string()),
)
})?;
let filename = path.file_name().ok_or_else(|| {
Error::internal_io(
format!("Invalid path: {}", path.display()),
Some(operation.to_string()),
)
})?;
let tmp_path = parent.join(format!("{}.tmp", filename.to_string_lossy()));
fs::write(&tmp_path, content).map_err(|e| {
Error::internal_io(e.to_string(), Some(format!("{} (write temp)", operation)))
})?;
fs::rename(&tmp_path, path)
.map_err(|e| Error::internal_io(e.to_string(), Some(format!("{} (rename)", operation))))?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
use tempfile::NamedTempFile;
#[test]
fn read_file_succeeds_for_existing_file() {
let mut temp = NamedTempFile::new().unwrap();
writeln!(temp, "test content").unwrap();
let content = read_file(temp.path(), "test read").unwrap();
assert!(content.contains("test content"));
}
#[test]
fn read_file_returns_error_for_missing_file() {
let result = read_file(Path::new("/nonexistent/path.txt"), "test read");
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.code.as_str(), "internal.io_error");
}
#[test]
fn write_file_succeeds_for_valid_path() {
let temp = NamedTempFile::new().unwrap();
let result = write_file(temp.path(), "new content", "test write");
assert!(result.is_ok());
let content = fs::read_to_string(temp.path()).unwrap();
assert_eq!(content, "new content");
}
#[test]
fn write_file_returns_error_for_invalid_path() {
let result = write_file(
Path::new("/nonexistent/dir/file.txt"),
"content",
"test write",
);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.code.as_str(), "internal.io_error");
}
}