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