use super::super::deposit::{DepositError, atomic_create, deposit, next_sequence};
use super::super::inbox_dir;
use crate::prompt::Clock;
use std::path::Path;
use tempfile::TempDir;
struct FixedClock;
impl Clock for FixedClock {
fn now_iso8601(&self) -> String {
"2026-07-11T00:00:00Z".into()
}
fn now_compact(&self) -> String {
unreachable!("deposit never reads the compact clock")
}
}
fn read(path: &Path) -> String {
std::fs::read_to_string(path).unwrap()
}
#[test]
fn deposit_writes_named_file_with_frontmatter_and_body() {
let ws = TempDir::new().unwrap();
let path = deposit(ws.path(), "p1-child", "user", "steer left\n", &FixedClock).unwrap();
assert_eq!(path, inbox_dir(ws.path(), "p1-child").join("user-001.md"));
assert_eq!(
read(&path),
"---\nfrom: user\ndeposited_at: 2026-07-11T00:00:00Z\n---\nsteer left\n"
);
}
#[test]
fn deposit_creates_inbox_directory_on_demand() {
let ws = TempDir::new().unwrap();
assert!(!inbox_dir(ws.path(), "a1").exists());
deposit(ws.path(), "a1", "user", "hi", &FixedClock).unwrap();
assert!(inbox_dir(ws.path(), "a1").is_dir());
}
#[test]
fn same_sender_sequence_increments() {
let ws = TempDir::new().unwrap();
let p1 = deposit(ws.path(), "a1", "user", "one", &FixedClock).unwrap();
let p2 = deposit(ws.path(), "a1", "user", "two", &FixedClock).unwrap();
let p3 = deposit(ws.path(), "a1", "user", "three", &FixedClock).unwrap();
assert!(p1.ends_with("user-001.md"));
assert!(p2.ends_with("user-002.md"));
assert!(p3.ends_with("user-003.md"));
for p in [&p1, &p2, &p3] {
assert!(p.exists());
}
}
#[test]
fn distinct_senders_keep_independent_sequences() {
let ws = TempDir::new().unwrap();
let a = deposit(ws.path(), "a1", "user", "u", &FixedClock).unwrap();
let b = deposit(ws.path(), "a1", "p2-agent", "g", &FixedClock).unwrap();
let a2 = deposit(ws.path(), "a1", "user", "u2", &FixedClock).unwrap();
assert!(a.ends_with("user-001.md"));
assert!(b.ends_with("p2-agent-001.md"));
assert!(a2.ends_with("user-002.md"));
}
#[test]
fn no_tmp_file_survives_a_deposit() {
let ws = TempDir::new().unwrap();
deposit(ws.path(), "a1", "user", "hi", &FixedClock).unwrap();
let dir = inbox_dir(ws.path(), "a1");
let names: Vec<String> = std::fs::read_dir(&dir)
.unwrap()
.flatten()
.map(|e| e.file_name().to_string_lossy().into_owned())
.collect();
assert_eq!(
names,
vec!["user-001.md".to_string()],
"no .tmp left behind"
);
}
#[test]
fn next_sequence_ignores_foreign_and_malformed_names() {
let ws = TempDir::new().unwrap();
let dir = inbox_dir(ws.path(), "a1");
std::fs::create_dir_all(&dir).unwrap();
for name in [
"user-abc.md",
"user-agent-001.md",
"p2-005.md",
"user-007.md",
] {
std::fs::write(dir.join(name), b"x").unwrap();
}
assert_eq!(next_sequence(&dir, "user").unwrap(), 8);
}
#[test]
fn next_sequence_surfaces_read_dir_error() {
let ws = TempDir::new().unwrap();
let missing = ws.path().join("nope");
assert!(next_sequence(&missing, "user").is_err());
}
#[test]
fn deposit_surfaces_io_error_when_inbox_home_blocked() {
let ws = TempDir::new().unwrap();
std::fs::write(ws.path().join("inbox"), b"not a dir").unwrap();
let err = deposit(ws.path(), "a1", "user", "hi", &FixedClock).unwrap_err();
let DepositError::Io { .. } = err;
}
#[test]
fn atomic_create_surfaces_write_error() {
let err = atomic_create(Path::new("/no/such/dir"), "user-001.md", b"x").unwrap_err();
let DepositError::Io { path, .. } = err;
assert!(path.ends_with(".user-001.md.tmp"), "{}", path.display());
}
#[test]
fn atomic_create_surfaces_rename_error() {
let ws = TempDir::new().unwrap();
let dir = ws.path();
let blocking = dir.join("user-001.md");
std::fs::create_dir(&blocking).unwrap();
std::fs::write(blocking.join("occupied"), b"x").unwrap();
let err = atomic_create(dir, "user-001.md", b"x").unwrap_err();
let DepositError::Io { path, .. } = err;
assert!(path.ends_with("user-001.md"), "{}", path.display());
}