1 /* Message Sequence Testing Code 2 * 3 * Copyright (C) 2007 James Hawkins 4 * Copyright (C) 2007 Lei Zhang 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #pragma once 22 23 #include <assert.h> 24 #include <windows.h> 25 #include "wine/heap.h" 26 #include "wine/test.h" 27 28 /* undocumented SWP flags - from SDK 3.1 */ 29 #define SWP_NOCLIENTSIZE 0x0800 30 #define SWP_NOCLIENTMOVE 0x1000 31 32 typedef enum 33 { 34 sent = 0x1, 35 posted = 0x2, 36 parent = 0x4, 37 wparam = 0x8, 38 lparam = 0x10, 39 defwinproc = 0x20, 40 beginpaint = 0x40, 41 optional = 0x80, 42 hook = 0x100, 43 winevent_hook =0x200, 44 id = 0x400, 45 custdraw = 0x800 46 } msg_flags_t; 47 48 struct message 49 { 50 UINT message; /* the WM_* code */ 51 msg_flags_t flags; /* message props */ 52 WPARAM wParam; /* expected value of wParam */ 53 LPARAM lParam; /* expected value of lParam */ 54 UINT id; /* extra message data: id of the window, 55 notify code etc. */ 56 DWORD stage; /* custom draw stage */ 57 }; 58 59 struct msg_sequence 60 { 61 int count; 62 int size; 63 struct message *sequence; 64 }; 65 66 static void add_message(struct msg_sequence **seq, int sequence_index, 67 const struct message *msg) 68 { 69 struct msg_sequence *msg_seq = seq[sequence_index]; 70 71 if (!msg_seq->sequence) 72 { 73 msg_seq->size = 10; 74 msg_seq->sequence = heap_alloc(msg_seq->size * sizeof (*msg_seq->sequence)); 75 } 76 77 if (msg_seq->count == msg_seq->size) 78 { 79 msg_seq->size *= 2; 80 msg_seq->sequence = heap_realloc(msg_seq->sequence, msg_seq->size * sizeof (*msg_seq->sequence)); 81 } 82 83 assert(msg_seq->sequence); 84 85 msg_seq->sequence[msg_seq->count] = *msg; 86 msg_seq->count++; 87 } 88 89 static inline void flush_sequence(struct msg_sequence **seg, int sequence_index) 90 { 91 struct msg_sequence *msg_seq = seg[sequence_index]; 92 heap_free(msg_seq->sequence); 93 msg_seq->sequence = NULL; 94 msg_seq->count = msg_seq->size = 0; 95 } 96 97 static inline void flush_sequences(struct msg_sequence **seq, int n) 98 { 99 int i; 100 101 for (i = 0; i < n; i++) 102 flush_sequence(seq, i); 103 } 104 105 static void dump_sequence( struct msg_sequence **seq, int sequence_index, 106 const struct message *expected, const char *context, 107 const char *file, int line ) 108 { 109 struct msg_sequence *msg_seq = seq[sequence_index]; 110 const struct message *actual, *sequence; 111 unsigned int count = 0; 112 113 sequence = msg_seq->sequence; 114 actual = sequence; 115 116 trace_(file, line)("Failed sequence %s:\n", context ); 117 while (expected->message && actual->message) 118 { 119 trace_(file, line)( " %u: expected: %04x - actual: %04x wp %08lx lp %08lx\n", 120 count, expected->message, actual->message, actual->wParam, actual->lParam ); 121 122 if (expected->message == actual->message) 123 { 124 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && 125 (expected->flags & optional)) 126 { 127 /* don't match messages if their defwinproc status differs */ 128 expected++; 129 } 130 else 131 { 132 expected++; 133 actual++; 134 } 135 } 136 else 137 { 138 expected++; 139 actual++; 140 } 141 count++; 142 } 143 144 /* optional trailing messages */ 145 while (expected->message && expected->flags & optional) 146 { 147 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message ); 148 expected++; 149 count++; 150 } 151 152 if (expected->message) 153 { 154 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message ); 155 return; 156 } 157 158 while (actual->message) 159 { 160 trace_(file, line)( " %u: expected: nothing - actual: %04x wp %08lx lp %08lx\n", 161 count, actual->message, actual->wParam, actual->lParam ); 162 actual++; 163 count++; 164 } 165 } 166 167 static inline void ok_sequence_(struct msg_sequence **seq, int sequence_index, 168 const struct message *expected_list, const char *context, BOOL todo, 169 const char *file, int line) 170 { 171 static const struct message end_of_sequence = {0, 0, 0, 0}; 172 struct msg_sequence *msg_seq = seq[sequence_index]; 173 const struct message *expected = expected_list; 174 const struct message *actual, *sequence; 175 int failcount = 0, dump = 0; 176 177 add_message(seq, sequence_index, &end_of_sequence); 178 179 sequence = msg_seq->sequence; 180 actual = sequence; 181 182 while (expected->message && actual->message) 183 { 184 if (expected->message == actual->message) 185 { 186 if (expected->flags & wparam) 187 { 188 if (expected->wParam != actual->wParam && todo) 189 { 190 todo_wine 191 { 192 failcount++; 193 dump++; 194 ok_(file, line) (FALSE, 195 "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", 196 context, expected->message, expected->wParam, actual->wParam); 197 } 198 } 199 else 200 { 201 ok_(file, line) (expected->wParam == actual->wParam, 202 "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", 203 context, expected->message, expected->wParam, actual->wParam); 204 if (expected->wParam != actual->wParam) dump++; 205 } 206 } 207 208 if (expected->flags & lparam) 209 { 210 if (expected->lParam != actual->lParam && todo) 211 { 212 todo_wine 213 { 214 failcount++; 215 dump++; 216 ok_(file, line) (FALSE, 217 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", 218 context, expected->message, expected->lParam, actual->lParam); 219 } 220 } 221 else 222 { 223 ok_(file, line) (expected->lParam == actual->lParam, 224 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", 225 context, expected->message, expected->lParam, actual->lParam); 226 if (expected->lParam != actual->lParam) dump++; 227 } 228 } 229 230 if (expected->flags & custdraw) 231 { 232 if (expected->stage != actual->stage && todo) 233 { 234 todo_wine 235 { 236 failcount++; 237 dump++; 238 ok_(file, line) (FALSE, 239 "%s: in msg 0x%04x expecting cd stage 0x%08x got 0x%08x\n", 240 context, expected->message, expected->stage, actual->stage); 241 } 242 } 243 else 244 { 245 ok_(file, line) (expected->stage == actual->stage, 246 "%s: in msg 0x%04x expecting cd stage 0x%08x got 0x%08x\n", 247 context, expected->message, expected->stage, actual->stage); 248 if (expected->stage != actual->stage) dump++; 249 } 250 } 251 252 if (expected->flags & id) 253 { 254 if (expected->id != actual->id && expected->flags & optional) 255 { 256 expected++; 257 continue; 258 } 259 if (expected->id != actual->id && todo) 260 { 261 todo_wine 262 { 263 failcount++; 264 dump++; 265 ok_(file, line) (FALSE, 266 "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n", 267 context, expected->message, expected->id, actual->id); 268 } 269 } 270 else 271 { 272 ok_(file, line) (expected->id == actual->id, 273 "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n", 274 context, expected->message, expected->id, actual->id); 275 if (expected->id != actual->id) dump++; 276 } 277 } 278 279 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo) 280 { 281 todo_wine 282 { 283 failcount++; 284 dump++; 285 ok_(file, line) (FALSE, 286 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", 287 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); 288 } 289 } 290 else 291 { 292 ok_(file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc), 293 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", 294 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); 295 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++; 296 } 297 298 ok_(file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint), 299 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n", 300 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT "); 301 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++; 302 303 ok_(file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)), 304 "%s: the msg 0x%04x should have been %s\n", 305 context, expected->message, (expected->flags & posted) ? "posted" : "sent"); 306 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++; 307 308 ok_(file, line) ((expected->flags & parent) == (actual->flags & parent), 309 "%s: the msg 0x%04x was expected in %s\n", 310 context, expected->message, (expected->flags & parent) ? "parent" : "child"); 311 if ((expected->flags & parent) != (actual->flags & parent)) dump++; 312 313 ok_(file, line) ((expected->flags & hook) == (actual->flags & hook), 314 "%s: the msg 0x%04x should have been sent by a hook\n", 315 context, expected->message); 316 if ((expected->flags & hook) != (actual->flags & hook)) dump++; 317 318 ok_(file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook), 319 "%s: the msg 0x%04x should have been sent by a winevent hook\n", 320 context, expected->message); 321 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++; 322 323 expected++; 324 actual++; 325 } 326 else if (expected->flags & optional) 327 expected++; 328 else if (todo) 329 { 330 failcount++; 331 dump++; 332 todo_wine 333 { 334 ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", 335 context, expected->message, actual->message); 336 } 337 goto done; 338 } 339 else 340 { 341 ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", 342 context, expected->message, actual->message); 343 dump++; 344 expected++; 345 actual++; 346 } 347 } 348 349 /* skip all optional trailing messages */ 350 while (expected->message && ((expected->flags & optional))) 351 expected++; 352 353 if (todo) 354 { 355 todo_wine 356 { 357 if (expected->message || actual->message) 358 { 359 failcount++; 360 dump++; 361 ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", 362 context, expected->message, actual->message); 363 } 364 } 365 } 366 else if (expected->message || actual->message) 367 { 368 dump++; 369 ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", 370 context, expected->message, actual->message); 371 } 372 373 if(todo && !failcount) /* succeeded yet marked todo */ 374 { 375 if (!strcmp(winetest_platform, "wine")) dump++; 376 todo_wine 377 { 378 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context); 379 } 380 } 381 382 done: 383 if (dump) dump_sequence( seq, sequence_index, expected_list, context, file, line ); 384 flush_sequence(seq, sequence_index); 385 } 386 387 #define ok_sequence(seq, index, exp, contx, todo) \ 388 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__) 389 390 391 static inline void init_msg_sequences(struct msg_sequence **seq, int n) 392 { 393 int i; 394 395 for (i = 0; i < n; i++) 396 seq[i] = heap_alloc_zero(sizeof(*seq[i])); 397 } 398