[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 TESTENTRY_NO_EXCLUSIVE_DEVICE = 8,
70 } KMT_TESTENTRY_FLAGS;
71
72 NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryPath, OUT PCWSTR *DeviceName, IN OUT INT *Flags);
73 VOID TestUnload(IN PDRIVER_OBJECT DriverObject);
74 #endif /* defined KMT_STANDALONE_DRIVER */
75
76 #ifdef KMT_KERNEL_MODE
77 /* Device Extension layout */
78 typedef struct
79 {
80 PKMT_RESULTBUFFER ResultBuffer;
81 PMDL Mdl;
82 } KMT_DEVICE_EXTENSION, *PKMT_DEVICE_EXTENSION;
83
84 extern BOOLEAN KmtIsCheckedBuild;
85 extern BOOLEAN KmtIsMultiProcessorBuild;
86 extern PCSTR KmtMajorFunctionNames[];
87 extern PDRIVER_OBJECT KmtDriverObject;
88
89 VOID KmtSetIrql(IN KIRQL NewIrql);
90 BOOLEAN KmtAreInterruptsEnabled(VOID);
91 ULONG KmtGetPoolTag(PVOID Memory);
92 #elif defined KMT_USER_MODE
93 DWORD KmtRunKernelTest(IN PCSTR TestName);
94
95 VOID KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
96 VOID KmtUnloadDriver(VOID);
97 VOID KmtOpenDriver(VOID);
98 VOID KmtCloseDriver(VOID);
99
100 DWORD KmtSendToDriver(IN DWORD ControlCode);
101 DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
102 DWORD KmtSendWStringToDriver(IN DWORD ControlCode, IN PCWSTR String);
103 DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer OPTIONAL, IN DWORD InLength, IN OUT PDWORD OutLength);
104 #else /* if !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
105 #error either KMT_KERNEL_MODE or KMT_USER_MODE must be defined
106 #endif /* !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
107
108 extern PKMT_RESULTBUFFER ResultBuffer;
109
110 #ifdef __GNUC__
111 /* TODO: GCC doesn't understand %wZ :( */
112 #define KMT_FORMAT(type, fmt, first) /*__attribute__((__format__(type, fmt, first)))*/
113 #elif !defined __GNUC__
114 #define KMT_FORMAT(type, fmt, first)
115 #endif /* !defined __GNUC__ */
116
117 #define START_TEST(name) VOID Test_##name(VOID)
118
119 #ifndef KMT_STRINGIZE
120 #define KMT_STRINGIZE(x) #x
121 #endif /* !defined KMT_STRINGIZE */
122 #define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
123 #define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
124 #define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__)
125
126 #define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
127 #define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
128 #define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
129
130 BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
131 BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
132 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 2, 0);
133 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 2, 3);
134 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
135 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
136 PVOID KmtAllocateGuarded(SIZE_T SizeRequested);
137 VOID KmtFreeGuarded(PVOID Pointer);
138
139 #ifdef KMT_KERNEL_MODE
140 #define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
141 #endif /* defined KMT_KERNEL_MODE */
142 #define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
143 #define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
144 #define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
145 #define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
146 #define ok_eq_long(value, expected) ok_eq_print(value, expected, "%ld")
147 #define ok_eq_ulong(value, expected) ok_eq_print(value, expected, "%lu")
148 #define ok_eq_longlong(value, expected) ok_eq_print(value, expected, "%I64d")
149 #define ok_eq_ulonglong(value, expected) ok_eq_print(value, expected, "%I64u")
150 #ifndef _WIN64
151 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%lu")
152 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%ld")
153 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%lu")
154 #elif defined _WIN64
155 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%I64u")
156 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%I64d")
157 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%I64u")
158 #endif /* defined _WIN64 */
159 #define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
160 #define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
161 #define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
162 #define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
163 (value) ? "TRUE" : "FALSE", \
164 (expected) ? "TRUE" : "FALSE")
165 #define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
166 #define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
167 #define ok_eq_tag(value, expected) ok_eq_print(value, expected, "0x%08lx")
168
169 #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
170 0xC00 + (ControlCode), \
171 METHOD_BUFFERED, \
172 FILE_ANY_ACCESS)
173
174 #define MICROSECOND 10
175 #define MILLISECOND (1000 * MICROSECOND)
176 #define SECOND (1000 * MILLISECOND)
177
178 #define KmtInvalidPointer ((PVOID)0x5555555555555555ULL)
179
180 #define KmtStartSeh() \
181 ExceptionStatus = STATUS_SUCCESS; \
182 _SEH2_TRY \
183 {
184 #define KmtEndSeh(ExpectedStatus) \
185 } \
186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) \
187 { \
188 ExceptionStatus = _SEH2_GetExceptionCode(); \
189 } _SEH2_END; \
190 ok_eq_hex(ExceptionStatus, ExpectedStatus)
191
192 #if defined KMT_DEFINE_TEST_FUNCTIONS
193
194 #if defined KMT_KERNEL_MODE
195 BOOLEAN KmtIsCheckedBuild;
196 BOOLEAN KmtIsMultiProcessorBuild;
197 PCSTR KmtMajorFunctionNames[] =
198 {
199 "Create",
200 "CreateNamedPipe",
201 "Close",
202 "Read",
203 "Write",
204 "QueryInformation",
205 "SetInformation",
206 "QueryEa",
207 "SetEa",
208 "FlushBuffers",
209 "QueryVolumeInformation",
210 "SetVolumeInformation",
211 "DirectoryControl",
212 "FileSystemControl",
213 "DeviceControl",
214 "InternalDeviceControl/Scsi",
215 "Shutdown",
216 "LockControl",
217 "Cleanup",
218 "CreateMailslot",
219 "QuerySecurity",
220 "SetSecurity",
221 "Power",
222 "SystemControl",
223 "DeviceChange",
224 "QueryQuota",
225 "SetQuota",
226 "Pnp/PnpPower"
227 };
228
229 VOID KmtSetIrql(IN KIRQL NewIrql)
230 {
231 KIRQL Irql = KeGetCurrentIrql();
232 if (Irql > NewIrql)
233 KeLowerIrql(NewIrql);
234 else if (Irql < NewIrql)
235 KeRaiseIrql(NewIrql, &Irql);
236 }
237
238 BOOLEAN KmtAreInterruptsEnabled(VOID)
239 {
240 return (__readeflags() & (1 << 9)) != 0;
241 }
242
243 typedef struct _POOL_HEADER
244 {
245 union
246 {
247 struct
248 {
249 #ifdef _M_AMD64
250 USHORT PreviousSize:8;
251 USHORT PoolIndex:8;
252 USHORT BlockSize:8;
253 USHORT PoolType:8;
254 #else
255 USHORT PreviousSize:9;
256 USHORT PoolIndex:7;
257 USHORT BlockSize:9;
258 USHORT PoolType:7;
259 #endif
260 };
261 ULONG Ulong1;
262 };
263 #ifdef _M_AMD64
264 ULONG PoolTag;
265 #endif
266 union
267 {
268 #ifdef _M_AMD64
269 PEPROCESS ProcessBilled;
270 #else
271 ULONG PoolTag;
272 #endif
273 struct
274 {
275 USHORT AllocatorBackTraceIndex;
276 USHORT PoolTagHash;
277 };
278 };
279 } POOL_HEADER, *PPOOL_HEADER;
280
281 ULONG KmtGetPoolTag(PVOID Memory)
282 {
283 PPOOL_HEADER Header;
284
285 /* it's not so easy for allocations of PAGE_SIZE */
286 if (((ULONG_PTR)Memory & (PAGE_SIZE - 1)) == 0)
287 return 'TooL';
288
289 Header = Memory;
290 Header--;
291
292 return Header->PoolTag;
293 }
294
295 INT __cdecl KmtVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
296 #elif defined KMT_USER_MODE
297 static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T ResultBufferSize)
298 {
299 PKMT_RESULTBUFFER Buffer = HeapAlloc(GetProcessHeap(), 0, ResultBufferSize);
300 if (!Buffer)
301 return NULL;
302
303 Buffer->Successes = 0;
304 Buffer->Failures = 0;
305 Buffer->Skipped = 0;
306 Buffer->LogBufferLength = 0;
307 Buffer->LogBufferMaxLength = (ULONG)ResultBufferSize - FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer);
308
309 return Buffer;
310 }
311
312 static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
313 {
314 HeapFree(GetProcessHeap(), 0, Buffer);
315 }
316
317 #define KmtVSNPrintF vsnprintf
318 #endif /* defined KMT_USER_MODE */
319
320 PKMT_RESULTBUFFER ResultBuffer = NULL;
321
322 static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
323 {
324 LONG OldLength;
325 LONG NewLength;
326
327 if (!Buffer)
328 return;
329
330 do
331 {
332 OldLength = Buffer->LogBufferLength;
333 NewLength = OldLength + (ULONG)Length;
334 if (NewLength > Buffer->LogBufferMaxLength)
335 return;
336 } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
337
338 memcpy(&Buffer->LogBuffer[OldLength], String, Length);
339 }
340
341 KMT_FORMAT(ms_printf, 5, 0)
342 static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
343 {
344 SIZE_T BufferLength = 0;
345 SIZE_T Length;
346
347 if (FileAndLine)
348 {
349 PCSTR Slash;
350 Slash = strrchr(FileAndLine, '\\');
351 if (Slash)
352 FileAndLine = Slash + 1;
353 Slash = strrchr(FileAndLine, '/');
354 if (Slash)
355 FileAndLine = Slash + 1;
356
357 Length = min(BufferMaxLength, strlen(FileAndLine));
358 memcpy(Buffer, FileAndLine, Length);
359 Buffer += Length;
360 BufferLength += Length;
361 BufferMaxLength -= Length;
362 }
363 if (Prepend)
364 {
365 Length = min(BufferMaxLength, strlen(Prepend));
366 memcpy(Buffer, Prepend, Length);
367 Buffer += Length;
368 BufferLength += Length;
369 BufferMaxLength -= Length;
370 }
371 if (Format)
372 {
373 Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
374 /* vsnprintf can return more than maxLength, we don't want to do that */
375 BufferLength += min(Length, BufferMaxLength);
376 }
377 return BufferLength;
378 }
379
380 KMT_FORMAT(ms_printf, 5, 6)
381 static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
382 {
383 SIZE_T BufferLength;
384 va_list Arguments;
385 va_start(Arguments, Format);
386 BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
387 va_end(Arguments);
388 return BufferLength;
389 }
390
391 VOID KmtFinishTest(PCSTR TestName)
392 {
393 CHAR MessageBuffer[512];
394 SIZE_T MessageLength;
395
396 if (!ResultBuffer)
397 return;
398
399 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
400 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
401 TestName,
402 ResultBuffer->Successes + ResultBuffer->Failures,
403 ResultBuffer->Failures,
404 ResultBuffer->Skipped);
405 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
406 }
407
408 BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
409 {
410 CHAR MessageBuffer[512];
411 SIZE_T MessageLength;
412
413 if (!ResultBuffer)
414 return Condition != 0;
415
416 if (Condition)
417 {
418 InterlockedIncrement(&ResultBuffer->Successes);
419
420 if (0/*KmtReportSuccess*/)
421 {
422 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
423 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
424 }
425 }
426 else
427 {
428 InterlockedIncrement(&ResultBuffer->Failures);
429 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
430 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
431 }
432
433 return Condition != 0;
434 }
435
436 BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
437 {
438 BOOLEAN Ret;
439 va_list Arguments;
440 va_start(Arguments, Format);
441 Ret = KmtVOk(Condition, FileAndLine, Format, Arguments);
442 va_end(Arguments);
443 return Ret;
444 }
445
446 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
447 {
448 CHAR MessageBuffer[512];
449 SIZE_T MessageLength;
450
451 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
452 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
453 }
454
455 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
456 {
457 va_list Arguments;
458 va_start(Arguments, Format);
459 KmtVTrace(FileAndLine, Format, Arguments);
460 va_end(Arguments);
461 }
462
463 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
464 {
465 CHAR MessageBuffer[512];
466 SIZE_T MessageLength;
467
468 if (!ResultBuffer)
469 return !Condition;
470
471 if (!Condition)
472 {
473 InterlockedIncrement(&ResultBuffer->Skipped);
474 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
475 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
476 }
477
478 return !Condition;
479 }
480
481 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
482 {
483 BOOLEAN Ret;
484 va_list Arguments;
485 va_start(Arguments, Format);
486 Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
487 va_end(Arguments);
488 return Ret;
489 }
490
491 PVOID KmtAllocateGuarded(SIZE_T SizeRequested)
492 {
493 NTSTATUS Status;
494 SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
495 PVOID VirtualMemory = NULL;
496 PCHAR StartOfBuffer;
497
498 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
499
500 if (!NT_SUCCESS(Status))
501 return NULL;
502
503 Size -= PAGE_SIZE;
504 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
505 if (!NT_SUCCESS(Status))
506 {
507 Size = 0;
508 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
509 ok_eq_hex(Status, STATUS_SUCCESS);
510 return NULL;
511 }
512
513 StartOfBuffer = VirtualMemory;
514 StartOfBuffer += Size - SizeRequested;
515
516 return StartOfBuffer;
517 }
518
519 VOID KmtFreeGuarded(PVOID Pointer)
520 {
521 NTSTATUS Status;
522 PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
523 SIZE_T Size = 0;
524
525 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
526 ok_eq_hex(Status, STATUS_SUCCESS);
527 }
528
529 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
530
531 #endif /* !defined _KMTEST_TEST_H_ */