use super::*;
#[test]
fn flush_launches_only_free_pending_inboxes() {
let ws = TempDir::new().unwrap();
deposit_msg(ws.path(), "a1", "user-001.md");
deposit_msg(ws.path(), "a2", "user-001.md");
deposit_msg(ws.path(), "a3", ".user-001.md.tmp");
let _held = try_acquire(&inbox_dir(ws.path(), "a2"))
.unwrap()
.expect("free");
let git = StubGit::with_branches(&["a1", "a2", "a3"]);
let launcher = StubLauncher::default();
let report = scan(ws.path(), &git, &FixedClock, &launcher).unwrap();
assert_eq!(report.flushed, vec!["a1".to_string()]);
assert_eq!(launcher.invocations(), vec!["a1".to_string()]);
}
#[test]
fn flush_is_a_noop_without_an_inbox_root() {
let ws = TempDir::new().unwrap();
let git = StubGit::with_branches(&[]);
let report = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap();
assert_eq!(report, ScanReport::default());
}
#[test]
fn branch_enumeration_error_is_surfaced() {
let ws = TempDir::new().unwrap();
let git = StubGit::with_branches(&[CHILD]).failing("branch");
let err = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap_err();
assert!(matches!(
err,
ScanError::Git {
op: "for-each-ref agents/",
..
}
));
}
#[test]
fn transcript_read_error_is_surfaced() {
let ws = TempDir::new().unwrap();
let git = StubGit::with_branches(&[PARENT, CHILD]).failing("ls-tree");
let err = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap_err();
assert!(matches!(
err,
ScanError::Git {
op: "ls-tree messages",
..
}
));
}
#[test]
fn branch_tip_read_error_is_surfaced() {
let ws = TempDir::new().unwrap();
let git = StubGit::with_branches(&[PARENT, CHILD]).failing("rev-parse");
let err = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap_err();
assert!(matches!(
err,
ScanError::Git {
op: "rev-parse branch tip",
..
}
));
}
#[test]
fn probe_error_is_surfaced() {
let ws = TempDir::new().unwrap();
std::fs::create_dir_all(ws.path().join(INBOX_DIR)).unwrap();
std::fs::write(inbox_dir(ws.path(), CHILD), b"not a dir").unwrap();
let git = StubGit::with_branches(&[CHILD]);
let err = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap_err();
assert!(matches!(err, ScanError::Probe { .. }), "{err}");
}
#[test]
fn launch_error_is_surfaced() {
let ws = TempDir::new().unwrap();
deposit_msg(ws.path(), "a1", "user-001.md");
let git = StubGit::with_branches(&["a1"]);
let err = scan(ws.path(), &git, &FixedClock, &FailLauncher).unwrap_err();
assert!(matches!(err, ScanError::Flush { .. }), "{err}");
}
#[test]
fn inbox_root_read_error_is_surfaced() {
let ws = TempDir::new().unwrap();
std::fs::write(ws.path().join(INBOX_DIR), b"not a dir").unwrap();
let git = StubGit::with_branches(&[]);
let err = scan(ws.path(), &git, &FixedClock, &StubLauncher::default()).unwrap_err();
assert!(matches!(err, ScanError::InboxRoot { .. }), "{err}");
}
#[test]
fn transcript_line_matcher_rejects_non_matches() {
assert!(transcript_line_from(
&format!("messages/007-{CHILD}.md"),
CHILD
));
assert!(transcript_line_from(&format!("007-{CHILD}.md"), CHILD));
assert!(!transcript_line_from("messages/007-other.md", CHILD));
assert!(!transcript_line_from("messages/notes.txt", CHILD));
assert!(!transcript_line_from("messages/noseq.md", CHILD));
}
#[test]
fn pending_deposit_matcher_rejects_non_deposits() {
assert!(is_pending_deposit("user-001.md"));
assert!(is_pending_deposit("a-b-c-042.md"));
assert!(!is_pending_deposit(".user-001.md.tmp"));
assert!(!is_pending_deposit("user-abc.md"));
assert!(!is_pending_deposit("user-001.txt"));
assert!(!is_pending_deposit("-001.md"));
assert!(!is_pending_deposit("noseq"));
assert!(!is_pending_deposit("nohyphen.md"));
}
#[test]
fn cli_run_surfaces_a_scan_error_loudly() {
let ws = TempDir::new().unwrap();
let err = cli_run(ws.path(), std::path::Path::new("true")).unwrap_err();
assert!(matches!(err, ScanError::Layout(_)), "{err}");
}
#[test]
fn crash_stranding_is_healed_by_an_explicit_scan() {
let (_h, ws) = crate::workspace::fixture::workspace();
crate::workspace::fixture::spawn_root(&ws, PARENT);
crate::workspace::fixture::spawn_agent(&ws, CHILD, &crate::workspace::agent_ref(PARENT));
let report = cli_run(&ws, std::path::Path::new("true")).unwrap();
assert_eq!(report.swept, vec![CHILD.to_string()]);
let deposited = inbox_dir(&ws, PARENT).join(format!("{CHILD}-001.md"));
let body = std::fs::read_to_string(&deposited).unwrap();
assert!(body.contains("epitaph: died"), "got {body:?}");
assert_eq!(report.flushed, vec![PARENT.to_string()]);
assert_eq!(
report.to_string(),
format!(
"silent deaths: 1 ({CHILD}); died deposits swept: 1; drivers launched: 1; \
inboxes with no agent branch: 0"
)
);
}
#[test]
fn an_inbox_with_no_agent_branch_is_reported_never_launched() {
let ws = TempDir::new().unwrap();
deposit_msg(ws.path(), "no-such-agent", "user-001.md");
let git = StubGit::with_branches(&[]);
let launcher = StubLauncher::default();
let report = scan(ws.path(), &git, &FixedClock, &launcher).unwrap();
assert!(report.flushed.is_empty(), "no driver is launched");
assert!(launcher.invocations().is_empty(), "nothing is spawned");
assert_eq!(
report.inboxes_without_branch,
vec!["no-such-agent".to_string()]
);
assert!(
inbox_dir(ws.path(), "no-such-agent")
.join("user-001.md")
.exists(),
"the scanner deletes nothing"
);
}
#[test]
fn has_pending_reads_a_real_inbox_dir() {
let ws = TempDir::new().unwrap();
assert!(!has_pending(&ws.path().join("nope")));
deposit_msg(ws.path(), "a1", "user-001.md");
assert!(has_pending(&inbox_dir(ws.path(), "a1")));
}
#[test]
fn message_from_matcher_is_sender_scoped() {
assert!(is_message_from(&format!("{CHILD}-003.md"), CHILD));
assert!(!is_message_from("other-003.md", CHILD));
assert!(!is_message_from(&format!("{CHILD}-x.md"), CHILD));
}