use crate::brain::agent::AgentError;
use crate::channels::background_work::{FlowOutcome, outcome_for_error};
use crate::channels::discord::tool_group::{GroupEntry, GroupState, SettledStatus, render_content};
use std::time::{Duration, Instant};
fn settled(outcome: Option<FlowOutcome>, waiting: Option<&str>) -> GroupState {
GroupState {
page: 0,
entries: vec![
GroupEntry {
call_id: String::new(),
name: "bash".into(),
context: String::new(),
status: Some(true),
},
GroupEntry {
call_id: String::new(),
name: "read_file".into(),
context: String::new(),
status: Some(true),
},
],
notes: vec![],
expanded: false,
started_at: Instant::now(),
settled: Some(SettledStatus {
elapsed: Duration::from_secs(42),
ctx: None,
waiting: waiting.map(|s| s.to_string()),
outcome,
}),
}
}
#[test]
fn a_timed_out_turn_reads_timed_out_and_not_a_cross() {
let line = render_content(&settled(Some(FlowOutcome::TimedOut), None));
assert!(line.contains("⏱ Timed out"), "got: {line}");
assert!(!line.contains('❌'), "a timeout is not a crash: {line}");
assert!(!line.contains('🕒'), "the live clock must be gone: {line}");
}
#[test]
fn a_failed_turn_reads_failed() {
let line = render_content(&settled(Some(FlowOutcome::Failed), None));
assert!(line.contains("❌ Failed"), "got: {line}");
assert!(
!line.contains('✅'),
"a failed turn cannot claim success: {line}"
);
}
#[test]
fn a_cancelled_turn_reads_cancelled() {
let line = render_content(&settled(Some(FlowOutcome::Cancelled), None));
assert!(line.contains("❌ Cancelled"), "got: {line}");
}
#[test]
fn a_normal_settle_keeps_the_plain_counts_chrome() {
let line = render_content(&settled(None, None));
assert!(line.contains("✅ **2 tool calls**"), "got: {line}");
}
#[test]
fn waiting_outranks_a_terminal_outcome() {
let line = render_content(&settled(
Some(FlowOutcome::TimedOut),
Some("waiting for 1 background task"),
));
assert!(
line.contains("⏳ waiting for 1 background task"),
"got: {line}"
);
assert!(!line.contains("Timed out"), "got: {line}");
}
#[test]
fn the_verb_vocabulary_is_pinned_for_both_channels() {
assert_eq!(FlowOutcome::Finished.icon_verb(), ("✅", "Finished"));
assert_eq!(FlowOutcome::Failed.icon_verb(), ("❌", "Failed"));
assert_eq!(FlowOutcome::TimedOut.icon_verb(), ("⏱", "Timed out"));
assert_eq!(FlowOutcome::Cancelled.icon_verb(), ("❌", "Cancelled"));
}
#[test]
fn timeout_wording_classifies_as_timed_out() {
for text in [
"request timed out after 300s",
"thinking-loop timeout after 600s",
"deadline exceeded",
] {
let err = AgentError::ToolError(text.into());
assert_eq!(
outcome_for_error(&err),
FlowOutcome::TimedOut,
"misclassified: {text}"
);
}
}
#[test]
fn any_other_error_classifies_as_failed() {
let err = AgentError::Internal("provider returned 500".into());
assert_eq!(outcome_for_error(&err), FlowOutcome::Failed);
}