use std::fs;
#[test]
fn only_accepts_a_bare_agent_binary_that_identifies_as_cursor() {
let markers = crate::agent::env_identity::identity_markers("agent").unwrap();
let identifies = |help| crate::agent::env_identity::help_identifies(help, markers);
assert!(identifies("Usage: cursor-agent [OPTIONS]\n -p, --print Print response\n"));
assert!(identifies("Start the Cursor Agent\n\nUsage: agent [options]\n"));
assert!(!identifies("Grok Build TUI\n\nUsage: agent [OPTIONS] [PROMPT] [COMMAND]\n"));
assert!(!identifies(
"Usage: agent [OPTIONS] [PROMPT] [COMMAND]\n cursor-worker Register this machine as a \
Cursor private worker (via the leader)\n"
));
assert!(!identifies(""));
}
#[test]
fn resolve_cursor_binary_walks_path_with_stubbed_identity() {
use std::cell::RefCell;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
fn write_agent(dir: &Path, executable: bool) {
fs::create_dir_all(dir).unwrap();
let agent = dir.join("agent");
fs::write(&agent, "#!/bin/sh\nexit 0\n").unwrap();
let mode = if executable { 0o755 } else { 0o644 };
let mut perms = fs::metadata(&agent).unwrap().permissions();
perms.set_mode(mode);
fs::set_permissions(&agent, perms).unwrap();
}
let root = tempfile::tempdir().unwrap();
let decoy = root.path().join("decoy");
let cursor_a = root.path().join("cursor_a");
let cursor_b = root.path().join("cursor_b");
let nonexec = root.path().join("nonexec");
write_agent(&decoy, true);
write_agent(&cursor_a, true);
write_agent(&cursor_b, true);
write_agent(&nonexec, false);
let decoy_agent = decoy.join("agent").to_str().unwrap().to_owned();
let cursor_a_agent = cursor_a.join("agent").to_str().unwrap().to_owned();
let cursor_b_agent = cursor_b.join("agent").to_str().unwrap().to_owned();
let nonexec_agent = nonexec.join("agent").to_str().unwrap().to_owned();
let expected_decoy_then_cursor = cursor_b_agent.clone();
let expected_cursor_first = cursor_a_agent.clone();
let expected_no_cursor = "cursor-agent".to_owned();
let expected_skip_nonexec = cursor_a_agent.clone();
let cases = [
(
"decoy_then_cursor",
vec![decoy.clone(), cursor_b.clone()],
expected_decoy_then_cursor,
),
(
"cursor_first",
vec![cursor_a.clone(), decoy.clone()],
expected_cursor_first,
),
("no_cursor", vec![decoy.clone()], expected_no_cursor),
(
"skip_nonexec",
vec![nonexec.clone(), cursor_a.clone()],
expected_skip_nonexec,
),
];
for (name, dirs, expected) in cases {
let path = std::env::join_paths(dirs.iter()).unwrap();
let probed = RefCell::new(Vec::<String>::new());
let cursor_a_hit = cursor_a_agent.clone();
let cursor_b_hit = cursor_b_agent.clone();
let got = super::resolve_cursor_binary_from_path(Some(path), |candidate| {
probed.borrow_mut().push(candidate.to_owned());
candidate == cursor_a_hit || candidate == cursor_b_hit
});
assert_eq!(got, expected.as_str(), "case {name}");
assert!(
!probed.borrow().iter().any(|p| p == &nonexec_agent),
"case {name}: non-executable agent must not be probed"
);
if name == "decoy_then_cursor" {
assert_eq!(
probed.borrow().as_slice(),
&[decoy_agent.as_str(), cursor_b_agent.as_str()],
"case {name}: probe order"
);
}
}
}