mfreadwrite/reader: Add missing allocation check (Coverity).
[wine/zf.git] / dlls / comctl32 / tests / datetime.c
blob47d7a8fbe560a2d198b993d4d4d52c0eb574b27b
1 /* Unit test suite for datetime control.
3 * Copyright 2007 Kanit Therdsteerasukdi
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.
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.
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
20 #include <windows.h>
21 #include <commctrl.h>
23 #include "wine/test.h"
24 #include "msg.h"
25 #include "v6util.h"
27 #define expect(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT))
29 #define expect_unsuccess(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d(unsuccessful), got %ld(successful)\n", (EXPECTED), (GOT))
31 #define NUM_MSG_SEQUENCES 1
32 #define DATETIME_SEQ_INDEX 0
34 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
36 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
38 static const struct message test_dtm_set_format_seq[] = {
39 { DTM_SETFORMATA, sent|wparam|lparam, 0, 0 },
40 { DTM_SETFORMATA, sent|wparam, 0 },
41 { 0 }
44 static const struct message test_dtm_set_and_get_mccolor_seq[] = {
45 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 },
46 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255, 255, 255) },
47 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(100, 180, 220) },
48 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 },
49 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 },
50 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255, 255, 255) },
51 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(100, 180, 220) },
52 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 },
53 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 },
54 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255, 255, 255) },
55 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(100, 180, 220) },
56 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 },
57 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 },
58 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255, 255, 255) },
59 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(100, 180, 220) },
60 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 },
61 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 },
62 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255, 255, 255) },
63 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(100, 180, 220) },
64 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 },
65 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 },
66 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255, 255, 255) },
67 { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(100, 180, 220) },
68 { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 },
69 { 0 }
72 static const struct message test_dtm_set_and_get_mcfont_seq[] = {
73 { DTM_SETMCFONT, sent|lparam, 0, 1 },
74 { DTM_GETMCFONT, sent|wparam|lparam, 0, 0 },
75 { 0 }
78 static const struct message test_dtm_get_monthcal_seq[] = {
79 { DTM_GETMONTHCAL, sent|wparam|lparam, 0, 0 },
80 { 0 }
83 static const struct message test_dtm_set_and_get_range_seq[] = {
84 { DTM_SETRANGE, sent|wparam, GDTR_MIN },
85 { DTM_GETRANGE, sent|wparam, 0 },
86 { DTM_SETRANGE, sent|wparam, GDTR_MAX },
87 { DTM_SETRANGE, sent|wparam, GDTR_MAX },
88 { DTM_GETRANGE, sent|wparam, 0 },
89 { DTM_SETRANGE, sent|wparam, GDTR_MIN },
90 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
91 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
92 { DTM_GETRANGE, sent|wparam, 0 },
93 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
94 { DTM_GETRANGE, sent|wparam, 0 },
95 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
96 { DTM_GETRANGE, sent|wparam, 0 },
97 { 0 }
100 static const struct message test_dtm_set_range_swap_min_max_seq[] = {
101 { DTM_SETSYSTEMTIME, sent|wparam, 0 },
102 { DTM_GETSYSTEMTIME, sent|wparam, 0 },
103 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
104 { DTM_GETRANGE, sent|wparam, 0 },
105 { DTM_SETSYSTEMTIME, sent|wparam, 0 },
106 { DTM_GETSYSTEMTIME, sent|wparam, 0 },
107 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
108 { DTM_GETRANGE, sent|wparam, 0 },
109 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
110 { DTM_GETRANGE, sent|wparam, 0 },
111 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
112 { DTM_GETRANGE, sent|wparam, 0 },
113 { 0 }
116 static const struct message test_dtm_set_and_get_system_time_seq[] = {
117 { DTM_SETSYSTEMTIME, sent|wparam, GDT_NONE },
118 { DTM_GETSYSTEMTIME, sent|wparam, 0 },
119 { DTM_SETSYSTEMTIME, sent|wparam, 0 },
120 { DTM_SETSYSTEMTIME, sent|wparam, 0 },
121 { DTM_SETSYSTEMTIME, sent|wparam, 0 },
122 { DTM_GETSYSTEMTIME, sent|wparam, 0 },
123 { DTM_SETSYSTEMTIME, sent|wparam, 0 },
124 { 0 }
127 static const struct message test_dtm_set_and_get_systime_with_limits[] = {
128 { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
129 { DTM_GETRANGE, sent|wparam, 0 },
130 { DTM_SETSYSTEMTIME, sent|wparam, 0 },
131 { DTM_GETSYSTEMTIME, sent|wparam, 0 },
132 { DTM_SETSYSTEMTIME, sent|wparam, 0 },
133 { DTM_GETSYSTEMTIME, sent|wparam, 0 },
134 { DTM_SETSYSTEMTIME, sent|wparam, 0 },
135 { DTM_GETSYSTEMTIME, sent|wparam, 0 },
136 { 0 }
139 static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
141 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
142 static LONG defwndproc_counter = 0;
143 struct message msg = { 0 };
144 LRESULT ret;
146 msg.message = message;
147 msg.flags = sent|wparam|lparam;
148 if (defwndproc_counter) msg.flags |= defwinproc;
149 msg.wParam = wParam;
150 msg.lParam = lParam;
151 add_message(sequences, DATETIME_SEQ_INDEX, &msg);
153 defwndproc_counter++;
154 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
155 defwndproc_counter--;
157 return ret;
160 static HWND create_datetime_control(DWORD style)
162 WNDPROC oldproc;
163 HWND hWndDateTime = NULL;
165 hWndDateTime = CreateWindowExA(0,
166 DATETIMEPICK_CLASSA,
167 NULL,
168 style,
169 0,50,300,120,
170 NULL,
171 NULL,
172 NULL,
173 NULL);
175 if (!hWndDateTime) return NULL;
177 oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC,
178 (LONG_PTR)datetime_subclass_proc);
179 SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)oldproc);
181 return hWndDateTime;
184 static void test_dtm_set_format(void)
186 HWND hWnd;
187 CHAR txt[256];
188 SYSTEMTIME systime;
189 LRESULT r;
191 hWnd = create_datetime_control(DTS_SHOWNONE);
193 flush_sequences(sequences, NUM_MSG_SEQUENCES);
195 r = SendMessageA(hWnd, DTM_SETFORMATA, 0, 0);
196 expect(1, r);
198 r = SendMessageA(hWnd, DTM_SETFORMATA, 0,
199 (LPARAM)"'Today is: 'hh':'m':'s dddd MMM dd', 'yyyy");
200 expect(1, r);
202 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_format_seq, "test_dtm_set_format", FALSE);
204 r = SendMessageA(hWnd, DTM_SETFORMATA, 0, (LPARAM)"'hh' hh");
205 expect(1, r);
206 ZeroMemory(&systime, sizeof(systime));
207 systime.wYear = 2000;
208 systime.wMonth = systime.wDay = 1;
209 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime);
210 expect(1, r);
211 GetWindowTextA(hWnd, txt, 256);
212 ok(strcmp(txt, "hh 12") == 0, "String mismatch (\"%s\" vs \"hh 12\")\n", txt);
214 DestroyWindow(hWnd);
217 static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name)
219 COLORREF theColor, prevColor, crColor;
221 theColor=RGB(0,0,0);
222 crColor = SendMessageA(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
223 ok(crColor != ~0u, "%s: Set RGB(0,0,0): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor);
224 prevColor=theColor;
225 theColor=RGB(255,255,255);
226 crColor = SendMessageA(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
227 ok(crColor==prevColor, "%s: Set RGB(255,255,255): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor);
228 prevColor=theColor;
229 theColor=RGB(100,180,220);
230 crColor = SendMessageA(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
231 ok(crColor==prevColor, "%s: Set RGB(100,180,220): Expected COLORREF of previous value, got %d\n", mccolor_name, crColor);
232 crColor = SendMessageA(hWndDateTime, DTM_GETMCCOLOR, mccolor_type, 0);
233 ok(crColor==theColor, "%s: GETMCCOLOR: Expected %d, got %d\n", mccolor_name, theColor, crColor);
236 static void test_dtm_set_and_get_mccolor(void)
238 HWND hWnd;
240 hWnd = create_datetime_control(DTS_SHOWNONE);
242 flush_sequences(sequences, NUM_MSG_SEQUENCES);
244 test_mccolor_types(hWnd, MCSC_BACKGROUND, "MCSC_BACKGROUND");
245 test_mccolor_types(hWnd, MCSC_MONTHBK, "MCSC_MONTHBK");
246 test_mccolor_types(hWnd, MCSC_TEXT, "MCSC_TEXT");
247 test_mccolor_types(hWnd, MCSC_TITLEBK, "MCSC_TITLEBK");
248 test_mccolor_types(hWnd, MCSC_TITLETEXT, "MCSC_TITLETEXT");
249 test_mccolor_types(hWnd, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT");
251 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mccolor_seq, "test_dtm_set_and_get_mccolor", FALSE);
253 DestroyWindow(hWnd);
256 static void test_dtm_set_and_get_mcfont(void)
258 HFONT hFontOrig, hFontNew;
259 HWND hWnd;
261 hWnd = create_datetime_control(DTS_SHOWNONE);
263 flush_sequences(sequences, NUM_MSG_SEQUENCES);
265 hFontOrig = GetStockObject(DEFAULT_GUI_FONT);
266 SendMessageA(hWnd, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE);
267 hFontNew = (HFONT)SendMessageA(hWnd, DTM_GETMCFONT, 0, 0);
268 ok(hFontOrig == hFontNew, "Expected hFontOrig==hFontNew, hFontOrig=%p, hFontNew=%p\n", hFontOrig, hFontNew);
270 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mcfont_seq, "test_dtm_set_and_get_mcfont", FALSE);
271 DestroyWindow(hWnd);
274 static void test_dtm_get_monthcal(void)
276 LRESULT r;
277 HWND hWnd;
279 hWnd = create_datetime_control(DTS_SHOWNONE);
281 flush_sequences(sequences, NUM_MSG_SEQUENCES);
283 todo_wine {
284 r = SendMessageA(hWnd, DTM_GETMONTHCAL, 0, 0);
285 ok(r == 0, "Expected NULL(no child month calendar control), got %ld\n", r);
288 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_get_monthcal_seq, "test_dtm_get_monthcal", FALSE);
289 DestroyWindow(hWnd);
292 static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds)
294 st->wYear = year;
295 st->wMonth = month;
296 st->wDayOfWeek = dayofweek;
297 st->wDay = day;
298 st->wHour = hour;
299 st->wMinute = minute;
300 st->wSecond = second;
301 st->wMilliseconds = milliseconds;
304 static LPARAM compare_systime_date(SYSTEMTIME *st1, SYSTEMTIME *st2)
306 return (st1->wYear == st2->wYear)
307 && (st1->wMonth == st2->wMonth)
308 && (st1->wDayOfWeek == st2->wDayOfWeek)
309 && (st1->wDay == st2->wDay);
312 static LPARAM compare_systime_time(SYSTEMTIME *st1, SYSTEMTIME *st2)
314 return (st1->wHour == st2->wHour)
315 && (st1->wMinute == st2->wMinute)
316 && (st1->wSecond == st2->wSecond)
317 && (st1->wMilliseconds == st2->wMilliseconds);
320 static LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2)
322 if(!compare_systime_date(st1, st2))
323 return 0;
325 return compare_systime_time(st1, st2);
328 #define expect_systime(ST1, ST2) ok(compare_systime((ST1), (ST2))==1, "ST1 != ST2\n")
329 #define expect_systime_date(ST1, ST2) ok(compare_systime_date((ST1), (ST2))==1, "ST1.date != ST2.date\n")
330 #define expect_systime_time(ST1, ST2) ok(compare_systime_time((ST1), (ST2))==1, "ST1.time != ST2.time\n")
332 static void test_dtm_set_and_get_range(void)
334 LRESULT r;
335 SYSTEMTIME st[2];
336 SYSTEMTIME getSt[2];
337 HWND hWnd;
339 hWnd = create_datetime_control(DTS_SHOWNONE);
341 flush_sequences(sequences, NUM_MSG_SEQUENCES);
343 /* initialize st[0] to lowest possible value */
344 fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
345 /* initialize st[1] to all invalid numbers */
346 fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000);
348 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
349 expect(1, r);
350 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
351 ok(r == GDTR_MIN, "Expected %x, not %x(GDTR_MAX) or %x(GDTR_MIN | GDTR_MAX), got %lx\n", GDTR_MIN, GDTR_MAX, GDTR_MIN | GDTR_MAX, r);
352 expect_systime(&st[0], &getSt[0]);
354 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
355 expect_unsuccess(0, r);
357 /* set st[0] to all invalid numbers */
358 fill_systime_struct(&st[0], 0, 0, 7, 0, 24, 60, 60, 1000);
359 /* set st[1] to highest possible value */
360 fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
362 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
363 expect(1, r);
364 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
365 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);
366 expect_systime(&st[1], &getSt[1]);
368 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
369 expect_unsuccess(0, r);
370 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
371 expect_unsuccess(0, r);
373 /* set st[0] to highest possible value */
374 fill_systime_struct(&st[0], 30827, 12, 6, 31, 23, 59, 59, 999);
376 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
377 expect(1, r);
378 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
379 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);
380 expect_systime(&st[0], &getSt[0]);
381 expect_systime(&st[1], &getSt[1]);
383 /* initialize st[0] to lowest possible value */
384 fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
385 /* set st[1] to highest possible value */
386 fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
388 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
389 expect(1, r);
390 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
391 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);
392 expect_systime(&st[0], &getSt[0]);
393 expect_systime(&st[1], &getSt[1]);
395 /* set st[0] to value higher than minimum */
396 fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
397 /* set st[1] to value lower than maximum */
398 fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
400 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
401 expect(1, r);
402 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
403 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);
404 expect_systime(&st[0], &getSt[0]);
405 expect_systime(&st[1], &getSt[1]);
407 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_range_seq, "test_dtm_set_and_get_range", FALSE);
409 /* DTM_SETRANGE with 0 flags */
410 r = SendMessageA(hWnd, DTM_SETRANGE, 0, (LPARAM)st);
411 ok(r, "got %lu\n", r);
412 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
413 ok(r == 0, "got %lu\n", r);
414 ok(getSt[0].wYear == 0 && getSt[1].wYear == 0, "got %u, %u\n", getSt[0].wYear, getSt[1].wYear);
416 DestroyWindow(hWnd);
419 /* when max<min for DTM_SETRANGE, Windows seems to swap the min and max values,
420 although that's undocumented. However, it doesn't seem to be implemented
421 correctly, causing some strange side effects */
422 static void test_dtm_set_range_swap_min_max(void)
424 LRESULT r;
425 SYSTEMTIME st[2];
426 SYSTEMTIME getSt[2];
427 SYSTEMTIME origSt;
428 HWND hWnd;
430 hWnd = create_datetime_control(DTS_SHOWNONE);
431 flush_sequences(sequences, NUM_MSG_SEQUENCES);
433 fill_systime_struct(&st[0], 2007, 2, 4, 15, 2, 2, 2, 2);
435 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
436 expect(1, r);
437 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&origSt);
438 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
439 expect_systime(&st[0], &origSt);
441 /* set st[0] to value higher than st[1] */
442 fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
443 fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
445 /* since min>max, min and max values should be swapped by DTM_SETRANGE
446 automatically */
447 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
448 expect(1, r);
449 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
450 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);
451 todo_wine {
452 ok(compare_systime(&st[0], &getSt[0]) == 1 ||
453 broken(compare_systime(&st[0], &getSt[1]) == 1), /* comctl32 version <= 5.80 */
454 "ST1 != ST2\n");
456 ok(compare_systime(&st[1], &getSt[1]) == 1 ||
457 broken(compare_systime(&st[1], &getSt[0]) == 1), /* comctl32 version <= 5.80 */
458 "ST1 != ST2\n");
461 fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
463 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
464 expect(1, r);
465 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
466 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
467 /* the time part seems to not change after swapping the min and max values
468 and doing DTM_SETSYSTEMTIME */
469 expect_systime_date(&st[0], &getSt[0]);
470 todo_wine {
471 ok(compare_systime_time(&origSt, &getSt[0]) == 1 ||
472 broken(compare_systime_time(&st[0], &getSt[0]) == 1), /* comctl32 version <= 5.80 */
473 "ST1.time != ST2.time\n");
476 /* set st[0] to value higher than minimum */
477 fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
478 /* set st[1] to value lower than maximum */
479 fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
481 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
482 expect(1, r);
483 /* for some reason after we swapped the min and max values before,
484 whenever we do a DTM_SETRANGE, the DTM_GETRANGE will return the values
485 swapped*/
486 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
487 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);
488 todo_wine {
489 ok(compare_systime(&st[0], &getSt[1]) == 1 ||
490 broken(compare_systime(&st[0], &getSt[0]) == 1), /* comctl32 version <= 5.80 */
491 "ST1 != ST2\n");
493 ok(compare_systime(&st[1], &getSt[0]) == 1 ||
494 broken(compare_systime(&st[1], &getSt[1]) == 1), /* comctl32 version <= 5.80 */
495 "ST1 != ST2\n");
498 /* set st[0] to value higher than st[1] */
499 fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
500 fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
502 /* set min>max again, so that the return values of DTM_GETRANGE are no
503 longer swapped the next time we do a DTM SETRANGE and DTM_GETRANGE*/
504 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
505 expect(1, r);
506 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
507 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);
508 expect_systime(&st[0], &getSt[1]);
509 expect_systime(&st[1], &getSt[0]);
511 /* initialize st[0] to lowest possible value */
512 fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
513 /* set st[1] to highest possible value */
514 fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
516 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
517 expect(1, r);
518 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
519 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);
520 expect_systime(&st[0], &getSt[0]);
521 expect_systime(&st[1], &getSt[1]);
523 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_range_swap_min_max_seq, "test_dtm_set_range_swap_min_max", FALSE);
525 DestroyWindow(hWnd);
528 static void test_dtm_set_and_get_system_time(void)
530 LRESULT r;
531 SYSTEMTIME st, getSt, ref;
532 HWND hWnd;
534 hWnd = create_datetime_control(0);
535 ok(hWnd !=NULL, "Expected non NULL, got %p\n", hWnd);
536 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
537 expect(0, r);
539 DestroyWindow(hWnd);
541 hWnd = create_datetime_control(DTS_SHOWNONE);
542 flush_sequences(sequences, NUM_MSG_SEQUENCES);
544 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
545 expect(1, r);
546 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
547 ok(r == GDT_NONE, "Expected %d, not %d(GDT_VALID) or %d(GDT_ERROR), got %ld\n", GDT_NONE, GDT_VALID, GDT_ERROR, r);
549 /* set st to lowest possible value */
550 fill_systime_struct(&st, 1601, 1, 0, 1, 0, 0, 0, 0);
552 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
553 expect(1, r);
555 /* set st to highest possible value */
556 fill_systime_struct(&st, 30827, 12, 6, 31, 23, 59, 59, 999);
558 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
559 expect(1, r);
561 /* set st to value between min and max */
562 fill_systime_struct(&st, 1980, 1, 3, 23, 14, 34, 37, 465);
564 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
565 expect(1, r);
566 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
567 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
568 expect_systime(&st, &getSt);
570 /* set st to invalid value */
571 fill_systime_struct(&st, 0, 0, 7, 0, 24, 60, 60, 1000);
573 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
574 expect_unsuccess(0, r);
576 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_system_time_seq, "test_dtm_set_and_get_system_time", FALSE);
578 /* set to some valid value */
579 GetSystemTime(&ref);
580 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&ref);
581 expect(1, r);
582 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
583 expect(GDT_VALID, r);
584 expect_systime(&ref, &getSt);
586 /* year invalid */
587 st = ref;
588 st.wYear = 0;
589 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
590 todo_wine expect(1, r);
591 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
592 expect(GDT_VALID, r);
593 expect_systime(&ref, &getSt);
594 /* month invalid */
595 st = ref;
596 st.wMonth = 13;
597 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
598 expect(0, r);
599 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
600 expect(GDT_VALID, r);
601 expect_systime(&ref, &getSt);
602 /* day invalid */
603 st = ref;
604 st.wDay = 32;
605 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
606 expect(0, r);
607 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
608 expect(GDT_VALID, r);
609 expect_systime(&ref, &getSt);
610 /* day invalid for current month */
611 st = ref;
612 st.wDay = 30;
613 st.wMonth = 2;
614 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
615 expect(0, r);
616 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
617 expect(GDT_VALID, r);
618 expect_systime(&ref, &getSt);
619 /* day of week isn't validated */
620 st = ref;
621 st.wDayOfWeek = 10;
622 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
623 expect(1, r);
624 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
625 expect(GDT_VALID, r);
626 expect_systime(&ref, &getSt);
627 /* hour invalid */
628 st = ref;
629 st.wHour = 25;
630 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
631 expect(0, r);
632 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
633 expect(GDT_VALID, r);
634 expect_systime(&ref, &getSt);
635 /* minute invalid */
636 st = ref;
637 st.wMinute = 60;
638 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
639 expect(0, r);
640 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
641 expect(GDT_VALID, r);
642 expect_systime(&ref, &getSt);
643 /* sec invalid */
644 st = ref;
645 st.wSecond = 60;
646 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
647 expect(0, r);
648 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
649 expect(GDT_VALID, r);
650 expect_systime(&ref, &getSt);
651 /* msec invalid */
652 st = ref;
653 st.wMilliseconds = 1000;
654 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
655 expect(0, r);
656 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
657 expect(GDT_VALID, r);
658 expect_systime(&ref, &getSt);
660 /* day of week should be calculated automatically,
661 actual day of week for this date is 4 */
662 fill_systime_struct(&st, 2009, 10, 1, 1, 0, 0, 10, 200);
663 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
664 expect(1, r);
665 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
666 expect(GDT_VALID, r);
667 /* 01.10.2009 is Thursday */
668 expect(4, (LRESULT)getSt.wDayOfWeek);
669 st.wDayOfWeek = 4;
670 expect_systime(&st, &getSt);
673 static void test_dtm_set_and_get_systemtime_with_limits(void)
675 LRESULT r;
676 SYSTEMTIME st[2], getSt[2], refSt;
677 HWND hWnd;
679 hWnd = create_datetime_control(DTS_SHOWNONE);
681 flush_sequences(sequences, NUM_MSG_SEQUENCES);
683 /* set range */
684 fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
685 fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
687 r = SendMessageA(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
688 expect(1, r);
689 r = SendMessageA(hWnd, DTM_GETRANGE, 0, (LPARAM)getSt);
690 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);
691 expect_systime(&st[0], &getSt[0]);
692 expect_systime(&st[1], &getSt[1]);
694 /* Initially set a valid time */
695 fill_systime_struct(&refSt, 1999, 9, 4, 9, 19, 9, 9, 999);
696 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&refSt);
697 expect(1, r);
698 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
699 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
700 expect_systime(&refSt, &getSt[0]);
702 /* Now set an out-of-bounds time */
703 fill_systime_struct(&st[0], 2010, 1, 0, 1, 0, 0, 0, 0);
705 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
706 expect(1, r);
707 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
708 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
709 expect_systime(&refSt, &getSt[0]);
711 fill_systime_struct(&st[0], 1977, 1, 0, 1, 0, 0, 0, 0);
713 r = SendMessageA(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
714 expect(1, r);
715 r = SendMessageA(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
716 ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
717 expect_systime(&refSt, &getSt[0]);
719 ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_systime_with_limits, "test_dtm_set_and_get_systime_with_limits", FALSE);
721 DestroyWindow(hWnd);
724 static void test_dtm_get_ideal_size(void)
726 HWND hwnd;
727 HDC hdc;
728 HFONT hfont;
729 LOGFONTA lf;
730 TEXTMETRICA tm;
731 SIZE size;
732 BOOL r;
734 hwnd = create_datetime_control(0);
735 r = SendMessageA(hwnd, DTM_GETIDEALSIZE, 0, (LPARAM)&size);
736 if (!r)
738 win_skip("DTM_GETIDEALSIZE is not available\n");
739 DestroyWindow(hwnd);
740 return;
743 /* Set font so that the test is consistent on Wine and Windows */
744 ZeroMemory(&lf, sizeof(lf));
745 lf.lfWeight = FW_NORMAL;
746 lf.lfHeight = 20;
747 lstrcpyA(lf.lfFaceName, "Tahoma");
748 hfont = CreateFontIndirectA(&lf);
749 SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
751 hdc = GetDC(hwnd);
752 GetTextMetricsA(hdc, &tm);
753 ReleaseDC(hwnd, hdc);
755 r = SendMessageA(hwnd, DTM_GETIDEALSIZE, 0, (LPARAM)&size);
756 ok(r, "Expect DTM_GETIDEALSIZE message to return true\n");
757 ok(size.cx > 0 && size.cy >= tm.tmHeight,
758 "Expect size.cx > 0 and size.cy >= %d, got cx:%d cy:%d\n", tm.tmHeight, size.cx, size.cy);
760 DestroyWindow(hwnd);
761 DeleteObject(hfont);
764 static void test_wm_set_get_text(void)
766 static const CHAR a_str[] = "a";
767 CHAR buff[16], time[16], caltype[3];
768 WCHAR buffW[16];
769 HWND hWnd;
770 LRESULT ret;
772 hWnd = create_datetime_control(0);
774 ret = SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)a_str);
775 ok(CB_ERR == ret ||
776 broken(0 == ret) || /* comctl32 <= 4.72 */
777 broken(1 == ret), /* comctl32 <= 4.70 */
778 "Expected CB_ERR, got %ld\n", ret);
780 buff[0] = 0;
781 ret = SendMessageA(hWnd, WM_GETTEXT, sizeof(buff), (LPARAM)buff);
782 ok(strcmp(buff, a_str) != 0, "Expected text to change, got %s\n", buff);
783 ok(ret != 0, "Expected non-zero return value\n");
785 SetLastError(0xdeadbeef);
786 ret = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICALENDARTYPE, caltype, 3);
787 if (ret == 0)
788 skip("Must know local calendar type (%x)\n", GetLastError());
789 else if (atoi(caltype) != CAL_GREGORIAN)
790 skip("DateTimePicker Control only supports Gregorian calendar (type: %s)\n", caltype);
791 else {
792 SetLastError(0xdeadbeef);
793 ret = GetDateFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, time, sizeof(time));
794 if (ret == 0)
795 skip("GetDateFormat failed, returned %ld, error %d\n", ret, GetLastError());
796 else
798 ok(!strcmp(buff, time), "Expected %s, got %s\n", time, buff);
800 ret = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
801 ok(ret == strlen(time), "Got wrong length: %ld, expected %d.\n", ret, strlen(time));
805 DestroyWindow(hWnd);
807 /* Window text is not preserved. */
808 hWnd = CreateWindowExA(0, DATETIMEPICK_CLASSA, "testname", 0, 0, 50, 300, 120,
809 NULL, NULL, NULL, NULL);
811 buffW[0] = 1;
812 InternalGetWindowText(hWnd, buffW, ARRAY_SIZE(buffW));
813 ok(!buffW[0], "Unexpected window text %s.\n", wine_dbgstr_w(buffW));
815 DestroyWindow(hWnd);
818 static void test_dts_shownone(void)
820 HWND hwnd;
821 DWORD style;
823 /* it isn't allowed to change DTS_SHOWNONE after creation */
824 hwnd = create_datetime_control(0);
825 style = GetWindowLongA(hwnd, GWL_STYLE);
826 SetWindowLongA(hwnd, GWL_STYLE, style | DTS_SHOWNONE);
827 style = GetWindowLongA(hwnd, GWL_STYLE);
828 ok(!(style & DTS_SHOWNONE), "Expected DTS_SHOWNONE not to be set\n");
829 DestroyWindow(hwnd);
831 hwnd = create_datetime_control(DTS_SHOWNONE);
832 style = GetWindowLongA(hwnd, GWL_STYLE);
833 SetWindowLongA(hwnd, GWL_STYLE, style & ~DTS_SHOWNONE);
834 style = GetWindowLongA(hwnd, GWL_STYLE);
835 ok(style & DTS_SHOWNONE, "Expected DTS_SHOWNONE to be set\n");
836 DestroyWindow(hwnd);
839 static void init_functions(void)
841 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
843 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
844 X(InitCommonControlsEx);
845 #undef X
848 START_TEST(datetime)
850 INITCOMMONCONTROLSEX iccex;
851 ULONG_PTR cookie;
852 HANDLE ctxt;
854 init_functions();
856 iccex.dwSize = sizeof(iccex);
857 iccex.dwICC = ICC_DATE_CLASSES;
858 pInitCommonControlsEx(&iccex);
860 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
862 test_dtm_set_format();
863 test_dtm_set_and_get_mccolor();
864 test_dtm_set_and_get_mcfont();
865 test_dtm_get_monthcal();
866 test_dtm_set_and_get_range();
867 test_dtm_set_range_swap_min_max();
868 test_dtm_set_and_get_system_time();
869 test_dtm_set_and_get_systemtime_with_limits();
870 test_wm_set_get_text();
871 test_dts_shownone();
873 if (!load_v6_module(&cookie, &ctxt))
874 return;
876 test_dtm_set_format();
877 test_dtm_set_and_get_mccolor();
878 test_dtm_set_and_get_mcfont();
879 test_dtm_get_monthcal();
880 test_dtm_get_ideal_size();
881 test_wm_set_get_text();
882 test_dts_shownone();
884 unload_v6_module(cookie, ctxt);