rename tests to dllname_winetest to make it less trouble on exception to change build...
[reactos.git] / reactos / regtests / shared / regtests.c
1 /*
2 * PROJECT: ReactOS kernel
3 * FILE: regtests/shared/regtests.c
4 * PURPOSE: Regression testing framework
5 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * UPDATE HISTORY:
7 * 06-07-2003 CSH Created
8 */
9 #include <windows.h>
10 #define NTOS_MODE_USER
11 #include <ndk/ntndk.h>
12 #include <pseh/pseh.h>
13 #include "regtests.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 typedef struct _PERFORM_TEST_ARGS
19 {
20 TestOutputRoutine OutputRoutine;
21 _PTEST Test;
22 LPSTR TestName;
23 DWORD Result;
24 char Buffer[5000];
25 DWORD Time;
26 } PERFORM_TEST_ARGS;
27
28 int _Result;
29 char *_Buffer;
30
31 static LIST_ENTRY AllTests;
32
33 VOID
34 InitializeTests()
35 {
36 InitializeListHead(&AllTests);
37 }
38
39 char*
40 FormatExecutionTime(char *buffer, ULONG milliseconds)
41 {
42 sprintf(buffer,
43 "%ldms",
44 milliseconds);
45 return buffer;
46 }
47
48 DWORD WINAPI
49 PerformTest(PVOID _arg)
50 {
51 PERFORM_TEST_ARGS *Args = (PERFORM_TEST_ARGS *)_arg;
52 _PTEST Test = Args->Test;
53
54 _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_IDLE);
55
56 memset(Args->Buffer, 0, sizeof(Args->Buffer));
57
58 _SEH_TRY {
59 _Result = TS_OK;
60 _Buffer = Args->Buffer;
61 (Test->Routine)(TESTCMD_RUN);
62 Args->Result = _Result;
63 } _SEH_HANDLE {
64 Args->Result = TS_FAILED;
65 sprintf(Args->Buffer, "due to exception 0x%lx", _SEH_GetExceptionCode());
66 } _SEH_END;
67 return 1;
68 }
69
70 BOOL
71 IsContextChanged(LPCONTEXT context1, LPCONTEXT context2)
72 {
73 return memcmp(context1, context2, sizeof(CONTEXT)) != 0;
74 }
75
76 VOID
77 ControlNormalTest(HANDLE hThread,
78 PERFORM_TEST_ARGS *Args,
79 DWORD TimeOut)
80 {
81 _FILETIME time;
82 _FILETIME executionTime;
83 DWORD status;
84
85 status = _WaitForSingleObject(hThread, TimeOut);
86 if (status == WAIT_TIMEOUT)
87 {
88 _TerminateThread(hThread, 0);
89 Args->Result = TS_TIMEDOUT;
90 }
91 status = _GetThreadTimes(hThread,
92 &time,
93 &time,
94 &time,
95 &executionTime);
96 Args->Time = executionTime.dwLowDateTime / 10000;
97 }
98
99 VOID
100 ControlPerformanceTest(HANDLE hThread,
101 PERFORM_TEST_ARGS *Args,
102 DWORD TimeOut)
103 {
104 DWORD status;
105 CONTEXT lastContext;
106 CONTEXT currentContext;
107
108 ZeroMemory(&lastContext, sizeof(CONTEXT));
109 lastContext.ContextFlags = CONTEXT_FULL;
110 ZeroMemory(&currentContext, sizeof(CONTEXT));
111 currentContext.ContextFlags = CONTEXT_FULL;
112
113 do {
114 _Sleep(1);
115
116 if (_SuspendThread(hThread) == (DWORD)-1)
117 break;
118
119 if (_GetThreadContext(hThread, &currentContext) == 0)
120 break;
121
122 if (IsContextChanged(&currentContext, &lastContext))
123 Args->Time++;
124
125 if (_ResumeThread(hThread) == (DWORD)-1)
126 break;
127
128 if (Args->Time >= TimeOut)
129 {
130 _TerminateThread(hThread, 0);
131 Args->Result = TS_TIMEDOUT;
132 break;
133 }
134
135 status = _WaitForSingleObject(hThread, 0);
136 if (status == WAIT_OBJECT_0 || status == WAIT_FAILED)
137 break;
138
139 lastContext = currentContext;
140 } while (TRUE);
141 }
142
143 VOID
144 DisplayResult(PERFORM_TEST_ARGS* Args,
145 LPSTR OutputBuffer)
146 {
147 char Buffer[5000];
148 char Format[100];
149
150 if (Args->Result == TS_OK)
151 {
152 sprintf(OutputBuffer,
153 "[%s] Success [%s]\n",
154 Args->TestName,
155 FormatExecutionTime(Format,
156 Args->Time));
157 }
158 else if (Args->Result == TS_TIMEDOUT)
159 {
160 sprintf(OutputBuffer,
161 "[%s] Timed out [%s]\n",
162 Args->TestName,
163 FormatExecutionTime(Format,
164 Args->Time));
165 }
166 else
167 sprintf(OutputBuffer, "[%s] Failed (%s)\n", Args->TestName, Buffer);
168
169 if (Args->OutputRoutine != NULL)
170 (*Args->OutputRoutine)(OutputBuffer);
171 else
172 DbgPrint(OutputBuffer);
173 }
174
175 VOID
176 ControlTest(HANDLE hThread,
177 PERFORM_TEST_ARGS *Args,
178 DWORD TestType,
179 DWORD TimeOut)
180 {
181 switch (TestType)
182 {
183 case TT_NORMAL:
184 ControlNormalTest(hThread, Args, TimeOut);
185 break;
186 case TT_PERFORMANCE:
187 ControlPerformanceTest(hThread, Args, TimeOut);
188 break;
189 default:
190 printf("Unknown test type %ld\n", TestType);
191 break;
192 }
193 }
194
195 VOID
196 PerformTests(TestOutputRoutine OutputRoutine, LPSTR TestName)
197 {
198 PLIST_ENTRY CurrentEntry;
199 PLIST_ENTRY NextEntry;
200 _PTEST Current;
201 PERFORM_TEST_ARGS Args;
202 HANDLE hThread;
203 char OutputBuffer[1024];
204 char Name[200];
205 DWORD TestType;
206 DWORD TimeOut;
207
208 Args.OutputRoutine = OutputRoutine;
209 Args.TestName = Name;
210 Args.Time = 0;
211
212 CurrentEntry = AllTests.Flink;
213 for (; CurrentEntry != &AllTests; CurrentEntry = NextEntry)
214 {
215 NextEntry = CurrentEntry->Flink;
216 Current = CONTAINING_RECORD(CurrentEntry, _TEST, ListEntry);
217 Args.Test = Current;
218
219 /* Get name of test */
220 memset(Name, 0, sizeof(Name));
221
222 _Result = TS_OK;
223 _Buffer = Name;
224 (Current->Routine)(TESTCMD_TESTNAME);
225 if (_Result != TS_OK)
226 {
227 if (TestName != NULL)
228 continue;
229 strcpy(Name, "Unnamed");
230 }
231
232 if ((TestName != NULL) && (_stricmp(Name, TestName) != 0))
233 continue;
234
235 TestType = TT_NORMAL;
236 _Result = TS_OK;
237 _Buffer = (char *)&TestType;
238 (Current->Routine)(TESTCMD_TESTTYPE);
239 if (_Result != TS_OK)
240 TestType = TT_NORMAL;
241
242 /* Get timeout for test */
243 TimeOut = 0;
244 _Result = TS_OK;
245 _Buffer = (char *)&TimeOut;
246 (Current->Routine)(TESTCMD_TIMEOUT);
247 if (_Result != TS_OK || TimeOut == INFINITE)
248 TimeOut = 5000;
249
250 /* Run test in a separate thread */
251 hThread = _CreateThread(NULL, 0, PerformTest, (PVOID)&Args, 0, NULL);
252 if (hThread == NULL)
253 {
254 printf("[%s] Failed (CreateThread() failed: %ld)\n",
255 Name,
256 _GetLastError());
257 Args.Result = TS_FAILED;
258 }
259 else
260 ControlTest(hThread, &Args, TestType, TimeOut);
261
262 DisplayResult(&Args, OutputBuffer);
263 }
264 }
265
266 VOID
267 AddTest(TestRoutine Routine)
268 {
269 _PTEST Test;
270
271 Test = (_PTEST) malloc(sizeof(_TEST));
272 if (Test == NULL)
273 {
274 DbgPrint("Out of memory");
275 return;
276 }
277
278 Test->Routine = Routine;
279
280 InsertTailList(&AllTests, &Test->ListEntry);
281 }
282
283 PVOID STDCALL
284 FrameworkGetHook(ULONG index)
285 {
286 return FrameworkGetHookInternal(index);
287 }