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