At WINETEST_DEBUG <= 1, only sequence mismatches will be checked and reported.
At WINETEST_DEBUG == 2, individual message mismatches will be checked and reported, expected / received sequences will be traced on mismatch.
At WINETEST_DEBUG > 2, individual message will be checked or traced, all expected / received sequences will be traced.
Wine-Bug: https://bugs.winehq.org//show_bug.cgi?id=51780 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/msg.c | 378 +++++++++++++--------------------------- 1 file changed, 122 insertions(+), 256 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 90816a9df52..0626d77b638 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -2619,294 +2619,157 @@ static void flush_sequence(void) LeaveCriticalSection( &sequence_cs ); }
-static void dump_sequence(const struct message *expected, const char *context, const char *file, int line) +static int try_compare_message( const struct message *expected, const struct recvd_message *received ) { - const struct recvd_message *actual = sequence; - unsigned int count = 0; + static DWORD type_flags = hook | winevent_hook | kbd_hook; + int ret;
- trace_(file, line)("Failed sequence %s:\n", context ); - while (expected->message && actual->message) + if ((ret = (expected->flags & type_flags) - (received->flags & type_flags))) return ret; + if ((ret = expected->message - received->message)) return ret; + + /* validate parent and defwinproc flags for optional messages */ + if (!(expected->flags & optional)) return 0; + if ((ret = (expected->flags & defwinproc) - (received->flags & defwinproc))) return ret; + if ((ret = (expected->flags & parent) - (received->flags & parent))) return ret; + + return 0; +} + +static int compare_message( const struct message *expected, const struct recvd_message *received, + BOOL todo, const char *file, int line ) +{ + static DWORD type_flags = hook | winevent_hook | kbd_hook; + static DWORD msg_flags = sent | posted; + int ret; + + if ((ret = (expected->flags & type_flags) - (received->flags & type_flags))) goto done; + if ((ret = expected->message - received->message)) goto done; + if ((ret = (expected->flags & defwinproc) - (received->flags & defwinproc))) goto done; + if ((ret = (expected->flags & parent) - (received->flags & parent))) goto done; + if ((ret = (expected->flags & msg_flags) - (received->flags & msg_flags))) goto done; + if ((ret = (expected->flags & beginpaint) - (received->flags & beginpaint))) goto done; + if ((expected->flags & wparam) && (ret = (expected->wParam & ~expected->wp_mask) - (received->wParam & ~expected->wp_mask))) goto done; + if ((expected->flags & lparam) && (ret = (expected->lParam & ~expected->lp_mask) - (received->lParam & ~expected->lp_mask))) goto done; + +done: + if (ret && winetest_debug > 1) { - if (actual->output[0]) + todo_wine_if(todo) + ok_(file, line)( 0, "mismatch %#x, %#x, %#lx, %#lx\n", received->message, + received->flags, received->wParam, received->lParam ); + } + if (!ret && winetest_debug > 2) + trace_(file, line)( "match %#x, %#x, %#lx, %#lx\n", received->message, + received->flags, received->wParam, received->lParam ); + return ret; +} + +static BOOL find_next_message( const struct message **expected, const struct recvd_message **received, + BOOL *matches, BOOL todo, const char *file, int line ) +{ + const struct recvd_message *first_received = *received, *tmp_received, *next_received; + const struct message *first_expected = *expected, *tmp_expected, *next_expected; + BOOL winhook_todo; + + /* try matching messages in expected list with first received message */ + for (next_expected = first_expected; next_expected->message; next_expected++) + if (!try_compare_message( next_expected, first_received )) break; + + /* if current message doesn't match anything in the received list, match a non-optional message */ + if (!next_expected->message) while (first_expected->flags & optional) first_expected++; + + /* try matching messages in received list with first non-optional message */ + for (next_received = first_received; next_received->message; next_received++) + if (!try_compare_message( first_expected, next_received ) && + !(first_expected->flags & optional)) break; + + /* couldn't find a match but there's more messages to try */ + if (!next_expected->message && next_expected - first_expected > 1 && + !next_received->message && next_received - first_received > 1) + return TRUE; + + /* report the smallest mismatch which doesn't end the sequence */ + if ((next_expected->message && next_expected - first_expected < next_received - first_received) || + !next_received->message) + { + for (tmp_expected = first_expected; tmp_expected != next_expected; ++tmp_expected) { - if (expected->flags & hook) + if (tmp_expected->flags & optional) continue; + if ((tmp_expected->flags & winevent_hook) && !hEvent_hook) continue; + winhook_todo = (tmp_expected->flags & winevent_hook) && (tmp_expected->flags & winevent_hook_todo); + if (!winhook_todo) *matches = FALSE; + if (winetest_debug > 1) { - trace_(file, line)( " %u: expected: hook %04x - actual: %s\n", - count, expected->message, actual->output ); - } - else if (expected->flags & winevent_hook) - { - trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n", - count, expected->message, actual->output ); - } - else if (expected->flags & kbd_hook) - { - trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n", - count, expected->message, actual->output ); - } - else - { - trace_(file, line)( " %u: expected: msg %04x - actual: %s\n", - count, expected->message, actual->output ); + todo_wine_if(todo || winhook_todo) + ok_(file, line)( 0, "missing %#x, %#x, %#lx, %#lx\n", tmp_expected->message, + tmp_expected->flags, tmp_expected->wParam, tmp_expected->lParam ); } } + *expected = next_expected; + }
- if (expected->message == actual->message) - { - if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && - (expected->flags & optional)) - { - /* don't match messages if their defwinproc status differs */ - expected++; - } - else - { - expected++; - actual++; - } - } - /* silently drop winevent messages if there is no support for them */ - else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook) || - ((expected->flags & winevent_hook_todo) && !strcmp(winetest_platform, "wine"))) - expected++; - else + if ((next_received->message && next_received - first_received < next_expected - first_expected) || + !next_expected->message) + { + for (tmp_received = first_received; tmp_received != next_received; ++tmp_received) { - expected++; - actual++; + *matches = FALSE; + if (winetest_debug > 1) + { + todo_wine_if(todo) + ok_(file, line)( 0, "spurious %#x, %#x, %#lx, %#lx\n", tmp_received->message, + tmp_received->flags, tmp_received->wParam, tmp_received->lParam ); + } } - count++; + *received = next_received; }
- /* optional trailing messages */ - while (expected->message && ((expected->flags & optional) || - ((expected->flags & winevent_hook) && !hEvent_hook))) - { - trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message ); - expected++; - count++; - } - - if (expected->message) - { - trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message ); - return; - } - - while (actual->message && actual->output[0]) - { - trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output ); - actual++; - count++; - } + return (*expected)->message && (*received)->message; }
#define ok_sequence( exp, contx, todo) \ ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
- -static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo, +static void ok_sequence_(const struct message *expected, const char *context, BOOL todo, const char *file, int line) { static const struct recvd_message end_of_sequence; - const struct message *expected = expected_list; - const struct recvd_message *actual; - int failcount = 0, dump = 0; - unsigned int count = 0; + const struct recvd_message *first_received, *received; + const struct message *first_expected = expected; + BOOL matches = TRUE;
add_message(&end_of_sequence); + received = first_received = sequence;
- actual = sequence; - - while (expected->message && actual->message) + while (expected->message || received->message) { - if (expected->message == actual->message && - !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook))) - { - if (expected->flags & wparam) - { - if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo) - { - todo_wine { - failcount ++; - if (strcmp(winetest_platform, "wine")) dump++; - ok_( file, line) (FALSE, - "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - context, count, expected->message, expected->wParam, actual->wParam); - } - } - else - { - ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0, - "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - context, count, expected->message, expected->wParam, actual->wParam); - if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++; - } - - } - if (expected->flags & lparam) - { - if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo) - { - todo_wine { - failcount ++; - if (strcmp(winetest_platform, "wine")) dump++; - ok_( file, line) (FALSE, - "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - context, count, expected->message, expected->lParam, actual->lParam); - } - } - else - { - ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0, - "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - context, count, expected->message, expected->lParam, actual->lParam); - if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++; - } - } - if ((expected->flags & optional) && - ((expected->flags ^ actual->flags) & (defwinproc|parent))) - { - /* don't match optional messages if their defwinproc or parent status differs */ - expected++; - count++; - continue; - } - if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo) - { - todo_wine { - failcount ++; - if (strcmp(winetest_platform, "wine")) dump++; - ok_( file, line) (FALSE, - "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n", - context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); - } - } - else - { - ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc), - "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n", - context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); - if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++; - } - - ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint), - "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n", - context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT "); - if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++; - - ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)), - "%s: %u: the msg 0x%04x should have been %s\n", - context, count, expected->message, (expected->flags & posted) ? "posted" : "sent"); - if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++; - - ok_( file, line) ((expected->flags & parent) == (actual->flags & parent), - "%s: %u: the msg 0x%04x was expected in %s\n", - context, count, expected->message, (expected->flags & parent) ? "parent" : "child"); - if ((expected->flags & parent) != (actual->flags & parent)) dump++; - - ok_( file, line) ((expected->flags & hook) == (actual->flags & hook), - "%s: %u: the msg 0x%04x should have been sent by a hook\n", - context, count, expected->message); - if ((expected->flags & hook) != (actual->flags & hook)) dump++; - - ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook), - "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n", - context, count, expected->message); - if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++; - - ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook), - "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n", - context, count, expected->message); - if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++; - - expected++; - actual++; - } - /* - * silently drop hook messages if there is no support for them, mark - * winevent todo's. - */ - else if ((expected->flags & optional) || - ((expected->flags & hook) && !hCBT_hook) || - ((expected->flags & winevent_hook) && !hEvent_hook) || - ((expected->flags & kbd_hook) && !hKBD_hook) || - ((expected->flags & winevent_hook_todo) && !strcmp(winetest_platform, "wine"))) + winetest_push_context( "%u", expected - first_expected ); + if (find_next_message( &expected, &received, &matches, todo, file, line )) { - if ((expected->flags & winevent_hook_todo) && hEvent_hook) - { - todo_wine { - ok_( file, line) (FALSE, - "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - context, count, expected->message, actual->message); - } - } - expected++; - } - else if (todo) - { - failcount++; - todo_wine { - if (strcmp(winetest_platform, "wine")) dump++; - ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - context, count, expected->message, actual->message); - } - goto done; - } - else - { - ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - context, count, expected->message, actual->message); - dump++; + if (compare_message( expected, received, todo, file, line )) matches = FALSE; expected++; - actual++; + received++; } - count++; + winetest_pop_context(); }
- /* skip all optional trailing messages, check for winevent todo's. */ - while (expected->message && ((expected->flags & optional) || - ((expected->flags & hook) && !hCBT_hook) || - ((expected->flags & winevent_hook) && !hEvent_hook) || - ((expected->flags & winevent_hook_todo) && !strcmp(winetest_platform, "wine")))) + todo_wine_if(todo) + ok_(file, line)( matches, "%s mismatches\n", context ); + + if (winetest_debug > (matches ? 2 : 1)) { - if ((expected->flags & winevent_hook_todo) && hEvent_hook) - { - todo_wine { - ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected 0x%04x - actual 0x%04x\n", - context, count, expected->message, actual->message); - } - } - expected++; + trace_(file, line)( "expected:\n" ); + for (expected = first_expected; expected->message; ++expected) + trace_(file, line)( " %u: %#x, %#x, %#lx, %#lx\n", expected - first_expected, + expected->message, expected->flags, expected->wParam, + expected->lParam ); + trace_(file, line)( "received:\n" ); + for (received = first_received; received->message; ++received) + trace_(file, line)( " %u: %#x, %#x, %#lx, %#lx\n", received - first_received, + received->message, received->flags, received->wParam, + received->lParam ); }
- if (todo) - { - todo_wine { - if (expected->message || actual->message) { - failcount++; - if (strcmp(winetest_platform, "wine")) dump++; - ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n", - context, count, expected->message, actual->message); - } - } - } - else - { - if (expected->message || actual->message) - { - dump++; - ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n", - context, count, expected->message, actual->message); - } - } - if( todo && !failcount) /* succeeded yet marked todo */ - todo_wine { - if (!strcmp(winetest_platform, "wine")) dump++; - ok_( file, line)( TRUE, "%s: marked "todo_wine" but succeeds\n", context); - } - -done: - if (dump) dump_sequence(expected_list, context, file, line); flush_sequence(); }
@@ -13997,6 +13860,7 @@ static void test_ShowWindow(void) }; char comment[64]; INT idx; /* index into the above array of names */ + winetest_push_context("%u", i);
idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
@@ -14038,6 +13902,8 @@ static void test_ShowWindow(void) if (0) /* FIXME: Wine behaves completely different here */ ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition)); + + winetest_pop_context(); } DestroyWindow(hwnd); flush_events();
Also try to make some sense in the failures this change introduces. Looks like from [1] that there's a SW_HIDE behavior change in Win10.
As the failures were more inconsistent when we were using the existing windows, and as the first SW_HIDE seems consistent, it likely also depends on the events the window previously received, probably similar to the user input time on X11.
[1] https://testbot.winehq.org/JobDetails.pl?Key=106683
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/win.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 289b2c5a276..7192e737b00 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3568,9 +3568,13 @@ static void test_SetActiveWindow_0( char **argv ) DestroyWindow( hwnd ); }
-static void test_SetActiveWindow(HWND hwnd) +static void test_SetActiveWindow(void) { - HWND hwnd2, ret; + DWORD style = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE; + HWND hwnd, hwnd2, active, ret; + + hwnd = CreateWindowExA( 0, "MainWindowClass", "Main window", style, 100, 100, 200, 200, 0, 0, NULL, NULL); + ok( !!hwnd, "CreateWindowExA failed, error %u\n", GetLastError() );
flush_events( TRUE ); ShowWindow(hwnd, SW_HIDE); @@ -3586,14 +3590,22 @@ static void test_SetActiveWindow(HWND hwnd) check_wnd_state(hwnd, hwnd, hwnd, 0);
ShowWindow(hwnd, SW_HIDE); - check_wnd_state(0, 0, 0, 0); + active = GetActiveWindow(); + /* SW_HIDE only sometimes deactivates the window, consistently on Win10 >= 1809 */ + ok(active == hwnd || active == 0, "got active window %p\n", active); + check_wnd_state(active, 0, 0, 0); + + SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); + check_wnd_state(active, 0, 0, 0);
/* Invisible window. */ SetActiveWindow(hwnd); - check_wnd_state(hwnd, hwnd, hwnd, 0); - + if (active == hwnd) check_wnd_state(hwnd, hwnd, 0, 0); /* not de-activated, focus isn't restored */ + else check_wnd_state(hwnd, hwnd, hwnd, 0); + ShowWindow(hwnd, SW_SHOW); - check_wnd_state(hwnd, hwnd, hwnd, 0); + if (active == hwnd) check_wnd_state(hwnd, hwnd, 0, 0); /* not de-activated, focus isn't restored */ + else check_wnd_state(hwnd, hwnd, hwnd, 0);
hwnd2 = CreateWindowExA(0, "static", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0, hwnd, 0, 0, NULL); check_wnd_state(hwnd2, hwnd2, hwnd2, 0); @@ -3629,6 +3641,7 @@ static void test_SetActiveWindow(HWND hwnd) check_wnd_state(hwnd, hwnd, hwnd, 0);
DestroyWindow(hwnd2); + DestroyWindow(hwnd); }
struct create_window_thread_params @@ -12674,8 +12687,6 @@ START_TEST(win) test_SetWindowPos(hwndMain, hwndMain2); test_SetMenu(hwndMain); test_SetFocus(hwndMain); - test_SetActiveWindow_0( argv ); - test_SetActiveWindow(hwndMain); test_NCRedraw();
test_children_zorder(hwndMain); @@ -12742,6 +12753,9 @@ START_TEST(win) DestroyWindow(hwndMain2); DestroyWindow(hwndMain);
+ test_SetActiveWindow_0( argv ); + test_SetActiveWindow(); + /* Make sure that following tests are executed last, under Windows they * tend to break the tests which are sensitive to z-order and activation * state of hwndMain and hwndMain2 windows.
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=106690
Your paranoid android.
=== debian11 (32 bit German report) ===
user32: win.c:10012: Test failed: Timed out waiting for the child process
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=106689
Your paranoid android.
=== w8adm (32 bit report) ===
user32: msg.c:15128: Test failed: unexpected message 31f msg.c:15129: Test failed: bad wparam 1 msg.c:15135: Test failed: unicode WM_CHAR mismatches
=== debian11 (32 bit report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches
=== debian11 (32 bit Arabic:Morocco report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches
=== debian11 (32 bit German report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches
=== debian11 (32 bit French report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches
=== debian11 (32 bit Hebrew:Israel report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches
=== debian11 (32 bit Hindi:India report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches
=== debian11 (32 bit Japanese:Japan report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches
=== debian11 (32 bit Chinese:China report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches
=== debian11 (32 bit WoW report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches
=== debian11 (64 bit WoW report) ===
user32: msg.c:5437: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped mismatches