Skip to main content

agent_trace/core/
util.rs

1use anyhow::Result;
2use std::path::Path;
3
4/// Write `content` to `path` atomically using a temp-file + rename pattern.
5/// Prevents file corruption if the process is interrupted mid-write.
6pub 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}