use super::{Harness, agent};
use crate::git_tree::AgentState;
#[test]
fn strip_total_counts_attention_bearing_agents() {
let h = Harness::new();
let (_c, model) = h.model();
assert_eq!(model.strip_total(), 1, "the one unseen stop");
}
#[test]
fn focused_agent_resolves_the_selected_row_else_none() {
let h = Harness::new();
let (_c, mut model) = h.model();
model.focus_workspace(&h.ws);
assert!(model.focused_agent().is_none());
model.focus_agent(&h.ws, "c-1");
assert_eq!(
model.focused_agent().map(|a| a.agent_id.as_str()),
Some("c-1")
);
model.focus_agent(&h.ws, "ghost");
assert!(model.focused_agent().is_none());
model.focus_agent(std::path::Path::new("/no/such/ws"), "x");
assert!(model.focused_agent().is_none());
}
#[test]
fn the_tab_bar_and_conversation_list_carry_the_derived_facts() {
let h = Harness::new();
let (_c, mut model) = h.model();
let bar = model.tab_bar();
assert!(bar.tabs.is_empty(), "no named workspaces, no wall tabs");
assert_eq!(bar.overflow.len(), 1);
let entry = &bar.overflow[0];
assert_eq!(entry.name, "ws");
assert_eq!(entry.attention, 1);
assert_eq!(entry.kind, crate::nav::tabs::Kind::Foreign);
model.focus_workspace(&h.ws);
let rows = model.conversations(10);
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].root_id, "c-1");
assert_eq!(rows[0].attention, 1);
assert_eq!(rows[0].members, 1);
assert_eq!(rows[0].depth, 0);
assert_eq!(rows[0].direct, 0, "a lone root dispatched nobody");
let expanded = std::collections::HashSet::from(["c-1".to_owned()]);
assert_eq!(model.visible_conversations(10, &expanded), rows);
model.focus_workspace(std::path::Path::new("/no/such"));
assert!(model.conversations(10).is_empty(), "unfetched ws: no rows");
assert!(model.visible_conversations(10, &expanded).is_empty());
}
#[test]
fn the_boundary_answer_is_the_frames_derivation_without_a_frame() {
use crate::boundary::reply::Reply;
use crate::boundary::{Query, answer};
use crate::cli_outbound::Cli;
use crate::ui_state::UiState;
let h = Harness::new();
let (_c, mut model) = h.model();
model.focus_workspace(&h.ws);
let deps = model.boundary_deps(&Cli::new("/no/lernie"), &Cli::new("/no/bl"));
let frame_rows = model.conversations(500);
assert_eq!(frame_rows.len(), 1, "the fixture's one conversation");
let Ok(Reply::Conversations(via_answer)) = model.answer(
&deps,
&Query::Conversations {
workspace: h.ws.clone(),
},
500,
) else {
panic!("conversations answers conversations");
};
assert_eq!(via_answer, frame_rows, "one derivation, two callers");
let snap = crate::state::latest_snapshot(&model.snapshot_cell());
let ui = UiState::open(model.ui_json_path());
assert_eq!(
answer::conversations(&snap, &ui, &h.ws, 500),
frame_rows,
"the snapshot derivation run without a frame"
);
let Ok(Reply::Workspaces(rows)) = model.answer(&deps, &Query::Workspaces, 500) else {
panic!("workspaces answers workspaces");
};
assert_eq!(rows.len(), 1);
assert_eq!(
(rows[0].attention, rows[0].agents, rows[0].running),
model.workspace_stats(&h.ws)
);
}
#[test]
fn the_live_mark_seats_the_focused_conversation_root_first() {
let h = Harness::new();
let (_c, mut model) = h.model();
assert!(model.mark_seats().is_empty(), "nothing selected, no seats");
model.focus_agent(&h.ws, "c-1");
assert_eq!(
model
.mark_seats()
.iter()
.map(|s| s.doing)
.collect::<Vec<_>>(),
vec![crate::nav::convs::Doing::Idle],
"a settled conversation seats its root, idle"
);
let mut streaming = agent("c-1", AgentState::InFlight);
streaming.stream.last_delta = Some(crate::git_tree::Delta::Thinking);
let mut kid = agent("c-1-20260427T120100Z-bbbb", AgentState::Live);
kid.tool_calls = vec![crate::git_tree::ToolCall {
tool_id: "toolu_1".into(),
name: Some("Bash".into()),
start_unix: None,
state: crate::git_tree::ToolCallState::InFlight,
}];
model.deriver.trees.get_mut(&h.ws).unwrap().agents = vec![streaming, kid];
model.publish();
assert_eq!(
model
.mark_seats()
.iter()
.map(|s| s.doing)
.collect::<Vec<_>>(),
vec![
crate::nav::convs::Doing::Thinking,
crate::nav::convs::Doing::Tools
]
);
model.focus_agent(&h.ws, "ghost");
assert!(model.mark_seats().is_empty());
model.focus_agent(std::path::Path::new("/no/such"), "c-1");
assert!(model.mark_seats().is_empty());
}
#[test]
fn the_in_flight_strip_follows_the_focused_conversation() {
let now = 1_800_000_000;
let h = Harness::new();
let (_c, mut model) = h.model();
assert!(
model.flight_strip(now).is_none(),
"nothing selected, no strip"
);
model.focus_agent(&h.ws, "c-1");
assert!(model.flight_strip(now).is_none(), "at rest, no strip");
let mut streaming = agent("c-1", AgentState::InFlight);
streaming.goal_name = Some("stench-pug".into());
streaming.stream.text = Some("hi".into());
streaming.call_start_unix = Some(now - 42);
model.deriver.trees.get_mut(&h.ws).unwrap().agents = vec![streaming];
model.publish();
let strip = model.flight_strip(now).unwrap();
assert_eq!(strip.class, crate::nav::convs::Flight::Inference);
assert_eq!(strip.facts, "stench-pug · 2 chars streamed · 42s");
assert_eq!(
model.flight_strip(now + 18).unwrap().facts,
"stench-pug · 2 chars streamed · 1m"
);
model.focus_agent(&h.ws, "ghost");
assert!(model.flight_strip(now).is_none());
model.focus_agent(std::path::Path::new("/no/such"), "c-1");
assert!(model.flight_strip(now).is_none());
}