1use anyhow::Result;
2use std::path::Path;
3
4pub fn atomic_write(path: &Path, content: &str) -> Result<()> {
7 let tmp_path = path.with_extension(format!(
8 "{}.tmp",
9 path.extension().and_then(|e| e.to_str()).unwrap_or("")
10 ));
11 std::fs::write(&tmp_path, content)?;
12 std::fs::rename(&tmp_path, path)?;
13 Ok(())
14}
15
16#[cfg(test)]
17mod tests {
18 use super::*;
19 use tempfile::TempDir;
20
21 #[test]
22 fn test_atomic_write_creates_file() {
23 let tmp = TempDir::new().unwrap();
24 let path = tmp.path().join("test.toml");
25 atomic_write(&path, "hello").unwrap();
26 assert_eq!(std::fs::read_to_string(&path).unwrap(), "hello");
27 }
28
29 #[test]
30 fn test_atomic_write_no_tmp_left_behind() {
31 let tmp = TempDir::new().unwrap();
32 let path = tmp.path().join("test.toml");
33 atomic_write(&path, "content").unwrap();
34 let tmp_path = path.with_extension("toml.tmp");
35 assert!(
36 !tmp_path.exists(),
37 "tmp file should not remain after atomic write"
38 );
39 }
40
41 #[test]
42 fn test_atomic_write_overwrites_existing() {
43 let tmp = TempDir::new().unwrap();
44 let path = tmp.path().join("out.toml");
45 atomic_write(&path, "first").unwrap();
46 atomic_write(&path, "second").unwrap();
47 assert_eq!(std::fs::read_to_string(&path).unwrap(), "second");
48 }
49}