1 /*
2  * PROJECT:     ReactOS API tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Tests for NtUserSetTimer
5  * COPYRIGHT:   Copyright 2008 Timo Kreuzer <timo.kreuzer@reactos.org>
6  *              Copyright 2024 Tomáš Veselý <turican0@gmail.com>
7  */
8 
9 #include "../win32nt.h"
10 
11 #define SLEEP_TIME 500
12 #define MIN_MESSAGES_TIME 1
13 #define MAX_MESSAGES_TIME 1000
14 
15 #define TEST1_COUNT 20
16 #define TEST1_INTERVAL 10
17 
18 #define TEST2_COUNT 40000
19 #define TEST2_INTERVAL 10
20 
21 #define TESTW1_COUNT 20
22 #define TESTW1_INTERVAL 10
23 
24 #define TESTW2_COUNT 40000
25 #define TESTW2_INTERVAL 10
26 
27 typedef struct TIMER_MESSAGE_STATE1
28 {
29     UINT_PTR index;
30     UINT counter;
31 } TIMER_MESSAGE_STATE1;
32 
33 TIMER_MESSAGE_STATE1 timerId1[TEST1_COUNT];
34 
35 typedef struct TIMER_MESSAGE_STATEW1
36 {
37     UINT counter;
38 } TIMER_MESSAGE_STATEW1;
39 
40 TIMER_MESSAGE_STATEW1 timerIdW1[TESTW1_COUNT];
41 
42 /* TIMERPROC for the test1,2,3() with messages without window */
43 static void CALLBACK
44 TimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
45 {
46     UINT i;
47     for (i = 0; i < TEST1_COUNT; i++)
48     {
49         if (timerId1[i].index == idEvent)
50             timerId1[i].counter++;
51     }
52 }
53 
54 /* TIMERPROC for the testW1,2() with messages with window */
55 static LRESULT CALLBACK
56 WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
57 {
58     switch (uMsg)
59     {
60     case WM_TIMER:
61         timerIdW1[wParam].counter++;
62         return 0;
63     }
64 
65     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
66 }
67 
68 // TEST WITH MESSAGES WITHOUT WINDOW - test count of sent messages
69 static BOOL test1(void)
70 {
71     UINT i, countErrors = 0;
72     ULONGLONG startTime;
73     MSG msg = { NULL };
74 
75     ZeroMemory(timerId1, sizeof(timerId1));
76 
77     for (i = 0; i < TEST1_COUNT; i++)
78     {
79         timerId1[i].index = SetTimer(NULL, 0, TEST1_INTERVAL, TimerProc);
80         if (timerId1[i].index == 0)
81             countErrors++;
82     }
83 
84     startTime = GetTickCount();
85 
86     while (GetMessageW(&msg, NULL, 0, 0))
87     {
88         TranslateMessage(&msg);
89         DispatchMessageW(&msg);
90 
91         if (GetTickCount() - startTime >= SLEEP_TIME)
92             PostQuitMessage(0);
93     }
94 
95     for (i = 0; i < TEST1_COUNT; i++)
96     {
97         if ((timerId1[i].counter < MIN_MESSAGES_TIME) || (timerId1[i].counter > MAX_MESSAGES_TIME))
98             countErrors++;
99     }
100 
101     for (i = 0; i < TEST1_COUNT; i++)
102     {
103         if (KillTimer(NULL, timerId1[i].index) == 0)
104             countErrors++;
105     }
106 
107     return (countErrors == 0);
108 }
109 
110 // TEST WITH MESSAGES WITHOUT WINDOW - create many timers
111 static BOOL test2(void)
112 {
113     UINT i, countErrors = 0;
114     UINT_PTR locIndex;
115 
116     for (i = 0; i < TEST2_COUNT; i++)
117     {
118         locIndex = SetTimer(NULL, 0, TEST2_INTERVAL, TimerProc);
119 
120         if (locIndex == 0)
121             countErrors++;
122         if (KillTimer(NULL, locIndex) == 0)
123             countErrors++;
124     }
125 
126     return (countErrors == 0);
127 }
128 
129 // TEST WITH MESSAGES WITHOUT WINDOW - test different ids
130 static BOOL test3(void)
131 {
132     UINT countErrors = 0;
133     UINT_PTR locIndex1;
134     UINT_PTR locIndex2;
135 
136     locIndex1 = SetTimer(NULL, 0, TEST1_INTERVAL, TimerProc);
137     if (locIndex1 == 0)
138         countErrors++;
139     if (KillTimer(NULL, locIndex1) == 0)
140         countErrors++;
141     locIndex2 = SetTimer(NULL, 0, TEST1_INTERVAL, TimerProc);
142     if (locIndex2 == 0)
143         countErrors++;
144     if (KillTimer(NULL, locIndex2) == 0)
145         countErrors++;
146     if (locIndex1 == locIndex2)
147         countErrors++;
148 
149     return (countErrors == 0);
150 }
151 
152 // TEST WITH MESSAGES WITH WINDOW - test count of sent messages
153 static BOOL testW1(HWND hwnd)
154 {
155     UINT i, countErrors = 0;
156     UINT_PTR locIndex;
157     ULONGLONG startTime;
158     MSG msg = { NULL };
159 
160     if (hwnd == NULL)
161         return FALSE;
162 
163     ZeroMemory(timerIdW1, sizeof(timerIdW1));
164 
165     for (i = 0; i < TESTW1_COUNT; i++)
166     {
167         locIndex = SetTimer(hwnd, i, TESTW1_INTERVAL, NULL);
168         if (locIndex == 0)
169             countErrors++;
170     }
171 
172     startTime = GetTickCount();
173 
174     while (GetMessageW(&msg, NULL, 0, 0))
175     {
176         TranslateMessage(&msg);
177         DispatchMessageW(&msg);
178 
179         if (GetTickCount() - startTime >= SLEEP_TIME)
180             PostQuitMessage(0);
181     }
182 
183     for (i = 0; i < TESTW1_COUNT; i++)
184     {
185         if ((timerIdW1[i].counter < MIN_MESSAGES_TIME) || (timerIdW1[i].counter > MAX_MESSAGES_TIME))
186             countErrors++;
187     }
188 
189     for (i = 0; i < TESTW1_COUNT; i++)
190     {
191         if (KillTimer(hwnd, i) == 0)
192             countErrors++;
193     }
194 
195     return (countErrors == 0);
196 }
197 
198 // TEST WITH MESSAGES WITH WINDOW - create many timers
199 static BOOL testW2(HWND hwnd)
200 {
201     UINT i, countErrors = 0;
202     UINT_PTR result;
203 
204     if (hwnd == NULL)
205         return FALSE;
206 
207     for (i = 0; i < TESTW2_COUNT; i++)
208     {
209         result = SetTimer(hwnd, 1, TESTW2_INTERVAL, NULL);
210         if (result == 0)
211             countErrors++;
212         if (KillTimer(hwnd, 1) == 0)
213             countErrors++;
214     }
215 
216     return (countErrors == 0);
217 }
218 
219 START_TEST(NtUserSetTimer)
220 {
221     WNDCLASSW wc = { 0 };
222     HWND hwnd;
223 
224     // TEST WITH MESSAGES WITHOUT WINDOW - test count of sent messages
225     TEST(test1());
226 
227     // TEST WITH MESSAGES WITHOUT WINDOW - create many timers
228     TEST(test2());
229 
230     // TEST WITH MESSAGES WITHOUT WINDOW - test different ids
231     TEST(test3());
232 
233     wc.lpfnWndProc = WindowProc;
234     wc.hInstance = GetModuleHandleW(NULL);
235     wc.lpszClassName = L"TimerWindowClass";
236     RegisterClassW(&wc);
237 
238     hwnd = CreateWindowExW(0, L"TimerWindowClass", L"Timer Window", 0,
239         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
240         HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL);
241 
242     // TEST WITH MESSAGES WITH WINDOW - test count of sent messages
243     TEST(testW1(hwnd));
244 
245     // TEST WITH MESSAGES WITH WINDOW - create many timers
246     TEST(testW2(hwnd));
247 
248     if (hwnd != NULL)
249         DestroyWindow(hwnd);
250     UnregisterClassW(L"TimerWindowClass", NULL);
251 }
252