use std::process::Command;
const MISSING_SOCKET: &str = "/tmp/sysknife-doctor-output-test-a41c/daemon.sock";
fn run_doctor(socket: &str) -> (String, Option<i32>) {
let out = Command::new(env!("CARGO_BIN_EXE_sysknife"))
.arg("doctor")
.env("SYSKNIFE_SOCKET", socket)
.env("ANTHROPIC_API_KEY", "sk-ant-test-not-used")
.output()
.expect("the sysknife binary runs");
(
String::from_utf8_lossy(&out.stderr).to_string(),
out.status.code(),
)
}
#[test]
fn names_the_socket_it_tried() {
let (stderr, code) = run_doctor(MISSING_SOCKET);
assert!(
stderr.contains(MISSING_SOCKET),
"the socket must appear, got:\n{stderr}"
);
assert_eq!(code, Some(4), "daemon/config failures exit 4");
}
#[test]
fn offers_a_command_to_run_next() {
let (stderr, _) = run_doctor(MISSING_SOCKET);
assert!(
stderr.contains("systemctl"),
"a next step must be offered, got:\n{stderr}"
);
}
#[test]
fn reports_the_failure_once_not_twice() {
let (stderr, _) = run_doctor(MISSING_SOCKET);
let mentions = stderr.matches(MISSING_SOCKET).count();
assert_eq!(
mentions, 1,
"the socket should be named exactly once; a second copy means the \
report and the top-level handler both printed it:\n{stderr}"
);
assert!(
!stderr.contains("subcommand exit code"),
"internal plumbing must not leak into user output:\n{stderr}"
);
}
#[test]
fn does_not_print_rust_debug_formatting_at_the_user() {
let (stderr, _) = run_doctor(MISSING_SOCKET);
assert!(
!stderr.contains("Unix("),
"sockets must render as URIs, not Debug:\n{stderr}"
);
}