https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e753d5e1086e96a4978d06...
commit e753d5e1086e96a4978d061e0ca6ff1b9cf4d896 Author: Katayama Hirofumi MZ katayama.hirofumi.mz@gmail.com AuthorDate: Thu Nov 14 22:52:31 2019 +0900 Commit: GitHub noreply@github.com CommitDate: Thu Nov 14 22:52:31 2019 +0900
[CMD_APITEST] Add cmd_apitest testcases (#2034)
Add some testcases for cmd.exe. CORE-12150 --- modules/rostests/apitests/CMakeLists.txt | 1 + modules/rostests/apitests/cmd/CMakeLists.txt | 11 + modules/rostests/apitests/cmd/cmd.c | 300 +++++++++++++++++++++++++++ modules/rostests/apitests/cmd/precomp.h | 6 + modules/rostests/apitests/cmd/testlist.c | 16 ++ 5 files changed, 334 insertions(+)
diff --git a/modules/rostests/apitests/CMakeLists.txt b/modules/rostests/apitests/CMakeLists.txt index 8910f89b56a..62ca4c742bc 100644 --- a/modules/rostests/apitests/CMakeLists.txt +++ b/modules/rostests/apitests/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(apphelp) add_subdirectory(appshim) add_subdirectory(atl) add_subdirectory(browseui) +add_subdirectory(cmd) add_subdirectory(com) add_subdirectory(comctl32) add_subdirectory(crt) diff --git a/modules/rostests/apitests/cmd/CMakeLists.txt b/modules/rostests/apitests/cmd/CMakeLists.txt new file mode 100644 index 00000000000..5eae6ccdee6 --- /dev/null +++ b/modules/rostests/apitests/cmd/CMakeLists.txt @@ -0,0 +1,11 @@ + +list(APPEND SOURCE + cmd.c + precomp.h) + +add_executable(cmd_apitest ${SOURCE} testlist.c) +target_link_libraries(cmd_apitest wine ${PSEH_LIB}) +set_module_type(cmd_apitest win32cui) +add_importlibs(cmd_apitest msvcrt kernel32) +add_pch(cmd_apitest precomp.h SOURCE) +add_rostests_file(TARGET cmd_apitest) diff --git a/modules/rostests/apitests/cmd/cmd.c b/modules/rostests/apitests/cmd/cmd.c new file mode 100644 index 00000000000..f4e79cc59bd --- /dev/null +++ b/modules/rostests/apitests/cmd/cmd.c @@ -0,0 +1,300 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: Test for cmd.exe + * COPYRIGHT: Copyright 2019 Katayama Hirofumi MZ katayama.hirofumi.mz@gmail.com + */ + +#include "precomp.h" + +#define TIMEOUT 3000 + +typedef struct TEST_ENTRY +{ + INT line; + DWORD dwExitCode; + const char *cmdline; + BOOL bStdOutput; + BOOL bStdError; +} TEST_ENTRY; + +static const TEST_ENTRY s_exit_entries[] = +{ + { __LINE__, 0, "cmd /c exit" }, + { __LINE__, 0, "cmd /c exit 0" }, + { __LINE__, 0, "cmd /c exit """ }, + { __LINE__, 0, "cmd /c exit ABC" }, + { __LINE__, 0, "cmd /c exit "ABC" }, + { __LINE__, 0, "cmd /c exit "ABC"" }, + { __LINE__, 1234, "cmd /c exit 1234" }, +}; + +static const TEST_ENTRY s_echo_entries[] = +{ + { __LINE__, 0, "cmd /c echo", TRUE, FALSE }, + { __LINE__, 0, "cmd /c echo.", TRUE, FALSE }, +}; + +static const TEST_ENTRY s_cd_entries[] = +{ + { __LINE__, 0, "cmd /c cd "C:\ ", }, + { __LINE__, 0, "cmd /c cd C:/", }, + { __LINE__, 0, "cmd /c cd """, TRUE, FALSE }, + { __LINE__, 0, "cmd /c cd", TRUE, FALSE }, + { __LINE__, 1234, "cmd /c cd C:\Program Files && exit 1234" }, + { __LINE__, 1234, "cmd /c cd "C:\ " && exit 1234", }, + { __LINE__, 1234, "cmd /c cd "C:\Program Files" && exit 1234", }, + { __LINE__, 1234, "cmd /c cd "" && exit 1234", TRUE, FALSE }, + { __LINE__, 1234, "cmd /c cd \ && exit 1234" }, +}; + +static const TEST_ENTRY s_pushd_entries[] = +{ + { __LINE__, 0, "cmd /c pushd C:\ " }, + { __LINE__, 0, "cmd /c pushd C:\ "" }, + { __LINE__, 0, "cmd /c pushd C:\ """ }, + { __LINE__, 0, "cmd /c pushd C:\ """" }, + { __LINE__, 0, "cmd /c pushd C:\ """"" }, + { __LINE__, 0, "cmd /c pushd C:\ " " }, + { __LINE__, 0, "cmd /c pushd C:\ "" " }, + { __LINE__, 0, "cmd /c pushd C:\ """ " }, + { __LINE__, 0, "cmd /c pushd C:\ """" " }, + { __LINE__, 0, "cmd /c pushd C:\" }, + { __LINE__, 0, "cmd /c pushd C:\"" }, + { __LINE__, 0, "cmd /c pushd C:\""" }, + { __LINE__, 0, "cmd /c pushd C:\"""" }, + { __LINE__, 0, "cmd /c pushd C:\""""" }, + { __LINE__, 0, "cmd /c pushd C:\" " }, + { __LINE__, 0, "cmd /c pushd C:\"" " }, + { __LINE__, 0, "cmd /c pushd C:\""" " }, + { __LINE__, 0, "cmd /c pushd C:\"""" " }, + { __LINE__, 0, "cmd /c pushd "C:\ " }, + { __LINE__, 0, "cmd /c pushd "C:\ "" }, + { __LINE__, 0, "cmd /c pushd "C:\ """ }, + { __LINE__, 0, "cmd /c pushd "C:\ """" }, + { __LINE__, 0, "cmd /c pushd "C:\ """"" }, + { __LINE__, 0, "cmd /c pushd "C:\ " " }, + { __LINE__, 0, "cmd /c pushd "C:\ "" " }, + { __LINE__, 0, "cmd /c pushd "C:\ """ " }, + { __LINE__, 0, "cmd /c pushd "C:\ """" " }, + { __LINE__, 0, "cmd /c pushd "C:\" }, + { __LINE__, 0, "cmd /c pushd "C:\"" }, + { __LINE__, 0, "cmd /c pushd "C:\""" }, + { __LINE__, 0, "cmd /c pushd "C:\"""" }, + { __LINE__, 0, "cmd /c pushd "C:\""""" }, + { __LINE__, 0, "cmd /c pushd "C:\"" }, + { __LINE__, 1, "cmd /c pushd " C:\ ", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd " C:\ "", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd " C:\ """, FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd " C:\ """", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd " C:\ """"", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd "" C:\ ", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd "" C:\ "", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd "" C:\ """, FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd "" C:\ """", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd "" C:\ """"", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd "" C:\"", FALSE, TRUE }, + { __LINE__, 1, "cmd /c popd ABC" }, + { __LINE__, 1, "cmd /c popd " " }, + { __LINE__, 1, "cmd /c popd """ }, + { __LINE__, 1, "cmd /c popd" }, + { __LINE__, 1, "cmd /c pushd ABC", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd C:/Program Files && popd && exit 1234", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd C:\ C:\ && popd && exit 1234", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd C:\Invalid Directory && exit 1234", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd C:\Invalid Directory && popd && exit 1234", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd " C:\ ", FALSE, TRUE }, + { __LINE__, 1, "cmd /c pushd "C:\ C:\" && popd && exit 1234", FALSE, TRUE }, + { __LINE__, 1234, "cmd /c pushd && exit 1234 " }, + { __LINE__, 1234, "cmd /c pushd C:\ && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd C:\ "" && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd C:\Program Files && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd "C:/Program Files/" && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd "C:/Program Files" && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd "C:\ " && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd "C:\ """ && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd "C:\ """"" && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd "C:\Program Files" && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd "C:\Program Files\" && popd && exit 1234" }, + { __LINE__, 1234, "cmd /c pushd "C:\" && popd && exit 1234" }, +}; + +static BOOL MyDuplicateHandle(HANDLE hFile, PHANDLE phFile, BOOL bInherit) +{ + HANDLE hProcess = GetCurrentProcess(); + return DuplicateHandle(hProcess, hFile, hProcess, phFile, 0, + bInherit, DUPLICATE_SAME_ACCESS); +} + +static BOOL PrepareForRedirect(STARTUPINFOA *psi, PHANDLE phInputWrite, + PHANDLE phOutputRead, PHANDLE phErrorRead) +{ + HANDLE hInputRead = NULL, hInputWriteTmp = NULL; + HANDLE hOutputReadTmp = NULL, hOutputWrite = NULL; + HANDLE hErrorReadTmp = NULL, hErrorWrite = NULL; + SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE }; + + psi->hStdInput = NULL; + psi->hStdOutput = NULL; + psi->hStdError = NULL; + + if (phInputWrite) + { + if (CreatePipe(&hInputRead, &hInputWriteTmp, &sa, 0)) + { + if (!MyDuplicateHandle(hInputWriteTmp, phInputWrite, FALSE)) + goto failed; + + CloseHandle(hInputWriteTmp); + } + else + goto failed; + } + + if (phOutputRead) + { + if (CreatePipe(&hOutputReadTmp, &hOutputWrite, &sa, 0)) + { + if (!MyDuplicateHandle(hOutputReadTmp, phOutputRead, FALSE)) + goto failed; + + CloseHandle(hOutputReadTmp); + } + else + goto failed; + } + + if (phOutputRead && phOutputRead == phErrorRead) + { + if (!MyDuplicateHandle(hOutputWrite, &hErrorWrite, TRUE)) + goto failed; + } + else if (phErrorRead) + { + if (CreatePipe(&hErrorReadTmp, &hErrorWrite, &sa, 0)) + { + if (!MyDuplicateHandle(hErrorReadTmp, phErrorRead, FALSE)) + goto failed; + CloseHandle(hErrorReadTmp); + } + else + goto failed; + } + + if (phInputWrite) + psi->hStdInput = hInputRead; + if (phOutputRead) + psi->hStdOutput = hOutputWrite; + if (phErrorRead) + psi->hStdError = hErrorWrite; + + return TRUE; + +failed: + CloseHandle(hInputRead); + CloseHandle(hInputWriteTmp); + CloseHandle(hOutputReadTmp); + CloseHandle(hOutputWrite); + CloseHandle(hErrorReadTmp); + CloseHandle(hErrorWrite); + return FALSE; +} + +static void DoTestEntry(const TEST_ENTRY *pEntry) +{ + STARTUPINFOA si; + PROCESS_INFORMATION pi; + DWORD dwExitCode, dwWait; + HANDLE hOutputRead = NULL; + HANDLE hErrorRead = NULL; + BYTE b; + DWORD dwRead; + BOOL bStdOutput, bStdError; + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + + if (!PrepareForRedirect(&si, NULL, &hOutputRead, &hErrorRead)) + { + skip("PrepareForRedirect failed\n"); + return; + } + + if (CreateProcessA(NULL, (char *)pEntry->cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) + { + CloseHandle(si.hStdInput); + dwWait = WaitForSingleObject(pi.hProcess, TIMEOUT); + if (dwWait == WAIT_TIMEOUT) + { + TerminateProcess(pi.hProcess, 9999); + } + GetExitCodeProcess(pi.hProcess, &dwExitCode); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + else + { + dwExitCode = 8888; + } + + PeekNamedPipe(hOutputRead, &b, 1, &dwRead, NULL, NULL); + bStdOutput = dwRead != 0; + PeekNamedPipe(hErrorRead, &b, 1, &dwRead, NULL, NULL); + bStdError = dwRead != 0; + + if (si.hStdInput) + CloseHandle(si.hStdInput); + if (si.hStdOutput) + CloseHandle(si.hStdOutput); + if (si.hStdError) + CloseHandle(si.hStdError); + + ok(pEntry->bStdOutput == bStdOutput, + "Line %u: bStdOutput %d vs %d\n", + pEntry->line, pEntry->bStdOutput, bStdOutput); + + ok(pEntry->bStdError == bStdError, + "Line %u: bStdError %d vs %d\n", + pEntry->line, pEntry->bStdError, bStdError); + + ok(pEntry->dwExitCode == dwExitCode, + "Line %u: dwExitCode %ld vs %ld\n", + pEntry->line, pEntry->dwExitCode, dwExitCode); +} + +START_TEST(exit) +{ + SIZE_T i; + for (i = 0; i < ARRAYSIZE(s_exit_entries); ++i) + { + DoTestEntry(&s_exit_entries[i]); + } +} + +START_TEST(echo) +{ + SIZE_T i; + for (i = 0; i < ARRAYSIZE(s_echo_entries); ++i) + { + DoTestEntry(&s_echo_entries[i]); + } +} + +START_TEST(cd) +{ + SIZE_T i; + for (i = 0; i < ARRAYSIZE(s_cd_entries); ++i) + { + DoTestEntry(&s_cd_entries[i]); + } +} + +START_TEST(pushd) +{ + SIZE_T i; + for (i = 0; i < ARRAYSIZE(s_pushd_entries); ++i) + { + DoTestEntry(&s_pushd_entries[i]); + } +} diff --git a/modules/rostests/apitests/cmd/precomp.h b/modules/rostests/apitests/cmd/precomp.h new file mode 100644 index 00000000000..13f2ddb0772 --- /dev/null +++ b/modules/rostests/apitests/cmd/precomp.h @@ -0,0 +1,6 @@ +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H + +#include <apitest.h> +#include <windows.h> diff --git a/modules/rostests/apitests/cmd/testlist.c b/modules/rostests/apitests/cmd/testlist.c new file mode 100644 index 00000000000..07ab34a2c97 --- /dev/null +++ b/modules/rostests/apitests/cmd/testlist.c @@ -0,0 +1,16 @@ +#define STANDALONE +#include <apitest.h> + +extern void func_cd(void); +extern void func_echo(void); +extern void func_exit(void); +extern void func_pushd(void); + +const struct test winetest_testlist[] = +{ + { "cd", func_cd }, + { "echo", func_echo }, + { "exit", func_exit }, + { "pushd", func_pushd }, + { 0, 0 } +};