I've tested this on XP, but I would like to get somebody to test on 9x and 
maybe even vista please and thank you.  These tests are the prelude to 
cursoricon patches including Griswold's animated cursors & themed cursors and 
my fixes for LOTRO (mostly handling invalid calls properly).

Thanks,
Daniel


      
From acbbfdee105878c1f5f78293a1082e5bce908682 Mon Sep 17 00:00:00 2001
From: Daniel Santos <[email protected]>
Date: Mon, 8 Jun 2009 15:51:40 -0500
Subject: user32/tests: Add more intensive tests for SetCursor.

---
 dlls/user32/tests/cursoricon.c |  166 +++++++++++++++++++++++++++++++++++-----
 1 files changed, 145 insertions(+), 21 deletions(-)

diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c
index 9475534..ea968fa 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -64,6 +64,14 @@ static HANDLE child_process;
 
 #define PROC_INIT (WM_USER+1)
 
+#define __STRIZE2(x) #x
+#define __STRIZE(x) __STRIZE2(x)
+#define __FILE_SPOT __FILE__ ":" __STRIZE(__LINE__)
+
+inline static int is_win9x() {
+    return GetVersion() & 0x80000000;
+}
+
 static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, 
LPARAM lParam)
 {
     BOOL ret;
@@ -76,10 +84,11 @@ static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, 
WPARAM wParam, LPARA
             SetLastError(0xdeadbeef);
             ret = DestroyCursor((HCURSOR) lParam);
             error = GetLastError();
-            todo_wine ok(!ret || broken(ret) /* win9x */, "DestroyCursor on 
the active cursor succeeded.\n");
+            todo_wine ok(!ret || broken(is_win9x() && ret), /* win9x */
+                    "DestroyCursor on the active cursor succeeded.\n");
             ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD ||
-               error == 0xdeadbeef,  /* vista */
-                "Last error: %u\n", error);
+                    error == 0xdeadbeef,  /* vista */
+                    "Last error: %u\n", error);
             return TRUE;
         case WM_DESTROY:
             PostQuitMessage(0);
@@ -768,9 +777,94 @@ static void test_LoadImageFile(const unsigned char * 
image_data,
     DeleteFileA(filename);
 }
 
+/*************************************************************************
+ * test_SetCursor
+ *
+ * Encapsulates tests to SetCursor() function.
+ *
+ * PARAMS
+ *  target     [I] A handle to use when calling SetCursor
+ *  shouldFail [I] Rather of not it should fail
+ *  filespot   [I] The file:line location this function was called from.
+ *  retValTodo [I] True if return value is broken in wine (wine's return value
+ *                 is broken in some, but not all cases)
+ *
+ * RETURNS
+ *  The return value of the SetCursor() call.
+ */
+static HCURSOR test_SetCursor(HANDLE hNewCursor, BOOL shouldFail,
+        const char *filespot, BOOL retValTodo)
+{
+    HCURSOR cursor1, cursor2, cursor3;
+    DWORD error;
+
+    /* GetCursor should have no errors */
+    SetLastError(0xdeadbeef);
+    cursor1 = GetCursor();
+    error = GetLastError();
+    ok(error == 0xdeadbeef, "(Called from %s) GetCursor() changed last error: "
+            "%u.\n",
+            filespot, error);
+
+    /* Call SetCursor on supplied handle */
+    SetLastError(0xdeadbeef);
+    cursor2 = SetCursor(hNewCursor);
+    error = GetLastError();
+    cursor3 = GetCursor();
+
+    if (shouldFail) {
+        todo_wine ok(error == ERROR_INVALID_CURSOR_HANDLE,
+                "(Called from %s) Last error is %u (0x%08x), expected "
+                "ERROR_INVALID_CURSOR_HANDLE (%u).\n",
+                filespot, error, error, ERROR_INVALID_CURSOR_HANDLE);
+
+        if(retValTodo) {
+            todo_wine ok(!cursor2,
+                    "(Called from %s) SetCursor() returned non-zero (%p).\n",
+                    filespot, cursor2);
+        } else {
+            ok(!cursor2,
+                    "(Called from %s) SetCursor() returned non-zero (%p).\n",
+                    filespot, cursor2);
+        }
+
+        todo_wine ok(cursor1 == cursor3,
+                "(Called from %s) SetCursor() changed cursor.\n",
+                filespot);
+    } else {
+        todo_wine ok(error == 0xdeadbeef,
+                "(Called from %s) Last error is %u (0x%08x), expected "
+                "0xdeadbeef.\n",
+                filespot, error, error);
+
+        /* WinXP: For some reason, SetCursor() is returning NULL when 
hNewCursor
+         * is NULL.  Is it this way on other versions?  MSDN says it should
+         * return the old cursor.
+         */
+        if(hNewCursor) {
+            ok(cursor1 == cursor2,
+                    "(Called from %s) SetCursor() did not return the previous "
+                    "cursor.  Expected %p, got %p.\n",
+                    filespot, cursor1, cursor2);
+        } else {
+            todo_wine ok(!cursor2,
+                    "(Called from %s) SetCursor() returned %p, expected 
NULL\n",
+                    filespot, cursor2);
+        }
+
+        ok(cursor3 == hNewCursor,
+                "(Called from %s) GetCursor() did not return the value we "
+                "previously passed to SetCursor(). Expected %p, got %p.\n",
+                filespot, hNewCursor, cursor3);
+    }
+
+    return cursor2;
+}
+
 static void test_LoadImage(void)
 {
     HANDLE handle;
+    HCURSOR cursor;
     BOOL ret;
     DWORD error, bytes_written;
     CURSORICONFILEDIR *icon_data;
@@ -845,6 +939,12 @@ static void test_LoadImage(void)
         ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
     }
 
