comctl32: monthcal: Correct the return value in MCM_SETFIRSTDAYOFWEEK.
[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_WINDOWPOSCHANGING, sent|wparam, 0 },
56     { WM_ACTIVATEAPP, sent|wparam, 1 },
57     { WM_NCACTIVATE, sent|wparam, 1 },
58     { WM_ACTIVATE, sent|wparam, 1 },
59     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
60     { WM_IME_NOTIFY, sent|defwinproc|optional },
61     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
62     /* Win9x adds SWP_NOZORDER below */
63     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
64     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
65     { WM_SIZE, sent },
66     { WM_MOVE, sent },
67     { 0 }
68 };
69
70 static const struct message create_monthcal_control_seq[] = {
71     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
72     { WM_QUERYUISTATE, sent },
73     { WM_GETFONT, sent },
74     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE},
75     { 0 }
76 };
77
78 static const struct message create_monthcal_multi_sel_style_seq[] = {
79     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
80     { WM_QUERYUISTATE, sent },
81     { WM_GETFONT, sent },
82     { 0 }
83 };
84
85 static const struct message monthcal_color_seq[] = {
86     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
87     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(0,0,0)},
88     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
89     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255,255,255)},
90     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
91
92     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
93     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(0,0,0)},
94     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
95     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255,255,255)},
96     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
97
98     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
99     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(0,0,0)},
100     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
101     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255,255,255)},
102     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
103
104     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
105     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(0,0,0)},
106     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
107     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255,255,255)},
108     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
109
110     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
111     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(0,0,0)},
112     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
113     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255,255,255)},
114     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
115
116     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
117     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(0,0,0)},
118     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
119     { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255,255,255)},
120     { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
121     { 0 }
122 };
123
124 static const struct message monthcal_curr_date_seq[] = {
125     { MCM_SETCURSEL, sent|wparam, 0},
126     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
127     { WM_NCPAINT, sent|wparam|lparam|defwinproc, 1, 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_HITTEST, sent|wparam, 0},
204     { MCM_HITTEST, sent|wparam, 0},
205     { MCM_HITTEST, sent|wparam, 0},
206     { MCM_HITTEST, sent|wparam, 0},
207     { 0 }
208 };
209
210 static const struct message monthcal_today_seq[] = {
211     { MCM_SETTODAY, sent|wparam, 0},
212     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
213     { MCM_GETTODAY, sent|wparam, 0},
214     { MCM_SETTODAY, sent|wparam, 0},
215     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
216     { MCM_GETTODAY, sent|wparam, 0},
217     { 0 }
218 };
219
220 static const struct message monthcal_scroll_seq[] = {
221     { MCM_SETMONTHDELTA, sent|wparam|lparam, 2, 0},
222     { MCM_SETMONTHDELTA, sent|wparam|lparam, 3, 0},
223     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
224     { MCM_SETMONTHDELTA, sent|wparam|lparam, 12, 0},
225     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
226     { MCM_SETMONTHDELTA, sent|wparam|lparam, 15, 0},
227     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
228     { MCM_SETMONTHDELTA, sent|wparam|lparam, -5, 0},
229     { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
230     { 0 }
231 };
232
233 static const struct message monthcal_max_sel_day_seq[] = {
234     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 5, 0},
235     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
236     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 15, 0},
237     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
238     { MCM_SETMAXSELCOUNT, sent|wparam|lparam, -1, 0},
239     { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
240     { 0 }
241 };
242
243 /* expected message sequence for parent*/
244 static const struct message destroy_monthcal_parent_msgs_seq[] = {
245     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY},
246     { 0 }
247 };
248
249 /* expected message sequence for child*/
250 static const struct message destroy_monthcal_child_msgs_seq[] = {
251     { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0},
252     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
253     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
254     { WM_DESTROY, sent|wparam|lparam, 0, 0},
255     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
256     { 0 }
257 };
258
259 static const struct message destroy_monthcal_multi_sel_style_seq[] = {
260     { WM_DESTROY, sent|wparam|lparam, 0, 0},
261     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
262     { 0 }
263 };
264
265 /* expected message sequence for parent window*/
266 static const struct message destroy_parent_seq[] = {
267     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
268     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
269     { WM_NCACTIVATE, sent|wparam|lparam, 0, 0},
270     { WM_ACTIVATE, sent|wparam|lparam, 0, 0},
271     { WM_ACTIVATEAPP, sent|wparam, 0},
272     { WM_KILLFOCUS, sent|wparam|lparam, 0, 0},
273     { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
274     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
275     { WM_DESTROY, sent|wparam|lparam, 0, 0},
276     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
277     { 0 }
278 };
279
280 static void test_monthcal(void)
281 {
282     HWND hwnd;
283     SYSTEMTIME st[2], st1[2];
284     INITCOMMONCONTROLSEX ic = {sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES};
285     int res, month_range;
286
287     InitCommonControlsEx(&ic);
288     hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
289                          0, 300, 300, 0, 0, NULL, NULL);
290     ok(hwnd != NULL, "Failed to create MonthCal\n");
291     GetSystemTime(&st[0]);
292     st[1] = st[0];
293
294     /* Invalid date/time */
295     st[0].wYear  = 2000;
296     /* Time should not matter */
297     st[1].wHour = st[1].wMinute = st[1].wSecond = 70;
298     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
299     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
300     ok(st1[0].wYear != 2000, "Lover limit changed\n");
301
302     st[1].wMonth = 0;
303     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");
304     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
305     ok(st1[0].wYear != 2000, "Lover limit changed\n");
306     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n");
307     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
308     ok(st1[0].wYear != 2000, "Lover limit changed\n");
309
310     GetSystemTime(&st[0]);
311     st[0].wDay = 20;
312     st[0].wMonth = 5;
313     st[1] = st[0];
314
315     month_range = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
316     st[1].wMonth--;
317     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
318     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
319     ok(res == month_range, "Invalid month range (%d)\n", res);
320     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Limits should be set\n");
321
322     st[1].wMonth += 2;
323     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
324     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
325     ok(res == month_range, "Invalid month range (%d)\n", res);
326
327     st[1].wYear --;
328     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
329     st[1].wYear += 1;
330     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
331
332     st[1].wMonth -= 3;
333     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
334     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
335     st[1].wMonth += 4;
336     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
337     st[1].wYear -= 3;
338     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
339     st[1].wYear += 4;
340     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
341     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
342
343     DestroyWindow(hwnd);
344 }
345
346 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
347 {
348     static long defwndproc_counter = 0;
349     LRESULT ret;
350     struct message msg;
351
352     /* do not log painting messages */
353     if (message != WM_PAINT &&
354         message != WM_ERASEBKGND &&
355         message != WM_NCPAINT &&
356         message != WM_NCHITTEST &&
357         message != WM_GETTEXT &&
358         message != WM_GETICON &&
359         message != WM_DEVICECHANGE)
360     {
361         trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
362
363         msg.message = message;
364         msg.flags = sent|wparam|lparam;
365         if (defwndproc_counter) msg.flags |= defwinproc;
366         msg.wParam = wParam;
367         msg.lParam = lParam;
368         add_message(sequences, PARENT_SEQ_INDEX, &msg);
369     }
370
371     defwndproc_counter++;
372     ret = DefWindowProcA(hwnd, message, wParam, lParam);
373     defwndproc_counter--;
374
375     return ret;
376 }
377
378 static BOOL register_parent_wnd_class()
379 {
380     WNDCLASSA cls;
381
382     cls.style = 0;
383     cls.lpfnWndProc = parent_wnd_proc;
384     cls.cbClsExtra = 0;
385     cls.cbWndExtra = 0;
386     cls.hInstance = GetModuleHandleA(NULL);
387     cls.hIcon = 0;
388     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
389     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
390     cls.lpszMenuName = NULL;
391     cls.lpszClassName = "Month-Cal test parent class";
392     return RegisterClassA(&cls);
393 }
394
395 static HWND create_parent_window(void)
396 {
397     HWND hwnd;
398
399     InitCommonControls();
400
401     /* flush message sequences, so we can check the new sequence by the end of function */
402     flush_sequences(sequences, NUM_MSG_SEQUENCES);
403
404     if (!register_parent_wnd_class())
405         return NULL;
406
407     hwnd = CreateWindowEx(0, "Month-Cal test parent class",
408                           "Month-Cal test parent window",
409                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
410                           WS_MAXIMIZEBOX | WS_VISIBLE,
411                           0, 0, 500, 500,
412                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
413
414     assert(hwnd);
415
416     /* check for message sequences */
417     ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", TRUE);
418
419     return hwnd;
420 }
421
422 static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
423 {
424     struct subclass_info *info = (struct subclass_info *)GetWindowLongA(hwnd, GWL_USERDATA);
425     static long defwndproc_counter = 0;
426     LRESULT ret;
427     struct message msg;
428
429     trace("monthcal: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
430
431     msg.message = message;
432     msg.flags = sent|wparam|lparam;
433     if (defwndproc_counter) msg.flags |= defwinproc;
434     msg.wParam = wParam;
435     msg.lParam = lParam;
436     add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
437
438     defwndproc_counter++;
439     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
440     defwndproc_counter--;
441
442     return ret;
443 }
444
445 static HWND create_monthcal_control(DWORD style, HWND parent_window)
446 {
447     struct subclass_info *info;
448     HWND hwnd;
449     static const INITCOMMONCONTROLSEX ic = {sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES};
450
451     InitCommonControlsEx(&ic);
452
453     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
454     if (!info)
455         return NULL;
456
457     hwnd = CreateWindowEx(0,
458                     MONTHCAL_CLASS,
459                     "",
460                     style,
461                     0, 0, 300, 300,
462                     parent_window, NULL, GetModuleHandleA(NULL), NULL);
463
464     if (!hwnd)
465     {
466         HeapFree(GetProcessHeap(), 0, info);
467         return NULL;
468     }
469
470     info->oldproc = (WNDPROC)SetWindowLongA(hwnd, GWL_WNDPROC,
471                                             (LONG)monthcal_subclass_proc);
472     SetWindowLongA(hwnd, GWL_USERDATA, (LONG)info);
473
474     return hwnd;
475 }
476
477
478 /* Setter and Getters Tests */
479
480 static void test_monthcal_color(HWND hwnd)
481 {
482     int res, temp;
483
484     flush_sequences(sequences, NUM_MSG_SEQUENCES);
485
486     /* Setter and Getters for color*/
487     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
488     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(0,0,0));
489     expect(temp, res);
490     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
491     expect(RGB(0,0,0), temp);
492     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(255,255,255));
493     expect(temp, res);
494     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
495     expect(RGB(255,255,255), temp);
496
497     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
498     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(0,0,0));
499     expect(temp, res);
500     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
501     expect(RGB(0,0,0), temp);
502     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(255,255,255));
503     expect(temp, res);
504     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
505     expect(RGB(255,255,255), temp);
506
507     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
508     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(0,0,0));
509     expect(temp, res);
510     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
511     expect(RGB(0,0,0), temp);
512     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(255,255,255));
513     expect(temp, res);
514     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
515     expect(RGB(255,255,255), temp);
516
517     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
518     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(0,0,0));
519     expect(temp, res);
520     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
521     expect(RGB(0,0,0), temp);
522     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(255,255,255));
523     expect(temp, res);
524     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
525     expect(RGB(255,255,255), temp);
526
527     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
528     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(0,0,0));
529     expect(temp, res);
530     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
531     expect(RGB(0,0,0), temp);
532     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(255,255,255));
533     expect(temp, res);
534     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
535     expect(RGB(255,255,255), temp);
536
537     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
538     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(0,0,0));
539     expect(temp, res);
540     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
541     expect(RGB(0,0,0), temp);
542     res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(255,255,255));
543     expect(temp, res);
544     temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
545     expect(RGB(255,255,255), temp);
546
547     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE);
548 }
549
550 static void test_monthcal_currDate(HWND hwnd)
551 {
552     SYSTEMTIME st_original, st_new, st_test;
553     int res;
554
555     flush_sequences(sequences, NUM_MSG_SEQUENCES);
556
557     /* Setter and Getters for current date selected */
558     st_original.wYear = 2000;
559     st_original.wMonth = 11;
560     st_original.wDay = 28;
561     st_original.wHour = 11;
562     st_original.wMinute = 59;
563     st_original.wSecond = 30;
564     st_original.wMilliseconds = 0;
565     st_original.wDayOfWeek = 0;
566
567     st_new = st_test = st_original;
568
569     /* Should not validate the time */
570     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
571     expect(1,res);
572
573     /* Overflow matters, check for wDay */
574     st_test.wDay += 4;
575     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
576     expect(0,res);
577
578     /* correct wDay before checking for wMonth */
579     st_test.wDay -= 4;
580     expect(st_original.wDay, st_test.wDay);
581
582     /* Overflow matters, check for wMonth */
583     st_test.wMonth += 4;
584     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
585     expect(0,res);
586
587     /* checking if gets the information right, modify st_new */
588     st_new.wYear += 4;
589     st_new.wMonth += 4;
590     st_new.wDay += 4;
591     st_new.wHour += 4;
592     st_new.wMinute += 4;
593     st_new.wSecond += 4;
594
595     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
596     expect(1, res);
597
598     /* st_new change to st_origin, above settings with overflow */
599     /* should not change the current settings */
600     expect(st_original.wYear, st_new.wYear);
601     expect(st_original.wMonth, st_new.wMonth);
602     expect(st_original.wDay, st_new.wDay);
603     expect(st_original.wHour, st_new.wHour);
604     expect(st_original.wMinute, st_new.wMinute);
605     expect(st_original.wSecond, st_new.wSecond);
606
607     /* lparam cannot be NULL */
608     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM) NULL);
609     expect(0, res);
610
611     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE);
612 }
613
614 static void test_monthcal_firstDay(HWND hwnd)
615 {
616     int res, fday, i, prev;
617     TCHAR b[128];
618     LCID lcid = LOCALE_USER_DEFAULT;
619
620     flush_sequences(sequences, NUM_MSG_SEQUENCES);
621
622     /* Setter and Getters for first day of week */
623     /* check for locale first day */
624     if(GetLocaleInfo(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){
625         fday = atoi(b);
626         res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
627         expect(fday, res);
628         prev = fday;
629
630         /* checking for the values that actually will be stored as */
631         /* current first day when we set a new value */
632         for (i = -5; i < 12; i++){
633             res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM) i);
634             expect(prev, res);
635             res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
636             prev = res;
637
638             if (i == -1){
639                 expect(MAKELONG(fday, FALSE), res);
640             }else if (i >= 7){
641                 expect(MAKELONG(fday, TRUE), res);
642             }else{
643                 expect(MAKELONG(i, TRUE), res);
644             }
645         }
646
647         ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_first_day_seq, "monthcal firstDay", FALSE);
648
649     }else{
650         skip("Cannot retrieve first day of the week\n");
651     }
652
653 }
654
655 static void test_monthcal_unicode(HWND hwnd)
656 {
657     int res, temp;
658
659     flush_sequences(sequences, NUM_MSG_SEQUENCES);
660
661     /* Setter and Getters for Unicode format */
662
663     /* getting the current settings */
664     temp = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
665
666     /* setting to 1, should return previous settings */
667     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
668     expect(temp, res);
669
670     /* current setting is 1, so, should return 1 */
671     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
672     todo_wine {expect(1, res);}
673
674     /* setting to 0, should return previous settings */
675     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
676     todo_wine {expect(1, res);}
677
678     /* current setting is 0, so, it should return 0 */
679     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
680     expect(0, res);
681
682     /* should return previous settings */
683     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
684     expect(0, res);
685
686     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
687 }
688
689 static void test_monthcal_HitTest(HWND hwnd)
690 {
691     MCHITTESTINFO mchit;
692     int res;
693
694     memset(&mchit, 0, sizeof(MCHITTESTINFO));
695
696     flush_sequences(sequences, NUM_MSG_SEQUENCES);
697
698     /* Setters for HITTEST */
699
700     /* (0, 0) is the top left of the control and should not be active */
701     mchit.cbSize = sizeof(MCHITTESTINFO);
702     mchit.pt.x = 0;
703     mchit.pt.y = 0;
704     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
705     expect(0, mchit.pt.x);
706     expect(0, mchit.pt.y);
707     expect(mchit.uHit, res);
708     todo_wine {expect(MCHT_NOWHERE, res);}
709
710     /* (300, 300) is the bottom right of the control and should not be active */
711     mchit.pt.x = 300;
712     mchit.pt.y = 300;
713     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
714     expect(300, mchit.pt.x);
715     expect(300, mchit.pt.y);
716     expect(mchit.uHit, res);
717     todo_wine {expect(MCHT_NOWHERE, res);}
718
719     /* (500, 500) is completely out of the control and should not be active */
720     mchit.pt.x = 500;
721     mchit.pt.y = 500;
722     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
723     expect(500, mchit.pt.x);
724     expect(500, mchit.pt.y);
725     expect(mchit.uHit, res);
726     todo_wine {expect(MCHT_NOWHERE, res);}
727
728     /* (150, 200) is in active area */
729     mchit.pt.x = 150;
730     mchit.pt.y = 200;
731     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
732     expect(150, mchit.pt.x);
733     expect(200, mchit.pt.y);
734     expect(mchit.uHit, res);
735
736     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", FALSE);
737 }
738
739 static void test_monthcal_today(HWND hwnd)
740 {
741     SYSTEMTIME st_test, st_new;
742     int res;
743
744     flush_sequences(sequences, NUM_MSG_SEQUENCES);
745
746     /* Setter and Getters for "today" information */
747
748     /* check for overflow, should be ok */
749     st_test.wDay = 38;
750     st_test.wMonth = 38;
751
752     st_new.wDay = 27;
753     st_new.wMonth = 27;
754
755     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
756
757     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
758     expect(1, res);
759
760     /* st_test should not change */
761     expect(38, st_test.wDay);
762     expect(38, st_test.wMonth);
763
764     /* st_new should change, overflow does not matter */
765     expect(38, st_new.wDay);
766     expect(38, st_new.wMonth);
767
768     /* check for zero, should be ok*/
769     st_test.wDay = 0;
770     st_test.wMonth = 0;
771
772     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
773
774     res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
775     expect(1, res);
776
777     /* st_test should not change */
778     expect(0, st_test.wDay);
779     expect(0, st_test.wMonth);
780
781     /* st_new should change to zero*/
782     expect(0, st_new.wDay);
783     expect(0, st_new.wMonth);
784
785     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
786 }
787
788 static void test_monthcal_scroll(HWND hwnd)
789 {
790     int res;
791
792     flush_sequences(sequences, NUM_MSG_SEQUENCES);
793
794     /* Setter and Getters for scroll rate */
795     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0);
796     expect(0, res);
797
798     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0);
799     expect(2, res);
800     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
801     expect(3, res);
802
803     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0);
804     expect(3, res);
805     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
806     expect(12, res);
807
808     res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0);
809     expect(12, res);
810     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
811     expect(15, res);
812
813     res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0);
814     expect(15, res);
815     res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
816     expect(-5, res);
817
818     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
819 }
820
821 static void test_monthcal_MaxSelDay(HWND hwnd)
822 {
823     int res;
824
825     flush_sequences(sequences, NUM_MSG_SEQUENCES);
826
827     /* Setter and Getters for max selected days */
828     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
829     expect(1, res);
830     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
831     expect(5, res);
832
833     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0);
834     expect(1, res);
835     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
836     expect(15, res);
837
838     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
839     todo_wine {expect(0, res);}
840     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
841     todo_wine {expect(15, res);}
842
843     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
844 }
845
846
847 START_TEST(monthcal)
848 {
849     HWND hwnd, parent_wnd;
850     test_monthcal();
851
852     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
853
854     parent_wnd = create_parent_window();
855
856     flush_sequences(sequences, NUM_MSG_SEQUENCES);
857     hwnd = create_monthcal_control(WS_CHILD | WS_BORDER | WS_VISIBLE, parent_wnd);
858     assert(hwnd);
859     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
860
861     test_monthcal_color(hwnd);
862     test_monthcal_currDate(hwnd);
863     test_monthcal_firstDay(hwnd);
864     test_monthcal_unicode(hwnd);
865     test_monthcal_HitTest(hwnd);
866     test_monthcal_today(hwnd);
867     test_monthcal_scroll(hwnd);
868
869     flush_sequences(sequences, NUM_MSG_SEQUENCES);
870     DestroyWindow(hwnd);
871     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE);
872     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE);
873
874     flush_sequences(sequences, NUM_MSG_SEQUENCES);
875     hwnd = create_monthcal_control(MCS_MULTISELECT, parent_wnd);
876     assert(hwnd);
877     ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
878
879     test_monthcal_MaxSelDay(hwnd);
880
881     flush_sequences(sequences, NUM_MSG_SEQUENCES);
882     DestroyWindow(hwnd);
883     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE);
884
885     flush_sequences(sequences, NUM_MSG_SEQUENCES);
886     DestroyWindow(parent_wnd);
887     ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE);
888 }