[KMTESTS]
[reactos.git] / rostests / 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 PVOID KmtAllocateGuarded(SIZE_T SizeRequested);
133 VOID KmtFreeGuarded(PVOID Pointer);
134
135 #ifdef KMT_KERNEL_MODE
136 #define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
137 #endif /* defined KMT_KERNEL_MODE */
138 #define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
139 #define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
140 #define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
141 #define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
142 #define ok_eq_long(value, expected) ok_eq_print(value, expected, "%ld")
143 #define ok_eq_ulong(value, expected) ok_eq_print(value, expected, "%lu")
144 #define ok_eq_longlong(value, expected) ok_eq_print(value, expected, "%I64d")
145 #define ok_eq_ulonglong(value, expected) ok_eq_print(value, expected, "%I64u")
146 #ifndef _WIN64
147 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%lu")
148 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%ld")
149 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%lu")
150 #elif defined _WIN64
151 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%I64u")
152 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%I64d")
153 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%I64u")
154 #endif /* defined _WIN64 */
155 #define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
156 #define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
157 #define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
158 #define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
159 (value) ? "TRUE" : "FALSE", \
160 (expected) ? "TRUE" : "FALSE")
161 #define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
162 #define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
163
164 #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
165 0xC00 + (ControlCode), \
166 METHOD_BUFFERED, \
167 FILE_ANY_ACCESS)
168
169 #define MICROSECOND 10
170 #define MILLISECOND (1000 * MICROSECOND)
171 #define SECOND (1000 * MILLISECOND)
172
173 #if defined KMT_DEFINE_TEST_FUNCTIONS
174
175 #if defined KMT_KERNEL_MODE
176 BOOLEAN KmtIsCheckedBuild;
177 BOOLEAN KmtIsMultiProcessorBuild;
178 PCSTR KmtMajorFunctionNames[] =
179 {
180 "Create",
181 "CreateNamedPipe",
182 "Close",
183 "Read",
184 "Write",
185 "QueryInformation",
186 "SetInformation",
187 "QueryEa",
188 "SetEa",
189 "FlushBuffers",
190 "QueryVolumeInformation",
191 "SetVolumeInformation",
192 "DirectoryControl",
193 "FileSystemControl",
194 "DeviceControl",
195 "InternalDeviceControl/Scsi",
196 "Shutdown",
197 "LockControl",
198 "Cleanup",
199 "CreateMailslot",
200 "QuerySecurity",
201 "SetSecurity",
202 "Power",
203 "SystemControl",
204 "DeviceChange",
205 "QueryQuota",
206 "SetQuota",
207 "Pnp/PnpPower"
208 };
209
210 VOID KmtSetIrql(IN KIRQL NewIrql)
211 {
212 KIRQL Irql = KeGetCurrentIrql();
213 if (Irql > NewIrql)
214 KeLowerIrql(NewIrql);
215 else if (Irql < NewIrql)
216 KeRaiseIrql(NewIrql, &Irql);
217 }
218
219 BOOLEAN KmtAreInterruptsEnabled(VOID)
220 {
221 return (__readeflags() & (1 << 9)) != 0;
222 }
223
224 INT __cdecl KmtVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
225 #elif defined KMT_USER_MODE
226 static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T ResultBufferSize)
227 {
228 PKMT_RESULTBUFFER Buffer = HeapAlloc(GetProcessHeap(), 0, ResultBufferSize);
229 if (!Buffer)
230 return NULL;
231
232 Buffer->Successes = 0;
233 Buffer->Failures = 0;
234 Buffer->Skipped = 0;
235 Buffer->LogBufferLength = 0;
236 Buffer->LogBufferMaxLength = ResultBufferSize - FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer);
237
238 return Buffer;
239 }
240
241 static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
242 {
243 HeapFree(GetProcessHeap(), 0, Buffer);
244 }
245
246 #define KmtVSNPrintF vsnprintf
247 #endif /* defined KMT_USER_MODE */
248
249 PKMT_RESULTBUFFER ResultBuffer = NULL;
250
251 static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
252 {
253 LONG OldLength;
254 LONG NewLength;
255
256 if (!Buffer)
257 return;
258
259 do
260 {
261 OldLength = Buffer->LogBufferLength;
262 NewLength = OldLength + Length;
263 if (NewLength > Buffer->LogBufferMaxLength)
264 return;
265 } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
266
267 memcpy(&Buffer->LogBuffer[OldLength], String, Length);
268 }
269
270 KMT_FORMAT(ms_printf, 5, 0)
271 static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
272 {
273 SIZE_T BufferLength = 0;
274 SIZE_T Length;
275
276 if (FileAndLine)
277 {
278 PCSTR Slash;
279 Slash = strrchr(FileAndLine, '\\');
280 if (Slash)
281 FileAndLine = Slash + 1;
282 Slash = strrchr(FileAndLine, '/');
283 if (Slash)
284 FileAndLine = Slash + 1;
285
286 Length = min(BufferMaxLength, strlen(FileAndLine));
287 memcpy(Buffer, FileAndLine, Length);
288 Buffer += Length;
289 BufferLength += Length;
290 BufferMaxLength -= Length;
291 }
292 if (Prepend)
293 {
294 Length = min(BufferMaxLength, strlen(Prepend));
295 memcpy(Buffer, Prepend, Length);
296 Buffer += Length;
297 BufferLength += Length;
298 BufferMaxLength -= Length;
299 }
300 if (Format)
301 {
302 Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
303 /* vsnprintf can return more than maxLength, we don't want to do that */
304 BufferLength += min(Length, BufferMaxLength);
305 }
306 return BufferLength;
307 }
308
309 KMT_FORMAT(ms_printf, 5, 6)
310 static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
311 {
312 SIZE_T BufferLength;
313 va_list Arguments;
314 va_start(Arguments, Format);
315 BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
316 va_end(Arguments);
317 return BufferLength;
318 }
319
320 VOID KmtFinishTest(PCSTR TestName)
321 {
322 CHAR MessageBuffer[512];
323 SIZE_T MessageLength;
324
325 if (!ResultBuffer)
326 return;
327
328 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
329 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
330 TestName,
331 ResultBuffer->Successes + ResultBuffer->Failures,
332 ResultBuffer->Failures,
333 ResultBuffer->Skipped);
334 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
335 }
336
337 VOID KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
338 {
339 CHAR MessageBuffer[512];
340 SIZE_T MessageLength;
341
342 if (!ResultBuffer)
343 return;
344
345 if (Condition)
346 {
347 InterlockedIncrement(&ResultBuffer->Successes);
348
349 if (0/*KmtReportSuccess*/)
350 {
351 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
352 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
353 }
354 }
355 else
356 {
357 InterlockedIncrement(&ResultBuffer->Failures);
358 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
359 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
360 }
361 }
362
363 VOID KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
364 {
365 va_list Arguments;
366 va_start(Arguments, Format);
367 KmtVOk(Condition, FileAndLine, Format, Arguments);
368 va_end(Arguments);
369 }
370
371 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
372 {
373 CHAR MessageBuffer[512];
374 SIZE_T MessageLength;
375
376 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
377 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
378 }
379
380 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
381 {
382 va_list Arguments;
383 va_start(Arguments, Format);
384 KmtVTrace(FileAndLine, Format, Arguments);
385 va_end(Arguments);
386 }
387
388 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
389 {
390 CHAR MessageBuffer[512];
391 SIZE_T MessageLength;
392
393 if (!ResultBuffer)
394 return !Condition;
395
396 if (!Condition)
397 {
398 InterlockedIncrement(&ResultBuffer->Skipped);
399 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
400 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
401 }
402
403 return !Condition;
404 }
405
406 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
407 {
408 BOOLEAN Ret;
409 va_list Arguments;
410 va_start(Arguments, Format);
411 Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
412 va_end(Arguments);
413 return Ret;
414 }
415
416 PVOID KmtAllocateGuarded(SIZE_T SizeRequested)
417 {
418 NTSTATUS Status;
419 SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
420 PVOID VirtualMemory = NULL;
421 PCHAR StartOfBuffer;
422
423 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
424
425 if (!NT_SUCCESS(Status))
426 return NULL;
427
428 Size -= PAGE_SIZE;
429 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
430 if (!NT_SUCCESS(Status))
431 {
432 Size = 0;
433 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
434 ok_eq_hex(Status, STATUS_SUCCESS);
435 return NULL;
436 }
437
438 StartOfBuffer = VirtualMemory;
439 StartOfBuffer += Size - SizeRequested;
440
441 return StartOfBuffer;
442 }
443
444 VOID KmtFreeGuarded(PVOID Pointer)
445 {
446 NTSTATUS Status;
447 PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
448 SIZE_T Size = 0;
449
450 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
451 ok_eq_hex(Status, STATUS_SUCCESS);
452 }
453
454 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
455
456 #endif /* !defined _KMTEST_TEST_H_ */