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