KeiSeiKit-1.0/_primitives/_rust/kei-frustration-loop/tests/persistence_atomic.rs
Parfii-bot a4e667de10 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

70 lines
2.2 KiB
Rust

//! Atomic-write test: pipe bytes through `<dest>.tmp` + rename, assert the
//! destination file contains exactly the bytes written.
use kei_frustration_loop::persistence::{
atomic_swap, atomic_write, read_last_scan_ts, write_last_scan_ts,
};
use std::fs;
use tempfile::TempDir;
#[test]
fn atomic_write_creates_destination_with_exact_bytes() {
let dir = TempDir::new().unwrap();
let dest = dir.path().join("output.bin");
let payload = b"hello world\n\xff\xfeHELLO";
atomic_write(&dest, payload).unwrap();
let read_back = fs::read(&dest).unwrap();
assert_eq!(read_back, payload, "destination contents must match");
let tmp = {
let mut s = dest.as_os_str().to_owned();
s.push(".tmp");
std::path::PathBuf::from(s)
};
assert!(!tmp.exists(), "tmp file must be renamed away, not left behind");
}
#[test]
fn atomic_write_overwrites_existing_destination() {
let dir = TempDir::new().unwrap();
let dest = dir.path().join("dst.txt");
fs::write(&dest, b"OLD").unwrap();
atomic_write(&dest, b"NEW").unwrap();
assert_eq!(fs::read(&dest).unwrap(), b"NEW");
}
#[test]
fn atomic_swap_renames_tmp_into_dest() {
let dir = TempDir::new().unwrap();
let tmp = dir.path().join("staging.bin");
let dst = dir.path().join("final.bin");
let payload = b"swap-me";
fs::write(&tmp, payload).unwrap();
atomic_swap(&tmp, &dst).unwrap();
assert!(!tmp.exists(), "tmp must be gone after swap");
assert_eq!(fs::read(&dst).unwrap(), payload);
}
#[test]
fn last_scan_ts_round_trip() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("alice.last-scan.ts");
assert_eq!(
read_last_scan_ts(&path),
0,
"missing file should read as 0"
);
write_last_scan_ts(&path, 1_700_000_000).unwrap();
assert_eq!(read_last_scan_ts(&path), 1_700_000_000);
write_last_scan_ts(&path, 1_700_000_999).unwrap();
assert_eq!(read_last_scan_ts(&path), 1_700_000_999);
}
#[test]
fn last_scan_ts_unparseable_reads_as_zero() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("bad.ts");
fs::write(&path, "not a number").unwrap();
assert_eq!(read_last_scan_ts(&path), 0);
}