use super::*;
use std::os::unix::fs::PermissionsExt;
fn fake_binary(dir: &Path, body: &str) -> String {
let path = dir.join("probe");
fs::write(&path, format!("#!/bin/sh\n{body}\n")).expect("write probe");
fs::set_permissions(&path, fs::Permissions::from_mode(0o755)).expect("executable probe");
path.to_str().expect("probe path").to_string()
}
#[test]
fn timeout_returns_promptly_and_reaps_the_probe_pid() {
let dir = tempfile::tempdir().expect("tempdir");
let pid_file = dir.path().join("pid");
let binary = fake_binary(dir.path(), "echo $$ > \"$1\"; exec sleep 60");
let timeout = Duration::from_millis(200);
let start = Instant::now();
let error = run_bounded(&binary, &[pid_file.to_str().expect("pid path")], timeout)
.expect_err("sleeping probe must time out");
let elapsed = start.elapsed();
assert!(error.to_string().contains("timed out"));
assert!(elapsed >= timeout && elapsed < timeout + Duration::from_secs(1), "{elapsed:?}");
let pid: i32 = fs::read_to_string(pid_file).expect("probe started").trim().parse().expect("pid");
assert_eq!(unsafe { libc::kill(pid, 0) }, -1, "probe pid still exists");
assert_eq!(std::io::Error::last_os_error().raw_os_error(), Some(libc::ESRCH));
let mut status = 0;
assert_eq!(unsafe { libc::waitpid(pid, &mut status, libc::WNOHANG) }, -1);
assert_eq!(std::io::Error::last_os_error().raw_os_error(), Some(libc::ECHILD));
}
#[test]
fn oversized_help_drains_both_pipes_and_preserves_success() {
let dir = tempfile::tempdir().expect("tempdir");
let binary = fake_binary(dir.path(),
"printf 'Cursor Agent\\n'; i=0; while [ $i -lt 8192 ]; do printf '0123456789abcdef'; printf 'fedcba9876543210' >&2; i=$((i + 1)); done");
let start = Instant::now();
let output = run_bounded(&binary, &["--help"], Duration::from_secs(2)).expect("large help");
assert!(output.success);
assert!(start.elapsed() < Duration::from_secs(2));
assert_eq!(output.stdout.len(), 64 * 1024);
assert_eq!(output.stderr.len(), 64 * 1024);
assert!(output.stdout.starts_with("Cursor Agent\n"));
assert!(output.stderr.starts_with("fedcba9876543210"));
assert!(binary_identity_matches(&binary, &["cursor agent"]));
}
#[test]
fn identity_timeout_is_bounded_and_reaps_the_probe() {
let dir = tempfile::tempdir().expect("tempdir");
let binary = fake_binary(dir.path(), "echo $$ > \"$0.pid\"; exec sleep 60");
let start = Instant::now();
assert!(!binary_identity_matches(&binary, &["cursor agent"]));
assert!(start.elapsed() < Duration::from_millis(1500));
let pid: i32 = fs::read_to_string(format!("{binary}.pid"))
.expect("probe started").trim().parse().expect("pid");
assert_eq!(unsafe { libc::kill(pid, 0) }, -1);
assert_eq!(std::io::Error::last_os_error().raw_os_error(), Some(libc::ESRCH));
}
#[test]
fn nonzero_exit_preserves_output_but_is_not_a_model_or_identity_match() {
let dir = tempfile::tempdir().expect("tempdir");
let binary = fake_binary(dir.path(), "echo 'Cursor Agent'; echo 'failure' >&2; exit 7");
let output = run_bounded(&binary, &[], Duration::from_secs(1)).expect("exit output");
assert!(!output.success);
assert_eq!(output.stdout, "Cursor Agent\n");
assert_eq!(output.stderr, "failure\n");
assert!(crate::agent::model_validation::run_probe_cmd(&binary, &["models"]).is_none());
assert!(!binary_identity_matches(&binary, &["cursor agent"]));
}
#[test]
fn missing_probe_is_an_error_and_model_probe_is_unavailable() {
let dir = tempfile::tempdir().expect("tempdir");
let binary = dir.path().join("missing");
let binary = binary.to_str().expect("probe path");
assert!(run_bounded(binary, &[], Duration::from_secs(1)).is_err());
assert!(crate::agent::model_validation::run_probe_cmd(binary, &[]).is_none());
}
#[test]
fn flag_definitions_exclude_prefixes_and_prose() {
for suffix in ["", " value", "\tvalue", "=value", ", -m"] {
assert!(help_defines_flag(&format!(" --model{suffix}"), "--model"));
}
assert!(!help_defines_flag(" --model-fallback value\nUse --model to select", "--model"));
}