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