#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::{NO_MCP, compose, note_skipped, skipped_hooks, skipped_mcp};
use crate::agents::BackendState::{self, Absent, Disabled, Healthy, NeedsRepair};
use crate::components::{HookBinding, McpKind, McpServer};
use crate::doctor::{CheckStatus, DoctorCheck};
fn tag(state: BackendState) -> &'static str {
match state {
Absent => "absent",
Healthy => "healthy",
Disabled => "disabled",
NeedsRepair => "needs_repair",
}
}
fn composed(states: impl IntoIterator<Item = BackendState>) -> &'static str {
tag(compose(states))
}
#[test]
fn empty_is_healthy_so_a_surfaceless_backend_keeps_its_marker() {
assert_eq!(composed([]), "healthy");
}
#[test]
fn single_surface_is_identity() {
assert_eq!(composed([Healthy]), "healthy");
assert_eq!(composed([Absent]), "absent");
assert_eq!(composed([Disabled]), "disabled");
assert_eq!(composed([NeedsRepair]), "needs_repair");
}
#[test]
fn any_disabled_freezes_the_backend() {
assert_eq!(composed([Disabled, Healthy]), "disabled");
assert_eq!(composed([Healthy, Disabled]), "disabled");
assert_eq!(composed([Disabled, NeedsRepair]), "disabled");
assert_eq!(composed([Disabled, Absent]), "disabled");
}
#[test]
fn all_absent_is_absent_so_a_gone_plugin_is_never_resurrected() {
assert_eq!(composed([Absent, Absent]), "absent");
assert_eq!(composed([Absent, Absent, Absent]), "absent");
}
#[test]
fn partial_absent_is_needs_repair() {
assert_eq!(composed([Healthy, Absent]), "needs_repair");
assert_eq!(composed([Absent, Healthy]), "needs_repair");
assert_eq!(composed([Healthy, Healthy, Absent]), "needs_repair");
}
#[test]
fn any_needs_repair_wins_over_healthy() {
assert_eq!(composed([NeedsRepair, Healthy]), "needs_repair");
assert_eq!(composed([Healthy, NeedsRepair]), "needs_repair");
}
#[test]
fn all_healthy_is_healthy() {
assert_eq!(composed([Healthy, Healthy, Healthy]), "healthy");
}
fn stdio(name: &str, command: &str) -> McpServer {
McpServer { name: name.into(), kind: McpKind::Stdio, command: command.into(), args: vec![], env: Default::default() }
}
fn hook(event: &str, command: &str) -> HookBinding {
HookBinding { event: event.into(), matcher: None, command: command.into() }
}
fn ok(detail: &str) -> DoctorCheck {
DoctorCheck { name: "mcp server registered", status: CheckStatus::Ok(detail.into()) }
}
fn detail(check: &DoctorCheck) -> String {
match &check.status {
CheckStatus::Ok(d) => format!("ok: {d}"),
CheckStatus::Warn(d) => format!("warn: {d}"),
CheckStatus::Fail { problem, .. } => format!("fail: {problem}"),
}
}
#[test]
fn nothing_dropped_leaves_the_check_untouched() {
assert_eq!(detail(¬e_skipped(ok("ez registered"), &[])), "ok: ez registered");
assert_eq!(detail(¬e_skipped(ok(NO_MCP), &[])), "ok: no portable mcp servers to register");
}
#[test]
fn every_entry_dropped_warns_instead_of_reading_ok() {
let servers = [stdio("ez", "${CLAUDE_PLUGIN_ROOT}/bin/ez"), stdio("fx", "${CLAUDE_PLUGIN_ROOT}/bin/fx")];
let skipped = skipped_mcp(&servers, &[]);
assert_eq!(
detail(¬e_skipped(ok(NO_MCP), &skipped)),
"warn: no portable mcp servers to register; skipped ez, fx: ${CLAUDE_PLUGIN_ROOT} expands only inside Claude Code (use a bare command name)"
);
}
#[test]
fn a_partial_drop_warns_and_still_names_what_survived() {
let servers = [stdio("ez", "ez"), stdio("fx", "${CLAUDE_PLUGIN_ROOT}/bin/fx")];
let skipped = skipped_mcp(&servers, &["ez"]);
assert_eq!(
detail(¬e_skipped(ok("ez registered"), &skipped)),
"warn: ez registered; skipped fx: ${CLAUDE_PLUGIN_ROOT} expands only inside Claude Code (use a bare command name)"
);
}
#[test]
fn a_real_failure_outranks_the_note() {
let servers = [stdio("ez", "ez"), stdio("fx", "${CLAUDE_PLUGIN_ROOT}/bin/fx")];
let skipped = skipped_mcp(&servers, &["ez"]);
let failing = DoctorCheck {
name: "mcp server registered",
status: CheckStatus::Fail { problem: "mcp server(s) not in mcp.json: ez".into(), fix: "run setup".into() },
};
assert_eq!(detail(¬e_skipped(failing, &skipped)), "fail: mcp server(s) not in mcp.json: ez");
}
#[test]
fn a_portable_entry_the_backend_cannot_render_reports_the_transport_reason() {
let servers =
[stdio("ez", "ez"), McpServer { name: "rm".into(), kind: McpKind::Sse { url: "https://x/sse".into() }, ..stdio("rm", "") }];
let skipped = skipped_mcp(&servers, &["ez"]);
assert_eq!(
detail(¬e_skipped(ok("ez registered"), &skipped)),
"warn: ez registered; skipped rm: this harness cannot host that transport"
);
}
#[test]
fn both_reasons_group_separately() {
let servers = [
stdio("np", "${CLAUDE_PLUGIN_ROOT}/bin/np"),
McpServer { name: "rm".into(), kind: McpKind::Sse { url: "https://x/sse".into() }, ..stdio("rm", "") },
];
let skipped = skipped_mcp(&servers, &[]);
assert_eq!(
detail(¬e_skipped(ok(NO_MCP), &skipped)),
"warn: no portable mcp servers to register; skipped np: ${CLAUDE_PLUGIN_ROOT} expands only inside Claude Code (use a bare command name); \
skipped rm: this harness cannot host that transport"
);
}
#[test]
fn only_a_non_portable_hook_is_named_never_an_unmappable_event() {
let hooks = [hook("SessionStart", "mytool self-heal"), hook("Stop", "${CLAUDE_PLUGIN_ROOT}/bin/mytool stop")];
let skipped = skipped_hooks(&hooks);
assert_eq!(skipped.len(), 1, "the portable hook must not be reported as dropped");
assert_eq!(
detail(¬e_skipped(ok("1 hook(s) present in hooks.json"), &skipped)),
"warn: 1 hook(s) present in hooks.json; skipped Stop: ${CLAUDE_PLUGIN_ROOT} expands only inside Claude Code (use a bare command name)"
);
}
#[test]
fn the_shared_mcp_check_wires_the_note_in() {
let servers = [stdio("ez", "${CLAUDE_PLUGIN_ROOT}/bin/ez")];
let check = super::check_mcp_registered(&servers, None, &["mcpServers"], "not in mcp.json", "run setup");
assert_eq!(
detail(&check),
"warn: no portable mcp servers to register; skipped ez: ${CLAUDE_PLUGIN_ROOT} expands only inside Claude Code (use a bare command name)"
);
}