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