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, const char *context, BOOL todo, 167 const char *file, int line) 168 { 169 struct msg_sequence *msg_seq = seq[sequence_index]; 170 static const struct message end_of_sequence = {0, 0, 0, 0}; 171 const struct message *actual, *sequence; 172 int failcount = 0, dump = 0; 173 174 add_message(seq, sequence_index, &end_of_sequence); 175 176 sequence = msg_seq->sequence; 177 actual = sequence; 178 179 while (expected->message && actual->message) 180 { 181 if (expected->message == actual->message) 182 { 183 if (expected->flags & wparam) 184 { 185 if (expected->wParam != actual->wParam && todo) 186 { 187 todo_wine 188 { 189 failcount++; 190 dump++; 191 ok_(file, line) (FALSE, 192 "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", 193 context, expected->message, expected->wParam, actual->wParam); 194 } 195 } 196 else 197 { 198 ok_(file, line) (expected->wParam == actual->wParam, 199 "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", 200 context, expected->message, expected->wParam, actual->wParam); 201 if (expected->wParam != actual->wParam) dump++; 202 } 203 } 204 205 if (expected->flags & lparam) 206 { 207 if (expected->lParam != actual->lParam && todo) 208 { 209 todo_wine 210 { 211 failcount++; 212 dump++; 213 ok_(file, line) (FALSE, 214 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", 215 context, expected->message, expected->lParam, actual->lParam); 216 } 217 } 218 else 219 { 220 ok_(file, line) (expected->lParam == actual->lParam, 221 "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", 222 context, expected->message, expected->lParam, actual->lParam); 223 if (expected->lParam != actual->lParam) dump++; 224 } 225 } 226 227 if (expected->flags & custdraw) 228 { 229 if (expected->stage != actual->stage && todo) 230 { 231 todo_wine 232 { 233 failcount++; 234 dump++; 235 ok_(file, line) (FALSE, 236 "%s: in msg 0x%04x expecting cd stage 0x%08x got 0x%08x\n", 237 context, expected->message, expected->stage, actual->stage); 238 } 239 } 240 else 241 { 242 ok_(file, line) (expected->stage == actual->stage, 243 "%s: in msg 0x%04x expecting cd stage 0x%08x got 0x%08x\n", 244 context, expected->message, expected->stage, actual->stage); 245 if (expected->stage != actual->stage) dump++; 246 } 247 } 248 249 if (expected->flags & id) 250 { 251 if (expected->id != actual->id && expected->flags & optional) 252 { 253 expected++; 254 continue; 255 } 256 if (expected->id != actual->id && todo) 257 { 258 todo_wine 259 { 260 failcount++; 261 dump++; 262 ok_(file, line) (FALSE, 263 "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n", 264 context, expected->message, expected->id, actual->id); 265 } 266 } 267 else 268 { 269 ok_(file, line) (expected->id == actual->id, 270 "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n", 271 context, expected->message, expected->id, actual->id); 272 if (expected->id != actual->id) dump++; 273 } 274 } 275 276 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo) 277 { 278 todo_wine 279 { 280 failcount++; 281 dump++; 282 ok_(file, line) (FALSE, 283 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", 284 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); 285 } 286 } 287 else 288 { 289 ok_(file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc), 290 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", 291 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); 292 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++; 293 } 294 295 ok_(file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint), 296 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n", 297 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT "); 298 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++; 299 300 ok_(file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)), 301 "%s: the msg 0x%04x should have been %s\n", 302 context, expected->message, (expected->flags & posted) ? "posted" : "sent"); 303 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++; 304 305 ok_(file, line) ((expected->flags & parent) == (actual->flags & parent), 306 "%s: the msg 0x%04x was expected in %s\n", 307 context, expected->message, (expected->flags & parent) ? "parent" : "child"); 308 if ((expected->flags & parent) != (actual->flags & parent)) dump++; 309 310 ok_(file, line) ((expected->flags & hook) == (actual->flags & hook), 311 "%s: the msg 0x%04x should have been sent by a hook\n", 312 context, expected->message); 313 if ((expected->flags & hook) != (actual->flags & hook)) dump++; 314 315 ok_(file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook), 316 "%s: the msg 0x%04x should have been sent by a winevent hook\n", 317 context, expected->message); 318 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++; 319 320 expected++; 321 actual++; 322 } 323 else if (expected->flags & optional) 324 expected++; 325 else if (todo) 326 { 327 failcount++; 328 dump++; 329 todo_wine 330 { 331 ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", 332 context, expected->message, actual->message); 333 } 334 goto done; 335 } 336 else 337 { 338 ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", 339 context, expected->message, actual->message); 340 dump++; 341 expected++; 342 actual++; 343 } 344 } 345 346 /* skip all optional trailing messages */ 347 while (expected->message && ((expected->flags & optional))) 348 expected++; 349 350 if (todo) 351 { 352 todo_wine 353 { 354 if (expected->message || actual->message) 355 { 356 failcount++; 357 dump++; 358 ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", 359 context, expected->message, actual->message); 360 } 361 } 362 } 363 else if (expected->message || actual->message) 364 { 365 dump++; 366 ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", 367 context, expected->message, actual->message); 368 } 369 370 if(todo && !failcount) /* succeeded yet marked todo */ 371 { 372 if (!strcmp(winetest_platform, "wine")) dump++; 373 todo_wine 374 { 375 ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context); 376 } 377 } 378 379 done: 380 if (dump) dump_sequence( seq, sequence_index, expected, context, file, line ); 381 flush_sequence(seq, sequence_index); 382 } 383 384 #define ok_sequence(seq, index, exp, contx, todo) \ 385 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__) 386 387 388 static inline void init_msg_sequences(struct msg_sequence **seq, int n) 389 { 390 int i; 391 392 for (i = 0; i < n; i++) 393 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct msg_sequence)); 394 } 395