jscript: Added Object function invocation implementation.
[wine] / dlls / comctl32 / tests / monthcal.c
1 /*
2  * comctl32 month calendar unit tests
3  *
4  * Copyright (C) 2006 Vitaliy Margolen
5  * Copyright (C) 2007 Farshad Agah
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27
28 #include "commctrl.h"
29
30 #include "wine/test.h"
31 #include <assert.h>
32 #include <windows.h>
33 #include "msg.h"
34
35 #define expect(expected, got) ok(expected == got, "Expected %d, got %d\n", expected, got);
36
37 #define NUM_MSG_SEQUENCES   2
38 #define PARENT_SEQ_INDEX    0
39 #define MONTHCAL_SEQ_INDEX  1
40
41 struct subclass_info
42 {
43     WNDPROC oldproc;
44 };
45
46 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
47
48 static const struct message create_parent_window_seq[] = {
49     { WM_GETMINMAXINFO, sent },
50     { WM_NCCREATE, sent },
51     { WM_NCCALCSIZE, sent|wparam, 0 },
52     { WM_CREATE, sent },
53     { WM_SHOWWINDOW, sent|wparam, 1 },
54     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
55     { WM_QUERYNEWPALETTE, sent|optional },
56     { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 },
57     { WM_WINDOWPOSCHANGED, sent|optional },
58     { WM_ACTIVATEAPP, sent|wparam, 1 },
59     { WM_NCACTIVATE, sent },
60     { WM_ACTIVATE, sent|wparam, 1 },
61     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
62     { WM_IME_NOTIFY, sent|defwinproc|optional },
63     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
64     /* Win9x adds SWP_NOZORDER below */
65     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
66     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
67     { WM_SIZE, sent },
68     { WM_MOVE, sent },
69     { 0 }
70 };
71
72 static const struct message create_monthcal_control_seq[] = {
73     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
74     { WM_QUERYUISTATE, sent|optional },
75     { WM_GETFONT, sent },
76     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE},
77     { 0 }
78 };
79
80 static const struct message create_monthcal_multi_sel_style_seq[] = {
81     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
82     { WM_QUERYUISTATE, sent|optional },
83     { WM_GETFONT, sent },
84     { 0 }
85 };
86
87 static const struct message monthcal_color_seq[] = {
88     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
89     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(0,0,0)},
90     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
91     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255,255,255)},
92     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
93
94     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
95     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(0,0,0)},
96     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
97     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255,255,255)},
98     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
99
100     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
101     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(0,0,0)},
102     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
103     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255,255,255)},
104     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
105
106     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
107     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(0,0,0)},
108     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
109     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255,255,255)},
110     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
111
112     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
113     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(0,0,0)},
114     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
115     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255,255,255)},
116     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
117
118     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
119     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(0,0,0)},
120     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
121     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255,255,255)},
122     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
123     { 0 }
124 };
125
126 static const struct message monthcal_curr_date_seq[] = {
127     { MCM_SETCURSEL, sent|wparam, 0},
128     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
129     { WM_ERASEBKGND, sent|lparam|defwinproc, 0},
130     { MCM_SETCURSEL, sent|wparam, 0},
131     { MCM_SETCURSEL, sent|wparam, 0},
132     { MCM_GETCURSEL, sent|wparam, 0},
133     { MCM_GETCURSEL, sent|wparam|lparam, 0, 0},
134     { 0 }
135 };
136
137 static const struct message monthcal_first_day_seq[] = {
138     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
139
140     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -5},
141     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
142
143     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -4},
144     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
145
146     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -3},
147     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
148
149     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -2},
150     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
151
152     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -1},
153     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
154
155     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
156     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
157
158     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 1},
159     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
160
161     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 2},
162     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
163
164     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 3},
165     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
166
167     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 4},
168     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
169
170     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 5},
171     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
172
173     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 6},
174     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
175
176     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 7},
177     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
178
179     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 8},
180     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
181
182     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 9},
183     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
184
185     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 10},
186     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
187
188     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 11},
189     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
190     { 0 }
191 };
192
193 static const struct message monthcal_unicode_seq[] = {
194     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
195     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
196     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
197     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
198     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
199     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
200     { 0 }
201 };
202
203 static const struct message monthcal_hit_test_seq[] = {
204     { MCM_SETCURSEL, sent|wparam, 0},
205     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
206     { MCM_HITTEST, sent|wparam, 0},
207     { MCM_HITTEST, sent|wparam, 0},
208     { MCM_HITTEST, sent|wparam, 0},
209     { MCM_HITTEST, sent|wparam, 0},
210     { MCM_HITTEST, sent|wparam, 0},
211     { MCM_HITTEST, sent|wparam, 0},
212     { MCM_HITTEST, sent|wparam, 0},
213     { MCM_HITTEST, sent|wparam, 0},
214     { MCM_HITTEST, sent|wparam, 0},
215     { MCM_HITTEST, sent|wparam, 0},
216     { MCM_HITTEST, sent|wparam, 0},
217     { MCM_HITTEST, sent|wparam, 0},
218     { MCM_HITTEST, sent|wparam, 0},
219     { 0 }
220 };
221
222 static const struct message monthcal_todaylink_seq[] = {
223     { MCM_HITTEST, sent|wparam, 0},
224     { MCM_SETTODAY, sent|wparam, 0},
225     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
226     { MCM_GETTODAY, sent|wparam, 0},
227     { WM_LBUTTONDOWN, sent|wparam|lparam, MK_LBUTTON, MAKELONG(70, 370)},
228     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0},
229     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
230     { MCM_GETCURSEL, sent|wparam, 0},
231     { 0 }
232 };
233
234 static const struct message monthcal_today_seq[] = {
235     { MCM_SETTODAY, sent|wparam, 0},
236     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
237     { MCM_GETTODAY, sent|wparam, 0},
238     { MCM_SETTODAY, sent|wparam, 0},
239     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
240     { MCM_GETTODAY, sent|wparam, 0},
241     { 0 }
242 };
243
244 static const struct message monthcal_scroll_seq[] = {
245     { MCM_SETMONTHDELTA, sent|wparam|lparam, 2, 0},
246     { MCM_SETMONTHDELTA, sent|wparam|lparam, 3, 0},
247     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
248     { MCM_SETMONTHDELTA, sent|wparam|lparam, 12, 0},
249     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
250     { MCM_SETMONTHDELTA, sent|wparam|lparam, 15, 0},
251     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
252     { MCM_SETMONTHDELTA, sent|wparam|lparam, -5, 0},
253     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
254     { 0 }
255 };
256
257 static const struct message monthcal_monthrange_seq[] = {
258     { MCM_GETMONTHRANGE, sent|wparam, GMR_VISIBLE},
259     { MCM_GETMONTHRANGE, sent|wparam, GMR_DAYSTATE},
260     { 0 }
261 };
262
263 static const struct message monthcal_max_sel_day_seq[] = {
264     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 5, 0},
265     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
266     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 15, 0},
267     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
268     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, -1, 0},
269     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
270     { 0 }
271 };
272
273 /* expected message sequence for parent*/
274 static const struct message destroy_monthcal_parent_msgs_seq[] = {
275     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY},
276     { 0 }
277 };
278
279 /* expected message sequence for child*/
280 static const struct message destroy_monthcal_child_msgs_seq[] = {
281     { 0x0090, sent|optional }, /* Vista */
282     { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0},
283     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
284     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
285     { WM_DESTROY, sent|wparam|lparam, 0, 0},
286     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
287     { 0 }
288 };
289
290 static const struct message destroy_monthcal_multi_sel_style_seq[] = {
291     { 0x0090, sent|optional }, /* Vista */
292     { WM_DESTROY, sent|wparam|lparam, 0, 0},
293     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
294     { 0 }
295 };
296
297 /* expected message sequence for parent window*/
298 static const struct message destroy_parent_seq[] = {
299     { 0x0090, sent|optional }, /* Vista */
300     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
301     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
302     { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
303     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
304     { WM_NCACTIVATE, sent|wparam|optional, 0},
305     { WM_ACTIVATE, sent|wparam|optional, 0},
306     { WM_NCACTIVATE, sent|wparam|lparam|optional, 0, 0},
307     { WM_ACTIVATE, sent|wparam|lparam|optional, 0, 0},
308     { WM_ACTIVATEAPP, sent|wparam|optional, 0},
309     { WM_KILLFOCUS, sent|wparam|lparam|optional, 0, 0},
310     { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
311     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
312     { WM_DESTROY, sent|wparam|lparam, 0, 0},
313     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
314     { 0 }
315 };
316
317 static void test_monthcal(void)
318 {
319     HWND hwnd;
320     SYSTEMTIME st[2], st1[2];
321     int res, month_range;
322
323     hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
324                          0, 300, 300, 0, 0, NULL, NULL);
325     ok(hwnd != NULL, "Failed to create MonthCal\n");
326     GetSystemTime(&st[0]);
327     st[1] = st[0];
328
329     /* Invalid date/time */
330     st[0].wYear  = 2000;
331     /* Time should not matter */
332     st[1].wHour = st[1].wMinute = st[1].wSecond = 70;
333     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
334     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
335     ok(st1[0].wYear != 2000, "Lover limit changed\n");
336
337     st[1].wMonth = 0;
338     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");
339     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
340     ok(st1[0].wYear != 2000, "Lover limit changed\n");
341     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n");
342     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
343     ok(st1[0].wYear != 2000, "Lover limit changed\n");
344
345     GetSystemTime(&st[0]);
346     st[0].wDay = 20;
347     st[0].wMonth = 5;
348     st[1] = st[0];
349
350     month_range = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
351     st[1].wMonth--;
352     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
353     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
354     ok(res == month_range, "Invalid month range (%d)\n", res);
355     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Limits should be set\n");
356
357     st[1].wMonth += 2;
358     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
359     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
360     ok(res == month_range, "Invalid month range (%d)\n", res);
361
362     st[1].wYear --;
363     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
364     st[1].wYear += 1;
365     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
366
367     st[1].wMonth -= 3;
368     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
369     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
370     st[1].wMonth += 4;
371     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
372     st[1].wYear -= 3;
373     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
374     st[1].wYear += 4;
375     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
376     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
377
378     DestroyWindow(hwnd);
379 }
380
381 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
382 {
383     static LONG defwndproc_counter = 0;
384     LRESULT ret;
385     struct message msg;
386
387     /* log system messages, except for painting */
388     if (message < WM_USER &&
389         message != WM_PAINT &&
390         message != WM_ERASEBKGND &&
391         message != WM_NCPAINT &&
392         message != WM_NCHITTEST &&
393         message != WM_GETTEXT &&
394         message != WM_GETICON &&
395         message != WM_DEVICECHANGE)
396     {
397         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
398
399         msg.message = message;
400         msg.flags = sent|wparam|lparam;
401         if (defwndproc_counter) msg.flags |= defwinproc;
402         msg.wParam = wParam;
403         msg.lParam = lParam;
404         add_message(sequences, PARENT_SEQ_INDEX, &msg);
405     }
406
407     defwndproc_counter++;
408     ret = DefWindowProcA(hwnd, message, wParam, lParam);
409     defwndproc_counter--;
410
411     return ret;
412 }
413
414 static BOOL register_parent_wnd_class(void)
415 {
416     WNDCLASSA cls;
417
418     cls.style = 0;
419     cls.lpfnWndProc = parent_wnd_proc;
420     cls.cbClsExtra = 0;
421     cls.cbWndExtra = 0;
422     cls.hInstance = GetModuleHandleA(NULL);
423     cls.hIcon = 0;
424     cls.hCursor = LoadCursorA(0, IDC_ARROW);
425     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
426     cls.lpszMenuName = NULL;
427     cls.lpszClassName = "Month-Cal test parent class";
428     return RegisterClassA(&cls);
429 }
430
431 static HWND create_parent_window(void)
432 {
433     HWND hwnd;
434
435     InitCommonControls();
436
437     /* flush message sequences, so we can check the new sequence by the end of function */
438     flush_sequences(sequences, NUM_MSG_SEQUENCES);
439
440     if (!register_parent_wnd_class())
441         return NULL;
442
443     hwnd = CreateWindowEx(0, "Month-Cal test parent class",
444                           "Month-Cal test parent window",
445                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
446                           WS_MAXIMIZEBOX | WS_VISIBLE,
447                           0, 0, 500, 500,
448                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
449
450     assert(hwnd);
451
452     /* check for message sequences */
453     ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", FALSE);
454
455     return hwnd;
456 }
457
458 static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
459 {
460     struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
461     static LONG defwndproc_counter = 0;
462     LRESULT ret;
463     struct message msg;
464
465     msg.message = message;
466     msg.flags = sent|wparam|lparam;
467     if (defwndproc_counter) msg.flags |= defwinproc;
468     msg.wParam = wParam;
469     msg.lParam = lParam;
470     add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
471
472     defwndproc_counter++;
473     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
474     defwndproc_counter--;
475
476     return ret;
477 }
478
479 static HWND create_monthcal_control(DWORD style, HWND parent_window)
480 {
481     struct subclass_info *info;
482     HWND hwnd;
483
484     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
485     if (!info)
486         return NULL;
487
488     hwnd = CreateWindowEx(0,
489                     MONTHCAL_CLASS,
490                     "",
491                     style,
492                     0, 0, 300, 400,
493                     parent_window, NULL, GetModuleHandleA(NULL), NULL);
494
495     if (!hwnd)
496     {
497         HeapFree(GetProcessHeap(), 0, info);
498         return NULL;
499     }
500
501     info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
502                                             (LONG_PTR)monthcal_subclass_proc);
503     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
504
505     return hwnd;
506 }
507
508
509 /* Setter and Getters Tests */
510
511 static void test_monthcal_color(HWND hwnd)
512 {
513     int res, temp;
514
515     flush_sequences(sequences, NUM_MSG_SEQUENCES);
516
517     /* Setter and Getters for color*/
518     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
519     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(0,0,0));
520     expect(temp, res);
521     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
522     expect(RGB(0,0,0), temp);
523     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(255,255,255));
524     expect(temp, res);
525     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
526     expect(RGB(255,255,255), temp);
527
528     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
529     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(0,0,0));
530     expect(temp, res);
531     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
532     expect(RGB(0,0,0), temp);
533     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(255,255,255));
534     expect(temp, res);
535     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
536     expect(RGB(255,255,255), temp);
537
538     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
539     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(0,0,0));
540     expect(temp, res);
541     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
542     expect(RGB(0,0,0), temp);
543     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(255,255,255));
544     expect(temp, res);
545     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
546     expect(RGB(255,255,255), temp);
547
548     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
549     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(0,0,0));
550     expect(temp, res);
551     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
552     expect(RGB(0,0,0), temp);
553     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(255,255,255));
554     expect(temp, res);
555     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
556     expect(RGB(255,255,255), temp);
557
558     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
559     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(0,0,0));
560     expect(temp, res);
561     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
562     expect(RGB(0,0,0), temp);
563     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(255,255,255));
564     expect(temp, res);
565     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
566     expect(RGB(255,255,255), temp);
567
568     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
569     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(0,0,0));
570     expect(temp, res);
571     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
572     expect(RGB(0,0,0), temp);
573     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(255,255,255));
574     expect(temp, res);
575     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
576     expect(RGB(255,255,255), temp);
577
578     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE);
579 }
580
581 static void test_monthcal_currDate(HWND hwnd)
582 {
583     SYSTEMTIME st_original, st_new, st_test;
584     int res;
585
586     flush_sequences(sequences, NUM_MSG_SEQUENCES);
587
588     /* Setter and Getters for current date selected */
589     st_original.wYear = 2000;
590     st_original.wMonth = 11;
591     st_original.wDay = 28;
592     st_original.wHour = 11;
593     st_original.wMinute = 59;
594     st_original.wSecond = 30;
595     st_original.wMilliseconds = 0;
596     st_original.wDayOfWeek = 0;
597
598     st_new = st_test = st_original;
599
600     /* Should not validate the time */
601     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
602     expect(1,res);
603
604     /* Overflow matters, check for wDay */
605     st_test.wDay += 4;
606     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
607     expect(0,res);
608
609     /* correct wDay before checking for wMonth */
610     st_test.wDay -= 4;
611     expect(st_original.wDay, st_test.wDay);
612
613     /* Overflow matters, check for wMonth */
614     st_test.wMonth += 4;
615     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
616     expect(0,res);
617
618     /* checking if gets the information right, modify st_new */
619     st_new.wYear += 4;
620     st_new.wMonth += 4;
621     st_new.wDay += 4;
622     st_new.wHour += 4;
623     st_new.wMinute += 4;
624     st_new.wSecond += 4;
625
626     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
627     expect(1, res);
628
629     /* st_new change to st_origin, above settings with overflow */
630     /* should not change the current settings */
631     expect(st_original.wYear, st_new.wYear);
632     expect(st_original.wMonth, st_new.wMonth);
633     expect(st_original.wDay, st_new.wDay);
634     expect(st_original.wHour, st_new.wHour);
635     expect(st_original.wMinute, st_new.wMinute);
636     expect(st_original.wSecond, st_new.wSecond);
637
638     /* lparam cannot be NULL */
639     res = SendMessage(hwnd, MCM_GETCURSEL, 0, 0);
640     expect(0, res);
641
642     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE);
643 }
644
645 static void test_monthcal_firstDay(HWND hwnd)
646 {
647     int res, fday, i, prev;
648     TCHAR b[128];
649     LCID lcid = LOCALE_USER_DEFAULT;
650
651     flush_sequences(sequences, NUM_MSG_SEQUENCES);
652
653     /* Setter and Getters for first day of week */
654     /* check for locale first day */
655     if(GetLocaleInfo(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){
656         fday = atoi(b);
657         trace("fday: %d\n", fday);
658         res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
659         expect(fday, res);
660         prev = fday;
661
662         /* checking for the values that actually will be stored as */
663         /* current first day when we set a new value */
664         for (i = -5; i < 12; i++){
665             res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM) i);
666             expect(prev, res);
667             res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
668             prev = res;
669
670             if (i == -1){
671                 expect(MAKELONG(fday, FALSE), res);
672             }else if (i >= 7){
673                 /* out of range sets max first day of week, locale is ignored */
674                 expect(MAKELONG(6, TRUE), res);
675             }else{
676                 expect(MAKELONG(i, TRUE), res);
677             }
678         }
679
680         ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_first_day_seq, "monthcal firstDay", FALSE);
681
682     }else{
683         skip("Cannot retrieve first day of the week\n");
684     }
685
686 }
687
688 static void test_monthcal_unicode(HWND hwnd)
689 {
690     int res, temp;
691
692     flush_sequences(sequences, NUM_MSG_SEQUENCES);
693
694     /* Setter and Getters for Unicode format */
695
696     /* getting the current settings */
697     temp = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
698
699     /* setting to 1, should return previous settings */
700     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
701     expect(temp, res);
702
703     /* current setting is 1, so, should return 1 */
704     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
705     todo_wine {expect(1, res);}
706
707     /* setting to 0, should return previous settings */
708     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
709     todo_wine {expect(1, res);}
710
711     /* current setting is 0, so, it should return 0 */
712     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
713     expect(0, res);
714
715     /* should return previous settings */
716     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
717     expect(0, res);
718
719     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
720 }
721
722 static void test_monthcal_HitTest(HWND hwnd)
723 {
724     MCHITTESTINFO mchit;
725     UINT res;
726     SYSTEMTIME st;
727     LONG x;
728     UINT title_index;
729     static const UINT title_hits[] =
730         { MCHT_NOWHERE, MCHT_TITLEBK, MCHT_TITLEBTNPREV, MCHT_TITLEBK,
731           MCHT_TITLEMONTH, MCHT_TITLEBK, MCHT_TITLEYEAR, MCHT_TITLEBK,
732           MCHT_TITLEBTNNEXT, MCHT_TITLEBK, MCHT_NOWHERE };
733
734     memset(&mchit, 0, sizeof(MCHITTESTINFO));
735
736     flush_sequences(sequences, NUM_MSG_SEQUENCES);
737
738     st.wYear = 2007;
739     st.wMonth = 4;
740     st.wDay = 11;
741     st.wHour = 1;
742     st.wMinute = 0;
743     st.wSecond = 0;
744     st.wMilliseconds = 0;
745     st.wDayOfWeek = 0;
746
747     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
748     expect(1,res);
749
750     /* (0, 0) is the top left of the control and should not be active */
751     mchit.cbSize = sizeof(MCHITTESTINFO);
752     mchit.pt.x = 0;
753     mchit.pt.y = 0;
754     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
755     expect(0, mchit.pt.x);
756     expect(0, mchit.pt.y);
757     expect(mchit.uHit, res);
758     todo_wine {expect(MCHT_NOWHERE, res);}
759
760     /* (300, 400) is the bottom right of the control and should not be active */
761     mchit.pt.x = 300;
762     mchit.pt.y = 400;
763     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
764     expect(300, mchit.pt.x);
765     expect(400, mchit.pt.y);
766     expect(mchit.uHit, res);
767     todo_wine {expect(MCHT_NOWHERE, res);}
768
769     /* (500, 500) is completely out of the control and should not be active */
770     mchit.pt.x = 500;
771     mchit.pt.y = 500;
772     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
773     expect(500, mchit.pt.x);
774     expect(500, mchit.pt.y);
775     expect(mchit.uHit, res);
776     todo_wine {expect(MCHT_NOWHERE, res);}
777
778     /* (120, 180) is in active area - calendar background */
779     mchit.pt.x = 120;
780     mchit.pt.y = 180;
781     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
782     expect(120, mchit.pt.x);
783     expect(180, mchit.pt.y);
784     expect(mchit.uHit, res);
785     expect(MCHT_CALENDARBK, res);
786
787     /* (70, 70) is in active area - day of the week */
788     mchit.pt.x = 70;
789     mchit.pt.y = 70;
790     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
791     expect(70, mchit.pt.x);
792     expect(70, mchit.pt.y);
793     expect(mchit.uHit, res);
794     todo_wine {expect(MCHT_CALENDARDAY, res);}
795
796     /* (70, 90) is in active area - date from prev month */
797     mchit.pt.x = 70;
798     mchit.pt.y = 90;
799     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
800     expect(70, mchit.pt.x);
801     expect(90, mchit.pt.y);
802     expect(mchit.uHit, res);
803     todo_wine {expect(MCHT_CALENDARDATEPREV, res);}
804
805 #if 0
806     /* (125, 115) is in active area - date from this month */
807     mchit.pt.x = 125;
808     mchit.pt.y = 115;
809     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
810     expect(125, mchit.pt.x);
811     expect(115, mchit.pt.y);
812     expect(mchit.uHit, res);
813     expect(MCHT_CALENDARDATE, res);
814 #endif
815
816     /* (80, 220) is in active area - background section of the title */
817     mchit.pt.x = 80;
818     mchit.pt.y = 220;
819     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
820     expect(80, mchit.pt.x);
821     expect(220, mchit.pt.y);
822     expect(mchit.uHit, res);
823     todo_wine {expect(MCHT_TITLEBK, res);}
824
825     /* (140, 215) is in active area - month section of the title */
826     mchit.pt.x = 140;
827     mchit.pt.y = 215;
828     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
829     expect(140, mchit.pt.x);
830     expect(215, mchit.pt.y);
831     expect(mchit.uHit, res);
832     todo_wine {expect(MCHT_TITLEMONTH, res);}
833
834     /* (170, 215) is in active area - year section of the title */
835     mchit.pt.x = 170;
836     mchit.pt.y = 215;
837     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
838     expect(170, mchit.pt.x);
839     expect(215, mchit.pt.y);
840     expect(mchit.uHit, res);
841     todo_wine {expect(MCHT_TITLEYEAR, res);}
842
843     /* (150, 260) is in active area - date from this month */
844     mchit.pt.x = 150;
845     mchit.pt.y = 260;
846     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
847     expect(150, mchit.pt.x);
848     expect(260, mchit.pt.y);
849     expect(mchit.uHit, res);
850     todo_wine {expect(MCHT_CALENDARDATE, res);}
851
852     /* (150, 350) is in active area - date from next month */
853     mchit.pt.x = 150;
854     mchit.pt.y = 350;
855     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
856     expect(150, mchit.pt.x);
857     expect(350, mchit.pt.y);
858     expect(mchit.uHit, res);
859     todo_wine {expect(MCHT_CALENDARDATENEXT, res);}
860
861     /* (150, 370) is in active area - today link */
862     mchit.pt.x = 150;
863     mchit.pt.y = 370;
864     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
865     expect(150, mchit.pt.x);
866     expect(370, mchit.pt.y);
867     expect(mchit.uHit, res);
868     todo_wine {expect(MCHT_TODAYLINK, res);}
869
870     /* (70, 370) is in active area - today link */
871     mchit.pt.x = 70;
872     mchit.pt.y = 370;
873     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
874     expect(70, mchit.pt.x);
875     expect(370, mchit.pt.y);
876     expect(mchit.uHit, res);
877     todo_wine {expect(MCHT_TODAYLINK, res);}
878
879     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE);
880
881     /* The horizontal position of title bar elements depends on locale (y pos
882        is constant), so we sample across a horizontal line and make sure we
883        find all elements. */
884     mchit.pt.y = 40;
885     title_index = 0;
886     for (x = 0; x < 300; x++){
887         mchit.pt.x = x;
888         res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
889         expect(x, mchit.pt.x);
890         expect(40, mchit.pt.y);
891         expect(mchit.uHit, res);
892         if (res != title_hits[title_index]){
893             title_index++;
894             if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index)
895                 break;
896             todo_wine {expect(title_hits[title_index], res);}
897         }
898     }
899     todo_wine {ok(300 <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]),
900         "Wrong title layout\n");}
901 }
902
903 static void test_monthcal_todaylink(HWND hwnd)
904 {
905     MCHITTESTINFO mchit;
906     SYSTEMTIME st_test, st_new;
907     BOOL error = FALSE;
908     UINT res;
909
910     memset(&mchit, 0, sizeof(MCHITTESTINFO));
911
912     flush_sequences(sequences, NUM_MSG_SEQUENCES);
913
914     /* (70, 370) is in active area - today link */
915     mchit.cbSize = sizeof(MCHITTESTINFO);
916     mchit.pt.x = 70;
917     mchit.pt.y = 370;
918     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
919     expect(70, mchit.pt.x);
920     expect(370, mchit.pt.y);
921     expect(mchit.uHit, res);
922     todo_wine {expect(MCHT_TODAYLINK, res);}
923     if (70 != mchit.pt.x || 370 != mchit.pt.y || mchit.uHit != res
924         || MCHT_TODAYLINK != res)
925         error = TRUE;
926
927     st_test.wDay = 1;
928     st_test.wMonth = 1;
929     st_test.wYear = 2005;
930     memset(&st_new, 0, sizeof(SYSTEMTIME));
931
932     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
933
934     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
935     expect(1, res);
936     expect(1, st_new.wDay);
937     expect(1, st_new.wMonth);
938     expect(2005, st_new.wYear);
939     if (1 != res || 1 != st_new.wDay || 1 != st_new.wMonth
940         || 2005 != st_new.wYear)
941         error = TRUE;
942
943     if (error) {
944         skip("cannot perform today link test\n");
945         return;
946     }
947
948     res = SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(70, 370));
949     expect(0, res);
950
951     memset(&st_new, 0, sizeof(SYSTEMTIME));
952     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
953     expect(1, res);
954     expect(1, st_new.wDay);
955     expect(1, st_new.wMonth);
956     expect(2005, st_new.wYear);
957
958     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE);
959 }
960
961 static void test_monthcal_today(HWND hwnd)
962 {
963     SYSTEMTIME st_test, st_new;
964     int res;
965
966     flush_sequences(sequences, NUM_MSG_SEQUENCES);
967
968     /* Setter and Getters for "today" information */
969
970     /* check for overflow, should be ok */
971     st_test.wDay = 38;
972     st_test.wMonth = 38;
973
974     st_new.wDay = 27;
975     st_new.wMonth = 27;
976
977     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
978
979     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
980     expect(1, res);
981
982     /* st_test should not change */
983     expect(38, st_test.wDay);
984     expect(38, st_test.wMonth);
985
986     /* st_new should change, overflow does not matter */
987     expect(38, st_new.wDay);
988     expect(38, st_new.wMonth);
989
990     /* check for zero, should be ok*/
991     st_test.wDay = 0;
992     st_test.wMonth = 0;
993
994     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
995
996     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
997     expect(1, res);
998
999     /* st_test should not change */
1000     expect(0, st_test.wDay);
1001     expect(0, st_test.wMonth);
1002
1003     /* st_new should change to zero*/
1004     expect(0, st_new.wDay);
1005     expect(0, st_new.wMonth);
1006
1007     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
1008 }
1009
1010 static void test_monthcal_scroll(HWND hwnd)
1011 {
1012     int res;
1013
1014     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1015
1016     /* Setter and Getters for scroll rate */
1017     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0);
1018     expect(0, res);
1019
1020     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0);
1021     expect(2, res);
1022     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1023     expect(3, res);
1024
1025     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0);
1026     expect(3, res);
1027     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1028     expect(12, res);
1029
1030     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0);
1031     expect(12, res);
1032     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1033     expect(15, res);
1034
1035     res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0);
1036     expect(15, res);
1037     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1038     expect(-5, res);
1039
1040     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
1041 }
1042
1043 static void test_monthcal_monthrange(HWND hwnd)
1044 {
1045     int res;
1046     SYSTEMTIME st_visible[2], st_daystate[2];
1047
1048     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1049     st_visible[0].wYear = 0;
1050     st_visible[0].wMonth = 0;
1051     st_visible[0].wDay = 0;
1052     st_daystate[1] = st_daystate[0] = st_visible[1] = st_visible[0];
1053
1054     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
1055     todo_wine {
1056         expect(2, res);
1057         expect(2000, st_visible[0].wYear);
1058         expect(11, st_visible[0].wMonth);
1059         expect(1, st_visible[0].wDay);
1060         expect(2000, st_visible[1].wYear);
1061         expect(12, st_visible[1].wMonth);
1062         expect(31, st_visible[1].wDay);
1063     }
1064     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate);
1065     todo_wine {
1066         expect(4, res);
1067         expect(2000, st_daystate[0].wYear);
1068         expect(10, st_daystate[0].wMonth);
1069         expect(29, st_daystate[0].wDay);
1070         expect(2001, st_daystate[1].wYear);
1071         expect(1, st_daystate[1].wMonth);
1072         expect(6, st_daystate[1].wDay);
1073     }
1074
1075     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE);
1076 }
1077
1078 static void test_monthcal_MaxSelDay(HWND hwnd)
1079 {
1080     int res;
1081
1082     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1083
1084     /* Setter and Getters for max selected days */
1085     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1086     expect(1, res);
1087     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1088     expect(5, res);
1089
1090     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0);
1091     expect(1, res);
1092     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1093     expect(15, res);
1094
1095     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
1096     todo_wine {expect(0, res);}
1097     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1098     todo_wine {expect(15, res);}
1099
1100     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
1101 }
1102
1103 static void test_monthcal_size(HWND hwnd)
1104 {
1105     int res;
1106     RECT r1, r2;
1107     HFONT hFont1, hFont2;
1108     LOGFONTA logfont;
1109
1110     lstrcpyA(logfont.lfFaceName, "Arial");
1111     memset(&logfont, 0, sizeof(logfont));
1112     logfont.lfHeight = 12;
1113     hFont1 = CreateFontIndirectA(&logfont);
1114
1115     logfont.lfHeight = 24;
1116     hFont2 = CreateFontIndirectA(&logfont);
1117
1118     /* initialize to a font we can compare against */
1119     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0);
1120     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1);
1121
1122     /* check that setting a larger font results in an larger rect */
1123     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0);
1124     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2);
1125
1126     OffsetRect(&r1, -r1.left, -r1.top);
1127     OffsetRect(&r2, -r2.left, -r2.top);
1128
1129     ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n");
1130 }
1131
1132 START_TEST(monthcal)
1133 {
1134     HMODULE hComctl32;
1135     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1136     INITCOMMONCONTROLSEX iccex;
1137     HWND hwnd, parent_wnd;
1138
1139     hComctl32 = GetModuleHandleA("comctl32.dll");
1140     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1141     if (!pInitCommonControlsEx)
1142     {
1143         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
1144         return;
1145     }
1146     iccex.dwSize = sizeof(iccex);
1147     iccex.dwICC  = ICC_DATE_CLASSES;
1148     pInitCommonControlsEx(&iccex);
1149
1150     test_monthcal();
1151
1152     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1153
1154     parent_wnd = create_parent_window();
1155
1156     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1157     hwnd = create_monthcal_control(WS_CHILD | WS_BORDER | WS_VISIBLE, parent_wnd);
1158     assert(hwnd);
1159     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
1160
1161     SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
1162
1163     test_monthcal_color(hwnd);
1164     test_monthcal_currDate(hwnd);
1165     test_monthcal_firstDay(hwnd);
1166     test_monthcal_unicode(hwnd);
1167     test_monthcal_today(hwnd);
1168     test_monthcal_scroll(hwnd);
1169     test_monthcal_monthrange(hwnd);
1170     test_monthcal_HitTest(hwnd);
1171     test_monthcal_todaylink(hwnd);
1172     test_monthcal_size(hwnd);
1173
1174     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1175     DestroyWindow(hwnd);
1176     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE);
1177     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE);
1178
1179     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1180     hwnd = create_monthcal_control(MCS_MULTISELECT, parent_wnd);
1181     assert(hwnd);
1182     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
1183
1184     test_monthcal_MaxSelDay(hwnd);
1185
1186     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1187     DestroyWindow(hwnd);
1188     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE);
1189
1190     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1191     DestroyWindow(parent_wnd);
1192     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE);
1193 }