po: Update French translation.
[wine] / dlls / comctl32 / tests / datetime.c
1 /* Unit test suite for datetime control.
2 *
3 * Copyright 2007 Kanit Therdsteerasukdi
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <windows.h>
21 #include <commctrl.h>
22
23 #include "wine/test.h"
24 #include "msg.h"
25
26 #define expect(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT))
27
28 #define expect_unsuccess(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d(unsuccessful), got %ld(successful)\n", (EXPECTED), (GOT))
29
30 #define NUM_MSG_SEQUENCES   1
31 #define DATETIME_SEQ_INDEX    0
32
33 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
34
35 static const struct message test_dtm_set_format_seq[] = {
36     { DTM_SETFORMATA, sent|wparam|lparam, 0, 0 },
37     { DTM_SETFORMATA, sent|wparam, 0 },
38     { 0 }
39 };
40
41 static const struct message test_dtm_set_and_get_mccolor_seq[] = {
42     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 },
43     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255, 255, 255) },
44     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(100, 180, 220) },
45     { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 },
46     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 },
47     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255, 255, 255) },
48     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(100, 180, 220) },
49     { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 },
50     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 },
51     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255, 255, 255) },
52     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(100, 180, 220) },
53     { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 },
54     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 },
55     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255, 255, 255) },
56     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(100, 180, 220) },
57     { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 },
58     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 },
59     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255, 255, 255) },
60     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(100, 180, 220) },
61     { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 },
62     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 },
63     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255, 255, 255) },
64     { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(100, 180, 220) },
65     { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 },
66     { 0 }
67 };
68
69 static const struct message test_dtm_set_and_get_mcfont_seq[] = {
70     { DTM_SETMCFONT, sent|lparam, 0, 1 },
71     { DTM_GETMCFONT, sent|wparam|lparam, 0, 0 },
72     { 0 }
73 };
74
75 static const struct message test_dtm_get_monthcal_seq[] = {
76     { DTM_GETMONTHCAL, sent|wparam|lparam, 0, 0 },
77     { 0 }
78 };
79
80 static const struct message test_dtm_set_and_get_range_seq[] = {
81     { DTM_SETRANGE, sent|wparam, GDTR_MIN },
82     { DTM_GETRANGE, sent|wparam, 0 },
83     { DTM_SETRANGE, sent|wparam, GDTR_MAX },
84     { DTM_SETRANGE, sent|wparam, GDTR_MAX },
85     { DTM_GETRANGE, sent|wparam, 0 },
86     { DTM_SETRANGE, sent|wparam, GDTR_MIN },
87     { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
88     { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
89     { DTM_GETRANGE, sent|wparam, 0 },
90     { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
91     { DTM_GETRANGE, sent|wparam, 0 },
92     { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
93     { DTM_GETRANGE, sent|wparam, 0 },
94     { 0 }
95 };
96
97 static const struct message test_dtm_set_range_swap_min_max_seq[] = {
98     { DTM_SETSYSTEMTIME, sent|wparam, 0 },
99     { DTM_GETSYSTEMTIME, sent|wparam, 0 },
100     { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
101     { DTM_GETRANGE, sent|wparam, 0 },
102     { DTM_SETSYSTEMTIME, sent|wparam, 0 },
103     { DTM_GETSYSTEMTIME, sent|wparam, 0 },
104     { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
105     { DTM_GETRANGE, sent|wparam, 0 },
106     { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
107     { DTM_GETRANGE, sent|wparam, 0 },
108     { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
109     { DTM_GETRANGE, sent|wparam, 0 },
110     { 0 }
111 };
112
113 static const struct message test_dtm_set_and_get_system_time_seq[] = {
114     { DTM_SETSYSTEMTIME, sent|wparam, GDT_NONE },
115     { DTM_GETSYSTEMTIME, sent|wparam, 0 },
116     { DTM_SETSYSTEMTIME, sent|wparam, 0 },
117     { DTM_SETSYSTEMTIME, sent|wparam, 0 },
118     { DTM_SETSYSTEMTIME, sent|wparam, 0 },
119     { DTM_GETSYSTEMTIME, sent|wparam, 0 },
120     { DTM_SETSYSTEMTIME, sent|wparam, 0 },
121     { 0 }
122 };
123
124 static const struct message test_dtm_set_and_get_systime_with_limits[] = {
125     { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
126     { DTM_GETRANGE, sent|wparam, 0 },
127     { DTM_SETSYSTEMTIME, sent|wparam, 0 },
128     { DTM_GETSYSTEMTIME, sent|wparam, 0 },
129     { DTM_SETSYSTEMTIME, sent|wparam, 0 },
130     { DTM_GETSYSTEMTIME, sent|wparam, 0 },
131     { DTM_SETSYSTEMTIME, sent|wparam, 0 },
132     { DTM_GETSYSTEMTIME, sent|wparam, 0 },
133     { 0 }
134 };
135
136 static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
137 {
138     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
139     static LONG defwndproc_counter = 0;
140     LRESULT ret;
141     struct message msg;
142
143     trace("datetime: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
144
145     msg.message = message;
146     msg.flags = sent|wparam|lparam;
147     if (defwndproc_counter) msg.flags |= defwinproc;
148     msg.wParam = wParam;
149     msg.lParam = lParam;
150     add_message(sequences, DATETIME_SEQ_INDEX, &msg);
151
152     defwndproc_counter++;
153     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
154     defwndproc_counter--;
155
156     return ret;
157 }
158
159 static HWND create_datetime_control(DWORD style)
160 {
161     WNDPROC oldproc;
162     HWND hWndDateTime = NULL;
163
164     hWndDateTime = CreateWindowEx(0,
165         DATETIMEPICK_CLASS,
166         NULL,
167         style,
168         0,50,300,120,
169         NULL,
170         NULL,
171         NULL,
172         NULL);
173
174     if (!hWndDateTime) return NULL;
175
176     oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC,
177                                          (LONG_PTR)datetime_subclass_proc);
178     SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)oldproc);
179
180     return hWndDateTime;
181 }
182
183 static void test_dtm_set_format(void)
184 {
185     HWND hWnd;
186     CHAR txt[256];
187     SYSTEMTIME systime;
188     LRESULT r;
189
190     hWnd = create_datetime_control(DTS_SHOWNONE);
191
192     flush_sequences(sequences, NUM_MSG_SEQUENCES);
193
194     r = SendMessage(hWnd, DTM_SETFORMAT, 0, 0);
195     expect(1, r);
196
197     r = SendMessage(hWnd, DTM_SETFORMAT, 0,
198                     (LPARAM)"'Today is: 'hh':'m':'s dddd MMM dd', 'yyyy");
199     expect(1, r);
200
201     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_format_seq, "test_dtm_set_format", FALSE);
202
203     r = SendMessage(hWnd, DTM_SETFORMAT, 0,
204                     (LPARAM)"'hh' hh");
205     expect(1, r);
206     ZeroMemory(&systime, sizeof(systime));
207     systime.wYear = 2000;
208     systime.wMonth = systime.wDay = 1;
209     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime);
210     expect(1, r);
211     GetWindowText(hWnd, txt, 256);
212     ok(strcmp(txt, "hh 12") == 0, "String mismatch (\"%s\" vs \"hh 12\")\n", txt);
213
214     DestroyWindow(hWnd);
215 }
216
217 static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name)
218 {
219     COLORREF theColor, prevColor, crColor;
220
221     theColor=RGB(0,0,0);
222     crColor = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
223     ok(crColor != ~0u, "%s: Set RGB(0,0,0): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor);
224     prevColor=theColor;
225     theColor=RGB(255,255,255);
226     crColor = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
227     ok(crColor==prevColor, "%s: Set RGB(255,255,255): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor);
228     prevColor=theColor;
229     theColor=RGB(100,180,220);
230     crColor = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
231     ok(crColor==prevColor, "%s: Set RGB(100,180,220): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor);
232     crColor = SendMessage(hWndDateTime, DTM_GETMCCOLOR, mccolor_type, 0);
233     ok(crColor==theColor, "%s: GETMCCOLOR: Expected %d, got %d\n", mccolor_name, theColor, crColor);
234 }
235
236 static void test_dtm_set_and_get_mccolor(void)
237 {
238     HWND hWnd;
239
240     hWnd = create_datetime_control(DTS_SHOWNONE);
241
242     flush_sequences(sequences, NUM_MSG_SEQUENCES);
243
244     test_mccolor_types(hWnd, MCSC_BACKGROUND, "MCSC_BACKGROUND");
245     test_mccolor_types(hWnd, MCSC_MONTHBK, "MCSC_MONTHBK");
246     test_mccolor_types(hWnd, MCSC_TEXT, "MCSC_TEXT");
247     test_mccolor_types(hWnd, MCSC_TITLEBK, "MCSC_TITLEBK");
248     test_mccolor_types(hWnd, MCSC_TITLETEXT, "MCSC_TITLETEXT");
249     test_mccolor_types(hWnd, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT");
250
251     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mccolor_seq, "test_dtm_set_and_get_mccolor", FALSE);
252
253     DestroyWindow(hWnd);
254 }
255
256 static void test_dtm_set_and_get_mcfont(void)
257 {
258     HFONT hFontOrig, hFontNew;
259     HWND hWnd;
260
261     hWnd = create_datetime_control(DTS_SHOWNONE);
262
263     flush_sequences(sequences, NUM_MSG_SEQUENCES);
264
265     hFontOrig = GetStockObject(DEFAULT_GUI_FONT);
266     SendMessage(hWnd, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE);
267     hFontNew = (HFONT)SendMessage(hWnd, DTM_GETMCFONT, 0, 0);
268     ok(hFontOrig == hFontNew, "Expected hFontOrig==hFontNew, hFontOrig=%p, hFontNew=%p\n", hFontOrig, hFontNew);
269
270     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mcfont_seq, "test_dtm_set_and_get_mcfont", FALSE);
271     DestroyWindow(hWnd);
272 }
273
274 static void test_dtm_get_monthcal(void)
275 {
276     LRESULT r;
277     HWND hWnd;
278
279     hWnd = create_datetime_control(DTS_SHOWNONE);
280
281     flush_sequences(sequences, NUM_MSG_SEQUENCES);
282
283     todo_wine {
284         r = SendMessage(hWnd, DTM_GETMONTHCAL, 0, 0);
285         ok(r == 0, "Expected NULL(no child month calendar control), got %ld\n", r);
286     }
287
288     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_get_monthcal_seq, "test_dtm_get_monthcal", FALSE);
289     DestroyWindow(hWnd);
290 }
291
292 static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds)
293 {
294     st->wYear = year;
295     st->wMonth = month;
296     st->wDayOfWeek = dayofweek;
297     st->wDay = day;
298     st->wHour = hour;
299     st->wMinute = minute;
300     st->wSecond = second;
301     st->wMilliseconds = milliseconds;
302 }
303
304 static LPARAM compare_systime_date(SYSTEMTIME *st1, SYSTEMTIME *st2)
305 {
306     return (st1->wYear == st2->wYear)
307             && (st1->wMonth == st2->wMonth)
308             && (st1->wDayOfWeek == st2->wDayOfWeek)
309             && (st1->wDay == st2->wDay);
310 }
311
312 static LPARAM compare_systime_time(SYSTEMTIME *st1, SYSTEMTIME *st2)
313 {
314     return (st1->wHour == st2->wHour)
315             && (st1->wMinute == st2->wMinute)
316             && (st1->wSecond == st2->wSecond)
317             && (st1->wMilliseconds == st2->wMilliseconds);
318 }
319
320 static LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2)
321 {
322     if(!compare_systime_date(st1, st2))
323         return 0;
324
325     return compare_systime_time(st1, st2);
326 }
327
328 #define expect_systime(ST1, ST2) ok(compare_systime((ST1), (ST2))==1, "ST1 != ST2\n")
329 #define expect_systime_date(ST1, ST2) ok(compare_systime_date((ST1), (ST2))==1, "ST1.date != ST2.date\n")
330 #define expect_systime_time(ST1, ST2) ok(compare_systime_time((ST1), (ST2))==1, "ST1.time != ST2.time\n")
331
332 static void test_dtm_set_and_get_range(void)
333 {
334     LRESULT r;
335     SYSTEMTIME st[2];
336     SYSTEMTIME getSt[2];
337     HWND hWnd;
338
339     hWnd = create_datetime_control(DTS_SHOWNONE);
340
341     flush_sequences(sequences, NUM_MSG_SEQUENCES);
342
343     /* initialize st[0] to lowest possible value */
344     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
345     /* initialize st[1] to all invalid numbers */
346     fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000);
347
348     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
349     expect(1, r);
350     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
351     ok(r == GDTR_MIN, "Expected %x, not %x(GDTR_MAX) or %x(GDTR_MIN | GDTR_MAX), got %lx\n", GDTR_MIN, GDTR_MAX, GDTR_MIN | GDTR_MAX, r);
352     expect_systime(&st[0], &getSt[0]);
353
354     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
355     expect_unsuccess(0, r);
356
357     /* set st[0] to all invalid numbers */
358     fill_systime_struct(&st[0], 0, 0, 7, 0, 24, 60, 60, 1000);
359     /* set st[1] to highest possible value */
360     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
361
362     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
363     expect(1, r);
364     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
365     todo_wine {
366         ok(r == GDTR_MAX, "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MIN | GDTR_MAX), got %lx\n", GDTR_MAX, GDTR_MIN, GDTR_MIN | GDTR_MAX, r);
367     }
368     expect_systime(&st[1], &getSt[1]);
369
370     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
371     expect_unsuccess(0, r);
372     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
373     expect_unsuccess(0, r);
374
375     /* set st[0] to highest possible value */
376     fill_systime_struct(&st[0], 30827, 12, 6, 31, 23, 59, 59, 999);
377
378     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
379     expect(1, r);
380     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
381     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
382     expect_systime(&st[0], &getSt[0]);
383     expect_systime(&st[1], &getSt[1]);
384
385     /* initialize st[0] to lowest possible value */
386     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
387     /* set st[1] to highest possible value */
388     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
389
390     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
391     expect(1, r);
392     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
393     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
394     expect_systime(&st[0], &getSt[0]);
395     expect_systime(&st[1], &getSt[1]);
396
397     /* set st[0] to value higher than minimum */
398     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
399     /* set st[1] to value lower than maximum */
400     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
401
402     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
403     expect(1, r);
404     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
405     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
406     expect_systime(&st[0], &getSt[0]);
407     expect_systime(&st[1], &getSt[1]);
408
409     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_range_seq, "test_dtm_set_and_get_range", FALSE);
410
411     DestroyWindow(hWnd);
412 }
413
414 /* when max<min for DTM_SETRANGE, Windows seems to swap the min and max values,
415 although that's undocumented.  However, it doesn't seem to be implemented
416 correctly, causing some strange side effects */
417 static void test_dtm_set_range_swap_min_max(void)
418 {
419     LRESULT r;
420     SYSTEMTIME st[2];
421     SYSTEMTIME getSt[2];
422     SYSTEMTIME origSt;
423     HWND hWnd;
424
425     hWnd = create_datetime_control(DTS_SHOWNONE);
426     flush_sequences(sequences, NUM_MSG_SEQUENCES);
427
428     fill_systime_struct(&st[0], 2007, 2, 4, 15, 2, 2, 2, 2);
429
430     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
431     expect(1, r);
432     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&origSt);
433     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
434     expect_systime(&st[0], &origSt);
435
436     /* set st[0] to value higher than st[1] */
437     fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
438     fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
439
440     /* since min>max, min and max values should be swapped by DTM_SETRANGE
441     automatically */
442     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
443     expect(1, r);
444     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
445     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
446     todo_wine {
447         ok(compare_systime(&st[0], &getSt[0]) == 1 ||
448            broken(compare_systime(&st[0], &getSt[1]) == 1), /* comctl32 version  <= 5.80 */
449            "ST1 != ST2\n");
450
451         ok(compare_systime(&st[1], &getSt[1]) == 1 ||
452            broken(compare_systime(&st[1], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
453            "ST1 != ST2\n");
454     }
455
456     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
457
458     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
459     expect(1, r);
460     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
461     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
462     /* the time part seems to not change after swapping the min and max values
463     and doing DTM_SETSYSTEMTIME */
464     expect_systime_date(&st[0], &getSt[0]);
465     todo_wine {
466         ok(compare_systime_time(&origSt, &getSt[0]) == 1 ||
467            broken(compare_systime_time(&st[0], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
468            "ST1.time != ST2.time\n");
469     }
470
471     /* set st[0] to value higher than minimum */
472     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
473     /* set st[1] to value lower than maximum */
474     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
475
476     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
477     expect(1, r);
478     /* for some reason after we swapped the min and max values before,
479     whenever we do a DTM_SETRANGE, the DTM_GETRANGE will return the values
480     swapped*/
481     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
482     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
483     todo_wine {
484         ok(compare_systime(&st[0], &getSt[1]) == 1 ||
485            broken(compare_systime(&st[0], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
486            "ST1 != ST2\n");
487
488         ok(compare_systime(&st[1], &getSt[0]) == 1 ||
489            broken(compare_systime(&st[1], &getSt[1]) == 1), /* comctl32 version <= 5.80 */
490            "ST1 != ST2\n");
491     }
492
493     /* set st[0] to value higher than st[1] */
494     fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
495     fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
496
497     /* set min>max again, so that the return values of DTM_GETRANGE are no
498     longer swapped the next time we do a DTM SETRANGE and DTM_GETRANGE*/
499     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
500     expect(1, r);
501     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
502     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
503     expect_systime(&st[0], &getSt[1]);
504     expect_systime(&st[1], &getSt[0]);
505
506     /* initialize st[0] to lowest possible value */
507     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
508     /* set st[1] to highest possible value */
509     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
510
511     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
512     expect(1, r);
513     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
514     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
515     expect_systime(&st[0], &getSt[0]);
516     expect_systime(&st[1], &getSt[1]);
517
518     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_range_swap_min_max_seq, "test_dtm_set_range_swap_min_max", FALSE);
519
520     DestroyWindow(hWnd);
521 }
522
523 static void test_dtm_set_and_get_system_time(void)
524 {
525     LRESULT r;
526     SYSTEMTIME st, getSt, ref;
527     HWND hWnd, hWndDateTime_test_gdt_none;
528
529     hWndDateTime_test_gdt_none = create_datetime_control(0);
530
531     ok(hWndDateTime_test_gdt_none!=NULL, "Expected non NULL, got %p\n", hWndDateTime_test_gdt_none);
532     if(hWndDateTime_test_gdt_none) {
533         r = SendMessage(hWndDateTime_test_gdt_none, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
534         expect(0, r);
535     }
536     else {
537         skip("hWndDateTime_test_gdt_none is NULL\n");
538         flush_sequences(sequences, NUM_MSG_SEQUENCES);
539
540         return;
541     }
542
543     DestroyWindow(hWndDateTime_test_gdt_none);
544
545     hWnd = create_datetime_control(DTS_SHOWNONE);
546     flush_sequences(sequences, NUM_MSG_SEQUENCES);
547
548     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
549     expect(1, r);
550     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
551     ok(r == GDT_NONE, "Expected %d, not %d(GDT_VALID) or %d(GDT_ERROR), got %ld\n", GDT_NONE, GDT_VALID, GDT_ERROR, r);
552
553     /* set st to lowest possible value */
554     fill_systime_struct(&st, 1601, 1, 0, 1, 0, 0, 0, 0);
555
556     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
557     expect(1, r);
558
559     /* set st to highest possible value */
560     fill_systime_struct(&st, 30827, 12, 6, 31, 23, 59, 59, 999);
561
562     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
563     expect(1, r);
564
565     /* set st to value between min and max */
566     fill_systime_struct(&st, 1980, 1, 3, 23, 14, 34, 37, 465);
567
568     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
569     expect(1, r);
570     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
571     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
572     expect_systime(&st, &getSt);
573
574     /* set st to invalid value */
575     fill_systime_struct(&st, 0, 0, 7, 0, 24, 60, 60, 1000);
576
577     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
578     expect_unsuccess(0, r);
579
580     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_system_time_seq, "test_dtm_set_and_get_system_time", FALSE);
581
582     /* set to some valid value */
583     GetSystemTime(&ref);
584     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&ref);
585     expect(1, r);
586     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
587     expect(GDT_VALID, r);
588     expect_systime(&ref, &getSt);
589
590     /* year invalid */
591     st = ref;
592     st.wYear = 0;
593     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
594     todo_wine expect(1, r);
595     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
596     expect(GDT_VALID, r);
597     expect_systime(&ref, &getSt);
598     /* month invalid */
599     st = ref;
600     st.wMonth = 13;
601     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
602     expect(0, r);
603     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
604     expect(GDT_VALID, r);
605     expect_systime(&ref, &getSt);
606     /* day invalid */
607     st = ref;
608     st.wDay = 32;
609     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
610     expect(0, r);
611     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
612     expect(GDT_VALID, r);
613     expect_systime(&ref, &getSt);
614     /* day invalid for current month */
615     st = ref;
616     st.wDay = 30;
617     st.wMonth = 2;
618     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
619     expect(0, r);
620     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
621     expect(GDT_VALID, r);
622     expect_systime(&ref, &getSt);
623     /* day of week isn't validated */
624     st = ref;
625     st.wDayOfWeek = 10;
626     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
627     expect(1, r);
628     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
629     expect(GDT_VALID, r);
630     expect_systime(&ref, &getSt);
631     /* hour invalid */
632     st = ref;
633     st.wHour = 25;
634     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
635     expect(0, r);
636     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
637     expect(GDT_VALID, r);
638     expect_systime(&ref, &getSt);
639     /* minute invalid */
640     st = ref;
641     st.wMinute = 60;
642     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
643     expect(0, r);
644     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
645     expect(GDT_VALID, r);
646     expect_systime(&ref, &getSt);
647     /* sec invalid */
648     st = ref;
649     st.wSecond = 60;
650     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
651     expect(0, r);
652     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
653     expect(GDT_VALID, r);
654     expect_systime(&ref, &getSt);
655     /* msec invalid */
656     st = ref;
657     st.wMilliseconds = 1000;
658     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
659     expect(0, r);
660     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
661     expect(GDT_VALID, r);
662     expect_systime(&ref, &getSt);
663
664     /* day of week should be calculated automatically,
665        actual day of week for this date is 4 */
666     fill_systime_struct(&st, 2009, 10, 1, 1, 0, 0, 10, 200);
667     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
668     expect(1, r);
669     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
670     expect(GDT_VALID, r);
671     /* 01.10.2009 is Thursday */
672     expect(4, (LRESULT)getSt.wDayOfWeek);
673     st.wDayOfWeek = 4;
674     expect_systime(&st, &getSt);
675 }
676
677 static void test_dtm_set_and_get_systemtime_with_limits(void)
678 {
679     LRESULT r;
680     SYSTEMTIME st[2], getSt[2], refSt;
681     HWND hWnd;
682
683     hWnd = create_datetime_control(DTS_SHOWNONE);
684
685     flush_sequences(sequences, NUM_MSG_SEQUENCES);
686
687     /* set range */
688     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
689     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
690
691     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
692     expect(1, r);
693     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
694     ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
695     expect_systime(&st[0], &getSt[0]);
696     expect_systime(&st[1], &getSt[1]);
697
698     /* Initially set a valid time */
699     fill_systime_struct(&refSt, 1999, 9, 4, 9, 19, 9, 9, 999);
700     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&refSt);
701     expect(1, r);
702     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
703     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
704     expect_systime(&refSt, &getSt[0]);
705
706     /* Now set an out-of-bounds time */
707     fill_systime_struct(&st[0], 2010, 1, 0, 1, 0, 0, 0, 0);
708
709     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
710     expect(1, r);
711     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
712     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
713     expect_systime(&refSt, &getSt[0]);
714
715     fill_systime_struct(&st[0], 1977, 1, 0, 1, 0, 0, 0, 0);
716
717     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
718     expect(1, r);
719     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
720     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
721     expect_systime(&refSt, &getSt[0]);
722
723     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_systime_with_limits, "test_dtm_set_and_get_systime_with_limits", FALSE);
724
725     DestroyWindow(hWnd);
726 }
727
728 static void test_wm_set_get_text(void)
729 {
730     static const CHAR a_str[] = "a";
731     CHAR buff[16], time[16], caltype[3];
732     HWND hWnd;
733     LRESULT ret;
734
735     hWnd = create_datetime_control(0);
736
737     ret = SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)a_str);
738     ok(CB_ERR == ret ||
739        broken(0 == ret) || /* comctl32 <= 4.72 */
740        broken(1 == ret), /* comctl32 <= 4.70 */
741        "Expected CB_ERR, got %ld\n", ret);
742
743     buff[0] = 0;
744     ret = SendMessage(hWnd, WM_GETTEXT, sizeof(buff), (LPARAM)buff);
745     ok(strcmp(buff, a_str) != 0, "Expected text to change, got %s\n", buff);
746     ok(ret != 0, "Expected non-zero return value\n");
747
748     SetLastError(0xdeadbeef);
749     ret = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICALENDARTYPE, caltype, 3);
750     if (ret == 0)
751         skip("Must know local calendar type (%x)\n", GetLastError());
752     else if (atoi(caltype) != CAL_GREGORIAN)
753         skip("DateTimePicker Control only supports Gregorian calendar (type: %s)\n", caltype);
754     else {
755         SetLastError(0xdeadbeef);
756         ret = GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, time, sizeof(time));
757         if (ret == 0)
758             skip("GetDateFormat failed, returned %ld, error %d\n", ret, GetLastError());
759         else
760             ok(!strcmp(buff, time), "Expected %s, got %s\n", time, buff);
761     }
762
763     DestroyWindow(hWnd);
764 }
765
766 static void test_dts_shownone(void)
767 {
768     HWND hwnd;
769     DWORD style;
770
771     /* it isn't allowed to change DTS_SHOWNONE after creation */
772     hwnd = create_datetime_control(0);
773     style = GetWindowLong(hwnd, GWL_STYLE);
774     SetWindowLong(hwnd, GWL_STYLE, style | DTS_SHOWNONE);
775     style = GetWindowLong(hwnd, GWL_STYLE);
776     ok(!(style & DTS_SHOWNONE), "Expected DTS_SHOWNONE not to be set\n");
777     DestroyWindow(hwnd);
778
779     hwnd = create_datetime_control(DTS_SHOWNONE);
780     style = GetWindowLong(hwnd, GWL_STYLE);
781     SetWindowLong(hwnd, GWL_STYLE, style & ~DTS_SHOWNONE);
782     style = GetWindowLong(hwnd, GWL_STYLE);
783     ok(style & DTS_SHOWNONE, "Expected DTS_SHOWNONE to be set\n");
784     DestroyWindow(hwnd);
785 }
786
787 START_TEST(datetime)
788 {
789     HMODULE hComctl32;
790     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
791     INITCOMMONCONTROLSEX iccex;
792
793     hComctl32 = GetModuleHandleA("comctl32.dll");
794     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
795     if (!pInitCommonControlsEx)
796     {
797         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
798         return;
799     }
800     iccex.dwSize = sizeof(iccex);
801     iccex.dwICC  = ICC_DATE_CLASSES;
802     pInitCommonControlsEx(&iccex);
803
804     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
805
806     test_dtm_set_format();
807     test_dtm_set_and_get_mccolor();
808     test_dtm_set_and_get_mcfont();
809     test_dtm_get_monthcal();
810     test_dtm_set_and_get_range();
811     test_dtm_set_range_swap_min_max();
812     test_dtm_set_and_get_system_time();
813     test_dtm_set_and_get_systemtime_with_limits();
814     test_wm_set_get_text();
815     test_dts_shownone();
816 }