[KMTESTS]
[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, IN 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 extern PCSTR KmtMajorFunctionNames[];
86
87 VOID KmtSetIrql(IN KIRQL NewIrql);
88 BOOLEAN KmtAreInterruptsEnabled(VOID);
89 #elif defined KMT_USER_MODE
90 DWORD KmtRunKernelTest(IN PCSTR TestName);
91
92 VOID KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
93 VOID KmtUnloadDriver(VOID);
94 VOID KmtOpenDriver(VOID);
95 VOID KmtCloseDriver(VOID);
96
97 DWORD KmtSendToDriver(IN DWORD ControlCode);
98 DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
99 DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer OPTIONAL, IN DWORD InLength, IN OUT PDWORD OutLength);
100 #else /* if !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
101 #error either KMT_KERNEL_MODE or KMT_USER_MODE must be defined
102 #endif /* !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
103
104 extern PKMT_RESULTBUFFER ResultBuffer;
105
106 #ifdef __GNUC__
107 /* TODO: GCC doesn't understand %wZ :( */
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 #ifndef _WIN64
145 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%lu")
146 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%ld")
147 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%lu")
148 #elif defined _WIN64
149 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%I64u")
150 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%I64d")
151 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%I64u")
152 #endif /* defined _WIN64 */
153 #define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
154 #define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
155 #define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
156 #define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
157 (value) ? "TRUE" : "FALSE", \
158 (expected) ? "TRUE" : "FALSE")
159 #define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
160 #define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
161
162 #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
163 0xC00 + (ControlCode), \
164 METHOD_BUFFERED, \
165 FILE_ANY_ACCESS)
166
167 #define MICROSECOND 10
168 #define MILLISECOND (1000 * MICROSECOND)
169 #define SECOND (1000 * MILLISECOND)
170
171 #if defined KMT_DEFINE_TEST_FUNCTIONS
172
173 #if defined KMT_KERNEL_MODE
174 BOOLEAN KmtIsCheckedBuild;
175 BOOLEAN KmtIsMultiProcessorBuild;
176 PCSTR KmtMajorFunctionNames[] =
177 {
178 "Create",
179 "CreateNamedPipe",
180 "Close",
181 "Read",
182 "Write",
183 "QueryInformation",
184 "SetInformation",
185 "QueryEa",
186 "SetEa",
187 "FlushBuffers",
188 "QueryVolumeInformation",
189 "SetVolumeInformation",
190 "DirectoryControl",
191 "FileSystemControl",
192 "DeviceControl",
193 "InternalDeviceControl/Scsi",
194 "Shutdown",
195 "LockControl",
196 "Cleanup",
197 "CreateMailslot",
198 "QuerySecurity",
199 "SetSecurity",
200 "Power",
201 "SystemControl",
202 "DeviceChange",
203 "QueryQuota",
204 "SetQuota",
205 "Pnp/PnpPower"
206 };
207
208 VOID KmtSetIrql(IN KIRQL NewIrql)
209 {
210 KIRQL Irql = KeGetCurrentIrql();
211 if (Irql > NewIrql)
212 KeLowerIrql(NewIrql);
213 else if (Irql < NewIrql)
214 KeRaiseIrql(NewIrql, &Irql);
215 }
216
217 BOOLEAN KmtAreInterruptsEnabled(VOID)
218 {
219 return (__readeflags() & (1 << 9)) != 0;
220 }
221
222 INT __cdecl KmtVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
223 #elif defined KMT_USER_MODE
224 static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T ResultBufferSize)
225 {
226 PKMT_RESULTBUFFER Buffer = HeapAlloc(GetProcessHeap(), 0, ResultBufferSize);
227 if (!Buffer)
228 return NULL;
229
230 Buffer->Successes = 0;
231 Buffer->Failures = 0;
232 Buffer->Skipped = 0;
233 Buffer->LogBufferLength = 0;
234 Buffer->LogBufferMaxLength = ResultBufferSize - FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer);
235
236 return Buffer;
237 }
238
239 static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
240 {
241 HeapFree(GetProcessHeap(), 0, Buffer);
242 }
243
244 #define KmtVSNPrintF vsnprintf
245 #endif /* defined KMT_USER_MODE */
246
247 PKMT_RESULTBUFFER ResultBuffer = NULL;
248
249 static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
250 {
251 LONG OldLength;
252 LONG NewLength;
253
254 if (!Buffer)
255 return;
256
257 do
258 {
259 OldLength = Buffer->LogBufferLength;
260 NewLength = OldLength + Length;
261 if (NewLength > Buffer->LogBufferMaxLength)
262 return;
263 } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
264
265 memcpy(&Buffer->LogBuffer[OldLength], String, Length);
266 }
267
268 KMT_FORMAT(ms_printf, 5, 0)
269 static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
270 {
271 SIZE_T BufferLength = 0;
272 SIZE_T Length;
273
274 if (FileAndLine)
275 {
276 PCSTR Slash;
277 Slash = strrchr(FileAndLine, '\\');
278 if (Slash)
279 FileAndLine = Slash + 1;
280 Slash = strrchr(FileAndLine, '/');
281 if (Slash)
282 FileAndLine = Slash + 1;
283
284 Length = min(BufferMaxLength, strlen(FileAndLine));
285 memcpy(Buffer, FileAndLine, Length);
286 Buffer += Length;
287 BufferLength += Length;
288 BufferMaxLength -= Length;
289 }
290 if (Prepend)
291 {
292 Length = min(BufferMaxLength, strlen(Prepend));
293 memcpy(Buffer, Prepend, Length);
294 Buffer += Length;
295 BufferLength += Length;
296 BufferMaxLength -= Length;
297 }
298 if (Format)
299 {
300 Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
301 /* vsnprintf can return more than maxLength, we don't want to do that */
302 BufferLength += min(Length, BufferMaxLength);
303 }
304 return BufferLength;
305 }
306
307 KMT_FORMAT(ms_printf, 5, 6)
308 static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
309 {
310 SIZE_T BufferLength;
311 va_list Arguments;
312 va_start(Arguments, Format);
313 BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
314 va_end(Arguments);
315 return BufferLength;
316 }
317
318 VOID KmtFinishTest(PCSTR TestName)
319 {
320 CHAR MessageBuffer[512];
321 SIZE_T MessageLength;
322
323 if (!ResultBuffer)
324 return;
325
326 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
327 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
328 TestName,
329 ResultBuffer->Successes + ResultBuffer->Failures,
330 ResultBuffer->Failures,
331 ResultBuffer->Skipped);
332 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
333 }
334
335 VOID KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
336 {
337 CHAR MessageBuffer[512];
338 SIZE_T MessageLength;
339
340 if (!ResultBuffer)
341 return;
342
343 if (Condition)
344 {
345 InterlockedIncrement(&ResultBuffer->Successes);
346
347 if (0/*KmtReportSuccess*/)
348 {
349 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
350 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
351 }
352 }
353 else
354 {
355 InterlockedIncrement(&ResultBuffer->Failures);
356 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
357 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
358 }
359 }
360
361 VOID KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
362 {
363 va_list Arguments;
364 va_start(Arguments, Format);
365 KmtVOk(Condition, FileAndLine, Format, Arguments);
366 va_end(Arguments);
367 }
368
369 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
370 {
371 CHAR MessageBuffer[512];
372 SIZE_T MessageLength;
373
374 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
375 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
376 }
377
378 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
379 {
380 va_list Arguments;
381 va_start(Arguments, Format);
382 KmtVTrace(FileAndLine, Format, Arguments);
383 va_end(Arguments);
384 }
385
386 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
387 {
388 CHAR MessageBuffer[512];
389 SIZE_T MessageLength;
390
391 if (!ResultBuffer)
392 return !Condition;
393
394 if (!Condition)
395 {
396 InterlockedIncrement(&ResultBuffer->Skipped);
397 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
398 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
399 }
400
401 return !Condition;
402 }
403
404 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
405 {
406 BOOLEAN Ret;
407 va_list Arguments;
408 va_start(Arguments, Format);
409 Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
410 va_end(Arguments);
411 return Ret;
412 }
413
414 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
415
416 #endif /* !defined _KMTEST_TEST_H_ */