]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/windows/process/tests.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.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 }