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