comctl32/datetime: It isn't allowed to change DTS_SHOWNONE after creation.
[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 LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
125 {
126     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
127     static LONG defwndproc_counter = 0;
128     LRESULT ret;
129     struct message msg;
130
131     trace("datetime: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
132
133     msg.message = message;
134     msg.flags = sent|wparam|lparam;
135     if (defwndproc_counter) msg.flags |= defwinproc;
136     msg.wParam = wParam;
137     msg.lParam = lParam;
138     add_message(sequences, DATETIME_SEQ_INDEX, &msg);
139
140     defwndproc_counter++;
141     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
142     defwndproc_counter--;
143
144     return ret;
145 }
146
147 static HWND create_datetime_control(DWORD style)
148 {
149     WNDPROC oldproc;
150     HWND hWndDateTime = NULL;
151
152     hWndDateTime = CreateWindowEx(0,
153         DATETIMEPICK_CLASS,
154         NULL,
155         style,
156         0,50,300,120,
157         NULL,
158         NULL,
159         NULL,
160         NULL);
161
162     if (!hWndDateTime) return NULL;
163
164     oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC,
165                                          (LONG_PTR)datetime_subclass_proc);
166     SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)oldproc);
167
168     return hWndDateTime;
169 }
170
171 static void test_dtm_set_format(void)
172 {
173     HWND hWnd;
174     CHAR txt[256];
175     SYSTEMTIME systime;
176     LRESULT r;
177
178     hWnd = create_datetime_control(DTS_SHOWNONE);
179
180     flush_sequences(sequences, NUM_MSG_SEQUENCES);
181
182     r = SendMessage(hWnd, DTM_SETFORMAT, 0, 0);
183     expect(1, r);
184
185     r = SendMessage(hWnd, DTM_SETFORMAT, 0,
186                     (LPARAM)"'Today is: 'hh':'m':'s dddd MMM dd', 'yyyy");
187     expect(1, r);
188
189     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_format_seq, "test_dtm_set_format", FALSE);
190
191     r = SendMessage(hWnd, DTM_SETFORMAT, 0,
192                     (LPARAM)"'hh' hh");
193     expect(1, r);
194     ZeroMemory(&systime, sizeof(systime));
195     systime.wYear = 2000;
196     systime.wMonth = systime.wDay = 1;
197     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime);
198     expect(1, r);
199     GetWindowText(hWnd, txt, 256);
200     todo_wine ok(strcmp(txt, "hh 12") == 0, "String mismatch (\"%s\" vs \"hh 12\")\n", txt);
201
202     DestroyWindow(hWnd);
203 }
204
205 static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name)
206 {
207     LRESULT r;
208     COLORREF theColor, prevColor;
209
210     theColor=RGB(0,0,0);
211     r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
212     ok(r != -1, "%s: Set RGB(0,0,0): Expected COLORREF of previous value, got %ld\n", mccolor_name, r);
213     prevColor=theColor;
214     theColor=RGB(255,255,255);
215     r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
216     ok(r==prevColor, "%s: Set RGB(255,255,255): Expected COLORREF of previous value, got %ld\n", mccolor_name, r);
217     prevColor=theColor;
218     theColor=RGB(100,180,220);
219     r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
220     ok(r==prevColor, "%s: Set RGB(100,180,220): Expected COLORREF of previous value, got %ld\n", mccolor_name, r);
221     r = SendMessage(hWndDateTime, DTM_GETMCCOLOR, mccolor_type, 0);
222     ok(r==theColor, "%s: GETMCCOLOR: Expected %d, got %ld\n", mccolor_name, theColor, r);
223 }
224
225 static void test_dtm_set_and_get_mccolor(void)
226 {
227     HWND hWnd;
228
229     hWnd = create_datetime_control(DTS_SHOWNONE);
230
231     flush_sequences(sequences, NUM_MSG_SEQUENCES);
232
233     test_mccolor_types(hWnd, MCSC_BACKGROUND, "MCSC_BACKGROUND");
234     test_mccolor_types(hWnd, MCSC_MONTHBK, "MCSC_MONTHBK");
235     test_mccolor_types(hWnd, MCSC_TEXT, "MCSC_TEXT");
236     test_mccolor_types(hWnd, MCSC_TITLEBK, "MCSC_TITLEBK");
237     test_mccolor_types(hWnd, MCSC_TITLETEXT, "MCSC_TITLETEXT");
238     test_mccolor_types(hWnd, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT");
239
240     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mccolor_seq, "test_dtm_set_and_get_mccolor", FALSE);
241
242     DestroyWindow(hWnd);
243 }
244
245 static void test_dtm_set_and_get_mcfont(void)
246 {
247     HFONT hFontOrig, hFontNew;
248     HWND hWnd;
249
250     hWnd = create_datetime_control(DTS_SHOWNONE);
251
252     flush_sequences(sequences, NUM_MSG_SEQUENCES);
253
254     hFontOrig = GetStockObject(DEFAULT_GUI_FONT);
255     SendMessage(hWnd, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE);
256     hFontNew = (HFONT)SendMessage(hWnd, DTM_GETMCFONT, 0, 0);
257     ok(hFontOrig == hFontNew, "Expected hFontOrig==hFontNew, hFontOrig=%p, hFontNew=%p\n", hFontOrig, hFontNew);
258
259     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mcfont_seq, "test_dtm_set_and_get_mcfont", FALSE);
260     DestroyWindow(hWnd);
261 }
262
263 static void test_dtm_get_monthcal(void)
264 {
265     LRESULT r;
266     HWND hWnd;
267
268     hWnd = create_datetime_control(DTS_SHOWNONE);
269
270     flush_sequences(sequences, NUM_MSG_SEQUENCES);
271
272     todo_wine {
273         r = SendMessage(hWnd, DTM_GETMONTHCAL, 0, 0);
274         ok(r == 0, "Expected NULL(no child month calendar control), got %ld\n", r);
275     }
276
277     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_get_monthcal_seq, "test_dtm_get_monthcal", FALSE);
278     DestroyWindow(hWnd);
279 }
280
281 static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds)
282 {
283     st->wYear = year;
284     st->wMonth = month;
285     st->wDayOfWeek = dayofweek;
286     st->wDay = day;
287     st->wHour = hour;
288     st->wMinute = minute;
289     st->wSecond = second;
290     st->wMilliseconds = milliseconds;
291 }
292
293 static LPARAM compare_systime_date(SYSTEMTIME *st1, SYSTEMTIME *st2)
294 {
295     return (st1->wYear == st2->wYear)
296             && (st1->wMonth == st2->wMonth)
297             && (st1->wDayOfWeek == st2->wDayOfWeek)
298             && (st1->wDay == st2->wDay);
299 }
300
301 static LPARAM compare_systime_time(SYSTEMTIME *st1, SYSTEMTIME *st2)
302 {
303     return (st1->wHour == st2->wHour)
304             && (st1->wMinute == st2->wMinute)
305             && (st1->wSecond == st2->wSecond)
306             && (st1->wMilliseconds == st2->wMilliseconds);
307 }
308
309 static LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2)
310 {
311     if(!compare_systime_date(st1, st2))
312         return 0;
313
314     return compare_systime_time(st1, st2);
315 }
316
317 #define expect_systime(ST1, ST2) ok(compare_systime((ST1), (ST2))==1, "ST1 != ST2\n")
318 #define expect_systime_date(ST1, ST2) ok(compare_systime_date((ST1), (ST2))==1, "ST1.date != ST2.date\n")
319 #define expect_systime_time(ST1, ST2) ok(compare_systime_time((ST1), (ST2))==1, "ST1.time != ST2.time\n")
320
321 static void test_dtm_set_and_get_range(void)
322 {
323     LRESULT r;
324     SYSTEMTIME st[2];
325     SYSTEMTIME getSt[2];
326     HWND hWnd;
327
328     hWnd = create_datetime_control(DTS_SHOWNONE);
329
330     flush_sequences(sequences, NUM_MSG_SEQUENCES);
331
332     /* initialize st[0] to lowest possible value */
333     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
334     /* initialize st[1] to all invalid numbers */
335     fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000);
336
337     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
338     expect(1, r);
339     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
340     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);
341     expect_systime(&st[0], &getSt[0]);
342
343     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
344     expect_unsuccess(0, r);
345
346     /* set st[0] to all invalid numbers */
347     fill_systime_struct(&st[0], 0, 0, 7, 0, 24, 60, 60, 1000);
348     /* set st[1] to highest possible value */
349     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
350
351     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
352     expect(1, r);
353     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
354     todo_wine {
355         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);
356     }
357     expect_systime(&st[1], &getSt[1]);
358
359     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
360     expect_unsuccess(0, r);
361     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
362     expect_unsuccess(0, r);
363
364     /* set st[0] to highest possible value */
365     fill_systime_struct(&st[0], 30827, 12, 6, 31, 23, 59, 59, 999);
366
367     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
368     expect(1, r);
369     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
370     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);
371     expect_systime(&st[0], &getSt[0]);
372     expect_systime(&st[1], &getSt[1]);
373
374     /* initialize st[0] to lowest possible value */
375     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
376     /* set st[1] to highest possible value */
377     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
378
379     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
380     expect(1, r);
381     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
382     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);
383     expect_systime(&st[0], &getSt[0]);
384     expect_systime(&st[1], &getSt[1]);
385
386     /* set st[0] to value higher than minimum */
387     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
388     /* set st[1] to value lower than maximum */
389     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
390
391     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
392     expect(1, r);
393     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
394     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);
395     expect_systime(&st[0], &getSt[0]);
396     expect_systime(&st[1], &getSt[1]);
397
398     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_range_seq, "test_dtm_set_and_get_range", FALSE);
399
400     DestroyWindow(hWnd);
401 }
402
403 /* when max<min for DTM_SETRANGE, Windows seems to swap the min and max values,
404 although that's undocumented.  However, it doesn't seem to be implemented
405 correctly, causing some strange side effects */
406 static void test_dtm_set_range_swap_min_max(void)
407 {
408     LRESULT r;
409     SYSTEMTIME st[2];
410     SYSTEMTIME getSt[2];
411     SYSTEMTIME origSt;
412     HWND hWnd;
413
414     hWnd = create_datetime_control(DTS_SHOWNONE);
415     flush_sequences(sequences, NUM_MSG_SEQUENCES);
416
417     fill_systime_struct(&st[0], 2007, 2, 4, 15, 2, 2, 2, 2);
418
419     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
420     expect(1, r);
421     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&origSt);
422     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
423     expect_systime(&st[0], &origSt);
424
425     /* set st[0] to value higher than st[1] */
426     fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
427     fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
428
429     /* since min>max, min and max values should be swapped by DTM_SETRANGE
430     automatically */
431     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
432     expect(1, r);
433     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
434     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);
435     todo_wine {
436         ok(compare_systime(&st[0], &getSt[0]) == 1 ||
437            broken(compare_systime(&st[0], &getSt[1]) == 1), /* comctl32 version  <= 5.80 */
438            "ST1 != ST2\n");
439
440         ok(compare_systime(&st[1], &getSt[1]) == 1 ||
441            broken(compare_systime(&st[1], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
442            "ST1 != ST2\n");
443     }
444
445     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
446
447     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
448     expect(1, r);
449     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
450     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
451     /* the time part seems to not change after swapping the min and max values
452     and doing DTM_SETSYSTEMTIME */
453     expect_systime_date(&st[0], &getSt[0]);
454     todo_wine {
455         ok(compare_systime_time(&origSt, &getSt[0]) == 1 ||
456            broken(compare_systime_time(&st[0], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
457            "ST1.time != ST2.time\n");
458     }
459
460     /* set st[0] to value higher than minimum */
461     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
462     /* set st[1] to value lower than maximum */
463     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
464
465     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
466     expect(1, r);
467     /* for some reason after we swapped the min and max values before,
468     whenever we do a DTM_SETRANGE, the DTM_GETRANGE will return the values
469     swapped*/
470     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
471     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);
472     todo_wine {
473         ok(compare_systime(&st[0], &getSt[1]) == 1 ||
474            broken(compare_systime(&st[0], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
475            "ST1 != ST2\n");
476
477         ok(compare_systime(&st[1], &getSt[0]) == 1 ||
478            broken(compare_systime(&st[1], &getSt[1]) == 1), /* comctl32 version <= 5.80 */
479            "ST1 != ST2\n");
480     }
481
482     /* set st[0] to value higher than st[1] */
483     fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
484     fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
485
486     /* set min>max again, so that the return values of DTM_GETRANGE are no
487     longer swapped the next time we do a DTM SETRANGE and DTM_GETRANGE*/
488     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
489     expect(1, r);
490     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
491     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);
492     expect_systime(&st[0], &getSt[1]);
493     expect_systime(&st[1], &getSt[0]);
494
495     /* initialize st[0] to lowest possible value */
496     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
497     /* set st[1] to highest possible value */
498     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
499
500     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
501     expect(1, r);
502     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
503     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);
504     expect_systime(&st[0], &getSt[0]);
505     expect_systime(&st[1], &getSt[1]);
506
507     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_range_swap_min_max_seq, "test_dtm_set_range_swap_min_max", FALSE);
508
509     DestroyWindow(hWnd);
510 }
511
512 static void test_dtm_set_and_get_system_time(void)
513 {
514     LRESULT r;
515     SYSTEMTIME st, getSt, ref;
516     HWND hWnd, hWndDateTime_test_gdt_none;
517
518     hWndDateTime_test_gdt_none = create_datetime_control(0);
519
520     ok(hWndDateTime_test_gdt_none!=NULL, "Expected non NULL, got %p\n", hWndDateTime_test_gdt_none);
521     if(hWndDateTime_test_gdt_none) {
522         r = SendMessage(hWndDateTime_test_gdt_none, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
523         expect(0, r);
524     }
525     else {
526         skip("hWndDateTime_test_gdt_none is NULL\n");
527         flush_sequences(sequences, NUM_MSG_SEQUENCES);
528
529         return;
530     }
531
532     DestroyWindow(hWndDateTime_test_gdt_none);
533
534     hWnd = create_datetime_control(DTS_SHOWNONE);
535     flush_sequences(sequences, NUM_MSG_SEQUENCES);
536
537     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
538     expect(1, r);
539     r = SendMessage(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 = SendMessage(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 = SendMessage(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 = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
558     expect(1, r);
559     r = SendMessage(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 = SendMessage(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 = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&ref);
574     expect(1, r);
575     r = SendMessage(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 = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
583     todo_wine expect(1, r);
584     r = SendMessage(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 = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
591     expect(0, r);
592     r = SendMessage(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 = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
599     expect(0, r);
600     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
601     expect(GDT_VALID, r);
602     expect_systime(&ref, &getSt);
603     /* day of week isn't validated */
604     st = ref;
605     st.wDayOfWeek = 10;
606     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
607     expect(1, r);
608     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
609     expect(GDT_VALID, r);
610     expect_systime(&ref, &getSt);
611     /* hour invalid */
612     st = ref;
613     st.wHour = 25;
614     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
615     expect(0, r);
616     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
617     expect(GDT_VALID, r);
618     expect_systime(&ref, &getSt);
619     /* minute invalid */
620     st = ref;
621     st.wMinute = 60;
622     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
623     expect(0, r);
624     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
625     expect(GDT_VALID, r);
626     expect_systime(&ref, &getSt);
627     /* sec invalid */
628     st = ref;
629     st.wSecond = 60;
630     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
631     expect(0, r);
632     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
633     expect(GDT_VALID, r);
634     expect_systime(&ref, &getSt);
635     /* msec invalid */
636     st = ref;
637     st.wMilliseconds = 1000;
638     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
639     expect(0, r);
640     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
641     expect(GDT_VALID, r);
642     expect_systime(&ref, &getSt);
643
644     /* day of week should be calculated automatically,
645        actual day of week for this date is 4 */
646     fill_systime_struct(&st, 2009, 10, 1, 1, 0, 0, 10, 200);
647     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
648     expect(1, r);
649     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
650     expect(GDT_VALID, r);
651     /* 01.10.2009 is Thursday */
652     expect(4, (LRESULT)getSt.wDayOfWeek);
653     st.wDayOfWeek = 4;
654     expect_systime(&st, &getSt);
655
656     DestroyWindow(hWnd);
657 }
658
659 static void test_wm_set_get_text(void)
660 {
661     static const CHAR a_str[] = "a";
662     char buff[10];
663     HWND hWnd;
664     LRESULT ret;
665
666     hWnd = create_datetime_control(0);
667
668     ret = SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)a_str);
669     ok(CB_ERR == ret ||
670        broken(1 == ret), /* comctl32 <= 4.72 */
671        "Expected CB_ERR, got %ld\n", ret);
672
673     buff[0] = 0;
674     ret = SendMessage(hWnd, WM_GETTEXT, sizeof(buff), (LPARAM)buff);
675     ok(strcmp(buff, a_str) != 0, "Expected text not to change, got %s\n", buff);
676
677     DestroyWindow(hWnd);
678 }
679
680 static void test_dts_shownone(void)
681 {
682     HWND hwnd;
683     DWORD style;
684
685     /* it isn't allowed to change DTS_SHOWNONE after creation */
686     hwnd = create_datetime_control(0);
687     style = GetWindowLong(hwnd, GWL_STYLE);
688     SetWindowLong(hwnd, GWL_STYLE, style | DTS_SHOWNONE);
689     style = GetWindowLong(hwnd, GWL_STYLE);
690     ok(!(style & DTS_SHOWNONE), "Expected DTS_SHOWNONE not to be set\n");
691     DestroyWindow(hwnd);
692
693     hwnd = create_datetime_control(DTS_SHOWNONE);
694     style = GetWindowLong(hwnd, GWL_STYLE);
695     SetWindowLong(hwnd, GWL_STYLE, style & ~DTS_SHOWNONE);
696     style = GetWindowLong(hwnd, GWL_STYLE);
697     ok(style & DTS_SHOWNONE, "Expected DTS_SHOWNONE to be set\n");
698     DestroyWindow(hwnd);
699 }
700
701 START_TEST(datetime)
702 {
703     HMODULE hComctl32;
704     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
705     INITCOMMONCONTROLSEX iccex;
706
707     hComctl32 = GetModuleHandleA("comctl32.dll");
708     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
709     if (!pInitCommonControlsEx)
710     {
711         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
712         return;
713     }
714     iccex.dwSize = sizeof(iccex);
715     iccex.dwICC  = ICC_DATE_CLASSES;
716     pInitCommonControlsEx(&iccex);
717
718     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
719
720     test_dtm_set_format();
721     test_dtm_set_and_get_mccolor();
722     test_dtm_set_and_get_mcfont();
723     test_dtm_get_monthcal();
724     test_dtm_set_and_get_range();
725     test_dtm_set_range_swap_min_max();
726     test_dtm_set_and_get_system_time();
727     test_wm_set_get_text();
728     test_dts_shownone();
729 }