+    /* Test SetCursor with this icon */
+    cursor = test_SetCursor(handle, FALSE, __FILE_SPOT, TRUE);
+
+    /* Now change it back to the previous cursor */
+    test_SetCursor(cursor, FALSE, __FILE_SPOT, FALSE);
+
     /* Clean up. */
     SetLastError(0xdeadbeef);
     ret = DestroyCursor(handle);
@@ -855,6 +955,10 @@ static void test_LoadImage(void)
     HeapFree(GetProcessHeap(), 0, icon_data);
     DeleteFileA("icon.ico");
 
+    /* Test passing invalid handles to SetCursor. */
+    test_SetCursor(handle, TRUE, __FILE_SPOT, FALSE);
+    test_SetCursor(GetCurrentThread(), TRUE, __FILE_SPOT, TRUE);
+
     test_LoadImageFile(bmpimage, sizeof(bmpimage), "bmp", 1);
     test_LoadImageFile(gifimage, sizeof(gifimage), "gif", 0);
     test_LoadImageFile(gif4pixel, sizeof(gif4pixel), "gif", 0);
@@ -981,29 +1085,53 @@ static void test_DestroyCursor(void)
     if(!cursor) {
         return;
     }
-    SetCursor(cursor);
 
+    test_SetCursor(cursor, FALSE, __FILE_SPOT, FALSE);
+
+    /* When you attempt to destroy the current cursor, windows obliges you.
+     * On win9x, it returns TRUE (indicating success) and on NT it returns
+     * FALSE, but neither sets the last error.
+     */
     SetLastError(0xdeadbeef);
     ret = DestroyCursor(cursor);
-    ok(!ret || broken(ret)  /* succeeds on win9x */, "DestroyCursor on the 
active cursor succeeded\n");
     error = GetLastError();
-    ok(error == 0xdeadbeef, "Last error: %u\n", error);
+    ok(error == 0xdeadbeef, "Last error: 0x%x.\n", error);
+    ok(!ret || broken(is_win9x() && ret) /* succeeds on win9x */,
+            "DestroyCursor on the active cursor returned TRUE.\n");
+
+    /* QUESTION: This if statment effectively skips these tests on win9x, do we
+     * want to do that? */
     if (!ret)
     {
         cursor2 = GetCursor();
         ok(cursor2 == cursor, "Active was set to %p when trying to destroy 
it\n", cursor2);
-        SetCursor(NULL);
 
-        /* Trying to destroy the cursor properly fails now with
-         * ERROR_INVALID_CURSOR_HANDLE.  This happens because we called
-         * DestroyCursor() 2+ times after calling SetCursor().  The calls to
-         * GetCursor() and SetCursor(NULL) in between make no difference. */
+        /* Make sure showing/hiding the invalid cursor still works. */
+        SetLastError(0xdeadbeef);
+        ok(ShowCursor(TRUE) == 1, "Cursor count != 1\n");
+        ok(GetLastError() == 0xdeadbeef, "Last error: 0x%x.\n", 
GetLastError());
+
+        SetLastError(0xdeadbeef);
+        ok(ShowCursor(FALSE) == 0, "Cursor count != 0\n");
+        ok(GetLastError() == 0xdeadbeef, "Last error: 0x%x.\n", 
GetLastError());
+        test_SetCursor(NULL, FALSE, __FILE_SPOT, FALSE);
+
+        /* Trying to destroy the cursor again fails now with
+         * ERROR_INVALID_CURSOR_HANDLE.  This happens because we've previously
+         * called DestroyCursor() on this handle.  The calls to GetCursor()
+         * and SetCursor(NULL) in between make no difference.  It would appear
+         * that windows doesn't mind having an invalid cursor handle as its
+         * current cursor much the way a comatose person doesn't mind a
+         * stranger in their hospital room.
+         */
+        SetLastError(0xdeadbeef);
         ret = DestroyCursor(cursor);
         todo_wine {
             ok(!ret, "DestroyCursor succeeded.\n");
             error = GetLastError();
-            ok(error == ERROR_INVALID_CURSOR_HANDLE || error == 0xdeadbeef, /* 
vista */
-               "Last error: 0x%08x\n", error);
+            ok(error == ERROR_INVALID_CURSOR_HANDLE
+                    || broken(error == 0xdeadbeef), /* vista */
+                    "Last error: 0x%08x\n", error);
         }
     }
 
@@ -1015,17 +1143,13 @@ static void test_DestroyCursor(void)
 
     SetLastError(0xdeadbeef);
     ret = DestroyCursor(cursor);
-    ok(ret || broken(!ret) /* fails on win9x */, "DestroyCursor on the active 
cursor failed.\n");
     error = GetLastError();
-    ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
+    ok(error == 0xdeadbeef, "Last error: 0x%x.\n", error);
+    ok(ret || broken(is_win9x() && !ret) /* fails on win9x */,
+            "DestroyCursor on OEM cursor failed.\n");
 
     /* Try setting the cursor to a destroyed OEM cursor. */
-    SetLastError(0xdeadbeef);
-    SetCursor(cursor);
-    error = GetLastError();
-    todo_wine {
-        ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
-    }
+    test_SetCursor(cursor, FALSE, __FILE_SPOT, FALSE);
 
     /* Check if LoadCursor() returns the same handle with the same icon. */
     cursor2 = LoadCursor(NULL, IDC_ARROW);
-- 
1.6.2.3



Reply via email to