fltlib: Add a stub dll.
[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 #define expect_hex(expected, got) ok(expected == got, "Expected %x, got %x\n", expected, got);
37
38 #define NUM_MSG_SEQUENCES   2
39 #define PARENT_SEQ_INDEX    0
40 #define MONTHCAL_SEQ_INDEX  1
41
42 struct subclass_info
43 {
44     WNDPROC oldproc;
45 };
46
47 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
48
49 static HWND parent_wnd;
50
51 static const struct message create_parent_window_seq[] = {
52     { WM_GETMINMAXINFO, sent },
53     { WM_NCCREATE, sent },
54     { WM_NCCALCSIZE, sent|wparam, 0 },
55     { WM_CREATE, sent },
56     { WM_SHOWWINDOW, sent|wparam, 1 },
57     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
58     { WM_QUERYNEWPALETTE, sent|optional },
59     { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 },
60     { WM_WINDOWPOSCHANGED, sent|optional },
61     { WM_ACTIVATEAPP, sent|wparam, 1 },
62     { WM_NCACTIVATE, sent },
63     { WM_ACTIVATE, sent|wparam, 1 },
64     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
65     { WM_IME_NOTIFY, sent|defwinproc|optional },
66     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
67     /* Win9x adds SWP_NOZORDER below */
68     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
69     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
70     { WM_SIZE, sent },
71     { WM_MOVE, sent },
72     { 0 }
73 };
74
75 static const struct message create_monthcal_control_seq[] = {
76     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
77     { WM_QUERYUISTATE, sent|optional },
78     { WM_GETFONT, sent },
79     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE},
80     { 0 }
81 };
82
83 static const struct message create_monthcal_multi_sel_style_seq[] = {
84     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
85     { WM_QUERYUISTATE, sent|optional },
86     { WM_GETFONT, sent },
87     { WM_PARENTNOTIFY, sent },
88     { 0 }
89 };
90
91 static const struct message monthcal_color_seq[] = {
92     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
93     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(0,0,0)},
94     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
95     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255,255,255)},
96     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
97
98     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
99     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(0,0,0)},
100     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
101     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255,255,255)},
102     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
103
104     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
105     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(0,0,0)},
106     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
107     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255,255,255)},
108     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
109
110     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
111     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(0,0,0)},
112     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
113     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255,255,255)},
114     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
115
116     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
117     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(0,0,0)},
118     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
119     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255,255,255)},
120     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
121
122     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
123     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(0,0,0)},
124     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
125     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255,255,255)},
126     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
127     { 0 }
128 };
129
130 static const struct message monthcal_curr_date_seq[] = {
131     { MCM_SETCURSEL, sent|wparam, 0},
132     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
133     { MCM_SETCURSEL, sent|wparam, 0},
134     { MCM_SETCURSEL, sent|wparam, 0},
135     { MCM_GETCURSEL, sent|wparam, 0},
136     { MCM_GETCURSEL, sent|wparam|lparam, 0, 0},
137     { 0 }
138 };
139
140 static const struct message monthcal_first_day_seq[] = {
141     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
142
143     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -5},
144     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
145
146     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -4},
147     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
148
149     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -3},
150     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
151
152     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -2},
153     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
154
155     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -1},
156     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
157
158     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
159     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
160
161     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 1},
162     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
163
164     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 2},
165     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
166
167     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 3},
168     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
169
170     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 4},
171     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
172
173     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 5},
174     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
175
176     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 6},
177     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
178
179     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 7},
180     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
181
182     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 8},
183     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
184
185     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 9},
186     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
187
188     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 10},
189     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
190
191     { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 11},
192     { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
193     { 0 }
194 };
195
196 static const struct message monthcal_unicode_seq[] = {
197     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
198     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
199     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
200     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
201     { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
202     { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
203     { 0 }
204 };
205
206 static const struct message monthcal_hit_test_seq[] = {
207     { MCM_SETCURSEL, sent|wparam, 0},
208     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 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_SHOWWINDOW, sent|wparam|lparam, 0, 0},
296     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
297     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
298     { WM_DESTROY, sent|wparam|lparam, 0, 0},
299     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
300     { 0 }
301 };
302
303 /* expected message sequence for parent window*/
304 static const struct message destroy_parent_seq[] = {
305     { 0x0090, sent|optional }, /* Vista */
306     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
307     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
308     { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
309     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
310     { WM_NCACTIVATE, sent|wparam|optional, 0},
311     { WM_ACTIVATE, sent|wparam|optional, 0},
312     { WM_NCACTIVATE, sent|wparam|lparam|optional, 0, 0},
313     { WM_ACTIVATE, sent|wparam|lparam|optional, 0, 0},
314     { WM_ACTIVATEAPP, sent|wparam|optional, 0},
315     { WM_KILLFOCUS, sent|wparam|lparam|optional, 0, 0},
316     { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
317     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
318     { WM_DESTROY, sent|wparam|lparam, 0, 0},
319     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
320     { 0 }
321 };
322
323 static void test_monthcal(void)
324 {
325     HWND hwnd;
326     SYSTEMTIME st[2], st1[2], today;
327     int res, month_range;
328
329     hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
330                          0, 300, 300, 0, 0, NULL, NULL);
331     ok(hwnd != NULL, "Failed to create MonthCal\n");
332
333     /* test range just after creation */
334     memset(&st, 0xcc, sizeof(st));
335     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st) == 0, "No limits should be set\n");
336
337     expect(0, st[0].wYear);
338     expect(0, st[0].wMonth);
339     expect(0, st[0].wDay);
340     expect(0, st[0].wDayOfWeek);
341     expect(0, st[0].wHour);
342     expect(0, st[0].wMinute);
343     expect(0, st[0].wSecond);
344     expect(0, st[0].wMilliseconds);
345
346     expect(0, st[1].wYear);
347     expect(0, st[1].wMonth);
348     expect(0, st[1].wDay);
349     expect(0, st[1].wDayOfWeek);
350     expect(0, st[1].wHour);
351     expect(0, st[1].wMinute);
352     expect(0, st[1].wSecond);
353     expect(0, st[1].wMilliseconds);
354
355     GetSystemTime(&st[0]);
356     st[1] = st[0];
357
358     SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&today);
359
360     /* Invalid date/time */
361     st[0].wYear  = 2000;
362     /* Time should not matter */
363     st[1].wHour = st[1].wMinute = st[1].wSecond = 70;
364     st[1].wMilliseconds = 1200;
365     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
366     /* invalid timestamp is written back with today data and msecs untouched */
367     expect(today.wHour, st[1].wHour);
368     expect(today.wMinute, st[1].wMinute);
369     expect(today.wSecond, st[1].wSecond);
370     expect(1200, st[1].wMilliseconds);
371
372     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
373     ok(st1[0].wYear != 2000, "Lover limit changed\n");
374     /* invalid timestamp should be replaced with today data, except msecs */
375     expect(today.wHour, st1[1].wHour);
376     expect(today.wMinute, st1[1].wMinute);
377     expect(today.wSecond, st1[1].wSecond);
378     expect(1200, st1[1].wMilliseconds);
379
380     /* Invalid date/time with invalid milliseconds only */
381     GetSystemTime(&st[0]);
382     st[1] = st[0];
383     /* Time should not matter */
384     st[1].wMilliseconds = 1200;
385     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
386     /* invalid milliseconds field doesn't lead to invalid timestamp */
387     expect(st[0].wHour,   st[1].wHour);
388     expect(st[0].wMinute, st[1].wMinute);
389     expect(st[0].wSecond, st[1].wSecond);
390     expect(1200, st[1].wMilliseconds);
391
392     GetSystemTime(&st[0]);
393
394     st[1].wMonth = 0;
395     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");
396     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
397     ok(st1[0].wYear != 2000, "Lover limit changed\n");
398     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n");
399     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
400     ok(st1[0].wYear != 2000, "Lover limit changed\n");
401
402     GetSystemTime(&st[0]);
403     st[0].wDay = 20;
404     st[0].wMonth = 5;
405     st[1] = st[0];
406
407     month_range = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
408     st[1].wMonth--;
409     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
410     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
411     ok(res == month_range, "Invalid month range (%d)\n", res);
412     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Limits should be set\n");
413
414     st[1].wMonth += 2;
415     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
416     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
417     ok(res == month_range, "Invalid month range (%d)\n", res);
418
419     st[1].wYear --;
420     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
421     st[1].wYear += 1;
422     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
423
424     st[1].wMonth -= 3;
425     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
426     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
427     st[1].wMonth += 4;
428     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
429     st[1].wYear -= 3;
430     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
431     st[1].wYear += 4;
432     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
433     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
434
435     /* set both limits, then set max < min */
436     GetSystemTime(&st[0]);
437     st[1] = st[0];
438     st[1].wYear++;
439     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN|GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
440     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Min limit expected\n");
441     st[1].wYear -= 2;
442     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
443     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Max limit expected\n");
444
445     expect(0, st1[0].wYear);
446     expect(0, st1[0].wMonth);
447     expect(0, st1[0].wDay);
448     expect(0, st1[0].wDayOfWeek);
449     expect(0, st1[0].wHour);
450     expect(0, st1[0].wMinute);
451     expect(0, st1[0].wSecond);
452     expect(0, st1[0].wMilliseconds);
453
454     expect(st[1].wYear,      st1[1].wYear);
455     expect(st[1].wMonth,     st1[1].wMonth);
456     expect(st[1].wDay,       st1[1].wDay);
457     expect(st[1].wDayOfWeek, st1[1].wDayOfWeek);
458     expect(st[1].wHour,      st1[1].wHour);
459     expect(st[1].wMinute,    st1[1].wMinute);
460     expect(st[1].wSecond,    st1[1].wSecond);
461     expect(st[1].wMilliseconds, st1[1].wMilliseconds);
462
463     st[1] = st[0];
464     st[1].wYear++;
465     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN|GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
466     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Min limit expected\n");
467     st[0].wYear++; /* start == end now */
468     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN, (LPARAM)st), "Failed to set limits\n");
469     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MIN, "Min limit expected\n");
470
471     expect(st[0].wYear,      st1[0].wYear);
472     expect(st[0].wMonth,     st1[0].wMonth);
473     expect(st[0].wDay,       st1[0].wDay);
474     expect(st[0].wDayOfWeek, st1[0].wDayOfWeek);
475     expect(st[0].wHour,      st1[0].wHour);
476     expect(st[0].wMinute,    st1[0].wMinute);
477     expect(st[0].wSecond,    st1[0].wSecond);
478     expect(st[0].wMilliseconds, st1[0].wMilliseconds);
479
480     expect(0, st1[1].wYear);
481     expect(0, st1[1].wMonth);
482     expect(0, st1[1].wDay);
483     expect(0, st1[1].wDayOfWeek);
484     expect(0, st1[1].wHour);
485     expect(0, st1[1].wMinute);
486     expect(0, st1[1].wSecond);
487     expect(0, st1[1].wMilliseconds);
488
489     DestroyWindow(hwnd);
490 }
491
492 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
493 {
494     static LONG defwndproc_counter = 0;
495     LRESULT ret;
496     struct message msg;
497
498     /* log system messages, except for painting */
499     if (message < WM_USER &&
500         message != WM_PAINT &&
501         message != WM_ERASEBKGND &&
502         message != WM_NCPAINT &&
503         message != WM_NCHITTEST &&
504         message != WM_GETTEXT &&
505         message != WM_GETICON &&
506         message != WM_DEVICECHANGE)
507     {
508         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
509
510         msg.message = message;
511         msg.flags = sent|wparam|lparam;
512         if (defwndproc_counter) msg.flags |= defwinproc;
513         msg.wParam = wParam;
514         msg.lParam = lParam;
515         add_message(sequences, PARENT_SEQ_INDEX, &msg);
516     }
517
518     defwndproc_counter++;
519     ret = DefWindowProcA(hwnd, message, wParam, lParam);
520     defwndproc_counter--;
521
522     return ret;
523 }
524
525 static BOOL register_parent_wnd_class(void)
526 {
527     WNDCLASSA cls;
528
529     cls.style = 0;
530     cls.lpfnWndProc = parent_wnd_proc;
531     cls.cbClsExtra = 0;
532     cls.cbWndExtra = 0;
533     cls.hInstance = GetModuleHandleA(NULL);
534     cls.hIcon = 0;
535     cls.hCursor = LoadCursorA(0, IDC_ARROW);
536     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
537     cls.lpszMenuName = NULL;
538     cls.lpszClassName = "Month-Cal test parent class";
539     return RegisterClassA(&cls);
540 }
541
542 static HWND create_parent_window(void)
543 {
544     HWND hwnd;
545
546     InitCommonControls();
547
548     /* flush message sequences, so we can check the new sequence by the end of function */
549     flush_sequences(sequences, NUM_MSG_SEQUENCES);
550
551     if (!register_parent_wnd_class())
552         return NULL;
553
554     hwnd = CreateWindowEx(0, "Month-Cal test parent class",
555                           "Month-Cal test parent window",
556                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
557                           WS_MAXIMIZEBOX | WS_VISIBLE,
558                           0, 0, 500, 500,
559                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
560
561     assert(hwnd);
562
563     /* check for message sequences */
564     ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", FALSE);
565
566     return hwnd;
567 }
568
569 static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
570 {
571     struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
572     static LONG defwndproc_counter = 0;
573     LRESULT ret;
574     struct message msg;
575
576     msg.message = message;
577     msg.flags = sent|wparam|lparam;
578     if (defwndproc_counter) msg.flags |= defwinproc;
579     msg.wParam = wParam;
580     msg.lParam = lParam;
581     add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
582
583     defwndproc_counter++;
584     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
585     defwndproc_counter--;
586
587     return ret;
588 }
589
590 static HWND create_monthcal_control(DWORD style)
591 {
592     struct subclass_info *info;
593     HWND hwnd;
594
595     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
596     if (!info)
597         return NULL;
598
599     hwnd = CreateWindowEx(0,
600                     MONTHCAL_CLASS,
601                     "",
602                     WS_CHILD | WS_BORDER | WS_VISIBLE | style,
603                     0, 0, 300, 400,
604                     parent_wnd, NULL, GetModuleHandleA(NULL), NULL);
605
606     if (!hwnd)
607     {
608         HeapFree(GetProcessHeap(), 0, info);
609         return NULL;
610     }
611
612     info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
613                                             (LONG_PTR)monthcal_subclass_proc);
614     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
615
616     SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
617
618     return hwnd;
619 }
620
621
622 /* Setter and Getters Tests */
623
624 static void test_monthcal_color(void)
625 {
626     int res, temp;
627     HWND hwnd;
628
629     hwnd = create_monthcal_control(0);
630
631     flush_sequences(sequences, NUM_MSG_SEQUENCES);
632
633     /* Setter and Getters for color*/
634     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
635     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(0,0,0));
636     expect(temp, res);
637     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
638     expect(RGB(0,0,0), temp);
639     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(255,255,255));
640     expect(temp, res);
641     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
642     expect(RGB(255,255,255), temp);
643
644     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
645     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(0,0,0));
646     expect(temp, res);
647     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
648     expect(RGB(0,0,0), temp);
649     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(255,255,255));
650     expect(temp, res);
651     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
652     expect(RGB(255,255,255), temp);
653
654     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
655     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(0,0,0));
656     expect(temp, res);
657     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
658     expect(RGB(0,0,0), temp);
659     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(255,255,255));
660     expect(temp, res);
661     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
662     expect(RGB(255,255,255), temp);
663
664     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
665     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(0,0,0));
666     expect(temp, res);
667     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
668     expect(RGB(0,0,0), temp);
669     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(255,255,255));
670     expect(temp, res);
671     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
672     expect(RGB(255,255,255), temp);
673
674     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
675     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(0,0,0));
676     expect(temp, res);
677     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
678     expect(RGB(0,0,0), temp);
679     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(255,255,255));
680     expect(temp, res);
681     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
682     expect(RGB(255,255,255), temp);
683
684     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
685     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(0,0,0));
686     expect(temp, res);
687     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
688     expect(RGB(0,0,0), temp);
689     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(255,255,255));
690     expect(temp, res);
691     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
692     expect(RGB(255,255,255), temp);
693
694     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE);
695
696     DestroyWindow(hwnd);
697 }
698
699 static void test_monthcal_currdate(void)
700 {
701     SYSTEMTIME st_original, st_new, st_test;
702     int res;
703     HWND hwnd;
704
705     hwnd = create_monthcal_control(0);
706
707     flush_sequences(sequences, NUM_MSG_SEQUENCES);
708
709     /* Setter and Getters for current date selected */
710     st_original.wYear = 2000;
711     st_original.wMonth = 11;
712     st_original.wDay = 28;
713     st_original.wHour = 11;
714     st_original.wMinute = 59;
715     st_original.wSecond = 30;
716     st_original.wMilliseconds = 0;
717     st_original.wDayOfWeek = 0;
718
719     st_new = st_test = st_original;
720
721     /* Should not validate the time */
722     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
723     expect(1,res);
724
725     /* Overflow matters, check for wDay */
726     st_test.wDay += 4;
727     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
728     expect(0,res);
729
730     /* correct wDay before checking for wMonth */
731     st_test.wDay -= 4;
732     expect(st_original.wDay, st_test.wDay);
733
734     /* Overflow matters, check for wMonth */
735     st_test.wMonth += 4;
736     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
737     expect(0,res);
738
739     /* checking if gets the information right, modify st_new */
740     st_new.wYear += 4;
741     st_new.wMonth += 4;
742     st_new.wDay += 4;
743     st_new.wHour += 4;
744     st_new.wMinute += 4;
745     st_new.wSecond += 4;
746
747     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
748     expect(1, res);
749
750     /* st_new change to st_origin, above settings with overflow */
751     /* should not change the current settings */
752     expect(st_original.wYear, st_new.wYear);
753     expect(st_original.wMonth, st_new.wMonth);
754     expect(st_original.wDay, st_new.wDay);
755     expect(st_original.wHour, st_new.wHour);
756     expect(st_original.wMinute, st_new.wMinute);
757     expect(st_original.wSecond, st_new.wSecond);
758
759     /* lparam cannot be NULL */
760     res = SendMessage(hwnd, MCM_GETCURSEL, 0, 0);
761     expect(0, res);
762
763     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE);
764
765     DestroyWindow(hwnd);
766 }
767
768 static void test_monthcal_firstDay(void)
769 {
770     int res, fday, i, prev;
771     CHAR b[128];
772     LCID lcid = LOCALE_USER_DEFAULT;
773     HWND hwnd;
774
775     hwnd = create_monthcal_control(0);
776
777     flush_sequences(sequences, NUM_MSG_SEQUENCES);
778
779     /* Setter and Getters for first day of week */
780     /* check for locale first day */
781     if(GetLocaleInfoA(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){
782         fday = atoi(b);
783         trace("fday: %d\n", fday);
784         res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
785         expect(fday, res);
786         prev = fday;
787
788         /* checking for the values that actually will be stored as */
789         /* current first day when we set a new value */
790         for (i = -5; i < 12; i++){
791             res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM) i);
792             expect(prev, res);
793             res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
794             prev = res;
795
796             if (i == -1){
797                 expect(MAKELONG(fday, FALSE), res);
798             }else if (i >= 7){
799                 /* out of range sets max first day of week, locale is ignored */
800                 expect(MAKELONG(6, TRUE), res);
801             }else{
802                 expect(MAKELONG(i, TRUE), res);
803             }
804         }
805
806         ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_first_day_seq, "monthcal firstDay", FALSE);
807
808     }else{
809         skip("Cannot retrieve first day of the week\n");
810     }
811
812     DestroyWindow(hwnd);
813 }
814
815 static void test_monthcal_unicode(void)
816 {
817     int res, temp;
818     HWND hwnd;
819
820     hwnd = create_monthcal_control(0);
821
822     flush_sequences(sequences, NUM_MSG_SEQUENCES);
823
824     /* Setter and Getters for Unicode format */
825
826     /* getting the current settings */
827     temp = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
828
829     /* setting to 1, should return previous settings */
830     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
831     expect(temp, res);
832
833     /* current setting is 1, so, should return 1 */
834     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
835     todo_wine {expect(1, res);}
836
837     /* setting to 0, should return previous settings */
838     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
839     todo_wine {expect(1, res);}
840
841     /* current setting is 0, so, it should return 0 */
842     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
843     expect(0, res);
844
845     /* should return previous settings */
846     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
847     expect(0, res);
848
849     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
850
851     DestroyWindow(hwnd);
852 }
853
854 static void test_monthcal_hittest(void)
855 {
856     typedef struct hittest_test
857     {
858         UINT ht;
859         int  todo;
860     } hittest_test_t;
861
862     static const hittest_test_t title_hits[] = {
863         { MCHT_NOWHERE,      0 },
864         { MCHT_TITLEBTNPREV, 0 },
865         { MCHT_TITLEMONTH,   1 },
866         { MCHT_TITLEYEAR,    1 },
867         { MCHT_TITLEBTNNEXT, 0 },
868         { MCHT_NOWHERE,      0 }
869     };
870
871     MCHITTESTINFO mchit;
872     UINT res, old_res;
873     SYSTEMTIME st;
874     LONG x;
875     UINT title_index;
876     HWND hwnd;
877     RECT r;
878
879     memset(&mchit, 0, sizeof(MCHITTESTINFO));
880
881     hwnd = create_monthcal_control(0);
882
883     /* test with invalid structure size */
884     mchit.cbSize = MCHITTESTINFO_V1_SIZE - 1;
885     mchit.pt.x = 0;
886     mchit.pt.y = 0;
887     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
888     expect(0, mchit.pt.x);
889     expect(0, mchit.pt.y);
890     expect(-1, res);
891     expect(0, mchit.uHit);
892     /* test with invalid pointer */
893     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)NULL);
894     expect(-1, res);
895
896     /* resize control to display single Calendar */
897     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r);
898     if (res == 0)
899     {
900         win_skip("Message MCM_GETMINREQRECT unsupported. Skipping.\n");
901         DestroyWindow(hwnd);
902         return;
903     }
904     MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE);
905
906     flush_sequences(sequences, NUM_MSG_SEQUENCES);
907
908     st.wYear = 2007;
909     st.wMonth = 4;
910     st.wDay = 11;
911     st.wHour = 1;
912     st.wMinute = 0;
913     st.wSecond = 0;
914     st.wMilliseconds = 0;
915     st.wDayOfWeek = 0;
916
917     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
918     expect(1,res);
919
920     /* (0, 0) is the top left of the control - title */
921     mchit.cbSize = MCHITTESTINFO_V1_SIZE;
922     mchit.pt.x = 0;
923     mchit.pt.y = 0;
924     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
925     expect(0, mchit.pt.x);
926     expect(0, mchit.pt.y);
927     expect(mchit.uHit, res);
928     expect_hex(MCHT_TITLE, res);
929
930     /* bottom right of the control and should not be active */
931     mchit.pt.x = r.right;
932     mchit.pt.y = r.bottom;
933     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
934     expect(r.right,  mchit.pt.x);
935     expect(r.bottom, mchit.pt.y);
936     expect(mchit.uHit, res);
937     todo_wine expect_hex(MCHT_NOWHERE, res);
938
939     /* completely out of the control, should not be active */
940     mchit.pt.x = 2 * r.right;
941     mchit.pt.y = 2 * r.bottom;
942     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
943     expect(2 * r.right, mchit.pt.x);
944     expect(2 * r.bottom, mchit.pt.y);
945     expect(mchit.uHit, res);
946     todo_wine expect_hex(MCHT_NOWHERE, res);
947
948     /* in active area - day of the week */
949     mchit.pt.x = r.right / 2;
950     mchit.pt.y = r.bottom / 2;
951     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
952     expect(r.right / 2, mchit.pt.x);
953     expect(r.bottom / 2, mchit.pt.y);
954     expect(mchit.uHit, res);
955     expect_hex(MCHT_CALENDARDATE, res);
956
957     /* in active area - day of the week #2 */
958     mchit.pt.x = r.right / 14; /* half of first day rect */
959     mchit.pt.y = r.bottom / 2;
960     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
961     expect(r.right / 14, mchit.pt.x);
962     expect(r.bottom / 2, mchit.pt.y);
963     expect(mchit.uHit, res);
964     expect_hex(MCHT_CALENDARDATE, res);
965
966     /* in active area - date from prev month */
967     mchit.pt.x = r.right / 14; /* half of first day rect */
968     mchit.pt.y = 6 * r.bottom / 19;
969     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
970     expect(r.right / 14, mchit.pt.x);
971     expect(6 * r.bottom / 19, mchit.pt.y);
972     expect(mchit.uHit, res);
973     expect_hex(MCHT_CALENDARDATEPREV, res);
974
975 #if 0
976     /* (125, 115) is in active area - date from this month */
977     mchit.pt.x = 125;
978     mchit.pt.y = 115;
979     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
980     expect(125, mchit.pt.x);
981     expect(115, mchit.pt.y);
982     expect(mchit.uHit, res);
983     expect(MCHT_CALENDARDATE, res);
984 #endif
985
986     /* in active area - background section of the title */
987     mchit.pt.x = 2 * r.right / 7;
988     mchit.pt.y = 2 * r.bottom / 19;
989     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
990     expect(2 * r.right / 7, mchit.pt.x);
991     expect(2 * r.bottom / 19, mchit.pt.y);
992     expect(mchit.uHit, res);
993     expect_hex(MCHT_TITLEBK, res);
994
995     /* in active area - month section of the title */
996     mchit.pt.x = r.right / 2;
997     mchit.pt.y = 2 * r.bottom / 19;
998     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
999     expect(r.right / 2, mchit.pt.x);
1000     expect(2 * r.bottom / 19, mchit.pt.y);
1001     expect(mchit.uHit, res);
1002     expect_hex(MCHT_TITLE, res);
1003
1004     /* in active area - year section of the title */
1005     mchit.pt.x = 3 * r.right / 4;
1006     mchit.pt.y = 2 * r.bottom / 19;
1007     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1008     expect(3 * r.right / 4, mchit.pt.x);
1009     expect(2 * r.bottom / 19, mchit.pt.y);
1010     expect(mchit.uHit, res);
1011     expect_hex(MCHT_TITLE, res);
1012
1013     /* in active area - date from next month */
1014     mchit.pt.x = 11 * r.right / 14;
1015     mchit.pt.y = 16 * r.bottom / 19;
1016     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1017     expect(11 * r.right / 14, mchit.pt.x);
1018     expect(16 * r.bottom / 19, mchit.pt.y);
1019     expect(mchit.uHit, res);
1020     expect_hex(MCHT_CALENDARDATENEXT, res);
1021
1022     /* in active area - today link */
1023     mchit.pt.x = r.right / 14;
1024     mchit.pt.y = 18 * r.bottom / 19;
1025     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1026     expect(r.right / 14, mchit.pt.x);
1027     expect(18 * r.bottom / 19, mchit.pt.y);
1028     expect(mchit.uHit, res);
1029     expect_hex(MCHT_TODAYLINK, res);
1030
1031     /* in active area - today link */
1032     mchit.pt.x = r.right / 2;
1033     mchit.pt.y = 18 * r.bottom / 19;
1034     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1035     expect(r.right / 2, mchit.pt.x);
1036     expect(18 * r.bottom / 19, mchit.pt.y);
1037     expect(mchit.uHit, res);
1038     expect_hex(MCHT_TODAYLINK, res);
1039
1040     /* in active area - today link */
1041     mchit.pt.x = r.right / 10;
1042     mchit.pt.y = 18 * r.bottom / 19;
1043     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1044     expect(r.right / 10, mchit.pt.x);
1045     expect(18 * r.bottom / 19, mchit.pt.y);
1046     expect(mchit.uHit, res);
1047     expect_hex(MCHT_TODAYLINK, res);
1048
1049     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE);
1050
1051     /* The horizontal position of title bar elements depends on locale (y pos
1052        is constant), so we sample across a horizontal line and make sure we
1053        find all elements. */
1054     mchit.pt.x = 0;
1055     mchit.pt.y = (5/2) * r.bottom / 19;
1056     title_index = 0;
1057     old_res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1058
1059     for (x = 0; x < r.right; x++){
1060         mchit.pt.x = x;
1061         res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1062         expect(x, mchit.pt.x);
1063         expect((5/2) * r.bottom / 19, mchit.pt.y);
1064         expect(mchit.uHit, res);
1065
1066         if (res != MCHT_TITLEBK && res != old_res) {
1067             title_index++;
1068             old_res = res;
1069
1070             if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index)
1071                 break;
1072
1073             if (title_hits[title_index].todo) {
1074                 todo_wine
1075                   ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n",
1076                                                          title_hits[title_index].ht, res, x);
1077             }
1078             else ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n",
1079                                                         title_hits[title_index].ht, res, x);
1080         }
1081     }
1082
1083     todo_wine
1084         ok(r.right <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]),
1085            "Wrong title layout\n");
1086
1087     DestroyWindow(hwnd);
1088 }
1089
1090 static void test_monthcal_todaylink(void)
1091 {
1092     MCHITTESTINFO mchit;
1093     SYSTEMTIME st_test, st_new;
1094     BOOL error = FALSE;
1095     UINT res;
1096     HWND hwnd;
1097
1098     memset(&mchit, 0, sizeof(MCHITTESTINFO));
1099
1100     hwnd = create_monthcal_control(0);
1101
1102     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1103
1104     /* (70, 370) is in active area - today link */
1105     mchit.cbSize = MCHITTESTINFO_V1_SIZE;
1106     mchit.pt.x = 70;
1107     mchit.pt.y = 370;
1108     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
1109     expect(70, mchit.pt.x);
1110     expect(370, mchit.pt.y);
1111     expect(mchit.uHit, res);
1112     todo_wine {expect(MCHT_TODAYLINK, res);}
1113     if (70 != mchit.pt.x || 370 != mchit.pt.y || mchit.uHit != res
1114         || MCHT_TODAYLINK != res)
1115         error = TRUE;
1116
1117     st_test.wDay = 1;
1118     st_test.wMonth = 1;
1119     st_test.wYear = 2005;
1120     memset(&st_new, 0, sizeof(SYSTEMTIME));
1121
1122     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1123
1124     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1125     expect(1, res);
1126     expect(1, st_new.wDay);
1127     expect(1, st_new.wMonth);
1128     expect(2005, st_new.wYear);
1129     if (1 != res || 1 != st_new.wDay || 1 != st_new.wMonth
1130         || 2005 != st_new.wYear)
1131         error = TRUE;
1132
1133     if (error) {
1134         skip("cannot perform today link test\n");
1135         return;
1136     }
1137
1138     res = SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(70, 370));
1139     expect(0, res);
1140
1141     memset(&st_new, 0, sizeof(SYSTEMTIME));
1142     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
1143     expect(1, res);
1144     expect(1, st_new.wDay);
1145     expect(1, st_new.wMonth);
1146     expect(2005, st_new.wYear);
1147
1148     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE);
1149
1150     DestroyWindow(hwnd);
1151 }
1152
1153 static void test_monthcal_today(void)
1154 {
1155     SYSTEMTIME st_test, st_new;
1156     int res;
1157     HWND hwnd;
1158
1159     hwnd = create_monthcal_control(0);
1160
1161     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1162
1163     /* Setter and Getters for "today" information */
1164
1165     /* check for overflow, should be ok */
1166     st_test.wDay = 38;
1167     st_test.wMonth = 38;
1168
1169     st_new.wDay = 27;
1170     st_new.wMonth = 27;
1171
1172     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1173
1174     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1175     expect(1, res);
1176
1177     /* st_test should not change */
1178     expect(38, st_test.wDay);
1179     expect(38, st_test.wMonth);
1180
1181     /* st_new should change, overflow does not matter */
1182     expect(38, st_new.wDay);
1183     expect(38, st_new.wMonth);
1184
1185     /* check for zero, should be ok*/
1186     st_test.wDay = 0;
1187     st_test.wMonth = 0;
1188
1189     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
1190
1191     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
1192     expect(1, res);
1193
1194     /* st_test should not change */
1195     expect(0, st_test.wDay);
1196     expect(0, st_test.wMonth);
1197
1198     /* st_new should change to zero*/
1199     expect(0, st_new.wDay);
1200     expect(0, st_new.wMonth);
1201
1202     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
1203
1204     DestroyWindow(hwnd);
1205 }
1206
1207 static void test_monthcal_scroll(void)
1208 {
1209     int res;
1210     HWND hwnd;
1211
1212     hwnd = create_monthcal_control(0);
1213
1214     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1215
1216     /* Setter and Getters for scroll rate */
1217     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0);
1218     expect(0, res);
1219
1220     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0);
1221     expect(2, res);
1222     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1223     expect(3, res);
1224
1225     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0);
1226     expect(3, res);
1227     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1228     expect(12, res);
1229
1230     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0);
1231     expect(12, res);
1232     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1233     expect(15, res);
1234
1235     res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0);
1236     expect(15, res);
1237     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
1238     expect(-5, res);
1239
1240     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
1241
1242     DestroyWindow(hwnd);
1243 }
1244
1245 static void test_monthcal_monthrange(void)
1246 {
1247     int res;
1248     SYSTEMTIME st_visible[2], st_daystate[2], st;
1249     HWND hwnd;
1250
1251     hwnd = create_monthcal_control(0);
1252
1253     st_visible[0].wYear = 0;
1254     st_visible[0].wMonth = 0;
1255     st_visible[0].wDay = 0;
1256     st_daystate[1] = st_daystate[0] = st_visible[1] = st_visible[0];
1257
1258     st.wYear = 2000;
1259     st.wMonth = 11;
1260     st.wDay = 28;
1261     st.wHour = 11;
1262     st.wMinute = 59;
1263     st.wSecond = 30;
1264     st.wMilliseconds = 0;
1265     st.wDayOfWeek = 0;
1266
1267     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
1268     expect(1,res);
1269
1270     /* to be locale independent */
1271     SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM)6);
1272
1273     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1274
1275     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
1276     todo_wine {
1277         expect(2, res);
1278         expect(2000, st_visible[0].wYear);
1279         expect(11, st_visible[0].wMonth);
1280         expect(1, st_visible[0].wDay);
1281         expect(2000, st_visible[1].wYear);
1282         expect(12, st_visible[1].wMonth);
1283         expect(31, st_visible[1].wDay);
1284     }
1285     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate);
1286     todo_wine {
1287         expect(4, res);
1288         expect(2000, st_daystate[0].wYear);
1289         expect(10, st_daystate[0].wMonth);
1290         expect(29, st_daystate[0].wDay);
1291         expect(2001, st_daystate[1].wYear);
1292         expect(1, st_daystate[1].wMonth);
1293         expect(6, st_daystate[1].wDay);
1294     }
1295
1296     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE);
1297
1298     DestroyWindow(hwnd);
1299 }
1300
1301 static void test_monthcal_maxselday(void)
1302 {
1303     int res;
1304     HWND hwnd;
1305
1306     hwnd = create_monthcal_control(MCS_MULTISELECT);
1307
1308     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1309
1310     /* Setter and Getters for max selected days */
1311     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
1312     expect(1, res);
1313     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1314     expect(5, res);
1315
1316     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0);
1317     expect(1, res);
1318     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1319     expect(15, res);
1320
1321     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
1322     todo_wine {expect(0, res);}
1323     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
1324     todo_wine {expect(15, res);}
1325
1326     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
1327
1328     DestroyWindow(hwnd);
1329 }
1330
1331 static void test_monthcal_size(void)
1332 {
1333     int res;
1334     RECT r1, r2;
1335     HFONT hFont1, hFont2;
1336     LOGFONTA logfont;
1337     HWND hwnd;
1338
1339     hwnd = create_monthcal_control(0);
1340
1341     lstrcpyA(logfont.lfFaceName, "Arial");
1342     memset(&logfont, 0, sizeof(logfont));
1343     logfont.lfHeight = 12;
1344     hFont1 = CreateFontIndirectA(&logfont);
1345
1346     logfont.lfHeight = 24;
1347     hFont2 = CreateFontIndirectA(&logfont);
1348
1349     /* initialize to a font we can compare against */
1350     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0);
1351     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1);
1352
1353     /* check that setting a larger font results in an larger rect */
1354     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0);
1355     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2);
1356
1357     OffsetRect(&r1, -r1.left, -r1.top);
1358     OffsetRect(&r2, -r2.left, -r2.top);
1359
1360     ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n");
1361
1362     DestroyWindow(hwnd);
1363 }
1364
1365 static void test_monthcal_create(void)
1366 {
1367     HWND hwnd;
1368
1369     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1370
1371     hwnd = create_monthcal_control(0);
1372     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
1373
1374     DestroyWindow(hwnd);
1375
1376     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1377     hwnd = create_monthcal_control(MCS_MULTISELECT);
1378     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
1379     DestroyWindow(hwnd);
1380 }
1381
1382 static void test_monthcal_destroy(void)
1383 {
1384     HWND hwnd;
1385
1386     hwnd = create_monthcal_control(0);
1387     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1388     DestroyWindow(hwnd);
1389     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE);
1390     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE);
1391
1392     /* MCS_MULTISELECT */
1393     hwnd = create_monthcal_control(MCS_MULTISELECT);
1394     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1395     DestroyWindow(hwnd);
1396     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE);
1397 }
1398
1399 static void test_monthcal_getselrange(void)
1400 {
1401     HWND hwnd;
1402     SYSTEMTIME st, range[2];
1403     BOOL ret;
1404
1405     hwnd = create_monthcal_control(MCS_MULTISELECT);
1406
1407     /* just after creation selection should start and end today */
1408     ret = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st);
1409     expect(TRUE, ret);
1410
1411     ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range);
1412     expect(TRUE, ret);
1413     expect(st.wYear,      range[0].wYear);
1414     expect(st.wMonth,     range[0].wMonth);
1415     expect(st.wDay,       range[0].wDay);
1416     expect(st.wDayOfWeek, range[0].wDayOfWeek);
1417     expect(st.wHour,      range[0].wHour);
1418     expect(st.wMinute,    range[0].wMinute);
1419     expect(st.wSecond,    range[0].wSecond);
1420     expect(st.wMilliseconds, range[0].wMilliseconds);
1421
1422     expect(st.wYear,      range[1].wYear);
1423     expect(st.wMonth,     range[1].wMonth);
1424     expect(st.wDay,       range[1].wDay);
1425     expect(st.wDayOfWeek, range[1].wDayOfWeek);
1426     expect(st.wHour,      range[1].wHour);
1427     expect(st.wMinute,    range[1].wMinute);
1428     expect(st.wSecond,    range[1].wSecond);
1429     expect(st.wMilliseconds, range[1].wMilliseconds);
1430
1431     DestroyWindow(hwnd);
1432 }
1433
1434 START_TEST(monthcal)
1435 {
1436     HMODULE hComctl32;
1437     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1438     INITCOMMONCONTROLSEX iccex;
1439
1440     hComctl32 = GetModuleHandleA("comctl32.dll");
1441     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1442     if (!pInitCommonControlsEx)
1443     {
1444         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
1445         return;
1446     }
1447     iccex.dwSize = sizeof(iccex);
1448     iccex.dwICC  = ICC_DATE_CLASSES;
1449     pInitCommonControlsEx(&iccex);
1450
1451     test_monthcal();
1452
1453     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1454
1455     parent_wnd = create_parent_window();
1456
1457     test_monthcal_create();
1458     test_monthcal_destroy();
1459     test_monthcal_color();
1460     test_monthcal_currdate();
1461     test_monthcal_firstDay();
1462     test_monthcal_unicode();
1463     test_monthcal_today();
1464     test_monthcal_scroll();
1465     test_monthcal_monthrange();
1466     test_monthcal_hittest();
1467     test_monthcal_todaylink();
1468     test_monthcal_size();
1469     test_monthcal_maxselday();
1470     test_monthcal_getselrange();
1471
1472     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1473     DestroyWindow(parent_wnd);
1474     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE);
1475 }