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 #include <assert.h>
24 #include <windows.h>
25 
26 #include "wine/heap.h"
27 #include "wine/test.h"
28 
29 /* undocumented SWP flags - from SDK 3.1 */
30 #define SWP_NOCLIENTSIZE	0x0800
31 #define SWP_NOCLIENTMOVE	0x1000
32 
33 typedef enum
34 {
35     sent = 0x1,
36     posted = 0x2,
37     parent = 0x4,
38     wparam = 0x8,
39     lparam = 0x10,
40     defwinproc = 0x20,
41     beginpaint = 0x40,
42     optional = 0x80,
43     hook = 0x100,
44     winevent_hook =0x200,
45     id = 0x400
46 } msg_flags_t;
47 
48 struct message
49 {
50     UINT message;       /* the WM_* code */
51     msg_flags_t flags;  /* message props */
52     WPARAM wParam;      /* expected value of wParam */
53     LPARAM lParam;      /* expected value of lParam */
54     UINT id;            /* extra message data: id of the window,
55                            notify code etc. */
56 };
57 
58 struct msg_sequence
59 {
60     int count;
61     int size;
62     struct message *sequence;
63 };
64 
65 static void add_message(struct msg_sequence **seq, int sequence_index,
66     const struct message *msg)
67 {
68     struct msg_sequence *msg_seq = seq[sequence_index];
69 
70     if (!msg_seq->sequence)
71     {
72         msg_seq->size = 10;
73         msg_seq->sequence = heap_alloc(msg_seq->size * sizeof (struct message));
74     }
75 
76     if (msg_seq->count == msg_seq->size)
77     {
78         msg_seq->size *= 2;
79         msg_seq->sequence = heap_realloc(msg_seq->sequence, msg_seq->size * sizeof (struct message));
80     }
81 
82     assert(msg_seq->sequence);
83 
84     msg_seq->sequence[msg_seq->count].message = msg->message;
85     msg_seq->sequence[msg_seq->count].flags = msg->flags;
86     msg_seq->sequence[msg_seq->count].wParam = msg->wParam;
87     msg_seq->sequence[msg_seq->count].lParam = msg->lParam;
88     msg_seq->sequence[msg_seq->count].id = msg->id;
89 
90     msg_seq->count++;
91 }
92 
93 static void flush_sequence(struct msg_sequence **seg, int sequence_index)
94 {
95     struct msg_sequence *msg_seq = seg[sequence_index];
96     heap_free(msg_seq->sequence);
97     msg_seq->sequence = NULL;
98     msg_seq->count = msg_seq->size = 0;
99 }
100 
101 static void flush_sequences(struct msg_sequence **seq, int n)
102 {
103     int i;
104 
105     for (i = 0; i < n; i++)
106         flush_sequence(seq, i);
107 }
108 
109 static void ok_sequence_(struct msg_sequence **seq, int sequence_index,
110     const struct message *expected, const char *context, BOOL todo,
111     const char *file, int line)
112 {
113     struct msg_sequence *msg_seq = seq[sequence_index];
114     static const struct message end_of_sequence = {0, 0, 0, 0};
115     const struct message *actual, *sequence;
116     int failcount = 0;
117 
118     add_message(seq, sequence_index, &end_of_sequence);
119 
120     sequence = msg_seq->sequence;
121     actual = sequence;
122 
123     while (expected->message && actual->message)
124     {
125         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
126 
127         if (expected->message == actual->message)
128         {
129             if (expected->flags & wparam)
130             {
131                 if (expected->wParam != actual->wParam && todo)
132                 {
133                     todo_wine
134                     {
135                         failcount++;
136                         ok_(file, line) (FALSE,
137                             "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
138                             context, expected->message, expected->wParam, actual->wParam);
139                     }
140                 }
141                 else
142                 {
143                     ok_(file, line) (expected->wParam == actual->wParam,
144                         "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
145                         context, expected->message, expected->wParam, actual->wParam);
146                 }
147             }
148 
149             if (expected->flags & lparam)
150             {
151                 if (expected->lParam != actual->lParam && todo)
152                 {
153                     todo_wine
154                     {
155                         failcount++;
156                         ok_(file, line) (FALSE,
157                             "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
158                             context, expected->message, expected->lParam, actual->lParam);
159                     }
160                 }
161                 else
162                 {
163                     ok_(file, line) (expected->lParam == actual->lParam,
164                         "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
165                         context, expected->message, expected->lParam, actual->lParam);
166                 }
167             }
168 
169             if (expected->flags & id)
170             {
171                 if (expected->id != actual->id && expected->flags & optional)
172                 {
173                     expected++;
174                     continue;
175                 }
176                 if (expected->id != actual->id && todo)
177                 {
178                     todo_wine
179                     {
180                         failcount++;
181                         ok_(file, line) (FALSE,
182                             "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n",
183                             context, expected->message, expected->id, actual->id);
184                     }
185                 }
186                 else
187                 {
188                     ok_(file, line) (expected->id == actual->id,
189                         "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n",
190                         context, expected->message, expected->id, actual->id);
191                 }
192             }
193 
194             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
195             {
196                 todo_wine
197                 {
198                     failcount++;
199                     ok_(file, line) (FALSE,
200                         "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
201                         context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
202                 }
203             }
204             else
205             {
206                 ok_(file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
207                     "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
208                     context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
209             }
210 
211             ok_(file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
212                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
213                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
214             ok_(file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
215                 "%s: the msg 0x%04x should have been %s\n",
216                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
217             ok_(file, line) ((expected->flags & parent) == (actual->flags & parent),
218                 "%s: the msg 0x%04x was expected in %s\n",
219                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
220             ok_(file, line) ((expected->flags & hook) == (actual->flags & hook),
221                 "%s: the msg 0x%04x should have been sent by a hook\n",
222                 context, expected->message);
223             ok_(file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
224                 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
225                 context, expected->message);
226             expected++;
227             actual++;
228         }
229         else if (expected->flags & optional)
230             expected++;
231         else if (todo)
232         {
233             failcount++;
234             todo_wine
235             {
236                 ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
237                     context, expected->message, actual->message);
238             }
239 
240             flush_sequence(seq, sequence_index);
241             return;
242         }
243         else
244         {
245             ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
246                 context, expected->message, actual->message);
247             expected++;
248             actual++;
249         }
250     }
251 
252     /* skip all optional trailing messages */
253     while (expected->message && ((expected->flags & optional)))
254         expected++;
255 
256     if (todo)
257     {
258         todo_wine
259         {
260             if (expected->message || actual->message)
261             {
262                 failcount++;
263                 ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
264                     context, expected->message, actual->message);
265             }
266         }
267     }
268     else if (expected->message || actual->message)
269     {
270         ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
271             context, expected->message, actual->message);
272     }
273 
274     if(todo && !failcount) /* succeeded yet marked todo */
275     {
276         todo_wine
277         {
278             ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
279         }
280     }
281 
282     flush_sequence(seq, sequence_index);
283 }
284 
285 #define ok_sequence(seq, index, exp, contx, todo) \
286         ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
287 
288 
289 static void init_msg_sequences(struct msg_sequence **seq, int n)
290 {
291     int i;
292 
293     for (i = 0; i < n; i++)
294         seq[i] = heap_alloc_zero(sizeof(struct msg_sequence));
295 }
296