Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- dlls/kernel32/tests/pipe.c | 108 +++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c index f61d441303..227575ece3 100644 --- a/dlls/kernel32/tests/pipe.c +++ b/dlls/kernel32/tests/pipe.c @@ -3887,6 +3887,113 @@ static void test_wait_pipe(void) CloseHandle(ov.hEvent); }
+static DWORD CALLBACK test_nowait_read_thread(LPVOID arg) +{ + HANDLE *pipewrite = arg; + static const char buf[] = "bits"; + DWORD written; + + Sleep(2000); + WriteFile(*pipewrite, buf, sizeof(buf), &written, NULL); + return 0; +} +static DWORD CALLBACK test_nowait_write_thread(LPVOID arg) +{ + HANDLE *piperead = arg; + char buf[32768]; + DWORD read; + + Sleep(2000); + ReadFile(*piperead, buf, sizeof(buf), &read, NULL); + return 0; +} +static DWORD CALLBACK test_nowait_connect_thread(LPVOID arg) +{ + HANDLE hFile; + + Sleep(2000); + hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA failed\n"); + ok(CloseHandle(hFile), "CloseHandle failed\n"); + return 0; +} +static void test_nowait(void) +{ + SECURITY_ATTRIBUTES pipe_attr; + HANDLE piperead, pipewrite, hThread; + DWORD mode; + DWORD read, write; + char readbuf[32768]; + + pipe_attr.nLength = sizeof(SECURITY_ATTRIBUTES); + pipe_attr.bInheritHandle = TRUE; + pipe_attr.lpSecurityDescriptor = NULL; + + /* CreatePipe, use SetNamedHandleState to enable PIPE_NOWAIT, and read from empty pipe */ + ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n"); + mode = PIPE_NOWAIT; + ok(SetNamedPipeHandleState(piperead, &mode, NULL, NULL) != 0, "SetNamedPipeHandleState failed\n"); + /* spawn a thread that writes to the pipe after 2 seconds so the test won't hang if ReadFile blocks */ + hThread = CreateThread(NULL, 0, test_nowait_read_thread, &pipewrite, 0, NULL); + ok(hThread != NULL, "CreateThread failed. %d\n", GetLastError()); + SetLastError(0xdeadbeef); + todo_wine ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == FALSE, "ReadFile should fail\n"); + todo_wine ok(GetLastError() == ERROR_NO_DATA, "got %d should be ERROR_NO_DATA\n", GetLastError()); + ok(WaitForSingleObject(hThread,INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject\n"); + ok(CloseHandle(hThread), "CloseHandle for the thread failed\n"); + ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n"); + ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n"); + + /* CreatePipe, use SetNamedHandleState to enable PIPE_NOWAIT, and write to full pipe */ + ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 512) != 0, "CreatePipe failed\n"); + mode = PIPE_NOWAIT; + ok(SetNamedPipeHandleState(pipewrite, &mode, NULL, NULL) != 0, "SetNamedPipeHandleState failed\n"); + /* spawn a thread that reads from the pipe after 2 seconds so the test won't hang if WriteFile blocks */ + hThread = CreateThread(NULL, 0, test_nowait_write_thread, &piperead, 0, NULL); + ok(hThread != NULL, "CreateThread failed. %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ok(WriteFile(pipewrite,readbuf,sizeof(readbuf),&write, NULL) == TRUE, "WriteFile should return true\n"); + /* WriteFile only documents that 'write < sizeof(readbuf)' for this case, but Windows + * doesn't seem to do partial writes ('write == 0' always) + */ + todo_wine ok(write < sizeof(readbuf), "WriteFile should fail to write the whole buffer\n"); + todo_wine ok(write == 0, "WriteFile shouldn't do partial writes\n"); + ok(CloseHandle(hThread), "CloseHandle for the thread failed\n"); + ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n"); + ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n"); + + /* CreateNamedPipe with PIPE_NOWAIT, test ConnectNamedPipe */ + pipewrite = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_NOWAIT, + /* nMaxInstances */ 1, + /* nOutBufSize */ 512, + /* nInBufSize */ 512, + /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, + /* lpSecurityAttrib */ NULL); + ok(pipewrite != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + /* spawn a thread that connects to the pipe after 2 seconds so the test won't hang if ConnectNamedPipe blocks */ + hThread = CreateThread(NULL, 0, test_nowait_connect_thread, NULL, 0, NULL); + ok(hThread != NULL, "CreateThread failed. %d\n", GetLastError()); + SetLastError(0xdeadbeef); + todo_wine ok(ConnectNamedPipe(pipewrite,NULL) == FALSE, "ConnectNamedPipe should fail\n"); + todo_wine ok(GetLastError() == ERROR_PIPE_LISTENING, "got %d should be ERROR_PIPE_LISTENING\n", GetLastError()); + /* wait for thread to finish (connects and disconnects), then test ConnectNamedPipe again */ + ok(WaitForSingleObject(hThread,INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject\n"); + ok(CloseHandle(hThread), "CloseHandle for the thread failed\n"); + SetLastError(0xdeadbeef); + todo_wine ok(ConnectNamedPipe(pipewrite,NULL) == FALSE, "ConnectNamedPipe should fail\n"); + todo_wine ok(GetLastError() == ERROR_NO_DATA, "got %d should be ERROR_NO_DATA\n", GetLastError()); + /* call DisconnectNamedPipe and test ConnectNamedPipe again */ + ok(DisconnectNamedPipe(pipewrite) == TRUE, "DisconnectNamedPipe should succeed\n"); + hThread = CreateThread(NULL, 0, test_nowait_connect_thread, NULL, 0, NULL); + ok(hThread != NULL, "CreateThread failed. %d\n", GetLastError()); + SetLastError(0xdeadbeef); + todo_wine ok(ConnectNamedPipe(pipewrite,NULL) == FALSE, "ConnectNamedPipe should fail\n"); + todo_wine ok(GetLastError() == ERROR_PIPE_LISTENING, "got %d should be ERROR_PIPE_LISTENING\n", GetLastError()); + ok(WaitForSingleObject(hThread,INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject\n"); + ok(CloseHandle(hThread), "CloseHandle for the thread failed\n"); + ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n"); +} + START_TEST(pipe) { char **argv; @@ -3954,4 +4061,5 @@ START_TEST(pipe) test_namedpipe_session_id(); test_multiple_instances(); test_wait_pipe(); + test_nowait(); }