1@echo off
2
3::
4:: Some basic tests
5::
6
7echo ------------ Testing FOR loop ------------
8echo --- Multiple lines
9for %%i in (A
10B
11C) do echo %%i
12
13echo --- Lines and spaces
14for %%i in (D
15 E
16 F) do echo %%i
17
18echo --- Multiple lines and commas
19for %%i in (G,
20H,
21I
22) do echo %%i
23
24echo --- Multiple lines and %%I
25:: The FOR-variable is case-sensitive
26for %%i in (J
27 K
28 L) do echo %%I
29
30echo --- Multiple lines and %%j
31for %%i in (M,
32N,
33O
34) do echo %%j
35
36
37echo ---------- Testing AND operator ----------
38:: Test for TRUE condition - Should be displayed
39ver | find "Ver" > NUL && echo TRUE AND condition
40
41:: Test for FALSE condition - Should not display
42ver | find "1234" > NUL && echo FALSE AND condition
43
44echo ---------- Testing OR operator -----------
45:: Test for TRUE condition - Should not display
46ver | find "Ver" > NUL || echo TRUE OR condition
47
48:: Test for FALSE condition - Should be displayed
49ver | find "1234" > NUL || echo FALSE OR condition
50
51
52
53::
54:: Testing CMD exit codes and errorlevels.
55::
56:: Observations:
57:: - OR operator || converts the LHS error code to ERRORLEVEL only on failure;
58:: - Pipe operator | converts the last error code to ERRORLEVEL.
59::
60:: See https://stackoverflow.com/a/34987886/13530036
61:: and https://stackoverflow.com/a/34937706/13530036
62:: for more details.
63::
64setlocal enableextensions
65
66echo ---------- Testing CMD exit codes and errorlevels ----------
67
68:: Tests for CMD returned exit code.
69
70echo --- CMD /C Direct EXIT call
71
72call :setError 0
73cmd /c "exit 42"
74call :checkErrorLevel 42
75
76call :setError 111
77cmd /c "exit 42"
78call :checkErrorLevel 42
79
80echo --- CMD /C Direct EXIT /B call
81
82call :setError 0
83cmd /c "exit /b 42"
84call :checkErrorLevel 42
85
86call :setError 111
87cmd /c "exit /b 42"
88call :checkErrorLevel 42
89
90:: Non-existing ccommand, or command that only changes
91:: the returned code (but NOT the ERRORLEVEL) and EXIT.
92
93echo --- CMD /C Non-existing command
94
95:: EXIT alone does not change the ERRORLEVEL
96call :setError 0
97cmd /c "nonexisting & exit"
98call :checkErrorLevel 9009
99
100call :setError 111
101cmd /c "nonexisting & exit"
102call :checkErrorLevel 9009
103
104call :setError 0
105cmd /c "nonexisting & exit /b"
106call :checkErrorLevel 9009
107
108call :setError 111
109cmd /c "nonexisting & exit /b"
110call :checkErrorLevel 9009
111
112echo --- CMD /C RMDIR (no ERRORLEVEL set)
113
114call :setError 0
115cmd /c "rmdir nonexisting & exit"
116call :checkErrorLevel 0
117
118call :setError 111
119cmd /c "rmdir nonexisting & exit"
120call :checkErrorLevel 0
121
122call :setError 0
123cmd /c "rmdir nonexisting & exit /b"
124call :checkErrorLevel 0
125
126call :setError 111
127cmd /c "rmdir nonexisting & exit /b"
128call :checkErrorLevel 0
129
130:: Failing command (sets ERRORLEVEL to 1) and EXIT
131echo --- CMD /C DIR (sets ERRORLEVEL) - With failure
132
133:: EXIT alone does not change the ERRORLEVEL
134call :setError 0
135cmd /c "dir nonexisting>NUL & exit"
136call :checkErrorLevel 1
137
138call :setError 111
139cmd /c "dir nonexisting>NUL & exit"
140call :checkErrorLevel 1
141
142call :setError 0
143cmd /c "dir nonexisting>NUL & exit /b"
144call :checkErrorLevel 1
145
146call :setError 111
147cmd /c "dir nonexisting>NUL & exit /b"
148call :checkErrorLevel 1
149
150:: Here EXIT changes the ERRORLEVEL
151call :setError 0
152cmd /c "dir nonexisting>NUL & exit 42"
153call :checkErrorLevel 42
154
155call :setError 111
156cmd /c "dir nonexisting>NUL & exit 42"
157call :checkErrorLevel 42
158
159call :setError 0
160cmd /c "dir nonexisting>NUL & exit /b 42"
161call :checkErrorLevel 42
162
163call :setError 111
164cmd /c "dir nonexisting>NUL & exit /b 42"
165call :checkErrorLevel 42
166
167:: Succeeding command (sets ERRORLEVEL to 0) and EXIT
168echo --- CMD /C DIR (sets ERRORLEVEL) - With success
169
170call :setError 0
171cmd /c "dir>NUL & exit"
172call :checkErrorLevel 0
173
174call :setError 111
175cmd /c "dir>NUL & exit"
176call :checkErrorLevel 0
177
178call :setError 0
179cmd /c "dir>NUL & exit 42"
180call :checkErrorLevel 42
181
182call :setError 111
183cmd /c "dir>NUL & exit 42"
184call :checkErrorLevel 42
185
186call :setError 0
187cmd /c "dir>NUL & exit /b 42"
188call :checkErrorLevel 42
189
190call :setError 111
191cmd /c "dir>NUL & exit /b 42"
192call :checkErrorLevel 42
193
194
195:: Same sorts of tests, but now from within an external batch file:
196:: Tests for CALL command returned exit code.
197
198:: Use an auxiliary CMD file
199mkdir foobar && cd foobar
200
201:: Non-existing ccommand, or command that only changes
202:: the returned code (but NOT the ERRORLEVEL) and EXIT.
203
204echo --- CALL Batch Non-existing command
205
206:: EXIT alone does not change the ERRORLEVEL
207echo nonexisting ^& exit /b> tmp.cmd
208call :setError 0
209call tmp.cmd
210call :checkErrorLevel 9009
211
212echo nonexisting ^& exit /b> tmp.cmd
213call :setError 111
214call tmp.cmd
215call :checkErrorLevel 9009
216
217:: These tests show that || converts the returned error code
218:: from RMDIR on failure, and converts it to an ERRORLEVEL
219:: (first two tests: no ||, thus no ERRORLEVEL set;
220:: last two tests: ||used and ERRORLEVEL is set).
221::
222
223echo --- CALL Batch RMDIR (no ERRORLEVEL set)
224
225:: This test shows that if a batch returns error code 0 from CALL,
226:: then CALL will keep the existing ERRORLEVEL (here, 111)...
227echo rmdir nonexisting> tmp.cmd
228echo exit /b>> tmp.cmd
229call :setError 0
230call tmp.cmd
231call :checkErrorLevel 0
232
233echo rmdir nonexisting> tmp.cmd
234echo exit /b>> tmp.cmd
235call :setError 111
236call tmp.cmd
237call :checkErrorLevel 111
238
239echo --- CALL Batch RMDIR with ^|^| (sets ERRORLEVEL)
240
241:: ... but if a non-zero error code is returned from CALL,
242:: then CALL uses it as the new ERRORLEVEL.
243echo rmdir nonexisting ^|^| rem> tmp.cmd
244echo exit /b>> tmp.cmd
245call :setError 0
246call tmp.cmd
247call :checkErrorLevel 2
248:: This gives the same effect, since the last command's error code
249:: is returned and transformed by CALL into an ERRORLEVEL:
250echo rmdir nonexisting> tmp.cmd
251call :setError 0
252call tmp.cmd
253call :checkErrorLevel 2
254
255echo rmdir nonexisting ^|^| rem> tmp.cmd
256echo exit /b>> tmp.cmd
257call :setError 111
258call tmp.cmd
259call :checkErrorLevel 2
260:: This gives the same effect, since the last command's error code
261:: is returned and transformed by CALL into an ERRORLEVEL:
262echo rmdir nonexisting> tmp.cmd
263call :setError 111
264call tmp.cmd
265call :checkErrorLevel 2
266
267
268:: Failing command (sets ERRORLEVEL to 1) and EXIT
269echo --- CALL Batch DIR (sets ERRORLEVEL) - With failure
270
271echo dir nonexisting^>NUL> tmp.cmd
272call :setError 0
273call tmp.cmd
274call :checkErrorLevel 1
275
276echo dir nonexisting^>NUL> tmp.cmd
277call :setError 111
278call tmp.cmd
279call :checkErrorLevel 1
280
281echo dir nonexisting^>NUL ^& goto :eof> tmp.cmd
282call :setError 0
283call tmp.cmd
284call :checkErrorLevel 1
285
286echo dir nonexisting^>NUL ^& goto :eof> tmp.cmd
287call :setError 111
288call tmp.cmd
289call :checkErrorLevel 1
290
291echo dir nonexisting^>NUL ^& exit /b> tmp.cmd
292call :setError 0
293call tmp.cmd
294call :checkErrorLevel 1
295
296echo dir nonexisting^>NUL ^& exit /b> tmp.cmd
297call :setError 111
298call tmp.cmd
299call :checkErrorLevel 1
300
301echo dir nonexisting^>NUL ^& exit /b 42 > tmp.cmd
302call :setError 0
303call tmp.cmd
304call :checkErrorLevel 42
305
306echo dir nonexisting^>NUL ^& exit /b 42 > tmp.cmd
307call :setError 111
308call tmp.cmd
309call :checkErrorLevel 42
310
311:: Succeeding command (sets ERRORLEVEL to 0) and EXIT
312echo --- CALL Batch DIR (sets ERRORLEVEL) - With success
313
314echo dir^>NUL> tmp.cmd
315call :setError 0
316call tmp.cmd
317call :checkErrorLevel 0
318
319echo dir^>NUL> tmp.cmd
320call :setError 111
321call tmp.cmd
322call :checkErrorLevel 0
323
324echo dir^>NUL ^& goto :eof> tmp.cmd
325call :setError 0
326call tmp.cmd
327call :checkErrorLevel 0
328
329echo dir^>NUL ^& goto :eof> tmp.cmd
330call :setError 111
331call tmp.cmd
332call :checkErrorLevel 0
333
334echo dir^>NUL ^& exit /b> tmp.cmd
335call :setError 0
336call tmp.cmd
337call :checkErrorLevel 0
338
339echo dir^>NUL ^& exit /b> tmp.cmd
340call :setError 111
341call tmp.cmd
342call :checkErrorLevel 0
343
344echo dir^>NUL ^& exit /b 42 > tmp.cmd
345call :setError 0
346call tmp.cmd
347call :checkErrorLevel 42
348
349echo dir^>NUL ^& exit /b 42 > tmp.cmd
350call :setError 111
351call tmp.cmd
352call :checkErrorLevel 42
353
354
355:: Cleanup
356del tmp.cmd
357cd .. & rmdir /s/q foobar
358
359
360::
361:: Finished!
362::
363echo --------- Finished  --------------
364goto :EOF
365
366:checkErrorLevel
367if %errorlevel% neq %1 (echo Unexpected errorlevel %errorlevel%, expected %1) else echo OK
368goto :eof
369
370:: Subroutine to set errorlevel and return
371:: in windows nt 4.0, this always sets errorlevel 1, since /b isn't supported
372:setError
373exit /B %1
374:: This line runs under cmd in windows NT 4, but not in more modern versions.
375