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