#![allow(
clippy::missing_docs_in_private_items,
reason = "test helpers and fixtures do not need doc comments"
)]
use super::*;
fn scratch_dir() -> PathBuf {
let dir = std::env::temp_dir().join(format!("moadim-atomic-{}", Uuid::new_v4()));
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn tmp_residue(dir: &Path) -> usize {
std::fs::read_dir(dir)
.unwrap()
.filter_map(Result::ok)
.filter(|entry| entry.file_name().to_string_lossy().contains(".tmp"))
.count()
}
#[test]
fn writes_contents_and_leaves_no_tmp_residue() {
let dir = scratch_dir();
let target = dir.join("routine.toml");
atomic_write(&target, b"hello").unwrap();
assert_eq!(std::fs::read(&target).unwrap(), b"hello");
assert_eq!(
tmp_residue(&dir),
0,
"no .tmp file should remain on success"
);
std::fs::remove_dir_all(&dir).unwrap();
}
#[test]
fn overwrites_existing_file_atomically() {
let dir = scratch_dir();
let target = dir.join("prompt.md");
atomic_write(&target, b"first").unwrap();
atomic_write(&target, b"second").unwrap();
assert_eq!(std::fs::read(&target).unwrap(), b"second");
assert_eq!(tmp_residue(&dir), 0);
std::fs::remove_dir_all(&dir).unwrap();
}
#[test]
fn errors_when_temp_cannot_be_created() {
let target = std::env::temp_dir()
.join(format!("moadim-atomic-missing-{}", Uuid::new_v4()))
.join("routine.toml");
let err = atomic_write(&target, b"data").unwrap_err();
assert_eq!(err.kind(), io::ErrorKind::NotFound);
assert!(!target.exists());
}
#[test]
fn errors_and_cleans_up_when_rename_fails() {
let dir = scratch_dir();
let target = dir.join("occupied");
std::fs::create_dir(&target).unwrap();
assert!(atomic_write(&target, b"data").is_err());
assert_eq!(
tmp_residue(&dir),
0,
"temp file should be removed on rename failure"
);
assert!(target.is_dir(), "the occupying directory is left untouched");
std::fs::remove_dir_all(&dir).unwrap();
}
#[test]
fn tmp_path_falls_back_when_no_file_name() {
let tmp = tmp_path(Path::new("/some/dir/.."));
assert!(tmp.to_string_lossy().contains(".tmp"));
}
#[cfg(target_os = "linux")]
#[test]
fn write_tmp_propagates_a_write_failure_instead_of_panicking() {
let dir = scratch_dir();
let tmp = dir.join("routine.toml.tmp");
std::os::unix::fs::symlink("/dev/full", &tmp).unwrap();
assert!(
write_tmp(&tmp, b"data").is_err(),
"write_tmp must return the write error instead of panicking"
);
std::fs::remove_dir_all(&dir).unwrap();
}
#[cfg(unix)]
#[test]
fn published_file_is_owner_only() {
use std::os::unix::fs::PermissionsExt;
let dir = scratch_dir();
let target = dir.join("routine.toml");
atomic_write(&target, b"secret").unwrap();
let mode = std::fs::metadata(&target).unwrap().permissions().mode() & 0o777;
assert_eq!(
mode, 0o600,
"atomic_write must publish an owner-only file, got {mode:o}"
);
std::fs::remove_dir_all(&dir).unwrap();
}