use super::*;
use std::sync::Arc;
use crate::client::{
CommandExecutor, FocusOutcome, FocusTarget, InjectOutcome, SessionProxy, SummarizeOutcome,
};
fn offline_proxy() -> SessionProxy {
SessionProxy::new(Arc::new(CommandExecutor::new("http://127.0.0.1:0")))
}
fn target() -> FocusTarget {
FocusTarget {
id: "aaaa1111bbbb2222".into(),
name: "tmpm-api".into(),
}
}
#[test]
fn render_focus_focused_names_session() {
let html = render_focus(&FocusOutcome::Focused(target()));
assert!(html.contains("Focused on <b>tmpm-api</b>"), "{html}");
assert!(html.contains("/unfocus"), "{html}");
}
#[test]
fn render_focus_current_none_hints_usage() {
let html = render_focus(&FocusOutcome::Current(None));
assert!(html.contains("Usage"), "{html}");
}
#[test]
fn render_focus_not_found_escapes_and_reports() {
let html = render_focus(&FocusOutcome::NotFound {
target: "no-such".into(),
error: "managed session no-such not found".into(),
});
assert!(html.contains("Cannot focus"), "{html}");
assert!(html.contains("no-such"), "{html}");
}
#[test]
fn render_inject_sent_echoes_text() {
let html = render_inject(&InjectOutcome::Sent {
target: target(),
text: "run the tests".into(),
});
assert!(html.contains("tmpm-api"), "{html}");
assert!(html.contains("run the tests"), "{html}");
}
#[test]
fn render_inject_auto_unfocused_signals_gone() {
let html = render_inject(&InjectOutcome::AutoUnfocused {
target: target(),
error: "managed session x not found".into(),
});
assert!(html.contains("gone"), "{html}");
assert!(html.contains("tmpm-api"), "{html}");
}
#[test]
fn render_inject_failed_keeps_focus_prose() {
let html = render_inject(&InjectOutcome::Failed {
target: target(),
error: "connection refused".into(),
});
assert!(html.contains("failed"), "{html}");
assert!(html.contains("Still focused"), "{html}");
}
#[test]
fn render_inject_no_focus_hints() {
let html = render_inject(&InjectOutcome::NoFocus);
assert!(html.contains("No session is focused"), "{html}");
}
#[test]
fn render_summary_ok_shows_state_and_pending() {
let html = render_summary(&SummarizeOutcome::Summary {
target: target(),
state: "active".into(),
summary: "running cargo test".into(),
pending_decision: Some("apply patch?".into()),
});
assert!(html.contains("tmpm-api"), "{html}");
assert!(html.contains("active"), "{html}");
assert!(html.contains("running cargo test"), "{html}");
assert!(html.contains("pending: apply patch?"), "{html}");
}
#[test]
fn render_summary_no_focus_hints() {
let html = render_summary(&SummarizeOutcome::NoFocus);
assert!(html.contains("No session is focused"), "{html}");
}
#[test]
fn truncate_summary_leaves_short_text_untouched() {
let short = "running cargo test, all green";
assert_eq!(truncate_summary(short).as_ref(), short);
}
#[test]
fn truncate_summary_caps_long_text() {
let long: String = "x".repeat(MAX_SUMMARY_CHARS * 3);
let truncated = truncate_summary(&long);
assert!(
truncated.chars().count() <= MAX_SUMMARY_CHARS + " […truncated]".chars().count(),
"truncated length {} exceeds budget",
truncated.chars().count()
);
assert!(truncated.ends_with("[…truncated]"), "{truncated}");
}
#[test]
fn render_summary_caps_pathologically_long_digest() {
let mut ft = target();
ft.name = "tmpm-api".into();
let long_summary = "z".repeat(50_000);
let html = render_summary(&SummarizeOutcome::Summary {
target: ft,
state: "active".into(),
summary: long_summary,
pending_decision: None,
});
assert!(
html.len() < 4096,
"rendered summary reply must stay under Telegram's 4096-char body limit, got {}",
html.len()
);
}
#[tokio::test]
async fn handle_unfocus_when_none() {
let proxy = offline_proxy();
assert!(handle_unfocus(&proxy, 1).contains("No session was focused"));
}
#[tokio::test]
async fn handle_focus_empty_hints() {
let proxy = offline_proxy();
let html = handle_focus(&proxy, 1, " ").await;
assert!(html.contains("Usage"), "{html}");
}