rust/library/std/src/sys/windows/process/tests.rs

222 lines
7.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use super::make_command_line;
use super::Arg;
use crate::env;
use crate::ffi::{OsStr, OsString};
use crate::process::Command;
#[test]
fn test_raw_args() {
let command_line = &make_command_line(
OsStr::new("quoted exe"),
&[
Arg::Regular(OsString::from("quote me")),
Arg::Raw(OsString::from("quote me *not*")),
Arg::Raw(OsString::from("\t\\")),
Arg::Raw(OsString::from("internal \\\"backslash-\"quote")),
Arg::Regular(OsString::from("optional-quotes")),
],
false,
)
.unwrap();
assert_eq!(
String::from_utf16(command_line).unwrap(),
"\"quoted exe\" \"quote me\" quote me *not* \t\\ internal \\\"backslash-\"quote optional-quotes"
);
}
#[test]
fn test_thread_handle() {
use crate::os::windows::io::BorrowedHandle;
use crate::os::windows::process::{ChildExt, CommandExt};
const CREATE_SUSPENDED: u32 = 0x00000004;
let p = Command::new("cmd").args(&["/C", "exit 0"]).creation_flags(CREATE_SUSPENDED).spawn();
assert!(p.is_ok());
let mut p = p.unwrap();
extern "system" {
fn ResumeThread(_: BorrowedHandle<'_>) -> u32;
}
unsafe {
ResumeThread(p.main_thread_handle());
}
crate::thread::sleep(crate::time::Duration::from_millis(100));
let res = p.try_wait();
assert!(res.is_ok());
assert!(res.unwrap().is_some());
assert!(p.try_wait().unwrap().unwrap().success());
}
#[test]
fn test_make_command_line() {
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
let command_line = &make_command_line(
OsStr::new(prog),
&args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
force_quotes,
)
.unwrap();
String::from_utf16(command_line).unwrap()
}
assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
assert_eq!(test_wrapper("prog", &[r"C:\"], false), r#""prog" C:\"#);
assert_eq!(test_wrapper("prog", &[r"2slashes\\"], false), r#""prog" 2slashes\\"#);
assert_eq!(test_wrapper("prog", &[r" C:\"], false), r#""prog" " C:\\""#);
assert_eq!(test_wrapper("prog", &[r" 2slashes\\"], false), r#""prog" " 2slashes\\\\""#);
assert_eq!(
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
"\"C:\\Program Files\\blah\\blah.exe\" aaa"
);
assert_eq!(
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
"\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
);
assert_eq!(
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
"\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
);
assert_eq!(
test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
"\"C:\\Program Files\\test\" aa\\\"bb"
);
assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
assert_eq!(
test_wrapper("echo", &["\" \\\" \\", "\\"], false),
"\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
);
assert_eq!(
test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
"\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
);
}
// On Windows, environment args are case preserving but comparisons are case-insensitive.
// See: #85242
#[test]
fn windows_env_unicode_case() {
let test_cases = [
("ä", "Ä"),
("ß", "SS"),
("Ä", "Ö"),
("Ä", "Ö"),
("I", "İ"),
("I", "i"),
("I", "ı"),
("i", "I"),
("i", "İ"),
("i", "ı"),
("İ", "I"),
("İ", "i"),
("İ", "ı"),
("ı", "I"),
("ı", "i"),
("ı", "İ"),
("ä", "Ä"),
("ß", "SS"),
("Ä", "Ö"),
("Ä", "Ö"),
("I", "İ"),
("I", "i"),
("I", "ı"),
("i", "I"),
("i", "İ"),
("i", "ı"),
("İ", "I"),
("İ", "i"),
("İ", "ı"),
("ı", "I"),
("ı", "i"),
("ı", "İ"),
];
// Test that `cmd.env` matches `env::set_var` when setting two strings that
// may (or may not) be case-folded when compared.
for (a, b) in test_cases.iter() {
let mut cmd = Command::new("cmd");
cmd.env(a, "1");
cmd.env(b, "2");
env::set_var(a, "1");
env::set_var(b, "2");
for (key, value) in cmd.get_envs() {
assert_eq!(
env::var(key).ok(),
value.map(|s| s.to_string_lossy().into_owned()),
"command environment mismatch: {a} {b}",
);
}
}
}
// UWP applications run in a restricted environment which means this test may not work.
#[cfg(not(target_vendor = "uwp"))]
#[test]
fn windows_exe_resolver() {
use super::resolve_exe;
use crate::io;
use crate::sys::fs::symlink;
use crate::sys_common::io::test::tmpdir;
let env_paths = || env::var_os("PATH");
// Test a full path, with and without the `exe` extension.
let mut current_exe = env::current_exe().unwrap();
assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
current_exe.set_extension("");
assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
// Test lone file names.
assert!(resolve_exe(OsStr::new("cmd"), env_paths, None).is_ok());
assert!(resolve_exe(OsStr::new("cmd.exe"), env_paths, None).is_ok());
assert!(resolve_exe(OsStr::new("cmd.EXE"), env_paths, None).is_ok());
assert!(resolve_exe(OsStr::new("fc"), env_paths, None).is_ok());
// Invalid file names should return InvalidInput.
assert_eq!(
resolve_exe(OsStr::new(""), env_paths, None).unwrap_err().kind(),
io::ErrorKind::InvalidInput
);
assert_eq!(
resolve_exe(OsStr::new("\0"), env_paths, None).unwrap_err().kind(),
io::ErrorKind::InvalidInput
);
// Trailing slash, therefore there's no file name component.
assert_eq!(
resolve_exe(OsStr::new(r"C:\Path\to\"), env_paths, None).unwrap_err().kind(),
io::ErrorKind::InvalidInput
);
/*
Some of the following tests may need to be changed if you are deliberately
changing the behaviour of `resolve_exe`.
*/
let empty_paths = || None;
// The resolver looks in system directories even when `PATH` is empty.
assert!(resolve_exe(OsStr::new("cmd.exe"), empty_paths, None).is_ok());
// The application's directory is also searched.
let current_exe = env::current_exe().unwrap();
assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
// Create a temporary path and add a broken symlink.
let temp = tmpdir();
let mut exe_path = temp.path().to_owned();
exe_path.push("exists.exe");
// A broken symlink should still be resolved.
// Skip this check if not in CI and creating symlinks isn't possible.
let is_ci = env::var("CI").is_ok();
let result = symlink("<DOES NOT EXIST>".as_ref(), &exe_path);
if is_ci || result.is_ok() {
result.unwrap();
assert!(
resolve_exe(OsStr::new("exists.exe"), empty_paths, Some(temp.path().as_ref())).is_ok()
);
}
}