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