use super::FileIo;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Copy, Default)]
pub struct RealFileIo;
impl FileIo for RealFileIo {
fn read(&self, path: &Path) -> std::io::Result<Option<Vec<u8>>> {
match std::fs::read(path) {
Ok(bytes) => Ok(Some(bytes)),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(e) => Err(e),
}
}
fn write(&self, path: &Path, bytes: &[u8]) -> std::io::Result<()> {
std::fs::write(path, bytes)
}
fn rename(&self, from: &Path, to: &Path) -> std::io::Result<()> {
std::fs::rename(from, to)
}
fn remove(&self, path: &Path) -> std::io::Result<()> {
std::fs::remove_file(path)
}
fn list_dir(&self, dir: &Path) -> std::io::Result<Vec<PathBuf>> {
match std::fs::read_dir(dir) {
Ok(entries) => Ok(entries.flatten().map(|e| e.path()).collect()),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(Vec::new()),
Err(e) => Err(e),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[test]
fn read_write_rename_remove_roundtrip() {
let dir = tempdir().unwrap();
let io = RealFileIo;
let a = dir.path().join("a");
let b = dir.path().join("b");
assert_eq!(io.read(&a).unwrap(), None);
io.write(&a, b"hello").unwrap();
assert_eq!(io.read(&a).unwrap(), Some(b"hello".to_vec()));
io.rename(&a, &b).unwrap();
assert_eq!(io.read(&a).unwrap(), None);
assert_eq!(io.read(&b).unwrap(), Some(b"hello".to_vec()));
io.remove(&b).unwrap();
assert_eq!(io.read(&b).unwrap(), None);
}
#[test]
fn read_surfaces_non_notfound_errors() {
let dir = tempdir().unwrap();
assert!(RealFileIo.read(dir.path()).is_err());
}
#[test]
fn list_dir_lists_children_and_absent_is_empty() {
let dir = tempdir().unwrap();
let io = RealFileIo;
assert!(io.list_dir(&dir.path().join("nope")).unwrap().is_empty());
io.write(&dir.path().join("a.yaml"), b"1").unwrap();
io.write(&dir.path().join("b.txt"), b"2").unwrap();
let mut got = io.list_dir(dir.path()).unwrap();
got.sort();
assert_eq!(
got,
vec![dir.path().join("a.yaml"), dir.path().join("b.txt")]
);
}
#[test]
fn list_dir_surfaces_non_notfound_errors() {
let dir = tempdir().unwrap();
let f = dir.path().join("f");
RealFileIo.write(&f, b"x").unwrap();
assert!(RealFileIo.list_dir(&f).is_err());
}
}