Files
EasyCLIProxyAPI/src-tauri/src/tests/agent_paths.rs
T
lzt404 d7e39e8fdc Add Oh My Pi support through the OpenAI Responses API
Discover CPA models dynamically and route the managed provider to /v1/responses.
2026-10-08 18:36:58 +08:00

314 lines
9.9 KiB
Rust

use super::support::*;
use super::*;
#[test]
fn installation_detection_separates_executables_from_version_metadata() {
for client in [
AgentClient::ClaudeCode,
AgentClient::Codex,
AgentClient::OpenCode,
AgentClient::OpenClaw,
AgentClient::Hermes,
AgentClient::DeepSeekHarness,
AgentClient::KimiCode,
AgentClient::GrokBuild,
AgentClient::Omp,
] {
assert!(agent_installation_detected(client, None, true, false));
assert!(!agent_installation_detected(client, None, false, false));
assert!(!agent_installation_detected(
client,
Some("1.0.0"),
false,
false
));
}
assert!(agent_installation_detected(
AgentClient::Codex,
None,
false,
true
));
assert!(agent_installation_detected(
AgentClient::ClaudeDesktop,
Some("1.0.0"),
false,
false,
));
}
#[test]
fn executable_directories_preserve_path_precedence_and_package_manager_locations() {
let home = agent_test_home("agent-search-environment");
let inherited = home.join("inherited");
let registered = home.join("registered");
let npm = home.join("custom-npm");
let uv = home.join("custom-uv");
let volta = home.join("custom-volta");
let directories = agent_executable_directories_from_environment(
&home,
|name| match name {
"PATH" => Some(env::join_paths([&inherited, &inherited]).unwrap()),
"NPM_CONFIG_PREFIX" => Some(npm.clone().into_os_string()),
"UV_TOOL_BIN_DIR" => Some(uv.clone().into_os_string()),
"VOLTA_HOME" => Some(volta.clone().into_os_string()),
"BUN_INSTALL" => Some(std::ffi::OsString::new()),
_ => None,
},
&[registered.clone(), inherited.clone()],
);
assert_eq!(&directories[..2], &[inherited.clone(), registered]);
assert_eq!(
directories
.iter()
.filter(|path| **path == inherited)
.count(),
1
);
let npm_bin = if cfg!(target_os = "windows") {
npm
} else {
npm.join("bin")
};
assert!(directories.contains(&npm_bin));
assert!(directories.contains(&uv));
assert!(directories.contains(&volta.join("bin")));
assert!(directories.iter().all(|path| path.is_absolute()));
fs::remove_dir_all(home).unwrap();
}
#[cfg(target_os = "windows")]
#[test]
fn windows_cli_search_skips_shell_stubs_and_finds_runnable_shims() {
let home = agent_test_home("agent-search-shims");
let first = home.join("first");
let second = home.join("second");
fs::create_dir_all(first.join("agent.exe")).unwrap();
fs::create_dir_all(&second).unwrap();
fs::write(first.join("agent"), "shell stub").unwrap();
fs::write(first.join("agent.ps1"), "powershell stub").unwrap();
let executable = second.join("agent.cmd");
fs::write(&executable, "@exit /b 1\r\n").unwrap();
assert_eq!(
find_named_agent_executable_in_directories(&[first, second], &["agent"]),
Some(executable.clone()),
);
let version = read_agent_version(&executable, &home);
assert_eq!(version, None);
assert!(agent_installation_detected(
AgentClient::ClaudeCode,
version.as_deref(),
agent_cli_executable(&executable),
false,
));
fs::remove_dir_all(home).unwrap();
}
#[cfg(unix)]
#[test]
fn unix_cli_search_requires_executable_permissions() {
use std::os::unix::fs::PermissionsExt;
let home = agent_test_home("agent-search-permissions");
let executable = home.join("agent");
fs::write(&executable, "exit 1\n").unwrap();
fs::set_permissions(&executable, fs::Permissions::from_mode(0o644)).unwrap();
assert_eq!(
find_named_agent_executable_in_directories(&[home.clone()], &["agent"]),
None
);
fs::set_permissions(&executable, fs::Permissions::from_mode(0o755)).unwrap();
assert_eq!(
find_named_agent_executable_in_directories(&[home.clone()], &["agent"]),
Some(executable)
);
fs::remove_dir_all(home).unwrap();
}
#[test]
fn configuration_paths_ignore_inherited_environment() {
let home = agent_test_home("isolated-paths");
for client in [
"claude-code",
"claude-desktop",
"codex",
"opencode",
"openclaw",
"hermes",
"deepseek-harness",
"zcode",
"workbuddy",
"antigravity-cli",
"kimi-code",
"grok-build",
"pi",
] {
let paths = config_paths(client, &home).unwrap();
assert!(!paths.is_empty(), "{client}");
assert!(
paths.iter().all(|path| path.starts_with(&home)),
"{client}: {paths:?}"
);
}
if env::var_os("CPA_PATH_ISOLATION_CHILD").is_none() {
let outside = home.join("inherited-environment");
let mut command = Command::new(env::current_exe().unwrap());
command.args([
"--exact",
"tests::agent_paths::configuration_paths_ignore_inherited_environment",
"--nocapture",
]);
command.env("CPA_PATH_ISOLATION_CHILD", "1");
for variable in [
"LOCALAPPDATA",
"APPDATA",
"XDG_CONFIG_HOME",
"CODEX_HOME",
"HERMES_HOME",
"OPENCODE_CONFIG",
"KIMI_CODE_HOME",
"GROK_HOME",
"DSH_HOME",
"WORKBUDDY_CONFIG_DIR",
"CODEBUDDY_CONFIG_DIR",
"WORKBUDDY_INSTALL_DIR",
"PI_CODING_AGENT_DIR",
] {
command.env(variable, &outside);
}
configure_background_command(&mut command);
let output = command.output().unwrap();
assert!(
output.status.success(),
"{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
assert!(!outside.exists());
}
fs::remove_dir_all(home).unwrap();
}
#[test]
fn zcode_installation_does_not_require_version_metadata() {
assert!(agent_installation_detected(
AgentClient::ZCode,
None,
true,
false,
));
assert!(!agent_installation_detected(
AgentClient::ZCode,
None,
false,
false,
));
let targets = agent_launch_targets(
AgentClient::ZCode,
Some(Path::new("ZCode.exe")),
None,
false,
);
assert_eq!(targets.len(), 1);
assert_eq!(targets[0].id, "app");
}
#[cfg(target_os = "windows")]
#[test]
fn zcode_windows_finds_custom_installations_from_registered_paths() {
let home = agent_test_home("zcode-custom-installation");
let directory = home.join("自定义应用 [桌面]/ZCode's directory");
let executable = directory.join("ZCode.exe");
fs::create_dir_all(&directory).unwrap();
fs::write(&executable, []).unwrap();
let icon = directory.join("uninstallerIcon.ico");
let uninstaller = directory.join("Uninstall ZCode.exe");
for (kind, value) in [
("executable", path_to_string(&executable)),
("executable", format!("\"{}\"", executable.display())),
("directory", path_to_string(&directory)),
("icon", path_to_string(&icon)),
("icon", format!("{},0", executable.display())),
("icon", format!("\"{}\",-123", executable.display())),
(
"uninstaller",
format!("\"{}\" /currentuser", uninstaller.display()),
),
(
"uninstaller",
format!("{} /allusers", uninstaller.display()),
),
] {
assert_eq!(
parse_windows_zcode_registration(kind, &value),
Some(executable.clone()),
"kind={kind}, value={value}",
);
}
fs::remove_dir_all(home).unwrap();
}
#[cfg(target_os = "windows")]
#[test]
fn zcode_windows_display_name_matches_installer_variants() {
assert!(windows_display_name_matches_zcode("ZCode"));
assert!(windows_display_name_matches_zcode("ZCode (64-bit)"));
assert!(windows_display_name_matches_zcode("ZCode Desktop"));
assert!(!windows_display_name_matches_zcode("ZCodeHelper"));
assert!(!windows_display_name_matches_zcode("MyZCode"));
}
#[cfg(target_os = "windows")]
#[test]
fn zcode_windows_skips_stale_and_unrelated_registration_entries() {
let home = agent_test_home("zcode-stale-registration");
let unrelated = home.join("Uninstall ZCode.exe");
fs::write(&unrelated, []).unwrap();
let executable = home.join("valid/ZCode.exe");
fs::create_dir_all(executable.parent().unwrap()).unwrap();
fs::write(&executable, []).unwrap();
for (kind, value) in [
("directory", path_to_string(&home)),
("executable", path_to_string(&unrelated)),
(
"executable",
path_to_string(&home.join("missing/ZCode.exe")),
),
("executable", "ZCode.exe".to_string()),
("executable", "\"unterminated".to_string()),
("unknown", path_to_string(&executable)),
] {
assert_eq!(
parse_windows_zcode_registration(kind, &value),
None,
"kind={kind}, value={value}",
);
}
assert_eq!(
parse_windows_zcode_registration("executable", &path_to_string(&executable)),
Some(executable),
);
fs::remove_dir_all(home).unwrap();
}
#[cfg(target_os = "windows")]
#[test]
fn zcode_windows_version_discovery_does_not_launch_the_application() {
let home = agent_test_home("zcode-version-no-launch");
let executable = home.join("zcode.cmd");
let marker = home.join("launched.txt");
fs::write(
&executable,
format!(
"@echo off\r\necho launched > \"{}\"\r\necho 1.0.0\r\n",
marker.display()
),
)
.unwrap();
assert_eq!(read_zcode_app_version(&executable), None);
assert!(
!marker.exists(),
"version discovery launched the application"
);
fs::remove_dir_all(home).unwrap();
}