kernel32/tests: Add a read/write test for a COM port.
Dmitry Timoshkov
dmitry at baikal.ru
Wed Sep 11 00:42:54 CDT 2013
---
dlls/kernel32/tests/comm.c | 226 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 226 insertions(+)
diff --git a/dlls/kernel32/tests/comm.c b/dlls/kernel32/tests/comm.c
index 7646766..baf3368 100644
--- a/dlls/kernel32/tests/comm.c
+++ b/dlls/kernel32/tests/comm.c
@@ -20,7 +20,10 @@
#include <stdio.h>
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
#include "wine/test.h"
+#include "winternl.h"
#include "winbase.h"
#include "winnls.h"
@@ -48,6 +51,16 @@ static BOOL loopback_dtr_dsr = LOOPBACK_DTR_DSR;
static BOOL loopback_dtr_ring = LOOPBACK_DTR_RING;
static BOOL loopback_dtr_dcd = LOOPBACK_DTR_DCD;
+static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent,
+ PIO_APC_ROUTINE apc, void* apc_user,
+ PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
+ PLARGE_INTEGER offset, PULONG key);
+static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent,
+ PIO_APC_ROUTINE apc, void* apc_user,
+ PIO_STATUS_BLOCK io_status,
+ const void* buffer, ULONG length,
+ PLARGE_INTEGER offset, PULONG key);
+
typedef struct
{
char string[100];
@@ -2000,8 +2013,220 @@ static void test_FlushFileBuffers(void)
CloseHandle(hcom);
}
+static void test_read_write(void)
+{
+ static const char atz[]="ATZ\r\n";
+ char buf[256];
+ HANDLE hcom;
+ DCB dcb;
+ COMMTIMEOUTS timeouts;
+ DWORD ret, bytes, status, evtmask, before, after, last_event_time;
+ OVERLAPPED ovl_wait;
+ IO_STATUS_BLOCK iob;
+ LARGE_INTEGER offset;
+ LONG i;
+
+ if (!pNtReadFile || !pNtWriteFile)
+ {
+ win_skip("not running on NT, skipping test\n");
+ return;
+ }
+
+ hcom = test_OpenComm(TRUE);
+ if (hcom == INVALID_HANDLE_VALUE) return;
+
+ ret = GetCommState(hcom, &dcb);
+ ok(ret, "GetCommState error %d\n", GetLastError());
+ dcb.BaudRate = 9600;
+ dcb.ByteSize = 8;
+ dcb.Parity = NOPARITY;
+ dcb.fRtsControl = RTS_CONTROL_ENABLE;
+ dcb.fDtrControl = DTR_CONTROL_ENABLE;
+ dcb.StopBits = ONESTOPBIT;
+ ret = SetCommState(hcom, &dcb);
+ ok(ret, "SetCommState error %d\n", GetLastError());
+
+ memset(&timeouts, 0, sizeof(timeouts));
+ timeouts.ReadTotalTimeoutConstant = TIMEOUT;
+ ret = SetCommTimeouts(hcom, &timeouts);
+ ok(ret,"SetCommTimeouts error %d\n", GetLastError());
+
+ ret = SetupComm(hcom, 1024, 1024);
+ ok(ret, "SetUpComm error %d\n", GetLastError());
+
+ bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = WriteFile(hcom, atz, 0, &bytes, NULL);
+todo_wine
+ ok(!ret, "WriteFile should fail\n");
+todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+ ok(bytes == 0, "bytes %u\n", bytes);
+
+ iob.Status = -1;
+ iob.Information = -1;
+ status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, 0, NULL, NULL);
+todo_wine
+ ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status);
+todo_wine
+ ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status);
+todo_wine
+ ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information);
+
+ for (i = -20; i < 20; i++)
+ {
+ iob.Status = -1;
+ iob.Information = -1;
+ offset.QuadPart = (LONGLONG)i;
+ status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, 0, &offset, NULL);
+ if (i >= 0 || i == -1)
+ {
+ ok(status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, status);
+ ok(iob.Status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, iob.Status);
+ ok(iob.Information == 0, "%d: expected 0, got %lu\n", i, iob.Information);
+ }
+ else
+ {
+todo_wine
+ ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status);
+todo_wine
+ ok(iob.Status == -1, "%d: expected -1, got %#x\n", i, iob.Status);
+todo_wine
+ ok(iob.Information == -1, "%d: expected -1, got %ld\n", i, iob.Information);
+ }
+ }
+
+ iob.Status = -1;
+ iob.Information = -1;
+ offset.QuadPart = 0;
+ status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, sizeof(atz), &offset, NULL);
+todo_wine
+ ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %#x\n", status);
+ /* Under Windows checking IO_STATUS_BLOCK right after the call leads
+ * to races, iob.Status is either -1 or STATUS_SUCCESS, which means
+ * that it's set only when the operation completes.
+ */
+ ret = WaitForSingleObject(hcom, TIMEOUT);
+ if (ret == WAIT_TIMEOUT)
+ {
+ skip("Probably modem is not connected.\n");
+ CloseHandle(hcom);
+ return;
+ }
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret);
+ ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status);
+ ok(iob.Information == sizeof(atz), "expected sizeof(atz), got %lu\n", iob.Information);
+
+ ret = SetCommMask(hcom, EV_RXCHAR);
+ ok(ret, "SetCommMask error %d\n", GetLastError());
+
+ S(U(ovl_wait)).Offset = 0;
+ S(U(ovl_wait)).OffsetHigh = 0;
+ ovl_wait.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ trace("waiting 3 secs for modem response...\n");
+ last_event_time = 0;
+ before = GetTickCount();
+ do
+ {
+ evtmask = 0;
+ SetLastError(0xdeadbeef);
+ ret = WaitCommEvent(hcom, &evtmask, &ovl_wait);
+ ok(!ret && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent returned %d, error %d\n", ret, GetLastError());
+ if (GetLastError() != ERROR_IO_PENDING) goto done; /* no point in further testing */
+ for (;;)
+ {
+ ret = WaitForSingleObject(ovl_wait.hEvent, 100);
+ after = GetTickCount();
+ if (ret == WAIT_OBJECT_0)
+ {
+ trace("got modem response.\n");
+
+ last_event_time = after;
+ ret = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
+ ok(ret, "GetOverlappedResult reported error %d\n", GetLastError());
+todo_wine
+ ok(bytes == sizeof(evtmask), "expected sizeof(evtmask), got %u\n", bytes);
+ ok(evtmask & EV_RXCHAR, "EV_RXCHAR should be set\n");
+
+ bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadFile(hcom, buf, 0, &bytes, NULL);
+todo_wine
+ ok(!ret, "ReadFile should fail\n");
+todo_wine
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+ ok(bytes == 0, "bytes %u\n", bytes);
+
+ iob.Status = -1;
+ iob.Information = -1;
+ status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 0, NULL, NULL);
+todo_wine
+ ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status);
+ /* FIXME: Remove once Wine is fixed */
+ if (status == STATUS_PENDING) WaitForSingleObject(hcom, TIMEOUT);
+todo_wine
+ ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status);
+todo_wine
+ ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information);
+
+ for (i = -20; i < 20; i++)
+ {
+ iob.Status = -1;
+ iob.Information = -1;
+ offset.QuadPart = (LONGLONG)i;
+ status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 0, &offset, NULL);
+ /* FIXME: Remove once Wine is fixed */
+ if (status == STATUS_PENDING) WaitForSingleObject(hcom, TIMEOUT);
+ if (i >= 0)
+ {
+todo_wine
+ ok(status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, status);
+todo_wine
+ ok(iob.Status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, iob.Status);
+ ok(iob.Information == 0, "%d: expected 0, got %lu\n", i, iob.Information);
+ }
+ else
+ {
+todo_wine
+ ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status);
+todo_wine
+ ok(iob.Status == -1, "%d: expected -1, got %#x\n", i, iob.Status);
+todo_wine
+ ok(iob.Information == -1, "%d: expected -1, got %ld\n", i, iob.Information);
+ }
+ }
+
+ iob.Status = -1;
+ iob.Information = -1;
+ offset.QuadPart = 0;
+ status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 1, &offset, NULL);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", status);
+ ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status);
+ ok(iob.Information == 1, "expected 1, got %lu\n", iob.Information);
+ goto done;
+ }
+ else
+ {
+ if (last_event_time || after - before >= 3000) goto done;
+ }
+ }
+ } while (after - before < 3000);
+
+done:
+ CloseHandle(ovl_wait.hEvent);
+ CloseHandle(hcom);
+}
+
START_TEST(comm)
{
+ HMODULE ntdll = GetModuleHandle("ntdll.dll");
+ if (ntdll)
+ {
+ pNtReadFile = (void *)GetProcAddress(ntdll, "NtReadFile");
+ pNtWriteFile = (void *)GetProcAddress(ntdll, "NtWriteFile");
+ }
+
test_ClearCommError(); /* keep it the very first test */
test_FlushFileBuffers();
test_BuildCommDCB();
@@ -2021,6 +2246,7 @@ START_TEST(comm)
test_WaitDcd();
test_WaitBreak();
test_stdio();
+ test_read_write();
if (!winetest_interactive)
{
--
1.8.3.4
More information about the wine-patches
mailing list