1 /*
2 * PROJECT: ReactOS API tests
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: Test for cmd.exe
5 * COPYRIGHT: Copyright 2019 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8 #include "precomp.h"
9
10 #define TIMEOUT 3000
11
12 typedef struct TEST_ENTRY
13 {
14 INT line;
15 DWORD dwExitCode;
16 const char *cmdline;
17 BOOL bStdOutput;
18 BOOL bStdError;
19 const char *OutputContains;
20 const char *ErrorContains;
21 const char *OutputNotContains;
22 const char *ErrorNotContains;
23 } TEST_ENTRY;
24
25 static const TEST_ENTRY s_exit_entries[] =
26 {
27 { __LINE__, 0, "cmd /c exit" },
28 { __LINE__, 0, "cmd /c exit 0" },
29 { __LINE__, 0, "cmd /c exit \"\"" },
30 { __LINE__, 0, "cmd /c exit ABC" },
31 { __LINE__, 0, "cmd /c exit \"ABC" },
32 { __LINE__, 0, "cmd /c exit \"ABC\"" },
33 { __LINE__, 1234, "cmd /c exit 1234" },
34 };
35
36 static const TEST_ENTRY s_echo_entries[] =
37 {
38 // { __LINE__, 0, "cmd /c echo", TRUE, FALSE, NULL, "ECHO" },
39 { __LINE__, 0, "cmd /c echo.", TRUE, FALSE, "\r\n" },
40 { __LINE__, 0, "cmd /c echo ABC", TRUE, FALSE, "ABC\r\n" },
41 };
42
43 static const TEST_ENTRY s_cd_entries[] =
44 {
45 { __LINE__, 0, "cmd /c cd \"C:\\ " },
46 { __LINE__, 0, "cmd /c cd C:/" },
47 { __LINE__, 0, "cmd /c cd \"\"", TRUE, FALSE },
48 { __LINE__, 0, "cmd /c cd", TRUE, FALSE },
49 { __LINE__, 1234, "cmd /c cd C:\\Program Files && exit 1234" },
50 { __LINE__, 1234, "cmd /c cd \"C:\\ \" && exit 1234" },
51 { __LINE__, 1234, "cmd /c cd \"C:\\Program Files\" && exit 1234" },
52 { __LINE__, 1234, "cmd /c cd \"\" && exit 1234", TRUE, FALSE },
53 { __LINE__, 1234, "cmd /c cd \\ && exit 1234" },
54 };
55
56 static const TEST_ENTRY s_pushd_entries[] =
57 {
58 { __LINE__, 0, "cmd /c pushd C:\\ " },
59 { __LINE__, 0, "cmd /c pushd C:\\ \"" },
60 { __LINE__, 0, "cmd /c pushd C:\\ \"\"" },
61 { __LINE__, 0, "cmd /c pushd C:\\ \"\"\"" },
62 { __LINE__, 0, "cmd /c pushd C:\\ \"\"\"\"" },
63 { __LINE__, 0, "cmd /c pushd C:\\ \" " },
64 { __LINE__, 0, "cmd /c pushd C:\\ \"\" " },
65 { __LINE__, 0, "cmd /c pushd C:\\ \"\"\" " },
66 { __LINE__, 0, "cmd /c pushd C:\\ \"\"\"\" " },
67 { __LINE__, 0, "cmd /c pushd C:\\" },
68 { __LINE__, 0, "cmd /c pushd C:\\\"" },
69 { __LINE__, 0, "cmd /c pushd C:\\\"\"" },
70 { __LINE__, 0, "cmd /c pushd C:\\\"\"\"" },
71 { __LINE__, 0, "cmd /c pushd C:\\\"\"\"\"" },
72 { __LINE__, 0, "cmd /c pushd C:\\\" " },
73 { __LINE__, 0, "cmd /c pushd C:\\\"\" " },
74 { __LINE__, 0, "cmd /c pushd C:\\\"\"\" " },
75 { __LINE__, 0, "cmd /c pushd C:\\\"\"\"\" " },
76 { __LINE__, 0, "cmd /c pushd \"C:\\ " },
77 { __LINE__, 0, "cmd /c pushd \"C:\\ \"" },
78 { __LINE__, 0, "cmd /c pushd \"C:\\ \"\"" },
79 { __LINE__, 0, "cmd /c pushd \"C:\\ \"\"\"" },
80 { __LINE__, 0, "cmd /c pushd \"C:\\ \"\"\"\"" },
81 { __LINE__, 0, "cmd /c pushd \"C:\\ \" " },
82 { __LINE__, 0, "cmd /c pushd \"C:\\ \"\" " },
83 { __LINE__, 0, "cmd /c pushd \"C:\\ \"\"\" " },
84 { __LINE__, 0, "cmd /c pushd \"C:\\ \"\"\"\" " },
85 { __LINE__, 0, "cmd /c pushd \"C:\\" },
86 { __LINE__, 0, "cmd /c pushd \"C:\\\"" },
87 { __LINE__, 0, "cmd /c pushd \"C:\\\"\"" },
88 { __LINE__, 0, "cmd /c pushd \"C:\\\"\"\"" },
89 { __LINE__, 0, "cmd /c pushd \"C:\\\"\"\"\"" },
90 { __LINE__, 0, "cmd /c pushd \"C:\\\"" },
91 { __LINE__, 1, "cmd /c pushd \" C:\\ ", FALSE, TRUE },
92 { __LINE__, 1, "cmd /c pushd \" C:\\ \"", FALSE, TRUE },
93 { __LINE__, 1, "cmd /c pushd \" C:\\ \"\"", FALSE, TRUE },
94 { __LINE__, 1, "cmd /c pushd \" C:\\ \"\"\"", FALSE, TRUE },
95 { __LINE__, 1, "cmd /c pushd \" C:\\ \"\"\"\"", FALSE, TRUE },
96 { __LINE__, 1, "cmd /c pushd \"\" C:\\ ", FALSE, TRUE },
97 { __LINE__, 1, "cmd /c pushd \"\" C:\\ \"", FALSE, TRUE },
98 { __LINE__, 1, "cmd /c pushd \"\" C:\\ \"\"", FALSE, TRUE },
99 { __LINE__, 1, "cmd /c pushd \"\" C:\\ \"\"\"", FALSE, TRUE },
100 { __LINE__, 1, "cmd /c pushd \"\" C:\\ \"\"\"\"", FALSE, TRUE },
101 { __LINE__, 1, "cmd /c pushd \"\" C:\\\"", FALSE, TRUE },
102 { __LINE__, 1, "cmd /c popd ABC" },
103 { __LINE__, 1, "cmd /c popd \" " },
104 { __LINE__, 1, "cmd /c popd \"\"" },
105 { __LINE__, 1, "cmd /c popd" },
106 { __LINE__, 1, "cmd /c pushd ABC", FALSE, TRUE },
107 { __LINE__, 1, "cmd /c pushd C:/Program Files && popd && exit 1234", FALSE, TRUE },
108 { __LINE__, 1, "cmd /c pushd C:\\ C:\\ && popd && exit 1234", FALSE, TRUE },
109 { __LINE__, 1, "cmd /c pushd C:\\Invalid Directory && exit 1234", FALSE, TRUE },
110 { __LINE__, 1, "cmd /c pushd C:\\Invalid Directory && popd && exit 1234", FALSE, TRUE },
111 { __LINE__, 1, "cmd /c pushd \" C:\\ ", FALSE, TRUE },
112 { __LINE__, 1, "cmd /c pushd \"C:\\ C:\\\" && popd && exit 1234", FALSE, TRUE },
113 { __LINE__, 1234, "cmd /c pushd && exit 1234 " },
114 { __LINE__, 1234, "cmd /c pushd C:\\ && popd && exit 1234" },
115 { __LINE__, 1234, "cmd /c pushd C:\\ \"\" && popd && exit 1234" },
116 { __LINE__, 1234, "cmd /c pushd C:\\Program Files && popd && exit 1234" },
117 // { __LINE__, 1234, "cmd /c pushd \"C:/Program Files/\" && popd && exit 1234" },
118 // { __LINE__, 1234, "cmd /c pushd \"C:/Program Files\" && popd && exit 1234" },
119 { __LINE__, 1234, "cmd /c pushd \"C:\\ \" && popd && exit 1234" },
120 { __LINE__, 1234, "cmd /c pushd \"C:\\ \"\"\" && popd && exit 1234" },
121 { __LINE__, 1234, "cmd /c pushd \"C:\\ \"\"\"\"\" && popd && exit 1234" },
122 { __LINE__, 1234, "cmd /c pushd \"C:\\Program Files\" && popd && exit 1234" },
123 { __LINE__, 1234, "cmd /c pushd \"C:\\Program Files\\\" && popd && exit 1234" },
124 { __LINE__, 1234, "cmd /c pushd \"C:\\\" && popd && exit 1234" },
125 };
126
127 static const TEST_ENTRY s_attrib_entries[] =
128 {
129 /* invalid-path.txt */
130 { __LINE__, 0, "attrib invalid-path.txt", TRUE, FALSE },
131 { __LINE__, 0, "attrib +H invalid-path.txt", TRUE, FALSE },
132 { __LINE__, 0, "attrib -H invalid-path.txt", TRUE, FALSE },
133
134 /* attr-test.txt */
135 { __LINE__, 0, "cmd /c if exist attr-test.txt attrib -H attr-test.txt" },
136 { __LINE__, 0, "cmd /c if exist attr-test.txt del /Q attr-test.txt" },
137 { __LINE__, 0, "cmd /c copy NUL attr-test.txt ", TRUE, FALSE },
138 { __LINE__, 0, "attrib attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
139 { __LINE__, 0, "attrib +H attr-test.txt", FALSE, FALSE },
140 { __LINE__, 0, "attrib attr-test.txt", TRUE, FALSE, " H " },
141 { __LINE__, 0, "attrib -H attr-test.txt", FALSE, FALSE },
142 { __LINE__, 0, "attrib attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
143 { __LINE__, 0, "attrib attr-te*.txt", TRUE, FALSE, NULL, NULL, " H " },
144 { __LINE__, 0, "attrib +H attr-te*.txt", FALSE, FALSE },
145 { __LINE__, 0, "attrib attr-te*.txt", TRUE, FALSE, " H " },
146 { __LINE__, 0, "attrib -H attr-te*.txt", FALSE, FALSE },
147 { __LINE__, 0, "attrib attr-te*.txt", TRUE, FALSE, NULL, NULL, " H " },
148 { __LINE__, 0, "cmd /c if exist attr-test.txt attrib -H attr-test.txt" },
149 { __LINE__, 0, "cmd /c if exist attr-test.txt del /Q attr-test.txt" },
150
151 /* /S attr-test.txt */
152 { __LINE__, 0, "cmd /c if exist attr-test.txt attrib -H attr-test.txt" },
153 { __LINE__, 0, "cmd /c if exist attr-test.txt del /Q attr-test.txt" },
154 { __LINE__, 0, "cmd /c copy NUL attr-test.txt ", TRUE, FALSE },
155 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
156 { __LINE__, 0, "attrib /S +H attr-test.txt", FALSE, FALSE },
157 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, " H " },
158 { __LINE__, 0, "attrib /S -H attr-test.txt", FALSE, FALSE },
159 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
160 { __LINE__, 0, "attrib /S attr-te*.txt", TRUE, FALSE, NULL, NULL, " H " },
161 { __LINE__, 0, "attrib /S +H attr-te*.txt", FALSE, FALSE },
162 { __LINE__, 0, "attrib /S attr-te*.txt", TRUE, FALSE, " H " },
163 { __LINE__, 0, "attrib /S -H attr-te*.txt", FALSE, FALSE },
164 { __LINE__, 0, "attrib /S attr-te*.txt", TRUE, FALSE, NULL, NULL, " H " },
165 { __LINE__, 0, "attrib /S +H", FALSE, FALSE },
166 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, " H " },
167 { __LINE__, 0, "attrib /S -H", FALSE, FALSE },
168 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
169 { __LINE__, 0, "cmd /c if exist attr-test.txt attrib -H attr-test.txt" },
170 { __LINE__, 0, "cmd /c if exist attr-test.txt del /Q attr-test.txt" },
171
172 /* /S /D attr-test.txt */
173 { __LINE__, 0, "cmd /c if exist attr-test.txt attrib -H attr-test.txt" },
174 { __LINE__, 0, "cmd /c if exist attr-test.txt del /Q attr-test.txt" },
175 { __LINE__, 0, "cmd /c copy NUL attr-test.txt ", TRUE, FALSE },
176 { __LINE__, 0, "attrib /S /D attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
177 { __LINE__, 0, "attrib /S /D +H attr-test.txt", FALSE, FALSE },
178 { __LINE__, 0, "attrib /S /D attr-test.txt", TRUE, FALSE, " H " },
179 { __LINE__, 0, "attrib /S /D -H attr-test.txt", FALSE, FALSE },
180 { __LINE__, 0, "attrib /S /D attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
181 { __LINE__, 0, "attrib /S /D attr-te*.txt", TRUE, FALSE, NULL, NULL, " H " },
182 { __LINE__, 0, "attrib /S /D +H attr-te*.txt", FALSE, FALSE },
183 { __LINE__, 0, "attrib /S /D attr-te*.txt", TRUE, FALSE, " H " },
184 { __LINE__, 0, "attrib /S /D -H attr-te*.txt", FALSE, FALSE },
185 { __LINE__, 0, "attrib /S /D attr-te*.txt", TRUE, FALSE, NULL, NULL, " H " },
186 { __LINE__, 0, "cmd /c if exist attr-test.txt attrib -H attr-test.txt" },
187 { __LINE__, 0, "cmd /c if exist attr-test.txt del /Q attr-test.txt" },
188
189 /* attr-dir, attr-dir/test.txt */
190 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
191 { __LINE__, 0, "cmd /c mkdir attr-dir", FALSE, FALSE },
192 { __LINE__, 0, "cmd /c if exist attr-dir/test.txt attrib -H attr-dir/test.txt" },
193 { __LINE__, 0, "cmd /c if exist attr-dir/test.txt del /Q attr-dir/test.txt" },
194 { __LINE__, 1, "cmd /c copy NUL attr-dir/test.txt ", TRUE, FALSE },
195 { __LINE__, 0, "attrib attr-dir/test.txt", TRUE, FALSE, NULL, NULL, " H " },
196 { __LINE__, 0, "attrib +H attr-dir/test.txt", TRUE, FALSE },
197 { __LINE__, 0, "attrib attr-dir/test.txt", TRUE, FALSE, NULL, NULL, " H " },
198 { __LINE__, 0, "attrib -H attr-dir/test.txt", TRUE, FALSE, "test.txt" },
199 { __LINE__, 0, "attrib attr-dir/test.txt", TRUE, FALSE, NULL, NULL, " H " },
200 { __LINE__, 0, "attrib +H attr-dir", FALSE, FALSE, NULL, NULL, " H " },
201 { __LINE__, 0, "attrib attr-dir", TRUE, FALSE, " H " },
202 { __LINE__, 0, "attrib attr-dir/test.txt", TRUE, FALSE, NULL, NULL, " H " },
203 { __LINE__, 0, "attrib -H attr-dir", FALSE, FALSE, NULL, NULL, " H " },
204 { __LINE__, 0, "attrib attr-dir", TRUE, FALSE, NULL, NULL, " H " },
205 { __LINE__, 0, "cmd /c if exist attr-dir/test.txt attrib -H attr-dir/test.txt" },
206 { __LINE__, 0, "cmd /c if exist attr-dir/test.txt del /Q attr-dir/test.txt" },
207 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
208
209 /* attr-dir, attr-dir\\dir1 */
210 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
211 { __LINE__, 0, "cmd /c mkdir attr-dir", FALSE, FALSE },
212 { __LINE__, 0, "attrib attr-dir", TRUE, FALSE, NULL, NULL, " H " },
213 { __LINE__, 0, "cmd /c if exist attr-dir echo OK", TRUE, FALSE, "OK" },
214 { __LINE__, 0, "cmd /c mkdir attr-dir\\dir1", FALSE, FALSE },
215 { __LINE__, 0, "cmd /c if exist attr-dir\\dir1 echo OK", TRUE, FALSE, "OK" },
216 { __LINE__, 0, "attrib attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
217 { __LINE__, 0, "attrib +H attr-dir\\dir1", FALSE, FALSE },
218 { __LINE__, 0, "attrib attr-dir\\dir1", TRUE, FALSE, " H " },
219 { __LINE__, 0, "attrib -H attr-dir\\dir1", FALSE, FALSE },
220 { __LINE__, 0, "attrib attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
221 { __LINE__, 0, "attrib +H attr-dir", FALSE, FALSE },
222 { __LINE__, 0, "attrib attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
223 { __LINE__, 0, "attrib -H attr-dir", FALSE, FALSE },
224 { __LINE__, 0, "attrib attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
225 { __LINE__, 0, "attrib +H attr-d*", TRUE, FALSE, "attr-d*" },
226 { __LINE__, 0, "attrib attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
227 { __LINE__, 0, "attrib -H attr-d*", TRUE, FALSE, "attr-d*" },
228 { __LINE__, 0, "attrib attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
229 { __LINE__, 0, "attrib +H attr-dir\\d*", TRUE, FALSE, "attr-dir\\d*" },
230 { __LINE__, 0, "attrib attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
231 { __LINE__, 0, "attrib -H attr-dir\\d*", TRUE, FALSE, "attr-dir\\d*" },
232 { __LINE__, 0, "attrib attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
233 { __LINE__, 0, "attrib -H attr-dir\\dir1", FALSE, FALSE },
234 { __LINE__, 0, "attrib -H attr-dir", FALSE, FALSE },
235 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
236
237 /* /S attr-dir, attr-dir\\dir1 */
238 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
239 { __LINE__, 0, "cmd /c mkdir attr-dir", FALSE, FALSE },
240 { __LINE__, 0, "attrib /S attr-dir", TRUE, FALSE, NULL, NULL, " H " },
241 { __LINE__, 0, "cmd /c if exist attr-dir echo OK", TRUE, FALSE, "OK" },
242 { __LINE__, 0, "cmd /c mkdir attr-dir\\dir1", FALSE, FALSE },
243 { __LINE__, 0, "cmd /c if exist attr-dir\\dir1 echo OK", TRUE, FALSE, "OK" },
244 { __LINE__, 0, "attrib /S attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
245 { __LINE__, 0, "attrib /S +H attr-dir\\dir1", TRUE, FALSE, "attr-dir\\dir1", },
246 { __LINE__, 0, "attrib /S attr-dir\\dir1", TRUE, FALSE, "attr-dir\\dir1" },
247 { __LINE__, 0, "attrib /S -H attr-dir\\dir1", TRUE, FALSE, "attr-dir\\dir1" },
248 { __LINE__, 0, "attrib /S attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
249 { __LINE__, 0, "attrib /S +H attr-dir", TRUE, FALSE, "attr-dir" },
250 { __LINE__, 0, "attrib /S attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
251 { __LINE__, 0, "attrib /S -H attr-dir", TRUE, FALSE, "attr-dir" },
252 { __LINE__, 0, "attrib /S attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
253 { __LINE__, 0, "attrib /S +H attr-d*", TRUE, FALSE, "attr-d*" },
254 { __LINE__, 0, "attrib /S attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
255 { __LINE__, 0, "attrib /S -H attr-d*", TRUE, FALSE, "attr-d*" },
256 { __LINE__, 0, "attrib /S attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
257 { __LINE__, 0, "attrib /S +H attr-dir\\d*", TRUE, FALSE, "attr-dir\\d*" },
258 { __LINE__, 0, "attrib /S attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
259 { __LINE__, 0, "attrib /S -H attr-dir\\d*", TRUE, FALSE, "attr-dir\\d*" },
260 { __LINE__, 0, "attrib /S attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
261 { __LINE__, 0, "attrib /S -H attr-dir\\dir1", TRUE, FALSE, "attr-dir\\dir1" },
262 { __LINE__, 0, "attrib /S -H attr-dir", TRUE, FALSE, "attr-dir" },
263 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
264
265 /* /S /D attr-dir, attr-dir\\dir1 */
266 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
267 { __LINE__, 0, "cmd /c mkdir attr-dir", FALSE, FALSE },
268 { __LINE__, 0, "attrib /S /D attr-dir", TRUE, FALSE, NULL, NULL, " H " },
269 { __LINE__, 0, "cmd /c if exist attr-dir echo OK", TRUE, FALSE, "OK" },
270 { __LINE__, 0, "cmd /c mkdir attr-dir\\dir1", FALSE, FALSE },
271 { __LINE__, 0, "cmd /c if exist attr-dir\\dir1 echo OK", TRUE, FALSE, "OK" },
272 { __LINE__, 0, "attrib /S /D attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
273 { __LINE__, 0, "attrib /S /D +H attr-dir\\dir1", FALSE, FALSE },
274 { __LINE__, 0, "attrib /S /D attr-dir\\dir1", TRUE, FALSE, " H " },
275 { __LINE__, 0, "attrib /S /D -H attr-dir\\dir1", FALSE, FALSE },
276 { __LINE__, 0, "attrib /S /D attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
277 { __LINE__, 0, "attrib /S /D +H attr-dir", FALSE, FALSE },
278 { __LINE__, 0, "attrib /S /D attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
279 { __LINE__, 0, "attrib /S /D -H attr-dir", FALSE, FALSE },
280 { __LINE__, 0, "attrib /S /D attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
281 { __LINE__, 0, "attrib /S /D +H attr-d*", FALSE, FALSE },
282 { __LINE__, 0, "attrib /S /D attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
283 { __LINE__, 0, "attrib /S /D -H attr-d*", FALSE, FALSE },
284 { __LINE__, 0, "attrib /S /D attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
285 { __LINE__, 0, "attrib /S /D +H attr-dir\\d*", FALSE, FALSE },
286 { __LINE__, 0, "attrib /S /D attr-dir\\dir1", TRUE, FALSE, " H " },
287 { __LINE__, 0, "attrib /S /D -H attr-dir\\d*", FALSE, FALSE },
288 { __LINE__, 0, "attrib /S /D attr-dir\\dir1", TRUE, FALSE, NULL, NULL, " H " },
289 { __LINE__, 0, "attrib /S /D -H attr-dir\\dir1", FALSE, FALSE },
290 { __LINE__, 0, "attrib /S /D -H attr-dir", FALSE, FALSE },
291 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
292
293 /* /S attr-dir, attr-dir\\dir1\\file.txt */
294 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
295 { __LINE__, 0, "cmd /c mkdir attr-dir", FALSE, FALSE },
296 { __LINE__, 0, "attrib /S /D attr-dir", TRUE, FALSE, NULL, NULL, " H " },
297 { __LINE__, 0, "cmd /c if exist attr-dir echo OK", TRUE, FALSE, "OK" },
298 { __LINE__, 0, "cmd /c mkdir attr-dir\\dir1", FALSE, FALSE },
299 { __LINE__, 0, "cmd /c if exist attr-dir\\dir1 echo OK", TRUE, FALSE, "OK" },
300 { __LINE__, 0, "cmd /c copy NUL attr-dir\\dir1\\attr-test.txt ", TRUE, FALSE },
301 { __LINE__, 0, "attrib attr-dir\\dir1\\attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
302 { __LINE__, 0, "attrib /S +H attr-dir\\dir1\\attr-test.txt", FALSE, FALSE },
303 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, " H " },
304 { __LINE__, 0, "attrib /S -H attr-dir\\dir1\\attr-test.txt", FALSE, FALSE },
305 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
306 { __LINE__, 0, "attrib /S +H attr-test.txt", FALSE, FALSE },
307 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, " H " },
308 { __LINE__, 0, "attrib /S -H attr-test.txt", FALSE, FALSE },
309 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
310 { __LINE__, 0, "attrib /S +H", FALSE, FALSE },
311 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, " H " },
312 { __LINE__, 0, "attrib /S attr-tes*.*", TRUE, FALSE, " H " },
313 { __LINE__, 0, "attrib /S -H", FALSE, FALSE },
314 { __LINE__, 0, "attrib /S attr-test.txt", TRUE, FALSE, NULL, NULL, " H " },
315 { __LINE__, 0, "attrib /S attr-tes*.*", TRUE, FALSE, NULL, NULL, " H " },
316 { __LINE__, 0, "cmd /c if exist attr-dir/dir1/test.txt attrib -H attr-dir/dir1/test.txt" },
317 { __LINE__, 0, "cmd /c if exist attr-dir/dir1/test.txt del /Q attr-dir/dir1/test.txt" },
318 { __LINE__, 0, "cmd /c if exist attr-dir rmdir /s /q attr-dir" },
319
320 };
321
MyDuplicateHandle(HANDLE hFile,PHANDLE phFile,BOOL bInherit)322 static BOOL MyDuplicateHandle(HANDLE hFile, PHANDLE phFile, BOOL bInherit)
323 {
324 HANDLE hProcess = GetCurrentProcess();
325 return DuplicateHandle(hProcess, hFile, hProcess, phFile, 0,
326 bInherit, DUPLICATE_SAME_ACCESS);
327 }
328
PrepareForRedirect(STARTUPINFOA * psi,PHANDLE phInputWrite,PHANDLE phOutputRead,PHANDLE phErrorRead)329 static BOOL PrepareForRedirect(STARTUPINFOA *psi, PHANDLE phInputWrite,
330 PHANDLE phOutputRead, PHANDLE phErrorRead)
331 {
332 HANDLE hInputRead = NULL, hInputWriteTmp = NULL;
333 HANDLE hOutputReadTmp = NULL, hOutputWrite = NULL;
334 HANDLE hErrorReadTmp = NULL, hErrorWrite = NULL;
335 SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };
336
337 psi->hStdInput = NULL;
338 psi->hStdOutput = NULL;
339 psi->hStdError = NULL;
340
341 if (phInputWrite)
342 {
343 if (CreatePipe(&hInputRead, &hInputWriteTmp, &sa, 0))
344 {
345 if (!MyDuplicateHandle(hInputWriteTmp, phInputWrite, FALSE))
346 goto failed;
347
348 CloseHandle(hInputWriteTmp);
349 }
350 else
351 goto failed;
352 }
353
354 if (phOutputRead)
355 {
356 if (CreatePipe(&hOutputReadTmp, &hOutputWrite, &sa, 0))
357 {
358 if (!MyDuplicateHandle(hOutputReadTmp, phOutputRead, FALSE))
359 goto failed;
360
361 CloseHandle(hOutputReadTmp);
362 }
363 else
364 goto failed;
365 }
366
367 if (phOutputRead && phOutputRead == phErrorRead)
368 {
369 if (!MyDuplicateHandle(hOutputWrite, &hErrorWrite, TRUE))
370 goto failed;
371 }
372 else if (phErrorRead)
373 {
374 if (CreatePipe(&hErrorReadTmp, &hErrorWrite, &sa, 0))
375 {
376 if (!MyDuplicateHandle(hErrorReadTmp, phErrorRead, FALSE))
377 goto failed;
378 CloseHandle(hErrorReadTmp);
379 }
380 else
381 goto failed;
382 }
383
384 if (phInputWrite)
385 psi->hStdInput = hInputRead;
386 if (phOutputRead)
387 psi->hStdOutput = hOutputWrite;
388 if (phErrorRead)
389 psi->hStdError = hErrorWrite;
390
391 return TRUE;
392
393 failed:
394 CloseHandle(hInputRead);
395 CloseHandle(hInputWriteTmp);
396 CloseHandle(hOutputReadTmp);
397 CloseHandle(hOutputWrite);
398 CloseHandle(hErrorReadTmp);
399 CloseHandle(hErrorWrite);
400 return FALSE;
401 }
402
DoTestEntry(const TEST_ENTRY * pEntry)403 static void DoTestEntry(const TEST_ENTRY *pEntry)
404 {
405 STARTUPINFOA si;
406 PROCESS_INFORMATION pi;
407 DWORD dwExitCode, dwWait;
408 HANDLE hOutputRead = NULL;
409 HANDLE hErrorRead = NULL;
410 DWORD dwRead;
411 BOOL bStdOutput, bStdError;
412 CHAR szOut[512], szErr[512];
413
414 memset(&si, 0, sizeof(si));
415 si.cb = sizeof(si);
416 si.dwFlags = STARTF_USESTDHANDLES;
417
418 if (!PrepareForRedirect(&si, NULL, &hOutputRead, &hErrorRead))
419 {
420 skip("PrepareForRedirect failed\n");
421 return;
422 }
423
424 if (CreateProcessA(NULL, (char *)pEntry->cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
425 {
426 CloseHandle(si.hStdInput);
427 dwWait = WaitForSingleObject(pi.hProcess, TIMEOUT);
428 if (dwWait == WAIT_TIMEOUT)
429 {
430 TerminateProcess(pi.hProcess, 9999);
431 }
432 GetExitCodeProcess(pi.hProcess, &dwExitCode);
433 CloseHandle(pi.hThread);
434 CloseHandle(pi.hProcess);
435 }
436 else
437 {
438 dwExitCode = 8888;
439 }
440
441 ZeroMemory(szOut, sizeof(szOut));
442 PeekNamedPipe(hOutputRead, szOut, ARRAYSIZE(szOut), &dwRead, NULL, NULL);
443 szOut[ARRAYSIZE(szOut) - 1] = 0;
444 bStdOutput = dwRead != 0;
445
446 ZeroMemory(szErr, sizeof(szErr));
447 PeekNamedPipe(hErrorRead, szErr, ARRAYSIZE(szErr), &dwRead, NULL, NULL);
448 szErr[ARRAYSIZE(szErr) - 1] = 0;
449 bStdError = dwRead != 0;
450
451 if (si.hStdInput)
452 CloseHandle(si.hStdInput);
453 if (si.hStdOutput)
454 CloseHandle(si.hStdOutput);
455 if (si.hStdError)
456 CloseHandle(si.hStdError);
457
458 ok(pEntry->bStdOutput == bStdOutput,
459 "Line %u: bStdOutput %d vs %d\n",
460 pEntry->line, pEntry->bStdOutput, bStdOutput);
461
462 ok(pEntry->bStdError == bStdError,
463 "Line %u: bStdError %d vs %d\n",
464 pEntry->line, pEntry->bStdError, bStdError);
465
466 ok(pEntry->dwExitCode == dwExitCode,
467 "Line %u: dwExitCode %ld vs %ld\n",
468 pEntry->line, pEntry->dwExitCode, dwExitCode);
469
470 if (pEntry->OutputContains)
471 {
472 ok(strstr(szOut, pEntry->OutputContains) != NULL,
473 "Line %u: szOut was '%s'\n",
474 pEntry->line, szOut);
475 }
476
477 if (pEntry->ErrorContains)
478 {
479 ok(strstr(szErr, pEntry->ErrorContains) != NULL,
480 "Line %u: szErr was '%s'\n",
481 pEntry->line, szErr);
482 }
483
484 if (pEntry->OutputNotContains)
485 {
486 ok(strstr(szOut, pEntry->OutputNotContains) == NULL,
487 "Line %u: szOut was '%s'\n",
488 pEntry->line, szOut);
489 }
490
491 if (pEntry->ErrorNotContains)
492 {
493 ok(strstr(szErr, pEntry->ErrorNotContains) == NULL,
494 "Line %u: szErr was '%s'\n",
495 pEntry->line, szErr);
496 }
497 }
498
START_TEST(exit)499 START_TEST(exit)
500 {
501 SIZE_T i;
502 for (i = 0; i < ARRAYSIZE(s_exit_entries); ++i)
503 {
504 DoTestEntry(&s_exit_entries[i]);
505 }
506 }
507
START_TEST(echo)508 START_TEST(echo)
509 {
510 SIZE_T i;
511 for (i = 0; i < ARRAYSIZE(s_echo_entries); ++i)
512 {
513 DoTestEntry(&s_echo_entries[i]);
514 }
515 }
516
START_TEST(cd)517 START_TEST(cd)
518 {
519 SIZE_T i;
520 for (i = 0; i < ARRAYSIZE(s_cd_entries); ++i)
521 {
522 DoTestEntry(&s_cd_entries[i]);
523 }
524 }
525
START_TEST(pushd)526 START_TEST(pushd)
527 {
528 SIZE_T i;
529 for (i = 0; i < ARRAYSIZE(s_pushd_entries); ++i)
530 {
531 DoTestEntry(&s_pushd_entries[i]);
532 }
533 }
534
START_TEST(attrib)535 START_TEST(attrib)
536 {
537 SIZE_T i;
538 for (i = 0; i < ARRAYSIZE(s_attrib_entries); ++i)
539 {
540 DoTestEntry(&s_attrib_entries[i]);
541 }
542 }
543