]> git.proxmox.com Git - rustc.git/blob - library/std/src/sys/windows/process/tests.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / library / std / src / sys / windows / process / tests.rs
1 use super::make_command_line;
2 use super::Arg;
3 use crate::env;
4 use crate::ffi::{OsStr, OsString};
5 use crate::process::Command;
6
7 #[test]
8 fn test_raw_args() {
9 let command_line = &make_command_line(
10 OsStr::new("quoted exe"),
11 &[
12 Arg::Regular(OsString::from("quote me")),
13 Arg::Raw(OsString::from("quote me *not*")),
14 Arg::Raw(OsString::from("\t\\")),
15 Arg::Raw(OsString::from("internal \\\"backslash-\"quote")),
16 Arg::Regular(OsString::from("optional-quotes")),
17 ],
18 false,
19 )
20 .unwrap();
21 assert_eq!(
22 String::from_utf16(command_line).unwrap(),
23 "\"quoted exe\" \"quote me\" quote me *not* \t\\ internal \\\"backslash-\"quote optional-quotes"
24 );
25 }
26
27 #[test]
28 fn test_thread_handle() {
29 use crate::os::windows::io::BorrowedHandle;
30 use crate::os::windows::process::{ChildExt, CommandExt};
31 const CREATE_SUSPENDED: u32 = 0x00000004;
32
33 let p = Command::new("cmd").args(&["/C", "exit 0"]).creation_flags(CREATE_SUSPENDED).spawn();
34 assert!(p.is_ok());
35 let mut p = p.unwrap();
36
37 extern "system" {
38 fn ResumeThread(_: BorrowedHandle<'_>) -> u32;
39 }
40 unsafe {
41 ResumeThread(p.main_thread_handle());
42 }
43
44 crate::thread::sleep(crate::time::Duration::from_millis(100));
45
46 let res = p.try_wait();
47 assert!(res.is_ok());
48 assert!(res.unwrap().is_some());
49 assert!(p.try_wait().unwrap().unwrap().success());
50 }
51
52 #[test]
53 fn test_make_command_line() {
54 fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
55 let command_line = &make_command_line(
56 OsStr::new(prog),
57 &args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
58 force_quotes,
59 )
60 .unwrap();
61 String::from_utf16(command_line).unwrap()
62 }
63
64 assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
65
66 assert_eq!(test_wrapper("prog", &[r"C:\"], false), r#""prog" C:\"#);
67 assert_eq!(test_wrapper("prog", &[r"2slashes\\"], false), r#""prog" 2slashes\\"#);
68 assert_eq!(test_wrapper("prog", &[r" C:\"], false), r#""prog" " C:\\""#);
69 assert_eq!(test_wrapper("prog", &[r" 2slashes\\"], false), r#""prog" " 2slashes\\\\""#);
70
71 assert_eq!(
72 test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
73 "\"C:\\Program Files\\blah\\blah.exe\" aaa"
74 );
75 assert_eq!(
76 test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
77 "\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
78 );
79 assert_eq!(
80 test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
81 "\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
82 );
83 assert_eq!(
84 test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
85 "\"C:\\Program Files\\test\" aa\\\"bb"
86 );
87 assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
88 assert_eq!(
89 test_wrapper("echo", &["\" \\\" \\", "\\"], false),
90 "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
91 );
92 assert_eq!(
93 test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
94 "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
95 );
96 }
97
98 // On Windows, environment args are case preserving but comparisons are case-insensitive.
99 // See: #85242
100 #[test]
101 fn windows_env_unicode_case() {
102 let test_cases = [
103 ("ä", "Ä"),
104 ("ß", "SS"),
105 ("Ä", "Ö"),
106 ("Ä", "Ö"),
107 ("I", "İ"),
108 ("I", "i"),
109 ("I", "ı"),
110 ("i", "I"),
111 ("i", "İ"),
112 ("i", "ı"),
113 ("İ", "I"),
114 ("İ", "i"),
115 ("İ", "ı"),
116 ("ı", "I"),
117 ("ı", "i"),
118 ("ı", "İ"),
119 ("ä", "Ä"),
120 ("ß", "SS"),
121 ("Ä", "Ö"),
122 ("Ä", "Ö"),
123 ("I", "İ"),
124 ("I", "i"),
125 ("I", "ı"),
126 ("i", "I"),
127 ("i", "İ"),
128 ("i", "ı"),
129 ("İ", "I"),
130 ("İ", "i"),
131 ("İ", "ı"),
132 ("ı", "I"),
133 ("ı", "i"),
134 ("ı", "İ"),
135 ];
136 // Test that `cmd.env` matches `env::set_var` when setting two strings that
137 // may (or may not) be case-folded when compared.
138 for (a, b) in test_cases.iter() {
139 let mut cmd = Command::new("cmd");
140 cmd.env(a, "1");
141 cmd.env(b, "2");
142 env::set_var(a, "1");
143 env::set_var(b, "2");
144
145 for (key, value) in cmd.get_envs() {
146 assert_eq!(
147 env::var(key).ok(),
148 value.map(|s| s.to_string_lossy().into_owned()),
149 "command environment mismatch: {a} {b}",
150 );
151 }
152 }
153 }
154
155 // UWP applications run in a restricted environment which means this test may not work.
156 #[cfg(not(target_vendor = "uwp"))]
157 #[test]
158 fn windows_exe_resolver() {
159 use super::resolve_exe;
160 use crate::io;
161 use crate::sys::fs::symlink;
162 use crate::sys_common::io::test::tmpdir;
163
164 let env_paths = || env::var_os("PATH");
165
166 // Test a full path, with and without the `exe` extension.
167 let mut current_exe = env::current_exe().unwrap();
168 assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
169 current_exe.set_extension("");
170 assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
171
172 // Test lone file names.
173 assert!(resolve_exe(OsStr::new("cmd"), env_paths, None).is_ok());
174 assert!(resolve_exe(OsStr::new("cmd.exe"), env_paths, None).is_ok());
175 assert!(resolve_exe(OsStr::new("cmd.EXE"), env_paths, None).is_ok());
176 assert!(resolve_exe(OsStr::new("fc"), env_paths, None).is_ok());
177
178 // Invalid file names should return InvalidInput.
179 assert_eq!(
180 resolve_exe(OsStr::new(""), env_paths, None).unwrap_err().kind(),
181 io::ErrorKind::InvalidInput
182 );
183 assert_eq!(
184 resolve_exe(OsStr::new("\0"), env_paths, None).unwrap_err().kind(),
185 io::ErrorKind::InvalidInput
186 );
187 // Trailing slash, therefore there's no file name component.
188 assert_eq!(
189 resolve_exe(OsStr::new(r"C:\Path\to\"), env_paths, None).unwrap_err().kind(),
190 io::ErrorKind::InvalidInput
191 );
192
193 /*
194 Some of the following tests may need to be changed if you are deliberately
195 changing the behaviour of `resolve_exe`.
196 */
197
198 let empty_paths = || None;
199
200 // The resolver looks in system directories even when `PATH` is empty.
201 assert!(resolve_exe(OsStr::new("cmd.exe"), empty_paths, None).is_ok());
202
203 // The application's directory is also searched.
204 let current_exe = env::current_exe().unwrap();
205 assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
206
207 // Create a temporary path and add a broken symlink.
208 let temp = tmpdir();
209 let mut exe_path = temp.path().to_owned();
210 exe_path.push("exists.exe");
211
212 // A broken symlink should still be resolved.
213 // Skip this check if not in CI and creating symlinks isn't possible.
214 let is_ci = env::var("CI").is_ok();
215 let result = symlink("<DOES NOT EXIST>".as_ref(), &exe_path);
216 if is_ci || result.is_ok() {
217 result.unwrap();
218 assert!(
219 resolve_exe(OsStr::new("exists.exe"), empty_paths, Some(temp.path().as_ref())).is_ok()
220 );
221 }
222 }