1@echo off
2setlocal enableextensions
3setlocal enabledelayedexpansion
4
5
6::
7:: Tests for GOTO and CALL.
8::
9
10
11:: GOTO/CALL jump to labels present forward to their call-point. Only when
12:: the label cannot be found forward, the search is then restarted from the
13:: beginning of the batch file onwards up to the original call-point.
14
15:: GOTO with a label parameter without ':' works.
16goto test_start
17
18:: Execution must never go there!
19:test_goto
20echo Unexpected GOTO jump^^!
21exit
22:test_call
23echo Unexpected CALL jump^^!
24goto :EOF
25
26
27:test_start
28
29:: Testing GOTO/CALL forwards.
30echo --------- Testing GOTO ---------
31goto :test_goto
32
33:do_test_call
34echo --------- Testing CALL within batch ---------
35call :test_call
36goto :continue
37
38:test_goto
39echo Test GOTO ok
40:: GOTO also understands '+' instead of ':' in its label parameter.
41goto +do_test_call
42
43:test_call
44echo Test CALL ok from %0
45:: We exit this CALL invocation
46goto :EOF
47
48
49::
50:: Next suite of tests.
51::
52
53:: GOTO label search algorithm ignores any whitespace between ':'
54:: and the label name, as well as leading and trailing whitespace.
55  :@tab@continue@space@@space@
56
57
58:: Jumping to a label with escape carets.
59goto :la^^bel2
60
61:la^bel2
62echo Unexpected GOTO jump^^!
63:la^^bel2
64echo GOTO with escape caret worked
65
66
67:: Go to the next tests below.
68goto :continue
69
70
71::
72:: Next suite of tests.
73::
74:continue
75
76
77::
78:: Extra GOTO syntax checks: separators in the label parameter
79::
80
81:: Whitespace
82goto :testLbl1@tab@ignored
83:testLbl1
84echo Hi there^^!
85
86:: Colon
87goto :testLbl2:ignored
88:testLbl2
89echo Hi there^^!
90
91:: Plus sign
92goto :testLbl3+ignored
93:testLbl3
94echo Hi there^^!
95
96:: Comma
97goto :testLbl4,ignored
98:testLbl4
99echo Hi there^^!
100
101:: Semicolon
102goto :testLbl5;ignored
103:testLbl5
104echo Hi there^^!
105
106:: Equals
107goto :testLbl6;ignored
108:testLbl6
109echo Hi there^^!
110
111
112::
113:: Testing :EOF support
114::
115echo --------- Testing :EOF support ---------
116
117:: Use an auxiliary CMD file to test GOTO :EOF
118mkdir foobar && cd foobar
119
120:: GOTO :EOF is available only if commands extensions are enabled
121echo @echo off> tmp.cmd
122echo setlocal disableextensions>> tmp.cmd
123echo goto :eof>> tmp.cmd
124call :setError 0
125cmd /c tmp.cmd
126if %errorlevel% equ 0 (echo Unexpected: GOTO :EOF did not fail^^!) else echo OK
127
128:: GOTO :EOF is done only if the ":EOF" part is followed by whitespace or ends.
129:: The following two GOTO's fail because the labels cannot be found.
130echo @echo off> tmp.cmd
131echo setlocal enableextensions>> tmp.cmd
132echo goto :eof,lol>> tmp.cmd
133echo echo Batch continues^^!>> tmp.cmd
134call :setError 0
135cmd /c tmp.cmd
136if %errorlevel% equ 0 (echo Unexpected: GOTO :eof,lol did not fail^^!) else echo OK
137
138echo @echo off> tmp.cmd
139echo setlocal enableextensions>> tmp.cmd
140echo goto :eof:lol>> tmp.cmd
141echo echo Batch continues^^!>> tmp.cmd
142call :setError 0
143cmd /c tmp.cmd
144if %errorlevel% equ 0 (echo Unexpected: GOTO :eof:lol did not fail^^!) else echo OK
145
146:: GOTO :EOF expects at least one whitespace character before anything else.
147:: Not even '+',':' or other separators are allowed.
148echo @echo off> tmp.cmd
149echo setlocal enableextensions>> tmp.cmd
150echo goto :eof+lol>> tmp.cmd
151echo echo Batch continues^^!>> tmp.cmd
152call :setError 0
153cmd /c tmp.cmd
154if %errorlevel% equ 0 (echo Unexpected: GOTO :eof+lol did not fail^^!) else echo OK
155
156:: This GOTO :EOF works.
157echo @echo off> tmp.cmd
158echo setlocal enableextensions>> tmp.cmd
159echo goto :eof@tab@+lol>> tmp.cmd
160echo echo You should not see this^^!>> tmp.cmd
161call :setError 0
162cmd /c tmp.cmd
163if %errorlevel% neq 0 (echo Unexpected: GOTO :EOF did fail^^!) else echo OK
164
165
166:: Cleanup
167cd .. & rd /s/q foobar
168
169
170::
171:: Testing GOTO/CALL from and to within parenthesized blocks.
172::
173
174echo --------- Testing GOTO within block ---------
175(echo Block-test 1: Single-line& goto :block2 & echo Unexpected Block-test 1^^!)
176echo Unexpected echo 1^^!
177
178:block2
179(
180echo Block-test 2: Multi-line
181goto :block3
182echo Unexpected Block-test 2^^!
183)
184echo Unexpected echo 2-3^^!
185
186:test_call_block
187echo Test CALL in block OK from %0
188:: We exit this CALL invocation
189goto :EOF
190
191(
192:block3
193echo --------- Testing CALL within block ---------
194echo Block-test 3: CALL in block
195call :test_call_block
196echo CALL done
197)
198
199goto :block4
200echo Unexpected echo 4^^!
201(
202:block4
203echo Block-test 4 OK
204)
205
206
207::
208:: Testing GOTO/CALL from within FOR and IF.
209:: This is a situation similar to the parenthesized blocks.
210:: See bug-report CORE-13713
211::
212
213:: Testing CALL within FOR
214echo --------- Testing CALL within FOR ---------
215for /L %%A IN (0,1,3) DO (
216    set Number=%%A
217    if %%A==2 call :out_of_loop_1 %%A
218    if %%A==2 (echo %%A IS equal to 2) else (echo %%A IS NOT equal to 2)
219)
220goto :continue_2
221:out_of_loop_1
222echo Out of FOR 1 CALL from %0, number is %1
223:: We exit this CALL invocation
224goto :EOF
225:continue_2
226
227
228:: Testing GOTO within FOR
229echo --------- Testing GOTO within FOR ---------
230for /L %%A IN (0,1,3) DO (
231    set Number=%%A
232    if %%A==2 goto :out_of_loop_2
233    echo %%A IS NOT equal to 2
234)
235echo Unexpected FOR echo 2^^!
236:out_of_loop_2
237echo Out of FOR 2, number is %Number%
238
239
240
241::
242:: Show how each different FOR-loop stops when a GOTO is encountered.
243::
244echo --------- Testing FOR loop stopping with GOTO ---------
245
246:: FOR - Stops directly
247echo --- FOR
248@echo on
249for %%A in (1,2,3,4,5,6,7,8,9,10) do (
250    set Number=%%A
251    if %%A==5 goto :out_of_loop_2a
252)
253echo Unexpected FOR echo 2a^^!
254:out_of_loop_2a
255echo Out of FOR 2a, number is %Number%
256@echo off
257
258
259:: FOR /R - Stops directly
260echo --- FOR /R
261
262:: Use auxiliary directoreis to test for /R
263mkdir foobar && cd foobar
264mkdir foo1
265mkdir foo2
266mkdir bar1
267
268@echo on
269for /r %%A in (1,2,3,4,5,6,7,8,9,10) do (
270    set Number=%%~nA
271    if %%~nA==5 goto :out_of_loop_2b
272)
273echo Unexpected FOR echo 2b^^!
274:out_of_loop_2b
275echo Out of FOR 2b, number is %Number%
276@echo off
277
278:: Cleanup
279cd .. & rd /s/q foobar
280
281
282:: FOR /L - Does not stop directly. It continues looping until the end
283:: but does not execute its body code. This can cause problems e.g. for
284:: infinite loops "for /l %a in () do ( ... )" that are exited by EXIT /B,
285:: since the body code stops being executed, but the loop itself continues
286:: running forever.
287echo --- FOR /L
288@echo on
289for /l %%A in (1,1,10) do (
290    set Number=%%A
291    if %%A==5 goto :out_of_loop_2c
292)
293echo Unexpected FOR echo 2c^^!
294:out_of_loop_2c
295echo Out of FOR 2c, number is %Number%
296@echo off
297
298
299:: FOR /F - Stops directly.
300echo --- FOR /F
301@echo on
302for %%T in ( "1:2:3" "4:5:6:7" "8:9:10" ) do (
303   set "pc=%%~T"
304   for /f "delims=" %%A in (^"!pc::^=^
305% New line %
306!^") do (
307
308    set Number=%%A
309    if %%A==5 goto :out_of_loop_2d
310)
311)
312echo Unexpected FOR echo 2d^^!
313:out_of_loop_2d
314echo Out of FOR 2d, number is %Number%
315@echo off
316
317
318
319:: Testing CALL within IF
320echo --------- Testing CALL within IF ---------
321if 1==1 (
322    call :out_of_if_1 123
323    echo Success IF echo 1
324)
325goto :continue_3
326:out_of_if_1
327echo Out of IF CALL from %0, number is %1
328:: We exit this CALL invocation
329goto :EOF
330:continue_3
331
332
333:: Testing GOTO within IF
334echo --------- Testing GOTO within IF ---------
335if 1==1 (
336    goto :out_of_if_2
337    echo Unexpected IF echo 2a^^!
338)
339echo Unexpected IF echo 2b^^!
340:out_of_if_2
341echo Out of IF ok
342
343:: Same, but with line-continuation at the closing parenthesis of the IF block.
344if 1==1 (
345:labelA
346    echo A
347) ^
348else (
349:labelB
350    echo B
351    goto :continue
352)
353:: We are jumping inside the IF, whose block will be interpreted as
354:: separate commands; thus we will also run the :labelB block as well.
355goto :labelA
356
357
358::
359:: Next suite of tests.
360::
361:continue
362
363:: Testing EXIT within IF
364echo --------- Testing EXIT within IF ---------
365
366:: Use a CALL context, and we will only check EXIT /B.
367call :doExitIfTest 1
368call :doExitIfTest 2
369goto :finished
370
371:doExitIfTest
372if %1==1 (
373    echo First block
374    exit /b
375    echo Unexpected first block^^!
376) else (
377    echo Second block
378    exit /b
379    echo Unexpected second block^^!
380)
381echo You won't see this^^!
382exit /b
383
384
385
386::
387:: Finished!
388::
389:finished
390echo --------- Finished  --------------
391goto :EOF
392
393:: Subroutine to set errorlevel and return
394:: in windows nt 4.0, this always sets errorlevel 1, since /b isn't supported
395:setError
396exit /B %1
397:: This line runs under cmd in windows NT 4, but not in more modern versions.
398