Files
codex/codex-rs/windows-sandbox-rs/src/command_resolution_tests.rs
T

148 lines
5.0 KiB
Rust

use super::resolve_windows_executable;
use super::resolve_windows_launch;
use crate::process::ResolvedWindowsProcessLaunch;
use pretty_assertions::assert_eq;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;
#[test]
fn resolves_with_case_insensitive_child_path_and_pathext() {
let temp = TempDir::new().expect("tempdir");
let cwd = temp.path().join("cwd");
let tools = temp.path().join("tools");
fs::create_dir_all(&cwd).expect("create cwd");
fs::create_dir_all(&tools).expect("create tools");
let executable = tools.join("child-only.BIN");
fs::write(&executable, b"fixture").expect("write executable fixture");
let env = HashMap::from([
("Path".to_string(), tools.to_string_lossy().into_owned()),
("PathExt".to_string(), ".BIN".to_string()),
]);
let launch = resolve_windows_launch(
vec!["child-only".to_string(), "argument".to_string()],
&cwd,
&env,
)
.expect("resolve from child environment");
assert_eq!(
launch,
ResolvedWindowsProcessLaunch {
application_path: executable,
command: vec!["child-only".to_string(), "argument".to_string()],
}
);
}
#[test]
fn requested_cwd_precedes_child_path() {
let temp = TempDir::new().expect("tempdir");
let cwd = temp.path().join("cwd");
let tools = temp.path().join("tools");
fs::create_dir_all(&cwd).expect("create cwd");
fs::create_dir_all(&tools).expect("create tools");
let cwd_executable = cwd.join("tool.EXE");
fs::write(&cwd_executable, b"cwd").expect("write cwd fixture");
fs::write(tools.join("tool.EXE"), b"path").expect("write PATH fixture");
let env = HashMap::from([("PATH".to_string(), tools.to_string_lossy().into_owned())]);
assert_eq!(
resolve_windows_executable(&["tool".to_string()], &cwd, &env).expect("resolve executable"),
cwd_executable
);
}
#[test]
fn keeps_long_and_lexical_paths_unchanged() {
let temp = TempDir::new().expect("tempdir");
let mut cwd = temp.path().to_path_buf();
while cwd.to_string_lossy().len() <= 270 {
cwd.push("long-working-directory-segment");
}
fs::create_dir_all(cwd.join("nested")).expect("create long cwd");
let executable = cwd.join("tool.EXE");
fs::write(&executable, b"fixture").expect("write executable fixture");
let lexical = cwd.join("nested").join("..").join("tool.EXE");
assert_eq!(
resolve_windows_executable(
&[lexical.to_string_lossy().into_owned()],
&cwd,
&HashMap::new(),
)
.expect("resolve long lexical executable"),
lexical
);
}
#[test]
fn keeps_extended_length_paths_unchanged() {
let executable = dunce::canonicalize(std::env::current_exe().expect("current executable"))
.expect("canonical current executable");
let executable_text = executable.to_string_lossy();
let extended = if executable_text.starts_with(r"\\?\") {
executable
} else if let Some(unc) = executable_text.strip_prefix(r"\\") {
PathBuf::from(format!(r"\\?\UNC\{unc}"))
} else {
PathBuf::from(format!(r"\\?\{executable_text}"))
};
let cwd = std::env::current_dir().expect("current dir");
assert_eq!(
resolve_windows_executable(
&[extended.to_string_lossy().into_owned()],
&cwd,
&HashMap::new(),
)
.expect("resolve extended-length executable"),
extended
);
}
#[test]
fn does_not_fall_back_to_the_parent_path() {
let temp = TempDir::new().expect("tempdir");
let cwd = temp.path();
let env = HashMap::from([
("PATH".to_string(), String::new()),
("PATHEXT".to_string(), ".EXE".to_string()),
]);
let err = resolve_windows_executable(&["cmd".to_string()], cwd, &env)
.expect_err("parent PATH must not be consulted");
assert!(err.to_string().contains("child PATH and PATHEXT"));
}
#[test]
fn rejects_batch_files_instead_of_skipping_to_a_later_candidate() {
let temp = TempDir::new().expect("tempdir");
let cwd = temp.path().join("cwd");
let first = temp.path().join("first");
let second = temp.path().join("second");
for directory in [&cwd, &first, &second] {
fs::create_dir_all(directory).expect("create directory");
}
fs::write(first.join("tool.CMD"), b"@exit /b 0\r\n").expect("write batch fixture");
fs::write(second.join("tool.EXE"), b"fixture").expect("write executable fixture");
let env = HashMap::from([
(
"PATH".to_string(),
std::env::join_paths([first, second])
.expect("join PATH")
.to_string_lossy()
.into_owned(),
),
("PATHEXT".to_string(), ".CMD;.EXE".to_string()),
]);
let err = resolve_windows_executable(&["tool".to_string()], &cwd, &env)
.expect_err("batch candidate should fail closed");
assert!(err.to_string().contains("must be launched through cmd.exe"));
}