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