comdlg32: Correct title of "Save As" dialog.
[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     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     COLORREF theColor, prevColor, crColor;
208
209     theColor=RGB(0,0,0);
210     crColor = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
211     ok(crColor != ~0u, "%s: Set RGB(0,0,0): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor);
212     prevColor=theColor;
213     theColor=RGB(255,255,255);
214     crColor = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
215     ok(crColor==prevColor, "%s: Set RGB(255,255,255): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor);
216     prevColor=theColor;
217     theColor=RGB(100,180,220);
218     crColor = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
219     ok(crColor==prevColor, "%s: Set RGB(100,180,220): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor);
220     crColor = SendMessage(hWndDateTime, DTM_GETMCCOLOR, mccolor_type, 0);
221     ok(crColor==theColor, "%s: GETMCCOLOR: Expected %d, got %d\n", mccolor_name, theColor, crColor);
222 }
223
224 static void test_dtm_set_and_get_mccolor(void)
225 {
226     HWND hWnd;
227
228     hWnd = create_datetime_control(DTS_SHOWNONE);
229
230     flush_sequences(sequences, NUM_MSG_SEQUENCES);
231
232     test_mccolor_types(hWnd, MCSC_BACKGROUND, "MCSC_BACKGROUND");
233     test_mccolor_types(hWnd, MCSC_MONTHBK, "MCSC_MONTHBK");
234     test_mccolor_types(hWnd, MCSC_TEXT, "MCSC_TEXT");
235     test_mccolor_types(hWnd, MCSC_TITLEBK, "MCSC_TITLEBK");
236     test_mccolor_types(hWnd, MCSC_TITLETEXT, "MCSC_TITLETEXT");
237     test_mccolor_types(hWnd, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT");
238
239     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mccolor_seq, "test_dtm_set_and_get_mccolor", FALSE);
240
241     DestroyWindow(hWnd);
242 }
243
244 static void test_dtm_set_and_get_mcfont(void)
245 {
246     HFONT hFontOrig, hFontNew;
247     HWND hWnd;
248
249     hWnd = create_datetime_control(DTS_SHOWNONE);
250
251     flush_sequences(sequences, NUM_MSG_SEQUENCES);
252
253     hFontOrig = GetStockObject(DEFAULT_GUI_FONT);
254     SendMessage(hWnd, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE);
255     hFontNew = (HFONT)SendMessage(hWnd, DTM_GETMCFONT, 0, 0);
256     ok(hFontOrig == hFontNew, "Expected hFontOrig==hFontNew, hFontOrig=%p, hFontNew=%p\n", hFontOrig, hFontNew);
257
258     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mcfont_seq, "test_dtm_set_and_get_mcfont", FALSE);
259     DestroyWindow(hWnd);
260 }
261
262 static void test_dtm_get_monthcal(void)
263 {
264     LRESULT r;
265     HWND hWnd;
266
267     hWnd = create_datetime_control(DTS_SHOWNONE);
268
269     flush_sequences(sequences, NUM_MSG_SEQUENCES);
270
271     todo_wine {
272         r = SendMessage(hWnd, DTM_GETMONTHCAL, 0, 0);
273         ok(r == 0, "Expected NULL(no child month calendar control), got %ld\n", r);
274     }
275
276     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_get_monthcal_seq, "test_dtm_get_monthcal", FALSE);
277     DestroyWindow(hWnd);
278 }
279
280 static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds)
281 {
282     st->wYear = year;
283     st->wMonth = month;
284     st->wDayOfWeek = dayofweek;
285     st->wDay = day;
286     st->wHour = hour;
287     st->wMinute = minute;
288     st->wSecond = second;
289     st->wMilliseconds = milliseconds;
290 }
291
292 static LPARAM compare_systime_date(SYSTEMTIME *st1, SYSTEMTIME *st2)
293 {
294     return (st1->wYear == st2->wYear)
295             && (st1->wMonth == st2->wMonth)
296             && (st1->wDayOfWeek == st2->wDayOfWeek)
297             && (st1->wDay == st2->wDay);
298 }
299
300 static LPARAM compare_systime_time(SYSTEMTIME *st1, SYSTEMTIME *st2)
301 {
302     return (st1->wHour == st2->wHour)
303             && (st1->wMinute == st2->wMinute)
304             && (st1->wSecond == st2->wSecond)
305             && (st1->wMilliseconds == st2->wMilliseconds);
306 }
307
308 static LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2)
309 {
310     if(!compare_systime_date(st1, st2))
311         return 0;
312
313     return compare_systime_time(st1, st2);
314 }
315
316 #define expect_systime(ST1, ST2) ok(compare_systime((ST1), (ST2))==1, "ST1 != ST2\n")
317 #define expect_systime_date(ST1, ST2) ok(compare_systime_date((ST1), (ST2))==1, "ST1.date != ST2.date\n")
318 #define expect_systime_time(ST1, ST2) ok(compare_systime_time((ST1), (ST2))==1, "ST1.time != ST2.time\n")
319
320 static void test_dtm_set_and_get_range(void)
321 {
322     LRESULT r;
323     SYSTEMTIME st[2];
324     SYSTEMTIME getSt[2];
325     HWND hWnd;
326
327     hWnd = create_datetime_control(DTS_SHOWNONE);
328
329     flush_sequences(sequences, NUM_MSG_SEQUENCES);
330
331     /* initialize st[0] to lowest possible value */
332     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
333     /* initialize st[1] to all invalid numbers */
334     fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000);
335
336     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
337     expect(1, r);
338     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
339     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);
340     expect_systime(&st[0], &getSt[0]);
341
342     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
343     expect_unsuccess(0, r);
344
345     /* set st[0] to all invalid numbers */
346     fill_systime_struct(&st[0], 0, 0, 7, 0, 24, 60, 60, 1000);
347     /* set st[1] to highest possible value */
348     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
349
350     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
351     expect(1, r);
352     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
353     todo_wine {
354         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);
355     }
356     expect_systime(&st[1], &getSt[1]);
357
358     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
359     expect_unsuccess(0, r);
360     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
361     expect_unsuccess(0, r);
362
363     /* set st[0] to highest possible value */
364     fill_systime_struct(&st[0], 30827, 12, 6, 31, 23, 59, 59, 999);
365
366     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
367     expect(1, r);
368     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
369     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);
370     expect_systime(&st[0], &getSt[0]);
371     expect_systime(&st[1], &getSt[1]);
372
373     /* initialize st[0] to lowest possible value */
374     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
375     /* set st[1] to highest possible value */
376     fill_systime_struct(&st[1], 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     /* set st[0] to value higher than minimum */
386     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
387     /* set st[1] to value lower than maximum */
388     fill_systime_struct(&st[1], 2007, 3, 2, 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     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_range_seq, "test_dtm_set_and_get_range", FALSE);
398
399     DestroyWindow(hWnd);
400 }
401
402 /* when max<min for DTM_SETRANGE, Windows seems to swap the min and max values,
403 although that's undocumented.  However, it doesn't seem to be implemented
404 correctly, causing some strange side effects */
405 static void test_dtm_set_range_swap_min_max(void)
406 {
407     LRESULT r;
408     SYSTEMTIME st[2];
409     SYSTEMTIME getSt[2];
410     SYSTEMTIME origSt;
411     HWND hWnd;
412
413     hWnd = create_datetime_control(DTS_SHOWNONE);
414     flush_sequences(sequences, NUM_MSG_SEQUENCES);
415
416     fill_systime_struct(&st[0], 2007, 2, 4, 15, 2, 2, 2, 2);
417
418     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
419     expect(1, r);
420     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&origSt);
421     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
422     expect_systime(&st[0], &origSt);
423
424     /* set st[0] to value higher than st[1] */
425     fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
426     fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
427
428     /* since min>max, min and max values should be swapped by DTM_SETRANGE
429     automatically */
430     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
431     expect(1, r);
432     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
433     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);
434     todo_wine {
435         ok(compare_systime(&st[0], &getSt[0]) == 1 ||
436            broken(compare_systime(&st[0], &getSt[1]) == 1), /* comctl32 version  <= 5.80 */
437            "ST1 != ST2\n");
438
439         ok(compare_systime(&st[1], &getSt[1]) == 1 ||
440            broken(compare_systime(&st[1], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
441            "ST1 != ST2\n");
442     }
443
444     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
445
446     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
447     expect(1, r);
448     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
449     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
450     /* the time part seems to not change after swapping the min and max values
451     and doing DTM_SETSYSTEMTIME */
452     expect_systime_date(&st[0], &getSt[0]);
453     todo_wine {
454         ok(compare_systime_time(&origSt, &getSt[0]) == 1 ||
455            broken(compare_systime_time(&st[0], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
456            "ST1.time != ST2.time\n");
457     }
458
459     /* set st[0] to value higher than minimum */
460     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
461     /* set st[1] to value lower than maximum */
462     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
463
464     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
465     expect(1, r);
466     /* for some reason after we swapped the min and max values before,
467     whenever we do a DTM_SETRANGE, the DTM_GETRANGE will return the values
468     swapped*/
469     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
470     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);
471     todo_wine {
472         ok(compare_systime(&st[0], &getSt[1]) == 1 ||
473            broken(compare_systime(&st[0], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
474            "ST1 != ST2\n");
475
476         ok(compare_systime(&st[1], &getSt[0]) == 1 ||
477            broken(compare_systime(&st[1], &getSt[1]) == 1), /* comctl32 version <= 5.80 */
478            "ST1 != ST2\n");
479     }
480
481     /* set st[0] to value higher than st[1] */
482     fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
483     fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
484
485     /* set min>max again, so that the return values of DTM_GETRANGE are no
486     longer swapped the next time we do a DTM SETRANGE and DTM_GETRANGE*/
487     r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
488     expect(1, r);
489     r = SendMessage(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
490     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);
491     expect_systime(&st[0], &getSt[1]);
492     expect_systime(&st[1], &getSt[0]);
493
494     /* initialize st[0] to lowest possible value */
495     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
496     /* set st[1] to highest possible value */
497     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
498
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[0]);
504     expect_systime(&st[1], &getSt[1]);
505
506     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_range_swap_min_max_seq, "test_dtm_set_range_swap_min_max", FALSE);
507
508     DestroyWindow(hWnd);
509 }
510
511 static void test_dtm_set_and_get_system_time(void)
512 {
513     LRESULT r;
514     SYSTEMTIME st, getSt, ref;
515     HWND hWnd, hWndDateTime_test_gdt_none;
516
517     hWndDateTime_test_gdt_none = create_datetime_control(0);
518
519     ok(hWndDateTime_test_gdt_none!=NULL, "Expected non NULL, got %p\n", hWndDateTime_test_gdt_none);
520     if(hWndDateTime_test_gdt_none) {
521         r = SendMessage(hWndDateTime_test_gdt_none, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
522         expect(0, r);
523     }
524     else {
525         skip("hWndDateTime_test_gdt_none is NULL\n");
526         flush_sequences(sequences, NUM_MSG_SEQUENCES);
527
528         return;
529     }
530
531     DestroyWindow(hWndDateTime_test_gdt_none);
532
533     hWnd = create_datetime_control(DTS_SHOWNONE);
534     flush_sequences(sequences, NUM_MSG_SEQUENCES);
535
536     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
537     expect(1, r);
538     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
539     ok(r == GDT_NONE, "Expected %d, not %d(GDT_VALID) or %d(GDT_ERROR), got %ld\n", GDT_NONE, GDT_VALID, GDT_ERROR, r);
540
541     /* set st to lowest possible value */
542     fill_systime_struct(&st, 1601, 1, 0, 1, 0, 0, 0, 0);
543
544     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
545     expect(1, r);
546
547     /* set st to highest possible value */
548     fill_systime_struct(&st, 30827, 12, 6, 31, 23, 59, 59, 999);
549
550     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
551     expect(1, r);
552
553     /* set st to value between min and max */
554     fill_systime_struct(&st, 1980, 1, 3, 23, 14, 34, 37, 465);
555
556     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
557     expect(1, r);
558     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
559     ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
560     expect_systime(&st, &getSt);
561
562     /* set st to invalid value */
563     fill_systime_struct(&st, 0, 0, 7, 0, 24, 60, 60, 1000);
564
565     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
566     expect_unsuccess(0, r);
567
568     ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_system_time_seq, "test_dtm_set_and_get_system_time", FALSE);
569
570     /* set to some valid value */
571     GetSystemTime(&ref);
572     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&ref);
573     expect(1, r);
574     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
575     expect(GDT_VALID, r);
576     expect_systime(&ref, &getSt);
577
578     /* year invalid */
579     st = ref;
580     st.wYear = 0;
581     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
582     todo_wine expect(1, r);
583     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
584     expect(GDT_VALID, r);
585     expect_systime(&ref, &getSt);
586     /* month invalid */
587     st = ref;
588     st.wMonth = 13;
589     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
590     expect(0, r);
591     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
592     expect(GDT_VALID, r);
593     expect_systime(&ref, &getSt);
594     /* day invalid */
595     st = ref;
596     st.wDay = 32;
597     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
598     expect(0, r);
599     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
600     expect(GDT_VALID, r);
601     expect_systime(&ref, &getSt);
602     /* day invalid for current month */
603     st = ref;
604     st.wDay = 30;
605     st.wMonth = 2;
606     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
607     expect(0, r);
608     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
609     expect(GDT_VALID, r);
610     expect_systime(&ref, &getSt);
611     /* day of week isn't validated */
612     st = ref;
613     st.wDayOfWeek = 10;
614     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
615     expect(1, r);
616     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
617     expect(GDT_VALID, r);
618     expect_systime(&ref, &getSt);
619     /* hour invalid */
620     st = ref;
621     st.wHour = 25;
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     /* minute invalid */
628     st = ref;
629     st.wMinute = 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     /* sec invalid */
636     st = ref;
637     st.wSecond = 60;
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     /* msec invalid */
644     st = ref;
645     st.wMilliseconds = 1000;
646     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
647     expect(0, r);
648     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
649     expect(GDT_VALID, r);
650     expect_systime(&ref, &getSt);
651
652     /* day of week should be calculated automatically,
653        actual day of week for this date is 4 */
654     fill_systime_struct(&st, 2009, 10, 1, 1, 0, 0, 10, 200);
655     r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
656     expect(1, r);
657     r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
658     expect(GDT_VALID, r);
659     /* 01.10.2009 is Thursday */
660     expect(4, (LRESULT)getSt.wDayOfWeek);
661     st.wDayOfWeek = 4;
662     expect_systime(&st, &getSt);
663
664     DestroyWindow(hWnd);
665 }
666
667 static void test_wm_set_get_text(void)
668 {
669     static const CHAR a_str[] = "a";
670     CHAR buff[16], time[16], caltype[3];
671     HWND hWnd;
672     LRESULT ret;
673
674     hWnd = create_datetime_control(0);
675
676     ret = SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)a_str);
677     ok(CB_ERR == ret ||
678        broken(0 == ret) || /* comctl32 <= 4.72 */
679        broken(1 == ret), /* comctl32 <= 4.70 */
680        "Expected CB_ERR, got %ld\n", ret);
681
682     buff[0] = 0;
683     ret = SendMessage(hWnd, WM_GETTEXT, sizeof(buff), (LPARAM)buff);
684     ok(strcmp(buff, a_str) != 0, "Expected text to change, got %s\n", buff);
685     ok(ret != 0, "Expected non-zero return value\n");
686
687     SetLastError(0xdeadbeef);
688     ret = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICALENDARTYPE, caltype, 3);
689     if (ret == 0)
690         skip("Must know local calendar type (%x)\n", GetLastError());
691     else if (atoi(caltype) != CAL_GREGORIAN)
692         skip("DateTimePicker Control only supports Gregorian calendar (type: %s)\n", caltype);
693     else {
694         SetLastError(0xdeadbeef);
695         ret = GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, time, sizeof(time));
696         if (ret == 0)
697             skip("GetDateFormat failed, returned %ld, error %d\n", ret, GetLastError());
698         else
699             ok(!strcmp(buff, time), "Expected %s, got %s\n", time, buff);
700     }
701
702     DestroyWindow(hWnd);
703 }
704
705 static void test_dts_shownone(void)
706 {
707     HWND hwnd;
708     DWORD style;
709
710     /* it isn't allowed to change DTS_SHOWNONE after creation */
711     hwnd = create_datetime_control(0);
712     style = GetWindowLong(hwnd, GWL_STYLE);
713     SetWindowLong(hwnd, GWL_STYLE, style | DTS_SHOWNONE);
714     style = GetWindowLong(hwnd, GWL_STYLE);
715     ok(!(style & DTS_SHOWNONE), "Expected DTS_SHOWNONE not to be set\n");
716     DestroyWindow(hwnd);
717
718     hwnd = create_datetime_control(DTS_SHOWNONE);
719     style = GetWindowLong(hwnd, GWL_STYLE);
720     SetWindowLong(hwnd, GWL_STYLE, style & ~DTS_SHOWNONE);
721     style = GetWindowLong(hwnd, GWL_STYLE);
722     ok(style & DTS_SHOWNONE, "Expected DTS_SHOWNONE to be set\n");
723     DestroyWindow(hwnd);
724 }
725
726 START_TEST(datetime)
727 {
728     HMODULE hComctl32;
729     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
730     INITCOMMONCONTROLSEX iccex;
731
732     hComctl32 = GetModuleHandleA("comctl32.dll");
733     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
734     if (!pInitCommonControlsEx)
735     {
736         skip("InitCommonControlsEx() is missing. Skipping the tests\n");
737         return;
738     }
739     iccex.dwSize = sizeof(iccex);
740     iccex.dwICC  = ICC_DATE_CLASSES;
741     pInitCommonControlsEx(&iccex);
742
743     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
744
745     test_dtm_set_format();
746     test_dtm_set_and_get_mccolor();
747     test_dtm_set_and_get_mcfont();
748     test_dtm_get_monthcal();
749     test_dtm_set_and_get_range();
750     test_dtm_set_range_swap_min_max();
751     test_dtm_set_and_get_system_time();
752     test_wm_set_get_text();
753     test_dts_shownone();
754 }