[MSVCRT:APITEST]
[reactos.git] / rostests / apitests / msvcrt / CommandLine.c
diff --git a/rostests/apitests/msvcrt/CommandLine.c b/rostests/apitests/msvcrt/CommandLine.c
new file mode 100644 (file)
index 0000000..e6b6c99
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * PROJECT:         ReactOS API Tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         Test for CRT command-line handling.
+ * PROGRAMMER:      Hermès BÉLUSCA - MAÏTO <hermes.belusca@sfr.fr>
+ */
+
+#define WIN32_NO_STATUS
+#define UNICODE
+#include <stdio.h>
+#include <wine/test.h>
+#include <ndk/ntndk.h>
+
+#define COUNT_OF(x) (sizeof((x))/sizeof((x)[0]))
+
+/*
+ * The path to the data file is hardcoded in cmdline_util.c
+ * Please synchronize it whenever you do a change.
+ */
+#define DATAFILE    L"C:\\cmdline.dat"
+
+/**
+ * Extracts the command tail from the command line
+ * (deletes the program's name and keep the rest).
+ **/
+#define SPACECHAR   L' '
+#define DQUOTECHAR  L'\"'
+
+LPWSTR ExtractCmdLine(IN LPWSTR lpszCommandLine)
+{
+    BOOL inDoubleQuote = FALSE;
+
+    /*
+     * Skip the program's name (the first token in the command line).
+     * Handle quoted program's name.
+     */
+    if (lpszCommandLine)
+    {
+        while ( (*lpszCommandLine > SPACECHAR) ||
+                (*lpszCommandLine && inDoubleQuote) )
+        {
+            if (*lpszCommandLine == DQUOTECHAR)
+                inDoubleQuote = !inDoubleQuote;
+
+            ++lpszCommandLine;
+        }
+
+        /* Skip all white spaces preceeding the second token. */
+        while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR))
+            ++lpszCommandLine;
+    }
+
+    return lpszCommandLine;
+}
+
+VOID ExtractCmdLine_U(IN OUT PUNICODE_STRING pCommandLine_U)
+{
+    BOOL inDoubleQuote = FALSE;
+    PWSTR lpszCommandLine;
+
+    /*
+     * Skip the program's name (the first token in the command line).
+     * Handle quoted program's name.
+     */
+    if (pCommandLine_U && pCommandLine_U->Buffer && (pCommandLine_U->Length != 0))
+    {
+        lpszCommandLine = pCommandLine_U->Buffer;
+
+        while ( (pCommandLine_U->Length > 0) &&
+                ( (*lpszCommandLine > SPACECHAR) ||
+                  (*lpszCommandLine && inDoubleQuote) ) )
+        {
+            if (*lpszCommandLine == DQUOTECHAR)
+                inDoubleQuote = !inDoubleQuote;
+
+            ++lpszCommandLine;
+            pCommandLine_U->Length -= sizeof(WCHAR);
+        }
+
+        /* Skip all white spaces preceeding the second token. */
+        while ((pCommandLine_U->Length > 0) && *lpszCommandLine && (*lpszCommandLine <= SPACECHAR))
+        {
+            ++lpszCommandLine;
+            pCommandLine_U->Length -= sizeof(WCHAR);
+        }
+
+        pCommandLine_U->Buffer = lpszCommandLine;
+    }
+
+    return;
+}
+
+
+typedef struct _TEST_CASE
+{
+    LPWSTR CmdLine;
+} TEST_CASE, *PTEST_CASE;
+
+static TEST_CASE TestCases[] =
+{
+    {L"cmdline_util.exe"},
+    {L"cmdline_util.exe foo bar"},
+    {L"cmdline_util.exe \"foo bar\""},
+    {L"cmdline_util.exe foo \"bar John\" Doe"},
+
+    {L"\"cmdline_util.exe\""},
+    {L"\"cmdline_util.exe\" foo bar"},
+    {L"\"cmdline_util.exe\" \"foo bar\""},
+    {L"\"cmdline_util.exe\" foo \"bar John\" Doe"},
+
+    {L"\"cmdline_util.exe\""},
+    {L"\"cmdline_util.exe \"foo bar\"\""},
+};
+
+static void Test_CommandLine(IN ULONG TestNumber,
+                             IN PTEST_CASE TestCase)
+{
+    BOOL bRet;
+
+    WCHAR CmdLine[MAX_PATH];
+    STARTUPINFOW si;
+    PROCESS_INFORMATION pi;
+
+    ZeroMemory(&si, sizeof(si));
+    ZeroMemory(&pi, sizeof(pi));
+    si.cb = sizeof(si);
+
+    wcscpy(CmdLine, TestCase->CmdLine);
+
+    /*
+     * Launch the utility program and wait till it's terminated.
+     */
+    bRet = CreateProcessW(NULL,
+                          CmdLine,
+                          NULL, NULL,
+                          FALSE,
+                          CREATE_UNICODE_ENVIRONMENT,
+                          NULL, NULL,
+                          &si, &pi);
+    ok(bRet, "Test %lu - Failed to launch ' %S ', error = %lu.\n", TestNumber, TestCase->CmdLine, GetLastError());
+
+    if (bRet)
+    {
+        /* Wait until child process exits. */
+        WaitForSingleObject(pi.hProcess, INFINITE);
+
+        /* Close process and thread handles. */
+        CloseHandle(pi.hThread);
+        CloseHandle(pi.hProcess);
+    }
+
+    /*
+     * Analyses the result.
+     */
+    {
+        /* Open the data file. */
+        HANDLE hFile = CreateFileW(DATAFILE,
+                                   GENERIC_READ,
+                                   0, NULL,
+                                   OPEN_EXISTING,
+                                   FILE_ATTRIBUTE_NORMAL,
+                                   NULL);
+        ok(hFile != INVALID_HANDLE_VALUE, "Test %lu - Failed to open the data file 'C:\\cmdline.dat', error = %lu.\n", TestNumber, GetLastError());
+
+        if (hFile != INVALID_HANDLE_VALUE)
+        {
+            WCHAR BuffWinMain[MAX_PATH]; LPWSTR WinMainCmdLine = BuffWinMain;
+            WCHAR BuffWin32[MAX_PATH]  ; LPWSTR Win32CmdLine   = BuffWin32  ;
+            WCHAR BuffNT[0xffff /* Maximum USHORT size */];
+            UNICODE_STRING NTCmdLine;
+
+            DWORD dwSize, dwStringSize;
+
+            /*
+             * Format of the data file :
+             *
+             * [size_of_string 4 bytes][null_terminated_C_string]
+             * [size_of_string 4 bytes][null_terminated_C_string]
+             * [UNICODE_STRING_structure][string_buffer_of_UNICODE_STRING]
+             */
+
+            /* 1- Read the WinMain's command line. */
+            dwStringSize = 0;
+
+            ReadFile(hFile,
+                     &dwStringSize,
+                     sizeof(dwStringSize),
+                     &dwSize,
+                     NULL);
+
+            dwStringSize = min(dwStringSize, sizeof(BuffWinMain));
+            ReadFile(hFile,
+                     WinMainCmdLine,
+                     dwStringSize,
+                     &dwSize,
+                     NULL);
+            *(LPWSTR)((ULONG_PTR)WinMainCmdLine + dwStringSize) = 0;
+
+            /* 2- Read the Win32 mode command line. */
+            dwStringSize = 0;
+
+            ReadFile(hFile,
+                     &dwStringSize,
+                     sizeof(dwStringSize),
+                     &dwSize,
+                     NULL);
+
+            dwStringSize = min(dwStringSize, sizeof(BuffWin32));
+            ReadFile(hFile,
+                     Win32CmdLine,
+                     dwStringSize,
+                     &dwSize,
+                     NULL);
+            *(LPWSTR)((ULONG_PTR)Win32CmdLine + dwStringSize) = 0;
+
+            /* 3- Finally, read the UNICODE_STRING command line. */
+            ReadFile(hFile,
+                     &NTCmdLine,
+                     sizeof(NTCmdLine),
+                     &dwSize,
+                     NULL);
+
+            NTCmdLine.Buffer = BuffNT;
+            ReadFile(hFile,
+                     NTCmdLine.Buffer,
+                     NTCmdLine.Length,
+                     &dwSize,
+                     NULL);
+
+            /* Now close the file. */
+            CloseHandle(hFile);
+
+            /*
+             * Remove the program's name in the Win32 and NT command lines.
+             */
+            Win32CmdLine = ExtractCmdLine(Win32CmdLine);
+            ExtractCmdLine_U(&NTCmdLine);
+
+            /* Print the results */
+            *(LPWSTR)((ULONG_PTR)NTCmdLine.Buffer + NTCmdLine.Length) = 0;
+            printf("WinMain cmdline = '%S'\n"
+                   "Win32   cmdline = '%S'\n"
+                   "NT      cmdline = '%S'\n"
+                   "NT       length = %u\n",
+                   WinMainCmdLine,
+                   Win32CmdLine,
+                   NTCmdLine.Buffer, NTCmdLine.Length);
+
+            /*
+             * Now check the results.
+             */
+            dwStringSize = min(wcslen(WinMainCmdLine), wcslen(Win32CmdLine));
+            ok(wcslen(WinMainCmdLine) == wcslen(Win32CmdLine), "Test %lu - WinMain and Win32 command lines do not have the same length !\n", TestNumber);
+            ok(wcsncmp(WinMainCmdLine, Win32CmdLine, dwStringSize) == 0, "Test %lu - WinMain and Win32 command lines are different !\n", TestNumber);
+
+            dwStringSize = min(wcslen(WinMainCmdLine), NTCmdLine.Length / sizeof(WCHAR));
+            ok(wcsncmp(WinMainCmdLine, NTCmdLine.Buffer, dwStringSize) == 0, "Test %lu - WinMain and NT command lines are different !\n", TestNumber);
+
+            dwStringSize = min(wcslen(Win32CmdLine), NTCmdLine.Length / sizeof(WCHAR));
+            ok(wcsncmp(Win32CmdLine, NTCmdLine.Buffer, dwStringSize) == 0, "Test %lu - Win32 and NT command lines are different !\n", TestNumber);
+        }
+    }
+
+    /*
+     * Always delete the data file.
+     */
+    DeleteFileW(DATAFILE);
+}
+
+START_TEST(CommandLine)
+{
+    ULONG i;
+
+    for (i = 0 ; i < COUNT_OF(TestCases) ; ++i)
+    {
+        Test_CommandLine(i, &TestCases[i]);
+    }
+}
+
+/* EOF */