[KMTESTS/KE]
[reactos.git] / kmtests / include / kmt_test.h
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite test framework declarations
5 * PROGRAMMER: Thomas Faber <thfabba@gmx.de>
6 */
7
8 /* Inspired by Wine C unit tests, Copyright (C) 2002 Alexandre Julliard
9 * Inspired by ReactOS kernel-mode regression tests,
10 * Copyright (C) Aleksey Bragin, Filip Navara
11 */
12
13 #ifndef _KMTEST_TEST_H_
14 #define _KMTEST_TEST_H_
15
16 #include <kmt_platform.h>
17
18 typedef VOID KMT_TESTFUNC(VOID);
19 typedef KMT_TESTFUNC *PKMT_TESTFUNC;
20
21 typedef struct
22 {
23 const char *TestName;
24 KMT_TESTFUNC *TestFunction;
25 } KMT_TEST, *PKMT_TEST;
26
27 typedef const KMT_TEST CKMT_TEST, *PCKMT_TEST;
28
29 extern const KMT_TEST TestList[];
30
31 typedef struct
32 {
33 volatile LONG Successes;
34 volatile LONG Failures;
35 volatile LONG Skipped;
36 volatile LONG LogBufferLength;
37 LONG LogBufferMaxLength;
38 CHAR LogBuffer[ANYSIZE_ARRAY];
39 } KMT_RESULTBUFFER, *PKMT_RESULTBUFFER;
40
41 #ifdef KMT_STANDALONE_DRIVER
42 #define KMT_KERNEL_MODE
43
44 typedef NTSTATUS (KMT_IRP_HANDLER)(
45 IN PDEVICE_OBJECT DeviceObject,
46 IN PIRP Irp,
47 IN PIO_STACK_LOCATION IoStackLocation);
48 typedef KMT_IRP_HANDLER *PKMT_IRP_HANDLER;
49
50 NTSTATUS KmtRegisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
51 NTSTATUS KmtUnregisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
52
53 typedef NTSTATUS (KMT_MESSAGE_HANDLER)(
54 IN PDEVICE_OBJECT DeviceObject,
55 IN ULONG ControlCode,
56 IN PVOID Buffer OPTIONAL,
57 IN SIZE_T InLength,
58 IN OUT PSIZE_T OutLength);
59 typedef KMT_MESSAGE_HANDLER *PKMT_MESSAGE_HANDLER;
60
61 NTSTATUS KmtRegisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
62 NTSTATUS KmtUnregisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
63
64 typedef enum
65 {
66 TESTENTRY_NO_CREATE_DEVICE = 1,
67 TESTENTRY_NO_REGISTER_DISPATCH = 2,
68 TESTENTRY_NO_REGISTER_UNLOAD = 4,
69 } KMT_TESTENTRY_FLAGS;
70
71 NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryPath, OUT PCWSTR *DeviceName, OUT INT *Flags);
72 VOID TestUnload(IN PDRIVER_OBJECT DriverObject);
73 #endif /* defined KMT_STANDALONE_DRIVER */
74
75 #ifdef KMT_KERNEL_MODE
76 /* Device Extension layout */
77 typedef struct
78 {
79 PKMT_RESULTBUFFER ResultBuffer;
80 PMDL Mdl;
81 } KMT_DEVICE_EXTENSION, *PKMT_DEVICE_EXTENSION;
82
83 extern BOOLEAN KmtIsCheckedBuild;
84 extern BOOLEAN KmtIsMultiProcessorBuild;
85
86 VOID KmtSetIrql(IN KIRQL NewIrql);
87 BOOLEAN KmtAreInterruptsEnabled(VOID);
88 #elif defined KMT_USER_MODE
89 DWORD KmtRunKernelTest(IN PCSTR TestName);
90
91 VOID KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
92 VOID KmtUnloadDriver(VOID);
93 VOID KmtOpenDriver(VOID);
94 VOID KmtCloseDriver(VOID);
95
96 DWORD KmtSendToDriver(IN DWORD ControlCode);
97 DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
98 DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer OPTIONAL, IN DWORD InLength, IN OUT PDWORD OutLength);
99 #endif /* defined KMT_USER_MODE */
100
101 extern PKMT_RESULTBUFFER ResultBuffer;
102
103 #define MICROSECOND 10
104 #define MILLISECOND (1000 * MICROSECOND)
105 #define SECOND (1000 * MILLISECOND)
106
107 #ifdef __GNUC__
108 #define KMT_FORMAT(type, fmt, first) __attribute__((__format__(type, fmt, first)))
109 #elif !defined __GNUC__
110 #define KMT_FORMAT(type, fmt, first)
111 #endif /* !defined __GNUC__ */
112
113 #define START_TEST(name) VOID Test_##name(VOID)
114
115 #ifndef KMT_STRINGIZE
116 #define KMT_STRINGIZE(x) #x
117 #endif /* !defined KMT_STRINGIZE */
118 #define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
119 #define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
120 #define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__)
121
122 #define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
123 #define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
124 #define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
125
126 VOID KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
127 VOID KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
128 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 2, 0);
129 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 2, 3);
130 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
131 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
132
133 #ifdef KMT_KERNEL_MODE
134 #define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
135 #endif /* defined KMT_KERNEL_MODE */
136 #define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
137 #define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
138 #define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
139 #define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
140 #define ok_eq_long(value, expected) ok_eq_print(value, expected, "%ld")
141 #define ok_eq_ulong(value, expected) ok_eq_print(value, expected, "%lu")
142 #define ok_eq_longlong(value, expected) ok_eq_print(value, expected, "%I64d")
143 #define ok_eq_ulonglong(value, expected) ok_eq_print(value, expected, "%I64u")
144 #define ok_eq_size(value, expected) ok_eq_ulonglong((ULONGLONG)(value), (ULONGLONG)(expected))
145 #define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
146 #define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
147 #define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
148 #define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
149 (value) ? "TRUE" : "FALSE", \
150 (expected) ? "TRUE" : "FALSE")
151 #define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
152 #define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
153
154 #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
155 0xC00 + (ControlCode), \
156 METHOD_BUFFERED, \
157 FILE_ANY_ACCESS)
158
159 #if defined KMT_DEFINE_TEST_FUNCTIONS
160
161 #if defined KMT_KERNEL_MODE
162 BOOLEAN KmtIsCheckedBuild;
163 BOOLEAN KmtIsMultiProcessorBuild;
164
165 VOID KmtSetIrql(IN KIRQL NewIrql)
166 {
167 KIRQL Irql = KeGetCurrentIrql();
168 if (Irql > NewIrql)
169 KeLowerIrql(NewIrql);
170 else if (Irql < NewIrql)
171 KeRaiseIrql(NewIrql, &Irql);
172 }
173
174 BOOLEAN KmtAreInterruptsEnabled(VOID)
175 {
176 return (__readeflags() & (1 << 9)) != 0;
177 }
178
179 INT __cdecl KmtVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
180 #elif defined KMT_USER_MODE
181 static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T ResultBufferSize)
182 {
183 PKMT_RESULTBUFFER Buffer = HeapAlloc(GetProcessHeap(), 0, ResultBufferSize);
184 if (!Buffer)
185 return NULL;
186
187 Buffer->Successes = 0;
188 Buffer->Failures = 0;
189 Buffer->Skipped = 0;
190 Buffer->LogBufferLength = 0;
191 Buffer->LogBufferMaxLength = ResultBufferSize - FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer);
192
193 return Buffer;
194 }
195
196 static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
197 {
198 HeapFree(GetProcessHeap(), 0, Buffer);
199 }
200
201 #define KmtVSNPrintF vsnprintf
202 #endif /* defined KMT_USER_MODE */
203
204 PKMT_RESULTBUFFER ResultBuffer = NULL;
205
206 static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
207 {
208 LONG OldLength;
209 LONG NewLength;
210
211 if (!Buffer)
212 return;
213
214 do
215 {
216 OldLength = Buffer->LogBufferLength;
217 NewLength = OldLength + Length;
218 if (NewLength > Buffer->LogBufferMaxLength)
219 {
220 /* TODO: indicate failure somehow */
221 __debugbreak();
222 return;
223 }
224 } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
225
226 memcpy(&Buffer->LogBuffer[OldLength], String, Length);
227 }
228
229 KMT_FORMAT(ms_printf, 5, 0)
230 static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
231 {
232 SIZE_T BufferLength = 0;
233 SIZE_T Length;
234
235 if (FileAndLine)
236 {
237 PCSTR Slash;
238 Slash = strrchr(FileAndLine, '\\');
239 if (Slash)
240 FileAndLine = Slash + 1;
241 Slash = strrchr(FileAndLine, '/');
242 if (Slash)
243 FileAndLine = Slash + 1;
244
245 Length = min(BufferMaxLength, strlen(FileAndLine));
246 memcpy(Buffer, FileAndLine, Length);
247 Buffer += Length;
248 BufferLength += Length;
249 BufferMaxLength -= Length;
250 }
251 if (Prepend)
252 {
253 Length = min(BufferMaxLength, strlen(Prepend));
254 memcpy(Buffer, Prepend, Length);
255 Buffer += Length;
256 BufferLength += Length;
257 BufferMaxLength -= Length;
258 }
259 if (Format)
260 {
261 Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
262 /* vsnprintf can return more than maxLength, we don't want to do that */
263 BufferLength += min(Length, BufferMaxLength);
264 }
265 return BufferLength;
266 }
267
268 KMT_FORMAT(ms_printf, 5, 6)
269 static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
270 {
271 SIZE_T BufferLength;
272 va_list Arguments;
273 va_start(Arguments, Format);
274 BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
275 va_end(Arguments);
276 return BufferLength;
277 }
278
279 VOID KmtFinishTest(PCSTR TestName)
280 {
281 CHAR MessageBuffer[512];
282 SIZE_T MessageLength;
283
284 if (!ResultBuffer)
285 return;
286
287 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
288 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
289 TestName,
290 ResultBuffer->Successes + ResultBuffer->Failures,
291 ResultBuffer->Failures,
292 ResultBuffer->Skipped);
293 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
294 }
295
296 VOID KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
297 {
298 CHAR MessageBuffer[512];
299 SIZE_T MessageLength;
300
301 if (!ResultBuffer)
302 return;
303
304 if (Condition)
305 {
306 InterlockedIncrement(&ResultBuffer->Successes);
307
308 if (0/*KmtReportSuccess*/)
309 {
310 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
311 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
312 }
313 }
314 else
315 {
316 InterlockedIncrement(&ResultBuffer->Failures);
317 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
318 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
319 }
320 }
321
322 VOID KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
323 {
324 va_list Arguments;
325 va_start(Arguments, Format);
326 KmtVOk(Condition, FileAndLine, Format, Arguments);
327 va_end(Arguments);
328 }
329
330 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
331 {
332 CHAR MessageBuffer[512];
333 SIZE_T MessageLength;
334
335 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
336 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
337 }
338
339 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
340 {
341 va_list Arguments;
342 va_start(Arguments, Format);
343 KmtVTrace(FileAndLine, Format, Arguments);
344 va_end(Arguments);
345 }
346
347 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
348 {
349 CHAR MessageBuffer[512];
350 SIZE_T MessageLength;
351
352 if (!ResultBuffer)
353 return !Condition;
354
355 if (!Condition)
356 {
357 InterlockedIncrement(&ResultBuffer->Skipped);
358 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
359 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
360 }
361
362 return !Condition;
363 }
364
365 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
366 {
367 BOOLEAN Ret;
368 va_list Arguments;
369 va_start(Arguments, Format);
370 Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
371 va_end(Arguments);
372 return Ret;
373 }
374
375 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
376
377 #endif /* !defined _KMTEST_TEST_H_ */