Commit d15e08ae authored by Dmitry Timoshkov's avatar Dmitry Timoshkov Committed by Alexandre Julliard

kernel32/tests: Add a read/write test for a COM port.

parent e55aea83
......@@ -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)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment