kernel32/tests: Add a read/write test for a COM port.
This commit is contained in:
parent
e55aea83cd
commit
d15e08ae5e
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue