64daaccb24372521b06d1291e1bc5beb0301d7a4
[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 #define WIN32_NO_STATUS
10 #include <windows.h>
11 #define NTOS_MODE_USER
12 #include <ndk/ntndk.h>
13 #include <pseh/pseh.h>
14 #include "regtests.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 typedef struct _PERFORM_TEST_ARGS
20 {
21 TestOutputRoutine OutputRoutine;
22 _PTEST Test;
23 LPSTR TestName;
24 DWORD Result;
25 char Buffer[5000];
26 DWORD Time;
27 } PERFORM_TEST_ARGS;
28
29 int _Result;
30 char *_Buffer;
31
32 static LIST_ENTRY AllTests;
33
34 VOID
35 InitializeTests()
36 {
37 InitializeListHead(&AllTests);
38 }
39
40 char*
41 FormatExecutionTime(char *buffer, ULONG milliseconds)
42 {
43 sprintf(buffer,
44 "%ldms",
45 milliseconds);
46 return buffer;
47 }
48
49 DWORD WINAPI
50 PerformTest(PVOID _arg)
51 {
52 PERFORM_TEST_ARGS *Args = (PERFORM_TEST_ARGS *)_arg;
53 _PTEST Test = Args->Test;
54
55 _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_IDLE);
56
57 memset(Args->Buffer, 0, sizeof(Args->Buffer));
58
59 _SEH_TRY {
60 _Result = TS_OK;
61 _Buffer = Args->Buffer;
62 (Test->Routine)(TESTCMD_RUN);
63 Args->Result = _Result;
64 } _SEH_HANDLE {
65 Args->Result = TS_FAILED;
66 sprintf(Args->Buffer, "due to exception 0x%lx", _SEH_GetExceptionCode());
67 } _SEH_END;
68 return 1;
69 }
70
71 BOOL
72 IsContextChanged(LPCONTEXT context1, LPCONTEXT context2)
73 {
74 return memcmp(context1, context2, sizeof(CONTEXT)) != 0;
75 }
76
77 VOID
78 ControlNormalTest(HANDLE hThread,
79 PERFORM_TEST_ARGS *Args,
80 DWORD TimeOut)
81 {
82 _FILETIME time;
83 _FILETIME executionTime;
84 DWORD status;
85
86 status = _WaitForSingleObject(hThread, TimeOut);
87 if (status == WAIT_TIMEOUT)
88 {
89 _TerminateThread(hThread, 0);
90 Args->Result = TS_TIMEDOUT;
91 }
92 status = _GetThreadTimes(hThread,
93 &time,
94 &time,
95 &time,
96 &executionTime);
97 Args->Time = executionTime.dwLowDateTime / 10000;
98 }
99
100 VOID
101 ControlPerformanceTest(HANDLE hThread,
102 PERFORM_TEST_ARGS *Args,
103 DWORD TimeOut)
104 {
105 DWORD status;
106 CONTEXT lastContext;
107 CONTEXT currentContext;
108
109 ZeroMemory(&lastContext, sizeof(CONTEXT));
110 lastContext.ContextFlags = CONTEXT_FULL;
111 ZeroMemory(&currentContext, sizeof(CONTEXT));
112 currentContext.ContextFlags = CONTEXT_FULL;
113
114 do {
115 _Sleep(1);
116
117 if (_SuspendThread(hThread) == (DWORD)-1)
118 break;
119
120 if (_GetThreadContext(hThread, &currentContext) == 0)
121 break;
122
123 if (IsContextChanged(&currentContext, &lastContext))
124 Args->Time++;
125
126 if (_ResumeThread(hThread) == (DWORD)-1)
127 break;
128
129 if (Args->Time >= TimeOut)
130 {
131 _TerminateThread(hThread, 0);
132 Args->Result = TS_TIMEDOUT;
133 break;
134 }
135
136 status = _WaitForSingleObject(hThread, 0);
137 if (status == WAIT_OBJECT_0 || status == WAIT_FAILED)
138 break;
139
140 lastContext = currentContext;
141 } while (TRUE);
142 }
143
144 VOID
145 DisplayResult(PERFORM_TEST_ARGS* Args,
146 LPSTR OutputBuffer)
147 {
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, Args->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 }