xref: /reactos/modules/rostests/apitests/cmd/cmd.c (revision dbe1d36e)
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