https://git.reactos.org/?p=reactos.git;a=commitdiff;h=4c9d322c688054b74760cd...
commit 4c9d322c688054b74760cde38fc431589a6408f4 Author: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org AuthorDate: Wed Jul 29 22:31:23 2020 +0200 Commit: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org CommitDate: Wed Aug 19 20:36:02 2020 +0200
[CMD_ROSTEST] Add tests for EXIT and CMD returned exit code values. CORE-10495 CORE-13672
See also commits 8cf11060 (r40474), 26ff2c8e and 7bd33ac4.
More information can be also found at: https://stackoverflow.com/a/34987886/13530036 and https://stackoverflow.com/a/34937706/13530036 --- modules/rostests/win32/cmd/test_builtins.cmd | 328 ++++++++++++++++++++++- modules/rostests/win32/cmd/test_builtins.cmd.exp | 64 ++++- 2 files changed, 390 insertions(+), 2 deletions(-)
diff --git a/modules/rostests/win32/cmd/test_builtins.cmd b/modules/rostests/win32/cmd/test_builtins.cmd index dd4e1af9eab..9d03f175dc6 100644 --- a/modules/rostests/win32/cmd/test_builtins.cmd +++ b/modules/rostests/win32/cmd/test_builtins.cmd @@ -1,5 +1,9 @@ @echo off
+:: +:: Some basic tests +:: + echo ------------ Testing FOR loop ------------ echo --- Multiple lines for %%i in (A @@ -45,4 +49,326 @@ ver | find "Ver" > NUL || echo TRUE OR condition ver | find "1234" > NUL || echo FALSE OR condition
-echo ------------- End of Testing ------------- + +:: +:: Testing CMD exit codes and errorlevels. +:: +:: Observations: +:: - OR operator || converts the LHS error code to ERRORLEVEL only on failure; +:: - Pipe operator | converts the last error code to ERRORLEVEL. +:: +:: See https://stackoverflow.com/a/34987886/13530036 +:: and https://stackoverflow.com/a/34937706/13530036 +:: for more details. +:: +setlocal enableextensions + +echo ---------- Testing CMD exit codes and errorlevels ---------- + +:: Tests for CMD returned exit code. + +echo --- CMD /C Direct EXIT call + +call :setError 0 +cmd /c "exit 42" +call :checkErrorLevel 42 + +call :setError 111 +cmd /c "exit 42" +call :checkErrorLevel 42 + +echo --- CMD /C Direct EXIT /B call + +call :setError 0 +cmd /c "exit /b 42" +call :checkErrorLevel 42 + +call :setError 111 +cmd /c "exit /b 42" +call :checkErrorLevel 42 + +:: Non-existing ccommand, or command that only changes +:: the returned code (but NOT the ERRORLEVEL) and EXIT. + +echo --- CMD /C Non-existing command + +:: EXIT alone does not change the ERRORLEVEL +call :setError 0 +cmd /c "nonexisting & exit" +call :checkErrorLevel 9009 + +call :setError 111 +cmd /c "nonexisting & exit" +call :checkErrorLevel 9009 + +call :setError 0 +cmd /c "nonexisting & exit /b" +call :checkErrorLevel 9009 + +call :setError 111 +cmd /c "nonexisting & exit /b" +call :checkErrorLevel 9009 + +echo --- CMD /C RMDIR (no ERRORLEVEL set) + +call :setError 0 +cmd /c "rmdir nonexisting & exit" +call :checkErrorLevel 0 + +call :setError 111 +cmd /c "rmdir nonexisting & exit" +call :checkErrorLevel 0 + +call :setError 0 +cmd /c "rmdir nonexisting & exit /b" +call :checkErrorLevel 0 + +call :setError 111 +cmd /c "rmdir nonexisting & exit /b" +call :checkErrorLevel 0 + +:: Failing command (sets ERRORLEVEL to 1) and EXIT +echo --- CMD /C DIR (sets ERRORLEVEL) - With failure + +:: EXIT alone does not change the ERRORLEVEL +call :setError 0 +cmd /c "dir nonexisting>NUL & exit" +call :checkErrorLevel 1 + +call :setError 111 +cmd /c "dir nonexisting>NUL & exit" +call :checkErrorLevel 1 + +call :setError 0 +cmd /c "dir nonexisting>NUL & exit /b" +call :checkErrorLevel 1 + +call :setError 111 +cmd /c "dir nonexisting>NUL & exit /b" +call :checkErrorLevel 1 + +:: Here EXIT changes the ERRORLEVEL +call :setError 0 +cmd /c "dir nonexisting>NUL & exit 42" +call :checkErrorLevel 42 + +call :setError 111 +cmd /c "dir nonexisting>NUL & exit 42" +call :checkErrorLevel 42 + +call :setError 0 +cmd /c "dir nonexisting>NUL & exit /b 42" +call :checkErrorLevel 42 + +call :setError 111 +cmd /c "dir nonexisting>NUL & exit /b 42" +call :checkErrorLevel 42 + +:: Succeeding command (sets ERRORLEVEL to 0) and EXIT +echo --- CMD /C DIR (sets ERRORLEVEL) - With success + +call :setError 0 +cmd /c "dir>NUL & exit" +call :checkErrorLevel 0 + +call :setError 111 +cmd /c "dir>NUL & exit" +call :checkErrorLevel 0 + +call :setError 0 +cmd /c "dir>NUL & exit 42" +call :checkErrorLevel 42 + +call :setError 111 +cmd /c "dir>NUL & exit 42" +call :checkErrorLevel 42 + +call :setError 0 +cmd /c "dir>NUL & exit /b 42" +call :checkErrorLevel 42 + +call :setError 111 +cmd /c "dir>NUL & exit /b 42" +call :checkErrorLevel 42 + + +:: Same sorts of tests, but now from within an external batch file: +:: Tests for CALL command returned exit code. + +:: Use an auxiliary CMD file +mkdir foobar && cd foobar + +:: Non-existing ccommand, or command that only changes +:: the returned code (but NOT the ERRORLEVEL) and EXIT. + +echo --- CALL Batch Non-existing command + +:: EXIT alone does not change the ERRORLEVEL +echo nonexisting ^& exit /b> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 9009 + +echo nonexisting ^& exit /b> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 9009 + +:: These tests show that || converts the returned error code +:: from RMDIR on failure, and converts it to an ERRORLEVEL +:: (first two tests: no ||, thus no ERRORLEVEL set; +:: last two tests: ||used and ERRORLEVEL is set). +:: + +echo --- CALL Batch RMDIR (no ERRORLEVEL set) + +:: This test shows that if a batch returns error code 0 from CALL, +:: then CALL will keep the existing ERRORLEVEL (here, 111)... +echo rmdir nonexisting> tmp.cmd +echo exit /b>> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 0 + +echo rmdir nonexisting> tmp.cmd +echo exit /b>> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 111 + +echo --- CALL Batch RMDIR with ^|^| (sets ERRORLEVEL) + +:: ... but if a non-zero error code is returned from CALL, +:: then CALL uses it as the new ERRORLEVEL. +echo rmdir nonexisting ^|^| rem> tmp.cmd +echo exit /b>> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 2 +:: This gives the same effect, since the last command's error code +:: is returned and transformed by CALL into an ERRORLEVEL: +echo rmdir nonexisting> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 2 + +echo rmdir nonexisting ^|^| rem> tmp.cmd +echo exit /b>> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 2 +:: This gives the same effect, since the last command's error code +:: is returned and transformed by CALL into an ERRORLEVEL: +echo rmdir nonexisting> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 2 + + +:: Failing command (sets ERRORLEVEL to 1) and EXIT +echo --- CALL Batch DIR (sets ERRORLEVEL) - With failure + +echo dir nonexisting^>NUL> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 1 + +echo dir nonexisting^>NUL> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 1 + +echo dir nonexisting^>NUL ^& goto :eof> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 1 + +echo dir nonexisting^>NUL ^& goto :eof> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 1 + +echo dir nonexisting^>NUL ^& exit /b> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 1 + +echo dir nonexisting^>NUL ^& exit /b> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 1 + +echo dir nonexisting^>NUL ^& exit /b 42 > tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 42 + +echo dir nonexisting^>NUL ^& exit /b 42 > tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 42 + +:: Succeeding command (sets ERRORLEVEL to 0) and EXIT +echo --- CALL Batch DIR (sets ERRORLEVEL) - With success + +echo dir^>NUL> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 0 + +echo dir^>NUL> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 0 + +echo dir^>NUL ^& goto :eof> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 0 + +echo dir^>NUL ^& goto :eof> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 0 + +echo dir^>NUL ^& exit /b> tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 0 + +echo dir^>NUL ^& exit /b> tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 0 + +echo dir^>NUL ^& exit /b 42 > tmp.cmd +call :setError 0 +call tmp.cmd +call :checkErrorLevel 42 + +echo dir^>NUL ^& exit /b 42 > tmp.cmd +call :setError 111 +call tmp.cmd +call :checkErrorLevel 42 + + +:: Cleanup +del tmp.cmd +cd .. & rmdir /s/q foobar + + +:: +:: Finished! +:: +echo --------- Finished -------------- +goto :EOF + +:checkErrorLevel +if %errorlevel% neq %1 (echo Unexpected errorlevel %errorlevel%, expected %1) else echo OK +goto :eof + +:: Subroutine to set errorlevel and return +:: in windows nt 4.0, this always sets errorlevel 1, since /b isn't supported +:setError +exit /B %1 +:: This line runs under cmd in windows NT 4, but not in more modern versions. diff --git a/modules/rostests/win32/cmd/test_builtins.cmd.exp b/modules/rostests/win32/cmd/test_builtins.cmd.exp index 43f4a6b5b30..e2d609e8e03 100644 --- a/modules/rostests/win32/cmd/test_builtins.cmd.exp +++ b/modules/rostests/win32/cmd/test_builtins.cmd.exp @@ -23,4 +23,66 @@ I TRUE AND condition ---------- Testing OR operator ----------- FALSE OR condition -------------- End of Testing ------------- +---------- Testing CMD exit codes and errorlevels ---------- +--- CMD /C Direct EXIT call +OK +OK +--- CMD /C Direct EXIT /B call +OK +OK +--- CMD /C Non-existing command +OK +OK +OK +OK +--- CMD /C RMDIR (no ERRORLEVEL set) +OK +OK +OK +OK +--- CMD /C DIR (sets ERRORLEVEL) - With failure +OK +OK +OK +OK +OK +OK +OK +OK +--- CMD /C DIR (sets ERRORLEVEL) - With success +OK +OK +OK +OK +OK +OK +--- CALL Batch Non-existing command +OK +OK +--- CALL Batch RMDIR (no ERRORLEVEL set) +OK +OK +--- CALL Batch RMDIR with || (sets ERRORLEVEL) +OK +OK +OK +OK +--- CALL Batch DIR (sets ERRORLEVEL) - With failure +OK +OK +OK +OK +OK +OK +OK +OK +--- CALL Batch DIR (sets ERRORLEVEL) - With success +OK +OK +OK +OK +OK +OK +OK +OK +--------- Finished --------------