https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e753d5e1086e96a4978d061e0ca6ff1b9cf4d896
commit e753d5e1086e96a4978d061e0ca6ff1b9cf4d896 Author: Katayama Hirofumi MZ <[email protected]> AuthorDate: Thu Nov 14 22:52:31 2019 +0900 Commit: GitHub <[email protected]> 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 <[email protected]> + */ + +#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 } +};
