summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/thread/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
commita9bcc81f821d7c66f623779fa5147e728eb3c388 (patch)
tree98676963bcdd537ae5908a067a8eb110b93486a6 /winpr/libwinpr/thread/test
parentInitial commit. (diff)
downloadfreerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz
freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'winpr/libwinpr/thread/test')
-rw-r--r--winpr/libwinpr/thread/test/CMakeLists.txt27
-rw-r--r--winpr/libwinpr/thread/test/TestThreadCommandLineToArgv.c74
-rw-r--r--winpr/libwinpr/thread/test/TestThreadCreateProcess.c156
-rw-r--r--winpr/libwinpr/thread/test/TestThreadExitThread.c53
4 files changed, 310 insertions, 0 deletions
diff --git a/winpr/libwinpr/thread/test/CMakeLists.txt b/winpr/libwinpr/thread/test/CMakeLists.txt
new file mode 100644
index 0000000..a78e584
--- /dev/null
+++ b/winpr/libwinpr/thread/test/CMakeLists.txt
@@ -0,0 +1,27 @@
+
+set(MODULE_NAME "TestThread")
+set(MODULE_PREFIX "TEST_THREAD")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+ TestThreadCommandLineToArgv.c
+ TestThreadCreateProcess.c
+ TestThreadExitThread.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+target_link_libraries(${MODULE_NAME} winpr)
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+ get_filename_component(TestName ${test} NAME_WE)
+ add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
diff --git a/winpr/libwinpr/thread/test/TestThreadCommandLineToArgv.c b/winpr/libwinpr/thread/test/TestThreadCommandLineToArgv.c
new file mode 100644
index 0000000..33d0c94
--- /dev/null
+++ b/winpr/libwinpr/thread/test/TestThreadCommandLineToArgv.c
@@ -0,0 +1,74 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/thread.h>
+
+static const char* test_args_line_1 = "app.exe abc d e";
+
+static const char* test_args_list_1[] = { "app.exe", "abc", "d", "e", NULL };
+
+static const char* test_args_line_2 = "app.exe abc \t def";
+
+static const char* test_args_list_2[] = { "app.exe", "abc", "def", NULL };
+
+static const char* test_args_line_3 = "app.exe \"abc\" d e";
+
+static const char* test_args_list_3[] = { "app.exe", "abc", "d", "e", NULL };
+
+static const char* test_args_line_4 = "app.exe a\\\\b d\"e f\"g h";
+
+static const char* test_args_list_4[] = { "app.exe", "a\\\\b", "de fg", "h", NULL };
+
+static const char* test_args_line_5 = "app.exe a\\\\\\\"b c d";
+
+static const char* test_args_list_5[] = { "app.exe", "a\\\"b", "c", "d", NULL };
+
+static const char* test_args_line_6 = "app.exe a\\\\\\\\\"b c\" d e";
+
+static const char* test_args_list_6[] = { "app.exe", "a\\\\b c", "d", "e", NULL };
+
+static const char* test_args_line_7 = "app.exe a\\\\\\\\\"b c\" d e f\\\\\\\\\"g h\" i j";
+
+static const char* test_args_list_7[] = { "app.exe", "a\\\\b c", "d", "e",
+ "f\\\\g h", "i", "j", NULL };
+
+static int test_command_line_parsing_case(const char* line, const char** list)
+{
+ LPSTR* pArgs = NULL;
+ int numArgs = 0;
+
+ pArgs = NULL;
+ numArgs = 0;
+
+ printf("Parsing: %s\n", line);
+
+ pArgs = CommandLineToArgvA(line, &numArgs);
+
+ printf("pNumArgs: %d\n", numArgs);
+
+ for (int i = 0; i < numArgs; i++)
+ {
+ printf("argv[%d] = %s\n", i, pArgs[i]);
+ }
+
+ free(pArgs);
+
+ return 0;
+}
+
+int TestThreadCommandLineToArgv(int argc, char* argv[])
+{
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ test_command_line_parsing_case(test_args_line_1, test_args_list_1);
+ test_command_line_parsing_case(test_args_line_2, test_args_list_2);
+ test_command_line_parsing_case(test_args_line_3, test_args_list_3);
+ test_command_line_parsing_case(test_args_line_4, test_args_list_4);
+ test_command_line_parsing_case(test_args_line_5, test_args_list_5);
+ test_command_line_parsing_case(test_args_line_6, test_args_list_6);
+ test_command_line_parsing_case(test_args_line_7, test_args_list_7);
+
+ return 0;
+}
diff --git a/winpr/libwinpr/thread/test/TestThreadCreateProcess.c b/winpr/libwinpr/thread/test/TestThreadCreateProcess.c
new file mode 100644
index 0000000..1260c1b
--- /dev/null
+++ b/winpr/libwinpr/thread/test/TestThreadCreateProcess.c
@@ -0,0 +1,156 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/synch.h>
+#include <winpr/thread.h>
+#include <winpr/environment.h>
+#include <winpr/pipe.h>
+
+#define TESTENV_A "HELLO=WORLD"
+#define TESTENV_T _T(TESTENV_A)
+
+int TestThreadCreateProcess(int argc, char* argv[])
+{
+ BOOL status = 0;
+ DWORD exitCode = 0;
+ LPCTSTR lpApplicationName = NULL;
+
+#ifdef _WIN32
+ TCHAR lpCommandLine[200] = _T("cmd /C set");
+#else
+ TCHAR lpCommandLine[200] = _T("printenv");
+#endif
+
+ // LPTSTR lpCommandLine;
+ LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL;
+ LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL;
+ BOOL bInheritHandles = 0;
+ DWORD dwCreationFlags = 0;
+ LPVOID lpEnvironment = NULL;
+ LPCTSTR lpCurrentDirectory = NULL;
+ STARTUPINFO StartupInfo = { 0 };
+ PROCESS_INFORMATION ProcessInformation = { 0 };
+ LPTCH lpszEnvironmentBlock = NULL;
+ HANDLE pipe_read = NULL;
+ HANDLE pipe_write = NULL;
+ char buf[1024] = { 0 };
+ DWORD read_bytes = 0;
+ int ret = 0;
+ SECURITY_ATTRIBUTES saAttr;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ lpszEnvironmentBlock = GetEnvironmentStrings();
+
+ lpApplicationName = NULL;
+
+ lpProcessAttributes = NULL;
+ lpThreadAttributes = NULL;
+ bInheritHandles = FALSE;
+ dwCreationFlags = 0;
+#ifdef _UNICODE
+ dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
+#endif
+ lpEnvironment = lpszEnvironmentBlock;
+ lpCurrentDirectory = NULL;
+ StartupInfo.cb = sizeof(STARTUPINFO);
+
+ status = CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes,
+ lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
+ lpCurrentDirectory, &StartupInfo, &ProcessInformation);
+
+ if (!status)
+ {
+ printf("CreateProcess failed. error=%" PRIu32 "\n", GetLastError());
+ return 1;
+ }
+
+ if (WaitForSingleObject(ProcessInformation.hProcess, 5000) != WAIT_OBJECT_0)
+ {
+ printf("Failed to wait for first process. error=%" PRIu32 "\n", GetLastError());
+ return 1;
+ }
+
+ exitCode = 0;
+ status = GetExitCodeProcess(ProcessInformation.hProcess, &exitCode);
+
+ printf("GetExitCodeProcess status: %" PRId32 "\n", status);
+ printf("Process exited with code: 0x%08" PRIX32 "\n", exitCode);
+
+ CloseHandle(ProcessInformation.hProcess);
+ CloseHandle(ProcessInformation.hThread);
+ FreeEnvironmentStrings(lpszEnvironmentBlock);
+
+ /* Test stdin,stdout,stderr redirection */
+
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
+
+ if (!CreatePipe(&pipe_read, &pipe_write, &saAttr, 0))
+ {
+ printf("Pipe creation failed. error=%" PRIu32 "\n", GetLastError());
+ return 1;
+ }
+
+ bInheritHandles = TRUE;
+
+ ZeroMemory(&StartupInfo, sizeof(STARTUPINFO));
+ StartupInfo.cb = sizeof(STARTUPINFO);
+ StartupInfo.hStdOutput = pipe_write;
+ StartupInfo.hStdError = pipe_write;
+ StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+
+ ZeroMemory(&ProcessInformation, sizeof(PROCESS_INFORMATION));
+
+ if (!(lpEnvironment = calloc(1, sizeof(TESTENV_T) + sizeof(TCHAR))))
+ {
+ printf("Failed to allocate environment buffer. error=%" PRIu32 "\n", GetLastError());
+ return 1;
+ }
+ memcpy(lpEnvironment, (void*)TESTENV_T, sizeof(TESTENV_T));
+
+ status = CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes,
+ lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
+ lpCurrentDirectory, &StartupInfo, &ProcessInformation);
+
+ free(lpEnvironment);
+
+ if (!status)
+ {
+ CloseHandle(pipe_read);
+ CloseHandle(pipe_write);
+ printf("CreateProcess failed. error=%" PRIu32 "\n", GetLastError());
+ return 1;
+ }
+
+ if (WaitForSingleObject(ProcessInformation.hProcess, 5000) != WAIT_OBJECT_0)
+ {
+ printf("Failed to wait for second process. error=%" PRIu32 "\n", GetLastError());
+ return 1;
+ }
+
+ ZeroMemory(buf, sizeof(buf));
+ ReadFile(pipe_read, buf, sizeof(buf) - 1, &read_bytes, NULL);
+ if (!strstr((const char*)buf, TESTENV_A))
+ {
+ printf("No or unexpected data read from pipe\n");
+ ret = 1;
+ }
+
+ CloseHandle(pipe_read);
+ CloseHandle(pipe_write);
+
+ exitCode = 0;
+ status = GetExitCodeProcess(ProcessInformation.hProcess, &exitCode);
+
+ printf("GetExitCodeProcess status: %" PRId32 "\n", status);
+ printf("Process exited with code: 0x%08" PRIX32 "\n", exitCode);
+
+ CloseHandle(ProcessInformation.hProcess);
+ CloseHandle(ProcessInformation.hThread);
+
+ return ret;
+}
diff --git a/winpr/libwinpr/thread/test/TestThreadExitThread.c b/winpr/libwinpr/thread/test/TestThreadExitThread.c
new file mode 100644
index 0000000..015bb85
--- /dev/null
+++ b/winpr/libwinpr/thread/test/TestThreadExitThread.c
@@ -0,0 +1,53 @@
+// Copyright © 2015 Hewlett-Packard Development Company, L.P.
+
+#include <winpr/file.h>
+#include <winpr/synch.h>
+#include <winpr/thread.h>
+
+static DWORD WINAPI thread_func(LPVOID arg)
+{
+ WINPR_UNUSED(arg);
+
+ /* exists of the thread the quickest as possible */
+ ExitThread(0);
+ return 0;
+}
+
+int TestThreadExitThread(int argc, char* argv[])
+{
+ HANDLE thread = NULL;
+ DWORD waitResult = 0;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ /* FIXME: create some noise to better guaranty the test validity and
+ * decrease the number of loops */
+ for (int i = 0; i < 100; i++)
+ {
+ thread = CreateThread(NULL, 0, thread_func, NULL, 0, NULL);
+
+ if (thread == INVALID_HANDLE_VALUE)
+ {
+ fprintf(stderr, "Got an invalid thread!\n");
+ return -1;
+ }
+
+ waitResult = WaitForSingleObject(thread, 300);
+ if (waitResult != WAIT_OBJECT_0)
+ {
+ /* When the thread exits before the internal thread_list
+ * was updated, ExitThread() is not able to retrieve the
+ * related WINPR_THREAD object and is not able to signal
+ * the end of the thread. Therefore WaitForSingleObject
+ * never get the signal.
+ */
+ fprintf(stderr,
+ "300ms should have been enough for the thread to be in a signaled state\n");
+ return -1;
+ }
+
+ CloseHandle(thread);
+ }
+ return 0;
+}