use super::Harness;
use crate::cli_outbound::Cli;
use crate::git_tree::AgentState;
use crate::opslog;
use crate::test_support::spawn_guard;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use tempfile::{TempDir, tempdir};
fn fake_lernie(dir: &TempDir, stdout: &str, stderr: &str, code: i32) -> Cli {
let path = dir.path().join("lernie");
fs::write(
&path,
format!(
"#!/bin/sh\necho \"$@\" > {}/argv.log\nprintf '%s\\n' '{stdout}'\nprintf '%s' '{stderr}' 1>&2\nexit {code}\n",
dir.path().display()
),
)
.unwrap();
let mut perms = fs::metadata(&path).unwrap().permissions();
perms.set_mode(0o755);
fs::set_permissions(&path, perms).unwrap();
Cli::new(path)
}
fn logged_argv(dir: &TempDir) -> String {
fs::read_to_string(dir.path().join("argv.log"))
.unwrap_or_default()
.trim()
.to_owned()
}
fn unused_bl() -> Cli {
Cli::new("bl")
}
#[test]
fn the_confirmation_is_offered_only_inside_named_workspaces() {
let mut h = Harness::new();
let named = h.mint_named("alba-koi", "c-1");
let replay = h.add_replay("20260101T-rr", "c-9");
let (_c, model) = h.model();
let confirm = model.agent_delete_confirmation(&named, "c-1").unwrap();
assert_eq!(confirm.name, "hi", "the display ladder names the dialog");
assert!(!confirm.refused());
assert!(
model.agent_delete_confirmation(&h.ws, "c-1").is_none(),
"foreign"
);
assert!(
model.agent_delete_confirmation(&replay, "c-9").is_none(),
"replay"
);
}
#[test]
fn an_unnamed_workspace_is_refused_outright() {
let h = Harness::new();
let (_c, mut model) = h.model();
let err = model
.delete_agent(&unused_bl(), &unused_bl(), &h.ws, "c-1", "", "TS")
.unwrap_err();
assert_eq!(err, "not a yog-named workspace");
}
#[test]
fn a_live_member_refuses_before_anything_spawns() {
let mut h = Harness::new();
let named = h.mint_named("alba-koi", "c-1");
let (_c, mut model) = h.model();
for agent in &mut model.deriver.trees.get_mut(&named).unwrap().agents {
agent.state = AgentState::Live;
}
model.publish();
let err = model
.delete_agent(&unused_bl(), &unused_bl(), &named, "c-1", "", "TS")
.unwrap_err();
assert_eq!(err, "refused \u{2014} live: c-1 \u{2014} stop them first");
assert!(opslog::tail(&h.roots.yog_state, 8).is_empty());
}
#[test]
fn a_leaf_fires_the_bare_verb_and_the_typed_name_arms_the_subtree() {
let _g = spawn_guard();
let mut h = Harness::new();
let named = h.mint_named("alba-koi", "c-1");
let bin = tempdir().unwrap();
let lernie = fake_lernie(
&bin,
"deleted c-1; descendants: 0; pending deposits: 0",
"",
0,
);
let (_c, mut model) = h.model_focused(Some(named.clone()));
model.focus_agent(&named, "c-1");
assert!(model.focused_agent().is_some());
model
.delete_agent(&lernie, &unused_bl(), &named, "c-1", "", "TS")
.unwrap();
assert_eq!(logged_argv(&bin), format!("delete {} c-1", named.display()));
assert!(
model.focused_agent().is_none(),
"focus never points into the deleted subtree"
);
model
.delete_agent(&lernie, &unused_bl(), &named, "c-1", " hi ", "TS")
.unwrap();
assert_eq!(
logged_argv(&bin),
format!("delete {} c-1 --children", named.display())
);
let ops = opslog::tail(&h.roots.yog_state, 8);
assert_eq!(ops.len(), 2, "each removal leaves its ops row");
assert!(ops.iter().all(|e| e.exit == 0));
}
#[test]
fn a_declined_verb_rides_back_its_stderr_verbatim() {
let _g = spawn_guard();
let mut h = Harness::new();
let named = h.mint_named("alba-koi", "c-1");
let bin = tempdir().unwrap();
let decline = "agent \"c-1\" has 1 descendant(s); pass --children";
let lernie = fake_lernie(&bin, "", decline, 2);
let (_c, mut model) = h.model();
let err = model
.delete_agent(&lernie, &unused_bl(), &named, "c-1", "", "TS")
.unwrap_err();
assert_eq!(err, decline, "the substrate's own words, not a paraphrase");
let mute = tempdir().unwrap();
let silent = fake_lernie(&mute, "", "", 3);
let err = model
.delete_agent(&silent, &unused_bl(), &named, "c-1", "", "TS")
.unwrap_err();
assert_eq!(err, "lernie delete failed (exit 3)");
let gone = Cli::new(bin.path().join("no-such-lernie"));
let err = model
.delete_agent(&gone, &unused_bl(), &named, "c-1", "", "TS")
.unwrap_err();
assert!(err.contains("No such file"), "{err}");
}
#[test]
fn a_focus_on_a_descendant_clears_with_its_root_and_a_neighbour_survives() {
let _g = spawn_guard();
let mut h = Harness::new();
let named = h.mint_named("alba-koi", "r-aa");
h.last_added().build_agent("r-aa-c-bb", "child");
h.last_added().build_agent("z-zz", "other");
let bin = tempdir().unwrap();
let lernie = fake_lernie(
&bin,
"deleted r-aa; descendants: 1 (r-aa-c-bb); pending deposits: 0",
"",
0,
);
let (_c, mut model) = h.model_focused(Some(named.clone()));
model.focus_agent(&named, "r-aa-c-bb");
model
.delete_agent(&lernie, &unused_bl(), &named, "r-aa", "", "TS")
.unwrap();
assert!(model.focused_agent().is_none());
model.focus_agent(&named, "z-zz");
model
.delete_agent(&lernie, &unused_bl(), &named, "r-aa", "", "TS")
.unwrap();
assert_eq!(
model.focused_agent().map(|a| a.agent_id.clone()),
Some("z-zz".to_owned())
);
}