crypt32: Fix several failing tests in win9x.
[wine] / dlls / winmm / tests / timer.c
1 /*
2  * Test winmm timer
3  *
4  * Copyright (c) 2005 Robert Reif
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <math.h>
25
26 #include "wine/test.h"
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winnls.h"
30 #include "mmsystem.h"
31 #define NOBITMAP
32 #include "mmreg.h"
33
34 #include "winmm_test.h"
35
36 static TIMECAPS tc;
37
38 static void test_timeGetDevCaps(void)
39 {
40    MMRESULT rc;
41
42     rc = timeGetDevCaps(&tc, 0);
43     ok(rc == TIMERR_NOCANDO || rc == MMSYSERR_INVALPARAM,
44        "timeGetDevCaps() returned %s, should have returned TIMERR_NOCANDO "
45        "or MMSYSERR_INVALPARAM\n", mmsys_error(rc));
46
47     rc = timeGetDevCaps(0, sizeof(tc));
48     ok(rc == TIMERR_NOCANDO || rc == TIMERR_STRUCT,
49        "timeGetDevCaps() returned %s, should have returned TIMERR_NOCANDO "
50        "or TIMERR_STRUCT\n", mmsys_error(rc));
51
52     rc = timeGetDevCaps(0, 0);
53     ok(rc == TIMERR_NOCANDO || rc == MMSYSERR_INVALPARAM,
54        "timeGetDevCaps() returned %s, should have returned TIMERR_NOCANDO "
55        "or MMSYSERR_INVALPARAM\n", mmsys_error(rc));
56
57     rc = timeGetDevCaps(&tc, sizeof(tc));
58     ok(rc == TIMERR_NOERROR, "timeGetDevCaps() returned %s, "
59        "should have returned TIMERR_NOERROR\n", mmsys_error(rc));
60
61     if (rc == TIMERR_NOERROR)
62         trace("wPeriodMin = %u, wPeriodMax = %u\n",
63               tc.wPeriodMin, tc.wPeriodMax);
64 }
65
66 #define NUM_SAMPLES    100
67
68 static DWORD count = 0;
69 static DWORD times[NUM_SAMPLES];
70
71 static void CALLBACK testTimeProc(UINT uID, UINT uMsg, DWORD_PTR dwUser,
72                                   DWORD_PTR dw1, DWORD_PTR dw2)
73 {
74     if (count < NUM_SAMPLES)
75         times[count++] = timeGetTime();
76 }
77
78 static void test_timer(UINT period, UINT resolution)
79 {
80     MMRESULT rc;
81     UINT i, id, delta;
82     DWORD dwMin = 0xffffffff, dwMax = 0;
83     double sum = 0.0;
84     double deviation = 0.0;
85
86     count = 0;
87
88     for (i = 0; i < NUM_SAMPLES; i++)
89         times[i] = 0;
90
91     rc = timeBeginPeriod(period);
92     ok(rc == TIMERR_NOERROR, "timeBeginPeriod(%u) returned %s, "
93        "should have returned TIMERR_NOERROR\n", period, mmsys_error(rc));
94     if (rc != TIMERR_NOERROR)
95         return;
96
97     id = timeSetEvent(period, resolution, testTimeProc, 0, TIME_PERIODIC);
98     ok(id != 0, "timeSetEvent(%u, %u, %p, 0, TIME_PERIODIC) returned %d, "
99        "should have returned id > 0\n", period, resolution, testTimeProc, id);
100     if (id == 0)
101         return;
102
103     Sleep((NUM_SAMPLES * period) + (2 * period));
104
105     rc = timeEndPeriod(period);
106     ok(rc == TIMERR_NOERROR, "timeEndPeriod(%u) returned %s, "
107        "should have returned TIMERR_NOERROR\n", period, mmsys_error(rc));
108     if (rc != TIMERR_NOERROR)
109         return;
110
111     rc = timeKillEvent(id);
112     ok(rc == TIMERR_NOERROR, "timeKillEvent(%u) returned %s, "
113        "should have returned TIMERR_NOERROR\n", id, mmsys_error(rc));
114
115     trace("period = %u, resolution = %u\n", period, resolution);
116
117     for (i = 0; i < count; i++)
118     {
119         if (i == 0)
120         {
121             if (winetest_debug > 1)
122                 trace("time[%d] = %u\n", i, times[i]);
123         }
124         else
125         {
126             delta = times[i] - times[i - 1];
127
128             if (winetest_debug > 1)
129                 trace("time[%d] = %u delta = %d\n", i, times[i], delta);
130
131             sum += delta;
132             deviation += ((delta - period) * (delta - period));
133
134             if (delta < dwMin)
135                 dwMin = delta;
136
137             if (delta > dwMax)
138                 dwMax = delta;
139         }
140     }
141
142     trace("min = %u, max = %u, average = %f, standard deviation = %f\n",
143           dwMin, dwMax, sum / (count - 1), sqrt(deviation / (count - 2)));
144 }
145
146 static const char * get_priority(int priority)
147 {
148     static char     tmp[32];
149 #define STR(x) case x: return #x
150     switch(priority) {
151     STR(THREAD_PRIORITY_LOWEST);
152     STR(THREAD_PRIORITY_BELOW_NORMAL);
153     STR(THREAD_PRIORITY_NORMAL);
154     STR(THREAD_PRIORITY_HIGHEST);
155     STR(THREAD_PRIORITY_ABOVE_NORMAL);
156     STR(THREAD_PRIORITY_TIME_CRITICAL);
157     STR(THREAD_PRIORITY_IDLE);
158     }
159     sprintf(tmp, "UNKNOWN(%d)", priority);
160     return tmp;
161 }
162
163 static int priority = 0;
164 static BOOL fired = FALSE;
165
166 static void CALLBACK priorityTimeProc(UINT uID, UINT uMsg, DWORD_PTR dwUser,
167                                       DWORD_PTR dw1, DWORD_PTR dw2)
168 {
169     priority = GetThreadPriority(GetCurrentThread());
170     ok(priority!=THREAD_PRIORITY_ERROR_RETURN, "GetThreadPriority() failed, GetLastError() = %u\n", GetLastError());
171     fired = TRUE;
172 }
173
174 static void test_priority(void)
175 {
176     UINT id;
177
178     id = timeSetEvent(100, 100, priorityTimeProc, 0, TIME_ONESHOT);
179     ok(id != 0, "timeSetEvent(100, 100, %p, 0, TIME_ONESHOT) returned %d, "
180        "should have returned id > 0\n", priorityTimeProc, id);
181     if (id == 0)
182         return;
183
184     Sleep(200);
185
186     ok(fired == TRUE, "Callback not called\n");
187     if (fired)
188     {
189         ok(priority == THREAD_PRIORITY_TIME_CRITICAL,
190            "thread priority is %s, should be THREAD_PRIORITY_TIME_CRITICAL\n",
191            get_priority(priority));
192     }
193 }
194
195 START_TEST(timer)
196 {
197     test_timeGetDevCaps();
198
199     if (tc.wPeriodMin <= 1) {
200         test_timer(1, 0);
201         test_timer(1, 1);
202     }
203
204     if (tc.wPeriodMin <= 10) {
205         test_timer(10, 0);
206         test_timer(10, 1);
207         test_timer(10, 10);
208     }
209
210     if (tc.wPeriodMin <= 20) {
211         test_timer(20, 0);
212         test_timer(20, 1);
213         test_timer(20, 10);
214         test_timer(20, 20);
215     }
216
217     test_priority();
218 }