Sweden-Number/programs/cmd/tests/test_builtins.cmd

1576 lines
36 KiB
Batchfile

echo Tests for cmd's builtin commands
@echo on
echo ------------ Testing 'echo' [ON] ------------
echo word
echo 'singlequotedword'
echo "doublequotedword"
@echo at-echoed-word
echo "/?"
echo.
echo .
echo.word
echo .word
echo:
echo :
echo:word
echo :word
echo off now
echo word@space@
echo word@space@@space@
echo word
echo@tab@word
echo@tab@word @tab@
echo@tab@word@tab@@space@
@tab@echo word
echo @tab@word
echo @tab@word
echo@tab@@tab@word
echo @tab@ on @space@
@echo off
echo off@tab@@space@
echo ------------ Testing 'echo' [OFF] ------------
echo word
echo 'singlequotedword'
echo "doublequotedword"
@echo at-echoed-word
echo "/?"
echo.
echo .
echo.word
echo .word
echo:
echo :
echo:word
echo :word
echo on again
echo word@space@
echo word@space@@space@
echo word
echo@tab@word
echo@tab@word @tab@
echo@tab@word@tab@@space@
@tab@echo word
echo @tab@word
echo @tab@word
echo@tab@@tab@word
echo ------------ Testing mixed echo modes ------------
echo @echo on> mixedEchoModes.cmd
echo if 1==1 echo foo>> mixedEchoModes.cmd
echo if 1==1 @echo bar>> mixedEchoModes.cmd
echo @echo off>> mixedEchoModes.cmd
echo if 1==1 echo foo2>> mixedEchoModes.cmd
echo if 1==1 @echo bar2>> mixedEchoModes.cmd
type mixedEchoModes.cmd
cmd /c mixedEchoModes.cmd
del mixedEchoModes.cmd
echo ------------ Testing rem ------------
rem Hello
rem Hello
rem Hello || foo
rem echo lol
rem echo foo & echo bar
rem @tab@ Hello
rem@tab@ Hello
rem@tab@echo foo & echo bar
@echo on
rem Hello
rem Hello
rem Hello || foo
rem echo lol
rem echo foo & echo bar
rem @tab@ Hello
rem@tab@ Hello
rem@tab@echo foo & echo bar
@echo off
echo ------------ Testing redirection operators ------------
mkdir foobar & cd foobar
echo --- stdout redirection
echo foo>foo
type foo
echo foo 1> foo
type foo
echo foo@tab@1> foo
type foo
echo foo 1>@tab@foo
type foo
echo foo@tab@1>@tab@foo
type foo
echo foo7 7> foo
type foo
echo foo9 9> foo
type foo
echo foo1> foo
type foo
echo foo11> foo
type foo
echo foo12> foo
type foo
del foo
echo1>foo
type foo
echo --- stdout appending
echo foo>foo
echo foo >>foo
type foo
del foo
echo foob >> foo
type foo
echo fooc 1>>foo
type foo
echo food1>>foo
type foo
echo food2>>foo
type foo
del foo
echo food21>>foo
type foo
del foo
echo foo> foo
echo foo7 7>> foo || (echo not supported & del foo)
if exist foo (type foo) else echo not supported
echo --- redirections within IF statements
if 1==1 echo foo1>bar
type bar & del bar
echo -----
if 1==1 (echo foo2>bar) else echo baz2>bar
type bar & del bar
if 1==1 (echo foo3) else echo baz3>bar
type bar || echo file does not exist, ok
if 1==1 (echo foo4>bar) else echo baz4>bar
type bar & del bar
if 1==0 (echo foo5>bar) else echo baz5>bar
type bar & del bar
if 1==0 (echo foo6) else echo baz6 1>bar
type bar & del bar
if 1==0 (echo foo7 1>bar) else echo baz7>bar
type bar & del bar
if 1==0 (echo foo8 1>bar) else echo baz8>bak
type bak
if 1==1 (echo foo>bar & echo baz)
type bar
if 1==1 (
echo foo>bar
echo baz
)
type bar
(if 1==1 (echo A) else echo B) > C
type C
(if 1==0 (echo A) else echo B) > C
type C
(if 1==0 (echo A > B) else echo C)
cd .. & rd /s/q foobar
echo ------------ Testing circumflex escape character ------------
rem Using something like "echo foo^" asks for an additional char after a "More?" prompt on the following line; it's not possible to currently test that non-interactively
echo ^hell^o, world
echo hell^o, world
echo hell^^o, world
echo hell^^^o, world
mkdir foobar
echo baz> foobar\baz
type foobar\baz
type foobar^\baz
rd /s/q foobar
echo foo ^| echo bar
echo foo ^& echo bar
call :setError 0
echo bak ^&& echo baz 2> nul
echo %ErrorLevel%
echo foo ^> foo
echo ^<> foo
type foo
del foo
set FOO=oof
echo ff^%FOO%
set FOO=bar ^| baz
set FOO
rem FIXME: echoing %FOO% gives an error (baz not recognized) but prematurely
rem exits the script on windows; redirecting stdout and/or stderr doesn't help
echo %ErrorLevel%
call :setError 0
set FOO=bar ^^^| baz
set FOO
echo %FOO%
echo %ErrorLevel%
set FOO=
echo ------------ Testing 'set' ------------
call :setError 0
set FOOBAR 2> nul > nul
echo %ErrorLevel%
set FOOBAR = baz
echo %ErrorLevel%
echo %FOOBAR%FOOBAR not defined
echo %FOOBAR %
set FOOBAR 2> nul
set FOOBAR = baz2
echo %ErrorLevel%
echo %fOObAr %
set FOOBAR= bar
echo %ErrorLevel%
echo %FOOBAR%
set FOO
set FOOBAR=
set FOOB
echo %FOOBAR%FOOBAR not defined
set FOOBAR =
set FOOBA 2> nul > nul
echo %ErrorLevel%
set FOO=bar
echo %FOO%
set FOO=foo
set BAR=bar
echo %FOO%%BAR%
set BAR=
set FOO=
set FOO=%FOO%
echo %FOO%FOO not defined
set BAZ%=bazbaz
set BA
echo %BAZ%%
set BAZ%=
echo set "FOO=bar" should not include the quotes in the variable value
set "FOO=bar"
echo %FOO%
set@tab@FOO=foo
echo %FOO%
set@tab@FOO=
echo '%FOO%'
set FOO=foo@space@
echo '%FOO%'
set FOO=foo@tab@
echo '%FOO%'
set FOO=
echo ------------ Testing variable expansion ------------
call :setError 0
echo ~dp0 should be directory containing batch file
echo %~dp0
mkdir dummydir
cd dummydir
echo %~dp0
cd ..
rmdir dummydir
echo CD value %CD%
echo %%
echo P%
echo %P
echo %UNKNOWN%S
echo P%UNKNOWN%
echo P%UNKNOWN%S
echo %ERRORLEVEL
echo %ERRORLEVEL%
echo %ERRORLEVEL%%ERRORLEVEL%
echo %ERRORLEVEL%ERRORLEVEL%
echo %ERRORLEVEL%%
echo %ERRORLEVEL%%%
echo P%ERRORLEVEL%
echo %ERRORLEVEL%S
echo P%ERRORLEVEL%S
echo ------------ Testing variable substrings ------------
set VAR=qwerty
echo %VAR:~0,1%
echo %VAR:~0,3%
echo %VAR:~2,2%
echo '%VAR:~-2,3%'
echo '%VAR:~-2,1%'
echo %VAR:~2,-1%
echo %VAR:~2,-3%
echo '%VAR:~-2,-4%'
echo %VAR:~-3,-2%
set VAR=
echo ------------ Testing variable substitution ------------
echo --- in FOR variables
for %%i in ("A B" C) do echo %%i
rem quotes removal
for %%i in ("A B" C) do echo '%%~i'
rem fully qualified path
for %%f in ("C D" E) do echo %%~ff
rem drive letter
for %%i in ("F G" H) do echo %%~di
rem path
for %%d in ("I J" K) do echo %%~pd
rem filename
for %%i in ("L M" N) do echo %%~ni
rem file extension
for %%i in ("O. P.OOL" Q.TABC hello) do echo '%%~xi'
rem path with short path names
for %%I in ("R S" T ABCDEFGHIJK.LMNOP) do echo '%%~sI'
rem file attribute
for %%i in ("U V" W) do echo '%%~ai'
echo foo> foo
for %%i in (foo) do echo '%%~ai'
del foo
rem file date/time
rem Not fully testable, until we can grep dir's output to get foo's creation time in an envvar...
for %%i in ("a b" c) do echo '%%~ti'
rem file size
rem Similar issues as above
for %%i in ("a b" c) do echo '%%~zi'
rem combined options
for %%i in ("d e" f) do echo %%~dpi
for %%i in ("g h" i) do echo %%~sdi
for %%i in ("g h" i) do echo %%~dsi
for %%i in ("j k" l.eh) do echo '%%~xsi'
echo --- in parameters
for %%i in ("A B" C) do call :echoFun %%i
rem quotes removal
for %%i in ("A B" C) do call :echoFunQ %%i
rem fully qualified path
for %%f in ("C D" E) do call :echoFunF %%f
rem drive letter
for %%i in ("F G" H) do call :echoFunD %%i
rem path
for %%d in ("I J" K) do call :echoFunP %%d
rem filename
for %%i in ("L M" N) do call :echoFunN %%i
rem file extension
for %%i in ("O. P.OOL" Q.TABC hello) do call :echoFunX %%i
rem path with short path names
for %%I in ("R S" T ABCDEFGHIJK.LMNOP) do call :echoFunS %%I
rem NT4 aborts whole script execution when encountering ~a, ~t and ~z substitutions, preventing full testing
rem combined options
for %%i in ("d e" f) do call :echoFunDP %%i
for %%i in ("g h" i) do call :echoFunSD %%i
for %%i in ("g h" i) do call :echoFunDS %%i
for %%i in ("j k" l.eh) do call :echoFunXS %%i
goto :endEchoFuns
:echoFun
echo %1
goto :eof
:echoFunQ
echo '%~1'
goto :eof
:echoFunF
echo %~f1
goto :eof
:echoFunD
echo %~d1
goto :eof
:echoFunP
echo %~p1
goto :eof
:echoFunN
echo %~n1
goto :eof
:echoFunX
echo '%~x1'
goto :eof
:echoFunS
rem some NT4 workaround
set VAR='%~s1'
echo %VAR%
set VAR=
goto :eof
:echoFunDP
echo %~dp1
goto :eof
:echoFunSD
echo %~sd1
goto :eof
:echoFunDS
echo %~ds1
goto :eof
:echoFunXS
echo '%~xs1'
goto :eof
:endEchoFuns
echo ------------ Testing variable delayed expansion ------------
rem NT4 doesn't support this
echo --- default mode (load-time expansion)
set FOO=foo
echo %FOO%
echo !FOO!
if %FOO% == foo (
set FOO=bar
if %FOO% == bar (echo bar) else echo foo
)
set FOO=foo
if %FOO% == foo (
set FOO=bar
if !FOO! == bar (echo bar) else echo foo
)
echo --- runtime (delayed) expansion mode
setlocal EnableDelayedExpansion
set FOO=foo
echo %FOO%
echo !FOO!
if %FOO% == foo (
set FOO=bar
if %FOO% == bar (echo bar) else echo foo
)
set FOO=foo
if %FOO% == foo (
set FOO=bar
if !FOO! == bar (echo bar) else echo foo
)
echo %ErrorLevel%
setlocal DisableDelayedExpansion
echo %ErrorLevel%
set FOO=foo
echo %FOO%
echo !FOO!
set FOO=
echo --- using /V cmd flag
echo @echo off> tmp.cmd
echo set FOO=foo>> tmp.cmd
echo echo %%FOO%%>> tmp.cmd
echo echo !FOO!>> tmp.cmd
echo set FOO=>> tmp.cmd
cmd /V:ON /C tmp.cmd
cmd /V:OfF /C tmp.cmd
del tmp.cmd
echo ------------ Testing conditional execution ------------
echo --- unconditional ampersand
call :setError 123 & echo foo1
echo bar2 & echo foo2
mkdir foobar & cd foobar
echo > foobazbar
cd .. & rd /s/q foobar
if exist foobazbar (
echo foobar not deleted!
cd ..
rd /s/q foobar
) else echo foobar deleted
echo --- on success conditional and
call :setError 456 && echo foo3 > foo3
if exist foo3 (
echo foo3 created
del foo3
) else echo foo3 not created
echo bar4 && echo foo4
echo --- on failure conditional or
call :setError 789 || echo foo5
echo foo6 || echo bar6 > bar6
if exist bar6 (
echo bar6 created
del bar6
)
echo ------------ Testing cd ------------
mkdir foobar
cd foobar
echo blabla > singleFile
dir /b
echo Current dir: %CD%
cd
cd ..
cd
cd foobar@space@
cd
cd ..
cd
cd @space@foobar
cd
cd..
cd
cd foobar
cd..@space@
cd
if not exist foobar (cd ..)
cd foobar
cd@tab@..@tab@@space@@tab@
cd
if not exist foobar (cd ..)
cd foobar
mkdir "bar bak"
cd "bar bak"
cd
cd ..
cd bar bak
cd
cd "bar bak@space@"@tab@@space@
cd
cd ..\..
cd
rd /Q/s foobar
mkdir foobar
cd /d@tab@foobar
cd
cd ..
rd /q/s foobar
echo ------------ Testing type ------------
echo bar> foobaz
@echo on
type foobaz
echo ---
@echo off
type foobaz@tab@
echo ---
del foobaz
echo ------------ Testing NUL ------------
md foobar & cd foobar
rem NUL file (non) creation + case insensitivity
rem Note: "if exist" does not work with NUL, so to check for file existence we use a kludgy workaround
echo > bar
echo foo > NUL
dir /b /a-d
echo foo > nul
dir /b /a-d
echo foo > NuL
@tab@dir /b@tab@/a-d
del bar
rem NUL not special everywhere
call :setError 123
echo NUL> foo
if not exist foo (echo foo should have been created) else (
type foo
del foo
)
rem Empty file creation
copy nul foo > nul
if exist foo (
echo foo created
del foo
type foo
) else (
echo ***
)
cd .. & rd foobar
echo ------------ Testing if/else ------------
echo if/else should work with blocks
if 0 == 0 (
echo if seems to work
) else (
echo if seems to be broken
)
if 1 == 0 (
echo else seems to be broken
) else (
echo else seems to work
)
if /c==/c (
echo if seems not to detect /c as parameter
) else (
echo parameter detection seems to be broken
)
echo Testing case sensitivity with and without /i option
if bar==BAR echo if does not default to case sensitivity
if not bar==BAR echo if seems to default to case sensitivity
if /i foo==FOO echo if /i seems to work
if /i not foo==FOO echo if /i seems to be broken
if /I foo==FOO echo if /I seems to work
if /I not foo==FOO echo if /I seems to be broken
echo Testing string comparisons
if abc == abc (echo equal) else echo non equal
if abc =="abc" (echo equal) else echo non equal
if "abc"== abc (echo equal) else echo non equal
if "abc"== "abc" (echo equal) else echo non equal
echo Testing tabs handling
if@tab@1==1 echo doom
if @tab@1==1 echo doom
if 1==1 (echo doom) else@tab@echo quake
if@tab@not @tab@1==@tab@0 @tab@echo lol
if 1==0@tab@(echo doom) else echo quake
if 1==0 (echo doom)@tab@else echo quake
if 1==0 (echo doom) else@tab@echo quake
echo ------------ Testing for ------------
echo --- plain FOR
for %%i in (A B C) do echo %%i
for %%i in (A B C) do echo %%I
for %%i in (A B C) do echo %%j
for %%i in (A B C) do call :forTestFun1 %%i
for %%i in (1,4,1) do echo %%i
for %%i in (A, B,C) do echo %%i
for %%i in (X) do echo %%i
for@tab@%%i in (X2) do echo %%i
for %%i in@tab@(X3) do echo %%i
for %%i in (@tab@ foo@tab@) do echo %%i
for@tab@ %%i in@tab@(@tab@M) do echo %%i
for %%i@tab@in (X)@tab@do@tab@echo %%i
for@tab@ %%j in@tab@(@tab@M, N, O@tab@) do echo %%j
for %%i in (`echo A B`) do echo %%i
for %%i in ('echo A B') do echo %%i
for %%i in ("echo A B") do echo %%i
for %%i in ("A B" C) do echo %%i
goto :endForTestFun1
:forTestFun1
echo %1
goto :eof
:endForTestFun1
echo --- imbricated FORs
for %%i in (X) do (
for %%j in (Y) do (
echo %%i %%j))
for %%i in (X) do (
for %%I in (Y) do (
echo %%i %%I))
for %%i in (A B) do (
for %%j in (C D) do (
echo %%i %%j))
for %%i in (A B) do (
for %%j in (C D) do (
call :forTestFun2 %%i %%j ))
goto :endForTestFun2
:forTestFun2
echo %1 %2
goto :eof
:endForTestFun2
mkdir foobar & cd foobar
mkdir foo
mkdir bar
mkdir baz
echo > bazbaz
echo --- basic wildcards
for %%i in (ba*) do echo %%i
echo --- for /d
for /d %%i in (baz foo bar) do echo %%i
rem FIXME for /d incorrectly parses when wildcards are used
rem for /d %%i in (bazb*) do echo %%i
rem FIXME can't test wildcard expansion here since it's listed in directory
rem order, and not in alphabetic order.
rem Proper testing would need a currently missing "sort" program implementation.
rem for /d %%i in (ba*) do echo %%i>> tmp
rem sort < tmp
rem del tmp
rem for /d %%i in (?a*) do echo %%i>> tmp
rem sort < tmp
rem del tmp
rem for /d %%i in (*) do echo %%i>> tmp
rem sort < tmp
rem del tmp
cd .. & rd /s/Q foobar
echo --- for /L
rem Some cases loop forever writing 0s, like e.g. (1,0,1), (1,a,3) or (a,b,c); those can't be tested here
for /L %%i in (1,2,0) do echo %%i
for@tab@/L %%i in (1,2,0) do echo %%i
for /L %%i in (1,2,6) do echo %%i
for /l %%i in (1 ,2,6) do echo %%i
for /L %%i in (a,2,3) do echo %%i
for /L %%i in (1,2,-1) do echo %%i
for /L %%i in (-4,-1,-1) do echo %%i
for /L %%i in (1,-2,-2) do echo %%i
for /L %%i in (1,2,a) do echo %%i
echo ErrorLevel %ErrorLevel%
for /L %%i in (1,a,b) do echo %%i
echo ErrorLevel %ErrorLevel%
rem FIXME: following test cases cannot be currently tested due to an inconsistent/buggy 'for /L' parsing.
rem for /L %%i in (a,2,b) do echo %%i
rem for /L %%i in (1,1,1) do echo %%i
rem for /L %%i in (1,-2,-1) do echo %%i
rem for /L %%i in (-1,-1,-1) do echo %%i
rem for /L %%i in (1,2, 3) do echo %%i
echo --- for /a
rem No output when using "set expr" syntax, unless in interactive mode
rem Need to use "set envvar=expr" to use in a batch script
echo ------ individual operations
set var=0
set /a var=1 +2 & echo %var%
set /a var=1 +-2 & echo %var%
set /a var=1 --2 & echo %var%
set /a var=2* 3 & echo %var%
set /a var=-2* -5 & echo %var%
set /a var=12/3 & echo %var%
set /a var=13/3 & echo %var%
set /a var=-13/3 & echo %var%
rem FIXME Divide by zero should return an error, but error messages cannot be tested with current infrastructure
set /a var=5 %% 5 & echo %var%
set /a var=5 %% 3 & echo %var%
set /a var=5 %% -3 & echo %var%
set /a var=-5 %% -3 & echo %var%
set /a var=1 ^<^< 0 & echo %var%
set /a var=1 ^<^< 2 & echo %var%
set /a var=1 ^<^< -2 & echo %var%
set /a var=-1 ^<^< -2 & echo %var%
set /a var=-1 ^<^< 2 & echo %var%
set /a var=9 ^>^> 0 & echo %var%
set /a var=9 ^>^> 2 & echo %var%
set /a var=9 ^>^> -2 & echo %var%
set /a var=-9 ^>^> -2 & echo %var%
set /a var=-9 ^>^> 2 & echo %var%
set /a var=5 ^& 0 & echo %var%
set /a var=5 ^& 1 & echo %var%
set /a var=5 ^& 3 & echo %var%
set /a var=5 ^& 4 & echo %var%
set /a var=5 ^& 1 & echo %var%
set /a var=5 ^| 0 & echo %var%
set /a var=5 ^| 1 & echo %var%
set /a var=5 ^| 3 & echo %var%
set /a var=5 ^| 4 & echo %var%
set /a var=5 ^| 1 & echo %var%
set /a var=5 ^^ 0 & echo %var%
set /a var=5 ^^ 1 & echo %var%
set /a var=5 ^^ 3 & echo %var%
set /a var=5 ^^ 4 & echo %var%
set /a var=5 ^^ 1 & echo %var%
echo ------ precedence and grouping
set /a var=4 + 2*3 & echo %var%
set /a var=(4+2)*3 & echo %var%
set /a var=4 * 3/5 & echo %var%
set /a var=(4 * 3)/5 & echo %var%
set /a var=4 * 5 %% 4 & echo %var%
set /a var=4 * (5 %% 4) & echo %var%
set /a var=3 %% (5 + 8 %% 3 ^^ 2) & echo %var%
set /a var=3 %% (5 + 8 %% 3 ^^ -2) & echo %var%
echo ------ octal and hexadecimal
set /a var=0xf + 3 & echo %var%
set /a var=0xF + 3 & echo %var%
set /a var=015 + 2 & echo %var%
set /a var=3, 8+3,0 & echo %var%
echo ------ variables
set /a var=foo=3, foo+1 & echo %var%
if defined foo (echo %foo%) else (
echo foo not defined
)
set /a var=foo=3, foo+=1 & echo %var%
set /a var=foo=3, bar=1, bar+=foo, bar & echo %var%
set /a var=foo*= foo & echo %var%
set /a var=whateverNonExistingVar & echo %var%
set /a var=whateverNonExistingVar + bar & echo %var%
set /a var=foo -= foo + 7 & echo %var%
set /a var=foo /= 3 + 2 & echo %var%
set /a var=foo=5, foo %%=2 & echo %var%
set /a var=foo ^<^<= 2 & echo %var%
set /a var=foo ^>^>= 2 & echo %var%
set /a var=foo ^&= 2 & echo %var%
set /a var=foo=5, foo ^|= 2 & echo %var%
set /a var=foo=5, foo ^^= 2 & echo %var%
set /a var=foo=19, foo %%= 4 + (bar %%= 7) & echo.
set foo=
set bar=
set var=
echo --- for /F
mkdir foobar & cd foobar
echo ------ string argument
for /F %%i in ("a b c") do echo %%i
for /f %%i in ("a ") do echo %%i
for /f %%i in ("a") do echo %%i
fOr /f %%i in (" a") do echo %%i
for /f %%i in (" a ") do echo %%i
echo ------ fileset argument
echo --------- basic blank handling
echo a b c>foo
for /f %%i in (foo) do echo %%i
echo a >foo
for /f %%i in (foo) do echo %%i
echo a>foo
for /f %%i in (foo) do echo %%i
echo a>foo
for /f %%i in (foo) do echo %%i
echo a >foo
for /f %%i in (foo) do echo %%i
echo. > foo
for /f %%i in (foo) do echo %%i
echo. >> foo
echo b > foo
for /f %%i in (foo) do echo %%i
echo --------- multi-line with empty lines
echo a Z f> foo
echo. >> foo
echo.>> foo
echo b bC>> foo
echo c>> foo
echo. >> foo
for /f %%b in (foo) do echo %%b
echo --------- multiple files
echo q w > bar
echo.>> bar
echo kkk>>bar
for /f %%k in (foo bar) do echo %%k
for /f %%k in (bar foo) do echo %%k
rem echo ------ command argument
rem Not implemented on NT4
rem FIXME: Not testable right now in wine: not implemented and would need
rem preliminary grep-like program implementation (e.g. like findstr or fc) even
rem for a simple todo_wine test
rem (for /f "usebackq" %%i in (`echo z a b`) do echo %%i) || echo not supported
rem (for /f usebackq %%i in (`echo z a b`) do echo %%i) || echo not supported
echo ------ eol option
for /f "eol=@" %%i in (" ad") do echo %%i
for /f "eol=@" %%i in (" z@y") do echo %%i
for /f "eol=|" %%i in ("a|d") do echo %%i
for /f "eol=@" %%i in ("@y") do echo %%i > output_file
if not exist output_file (echo no output) else (del output_file)
for /f "eol==" %%i in ("=y") do echo %%i > output_file
if not exist output_file (echo no output) else (del output_file)
echo ------ delims option
for /f "delims=|" %%i in ("a|d") do echo %%i
for /f "delims=|" %%i in ("a |d") do echo %%i
for /f "delims=|" %%i in ("a d|") do echo %%i
for /f "delims=| " %%i in ("a d|") do echo %%i
for /f "delims==" %%i in ("C r=d|") do echo %%i
for /f "delims=" %%i in ("foo bar baz") do echo %%i
for /f "delims=" %%i in ("c:\foo bar baz\..") do echo %%~fi
echo ------ skip option
echo a > foo
echo b >> foo
echo c >> foo
for /f "skip=2" %%i in (foo) do echo %%i
for /f "skip=3" %%i in (foo) do echo %%i > output_file
if not exist output_file (echo no output) else (del output_file)
for /f "skip=4" %%i in (foo) do echo %%i > output_file
if not exist output_file (echo no output) else (del output_file)
cd ..
rd /s/q foobar
echo ------------ Testing del /a ------------
del /f/q *.test > nul
echo r > r.test
attrib +r r.test
echo not-r > not-r.test
if not exist not-r.test echo not-r.test not found before delete, bad
del /a:-r *.test
if not exist not-r.test echo not-r.test not found after delete, good
if not exist r.test echo r.test not found before delete, bad
if exist r.test echo r.test found before delete, good
del /a:r *.test
if not exist r.test echo r.test not found after delete, good
if exist r.test echo r.test found after delete, bad
echo ------------ Testing del /q ------------
mkdir del_q_dir
cd del_q_dir
echo abc > file1
echo abc > file2.dat
rem If /q doesn't work, cmd will prompt and the test case should hang
del /q * > nul
for %%a in (1 2.dat) do if exist file%%a echo del /q * failed on file%%a
for %%a in (1 2.dat) do if not exist file%%a echo del /q * succeeded on file%%a
cd ..
rmdir del_q_dir
echo ------------ Testing del /s ------------
mkdir "foo bar"
cd "foo bar"
mkdir "foo:"
echo hi > file1.dat
echo there > file2.dat
echo bub > file3.dat
echo bye > "file with spaces.dat"
cd ..
del /s file1.dat > nul
del file2.dat /s > nul
del "file3.dat" /s > nul
del "file with spaces.dat" /s > nul
cd "foo bar"
for %%f in (1 2 3) do if exist file%%f.dat echo Del /s failed on file%%f
for %%f in (1 2 3) do if exist file%%f.dat del file%%f.dat
if exist "file with spaces.dat" echo Del /s failed on "file with spaces.dat"
if exist "file with spaces.dat" del "file with spaces.dat"
rmdir "foo:"
cd ..
rmdir "foo bar"
echo ------------ Testing rename ------------
mkdir foobar & cd foobar
echo --- ren and rename are synonymous
echo > foo
rename foo bar
if exist foo echo foo should be renamed!
if exist bar echo foo renamed to bar
ren bar foo
if exist bar echo bar should be renamed!
if exist foo echo bar renamed to foo
echo --- name collision
echo foo>foo
echo bar>bar
ren foo bar 2> nul
type foo
type bar
rem no-op
ren foo foo
mkdir baz
ren foo baz\abc
echo --- rename read-only files
echo > file1
attrib +r file1
ren file1 file2
if not exist file1 (
if exist file2 (
echo read-only file renamed
)
) else (
echo read-only file not renamed!
)
echo --- rename directories
mkdir rep1
ren rep1 rep2
if not exist rep1 (
if exist rep2 (
echo dir renamed
)
)
attrib +r rep2
ren rep2 rep1
if not exist rep2 (
if exist rep1 (
echo read-only dir renamed
)
)
echo --- rename in other directory
if not exist baz\abc (
echo rename impossible in other directory
if exist foo echo original file still present
) else (
echo shouldn't rename in other directory!
if not exist foo echo original file not present anymore
)
cd .. & rd /s/q foobar
echo ------------ Testing move ------------
mkdir foobar & cd foobar
echo --- file move
echo >foo
move foo bar > nul 2>&1
if not exist foo (
if exist bar (
echo file move succeeded
)
)
echo bar>bar
echo baz> baz
move /Y bar baz > nul 2>&1
if not exist bar (
if exist baz (
echo file move with overwrite succeeded
)
) else (
echo file overwrite impossible!
del bar
)
type baz
attrib +r baz
move baz bazro > nul 2>&1
if not exist baz (
if exist bazro (
echo read-only files are moveable
move bazro baz > nul 2>&1
)
) else (
echo read-only file not moved!
)
attrib -r baz
mkdir rep
move baz rep > nul 2>&1
if not exist baz (
if exist rep\baz (
echo file moved in subdirectory
)
)
call :setError 0
move rep\baz . > nul 2>&1
move /Y baz baz > nul 2>&1
if errorlevel 1 (
echo moving a file to itself should be a no-op!
) else (
echo moving a file to itself is a no-op
)
echo ErrorLevel: %ErrorLevel%
call :setError 0
del baz
echo --- directory move
mkdir foo\bar
mkdir baz
echo baz2>baz\baz2
move baz foo\bar > nul 2>&1
if not exist baz (
if exist foo\bar\baz\baz2 (
echo simple directory move succeeded
)
)
call :setError 0
mkdir baz
move baz baz > nul 2>&1
echo moving a directory to itself gives error; errlevel %ErrorLevel%
echo ------ dir in dir move
rd /s/q foo
mkdir foo bar
echo foo2>foo\foo2
echo bar2>bar\bar2
move foo bar > nul 2>&1
if not exist foo (
if exist bar (
dir /b /ad bar
dir /b /a-d bar
dir /b bar\foo
)
)
cd .. & rd /s/q foobar
echo ------------ Testing mkdir ------------
call :setError 0
echo --- md and mkdir are synonymous
mkdir foobar
echo %ErrorLevel%
rmdir foobar
md foobar
echo %ErrorLevel%
rmdir foobar
echo --- creating an already existing directory/file must fail
mkdir foobar
md foobar
echo %ErrorLevel%
rmdir foobar
echo > foobar
mkdir foobar
echo %ErrorLevel%
del foobar
echo --- multilevel path creation
mkdir foo
echo %ErrorLevel%
mkdir foo\bar\baz
echo %ErrorLevel%
cd foo
echo %ErrorLevel%
cd bar
echo %ErrorLevel%
cd baz
echo %ErrorLevel%
echo > ..\..\bar2
mkdir ..\..\..\foo\bar2
echo %ErrorLevel%
del ..\..\bar2
mkdir ..\..\..\foo\bar2
echo %ErrorLevel%
rmdir ..\..\..\foo\bar2
cd ..
rmdir baz
cd ..
rmdir bar
cd ..
rmdir foo
echo %ErrorLevel%
echo --- trailing backslashes
mkdir foo\\\\
echo %ErrorLevel%
if exist foo (rmdir foo & echo dir created
) else ( echo dir not created )
echo %ErrorLevel%
echo --- invalid chars
mkdir ?
echo mkdir ? gives errorlevel %ErrorLevel%
call :setError 0
mkdir ?\foo
echo mkdir ?\foo gives errorlevel %ErrorLevel%
call :setError 0
mkdir foo\?
echo mkdir foo\? gives errorlevel %ErrorLevel%
if exist foo (rmdir foo & echo ok, foo created
) else ( echo foo not created )
call :setError 0
mkdir foo\bar\?
echo mkdir foo\bar\? gives errorlevel %ErrorLevel%
call :setError 0
if not exist foo (
echo bad, foo not created
) else (
cd foo
if exist bar (
echo ok, foo\bar created
rmdir bar
)
cd ..
rmdir foo
)
echo --- multiple directories at once
mkdir foobaz & cd foobaz
mkdir foo bar\baz foobar
if exist foo (echo foo created) else echo foo not created!
if exist bar (echo bar created) else echo bar not created!
if exist foobar (echo foobar created) else echo foobar not created!
if exist bar\baz (echo bar\baz created) else echo bar\baz not created!
cd .. & rd /s/q foobaz
call :setError 0
mkdir foo\*
echo mkdir foo\* errorlevel %ErrorLevel%
if exist foo (rmdir foo & echo ok, foo created
) else ( echo bad, foo not created )
echo ------------ Testing rmdir ------------
call :setError 0
rem rd and rmdir are synonymous
mkdir foobar
rmdir foobar
echo %ErrorLevel%
if not exist foobar echo dir removed
mkdir foobar
rd foobar
echo %ErrorLevel%
if not exist foobar echo dir removed
rem Removing nonexistent directory
rmdir foobar
echo %ErrorLevel%
rem Removing single-level directories
echo > foo
rmdir foo
echo %ErrorLevel%
if exist foo echo file not removed
del foo
mkdir foo
echo > foo\bar
rmdir foo
echo %ErrorLevel%
if exist foo echo non-empty dir not removed
del foo\bar
mkdir foo\bar
rmdir foo
echo %ErrorLevel%
if exist foo echo non-empty dir not removed
rmdir foo\bar
rmdir foo
rem Recursive rmdir
mkdir foo\bar\baz
rmdir /s /Q foo
if not exist foo (
echo recursive rmdir succeeded
) else (
rd foo\bar\baz
rd foo\bar
rd foo
)
mkdir foo\bar\baz
echo foo > foo\bar\brol
rmdir /s /Q foo
if not exist foo (
echo recursive rmdir succeeded
) else (
rd foo\bar\baz
del foo\bar\brol
rd foo\bar
rd foo
)
rem multiples directories at once
mkdir foobaz & cd foobaz
mkdir foo
mkdir bar\baz
mkdir foobar
rd /s/q foo bar foobar
if not exist foo (echo foo removed) else echo foo not removed!
if not exist bar (echo bar removed) else echo bar not removed!
if not exist foobar (echo foobar removed) else echo foobar not removed!
if not exist bar\baz (echo bar\baz removed) else echo bar\baz not removed!
cd .. & rd /s/q foobaz
echo ------------ Testing pushd/popd ------------
cd
echo --- popd is no-op when dir stack is empty
popd
cd
echo --- pushing non-existing dir
pushd foobar
cd
echo --- basic behaviour
mkdir foobar\baz
pushd foobar
cd
popd
cd
pushd foobar
pushd baz
cd
popd
cd
pushd baz
popd
cd
popd
cd
pushd .
cd foobar\baz
pushd ..
cd
popd
popd
cd
rd /s/q foobar
echo ------------ Testing attrib ------------
rem FIXME Add tests for archive, hidden and system attributes + mixed attributes modifications
mkdir foobar & cd foobar
echo foo original contents> foo
attrib foo
echo > bar
echo --- read-only attribute
rem Read-only files cannot be altered or deleted, unless forced
attrib +R foo
attrib foo
dir /Ar /B
echo bar>> foo
type foo
del foo > NUL 2>&1
if exist foo (
echo Read-only file not deleted
) else (
echo Should not delete read-only file!
)
del /F foo
if not exist foo (
echo Read-only file forcibly deleted
) else (
echo Should delete read-only file with del /F!
attrib -r foo
del foo
)
cd .. & rd /s/q foobar
echo --- recursive behaviour
mkdir foobar\baz & cd foobar
echo > level1
echo > whatever
echo > baz\level2
attrib baz\level2
cd ..
attrib +R l*vel? /S > nul 2>&1
cd foobar
attrib level1
attrib baz\level2
echo > bar
attrib bar
cd .. & rd /s/q foobar
echo --- folders processing
mkdir foobar
attrib foobar
cd foobar
mkdir baz
echo toto> baz\toto
attrib +r baz /s /d > nul 2>&1
attrib baz
attrib baz\toto
echo lulu>>baz\toto
type baz\toto
echo > baz\lala
rem Oddly windows allows file creation in a read-only directory...
if exist baz\lala (echo file created in read-only dir) else echo file not created
cd .. & rd /s/q foobar
echo ------------ Testing assoc ------------
rem FIXME Can't test error messages in the current test system, so we have to use some kludges
rem FIXME Revise once || conditional execution is fixed
mkdir foobar & cd foobar
echo --- setting association
assoc .foo > baz
type baz
echo ---
assoc .foo=bar
assoc .foo
rem association set system-wide
echo @echo off> tmp.cmd
echo echo +++>> tmp.cmd
echo assoc .foo>> tmp.cmd
cmd /c tmp.cmd
echo --- resetting association
assoc .foo=
assoc .foo > baz
type baz
echo ---
rem association removal set system-wide
cmd /c tmp.cmd > baz
type baz
echo ---
cd .. & rd /s/q foobar
echo ------------ Testing ftype ------------
rem FIXME Can't test error messages in the current test system, so we have to use some kludges
rem FIXME Revise once || conditional execution is fixed
mkdir foobar & cd foobar
echo --- setting association
ftype footype> baz
type baz
echo ---
ftype footype=foo_opencmd
assoc .foo=footype
ftype footype
rem association set system-wide
echo @echo off> tmp.cmd
echo echo +++>> tmp.cmd
echo ftype footype>> tmp.cmd
cmd /c tmp.cmd
echo --- resetting association
assoc .foo=
rem Removing a file type association doesn't work on XP due to a bug, so a workaround is needed
setlocal EnableDelayedExpansion
set FOO=original value
ftype footype=
ftype footype > baz
for /F %%i in ('type baz') do (set FOO=buggyXP)
rem Resetting actually works on wine/NT4, but is reported as failing due to the peculiar test (and non-support for EnabledDelayedExpansion)
rem FIXME Revisit once a grep-like program like ftype is implemented
rem (e.g. to check baz's size using dir /b instead)
echo !FOO!
rem cleanup registry
echo REGEDIT4> regCleanup.reg
echo.>> regCleanup.reg
echo [-HKEY_CLASSES_ROOT\footype]>> regCleanup.reg
regedit /s regCleanup.reg
set FOO=
endlocal
cd .. & rd /s/q foobar
echo ------------ Testing CALL ------------
mkdir foobar & cd foobar
echo --- external script
echo echo foo %%1> foo.cmd
call foo
call foo.cmd 8
echo echo %%1 %%2 > foo.cmd
call foo.cmd foo
call foo.cmd foo bar
call foo.cmd foo ""
call foo.cmd "" bar
call foo.cmd foo ''
call foo.cmd '' bar
del foo.cmd
echo --- internal routines
call :testRoutine :testRoutine
goto :endTestRoutine
:testRoutine
echo bar %1
goto :eof
:endTestRoutine
call :testRoutineArgs foo
call :testRoutineArgs foo bar
call :testRoutineArgs foo ""
call :testRoutineArgs "" bar
call :testRoutineArgs foo ''
call :testRoutineArgs '' bar
goto :endTestRoutineArgs
:testRoutineArgs
echo %1 %2
goto :eof
:endTestRoutineArgs
echo --- with builtins
call mkdir foo
echo %ErrorLevel%
if exist foo (echo foo created) else echo foo should exist!
rmdir foo
set FOOBAZ_VAR=foobaz
call echo Should expand %FOOBAZ_VAR%
set FOOBAZ_VAR=
echo>batfile
call dir /b
echo>robinfile
if 1==1 call del batfile
dir /b
if exist batfile echo batfile shouldn't exist
rem ... but not for 'if' or 'for'
call if 1==1 echo bar 2> nul
echo %ErrorLevel%
call :setError 0
call for %%i in (foo bar baz) do echo %%i 2> nul
echo %ErrorLevel%
rem First look for programs in the path before trying a builtin
echo echo non-builtin dir> dir.cmd
call dir /b
cd .. & rd /s/q foobar
echo ------------ Testing SHIFT ------------
call :shiftFun p1 p2 p3 p4 p5
goto :endShiftFun
:shiftFun
echo '%1' '%2' '%3' '%4' '%5'
shift
echo '%1' '%2' '%3' '%4' '%5'
shift@tab@ /1
echo '%1' '%2' '%3' '%4' '%5'
shift /2
echo '%1' '%2' '%3' '%4' '%5'
shift /-1
echo '%1' '%2' '%3' '%4' '%5'
shift /0
echo '%1' '%2' '%3' '%4' '%5'
goto :eof
:endShiftFun
echo ------------ Testing cmd invocation ------------
rem FIXME: only a stub ATM
echo --- a batch file can delete itself
echo del foo.cmd>foo.cmd
cmd /q /c foo.cmd
if not exist foo.cmd (
echo file correctly deleted
) else (
echo file should be deleted!
del foo.cmd
)
echo --- a batch file can alter itself
echo echo bar^>foo.cmd>foo.cmd
cmd /q /c foo.cmd > NUL 2>&1
if exist foo.cmd (
type foo.cmd
del foo.cmd
) else (
echo file not created!
)
echo ------------ Testing setlocal/endlocal ------------
call :setError 0
rem Note: setlocal EnableDelayedExpansion already tested in the variable delayed expansion test section
mkdir foobar & cd foobar
echo --- enable/disable extensions
setlocal DisableEXTensions
echo ErrLev: %ErrorLevel%
endlocal
echo ErrLev: %ErrorLevel%
echo @echo off> tmp.cmd
echo echo ErrLev: %%ErrorLevel%%>> tmp.cmd
rem Enabled by default
cmd /C tmp.cmd
cmd /E:OfF /C tmp.cmd
cmd /e:oN /C tmp.cmd
rem FIXME: creating file before setting envvar value to prevent parsing-time evaluation (due to EnableDelayedExpansion not being implemented/available yet)
echo --- setlocal with corresponding endlocal
echo @echo off> test.cmd
echo echo %%VAR%%>> test.cmd
echo setlocal>> test.cmd
echo set VAR=localval>> test.cmd
echo echo %%VAR%%>> test.cmd
echo endlocal>> test.cmd
echo echo %%VAR%%>> test.cmd
set VAR=globalval
call test.cmd
echo %VAR%
set VAR=
echo --- setlocal with no corresponding endlocal
echo @echo off> test.cmd
echo echo %%VAR%%>> test.cmd
echo setlocal>> test.cmd
echo set VAR=localval>> test.cmd
echo echo %%VAR%%>> test.cmd
set VAR=globalval
call test.cmd
echo %VAR%
set VAR=
cd .. & rd /q/s foobar
echo ------------ Testing Errorlevel ------------
rem WARNING: Do *not* add tests using ErrorLevel after this section
should_not_exist 2> nul > nul
echo %ErrorLevel%
rem nt 4.0 doesn't really support a way of setting errorlevel, so this is weak
rem See http://www.robvanderwoude.com/exit.php
call :setError 1
echo %ErrorLevel%
if errorlevel 2 echo errorlevel too high, bad
if errorlevel 1 echo errorlevel just right, good
if errorlevel 01 echo errorlevel with leading zero just right, good
if errorlevel -1 echo errorlevel with negative number OK
if errorlevel 0x1 echo hexa should not be recognized!
if errorlevel 1a echo invalid error level recognized!
call :setError 0
echo abc%ErrorLevel%def
if errorlevel 1 echo errorlevel nonzero, bad
if not errorlevel 1 echo errorlevel zero, good
if not errorlevel 0x1 echo hexa should not be recognized!
if not errorlevel 1a echo invalid error level recognized!
rem Now verify that setting a real variable hides its magic variable
set errorlevel=7
echo %ErrorLevel% should be 7
if errorlevel 7 echo setting var worked too well, bad
call :setError 3
echo %ErrorLevel% should still be 7
echo ------------ Testing GOTO ------------
if a==a goto dest1
:dest1
echo goto with no leading space worked
if b==b goto dest2
:dest2
echo goto with a leading space worked
if c==c goto dest3
:dest3
echo goto with a leading tab worked
if d==d goto dest4
:dest4@space@
echo goto with a following space worked
echo ------------ Testing combined CALLs/GOTOs ------------
echo @echo off>foo.cmd
echo goto :eof>>foot.cmd
echo :eof>>foot.cmd
echo echo world>>foo.cmd
echo @echo off>foot.cmd
echo echo cheball>>foot.cmd
echo.>>foot.cmd
echo call :bar>>foot.cmd
echo if "%%1"=="deleteMe" (del foot.cmd)>>foot.cmd
echo goto :eof>>foot.cmd
echo.>>foot.cmd
echo :bar>>foot.cmd
echo echo barbare>>foot.cmd
echo goto :eof>>foot.cmd
call foo.cmd
call foot
call :bar
del foo.cmd
rem Script execution stops after the following line
foot deleteMe
call :foo
call :foot
goto :endFuns
:foot
echo foot
:foo
echo foo
goto :eof
:endFuns
:bar
echo bar
call :foo
:baz
echo baz
goto :eof
echo Final message is not output since earlier 'foot' processing stops script execution
echo Do NOT add any tests below this line
echo ------------ Done, jumping to EOF -----------
goto :eof
rem Subroutine to set errorlevel and return
rem in windows nt 4.0, this always sets errorlevel 1, since /b isn't supported
:setError
exit /B %1
rem This line runs under cmd in windows NT 4, but not in more modern versions.