[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 #if defined KMT_DEFINE_TEST_FUNCTIONS
177
178 #if defined KMT_KERNEL_MODE
179 BOOLEAN KmtIsCheckedBuild;
180 BOOLEAN KmtIsMultiProcessorBuild;
181 PCSTR KmtMajorFunctionNames[] =
182 {
183 "Create",
184 "CreateNamedPipe",
185 "Close",
186 "Read",
187 "Write",
188 "QueryInformation",
189 "SetInformation",
190 "QueryEa",
191 "SetEa",
192 "FlushBuffers",
193 "QueryVolumeInformation",
194 "SetVolumeInformation",
195 "DirectoryControl",
196 "FileSystemControl",
197 "DeviceControl",
198 "InternalDeviceControl/Scsi",
199 "Shutdown",
200 "LockControl",
201 "Cleanup",
202 "CreateMailslot",
203 "QuerySecurity",
204 "SetSecurity",
205 "Power",
206 "SystemControl",
207 "DeviceChange",
208 "QueryQuota",
209 "SetQuota",
210 "Pnp/PnpPower"
211 };
212
213 VOID KmtSetIrql(IN KIRQL NewIrql)
214 {
215 KIRQL Irql = KeGetCurrentIrql();
216 if (Irql > NewIrql)
217 KeLowerIrql(NewIrql);
218 else if (Irql < NewIrql)
219 KeRaiseIrql(NewIrql, &Irql);
220 }
221
222 BOOLEAN KmtAreInterruptsEnabled(VOID)
223 {
224 return (__readeflags() & (1 << 9)) != 0;
225 }
226
227 typedef struct _POOL_HEADER
228 {
229 union
230 {
231 struct
232 {
233 #ifdef _M_AMD64
234 USHORT PreviousSize:8;
235 USHORT PoolIndex:8;
236 USHORT BlockSize:8;
237 USHORT PoolType:8;
238 #else
239 USHORT PreviousSize:9;
240 USHORT PoolIndex:7;
241 USHORT BlockSize:9;
242 USHORT PoolType:7;
243 #endif
244 };
245 ULONG Ulong1;
246 };
247 #ifdef _M_AMD64
248 ULONG PoolTag;
249 #endif
250 union
251 {
252 #ifdef _M_AMD64
253 PEPROCESS ProcessBilled;
254 #else
255 ULONG PoolTag;
256 #endif
257 struct
258 {
259 USHORT AllocatorBackTraceIndex;
260 USHORT PoolTagHash;
261 };
262 };
263 } POOL_HEADER, *PPOOL_HEADER;
264
265 ULONG KmtGetPoolTag(PVOID Memory)
266 {
267 PPOOL_HEADER Header;
268
269 /* it's not so easy for allocations of PAGE_SIZE */
270 if (((ULONG_PTR)Memory & (PAGE_SIZE - 1)) == 0)
271 return 'TooL';
272
273 Header = Memory;
274 Header--;
275
276 return Header->PoolTag;
277 }
278
279 INT __cdecl KmtVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
280 #elif defined KMT_USER_MODE
281 static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T ResultBufferSize)
282 {
283 PKMT_RESULTBUFFER Buffer = HeapAlloc(GetProcessHeap(), 0, ResultBufferSize);
284 if (!Buffer)
285 return NULL;
286
287 Buffer->Successes = 0;
288 Buffer->Failures = 0;
289 Buffer->Skipped = 0;
290 Buffer->LogBufferLength = 0;
291 Buffer->LogBufferMaxLength = (ULONG)ResultBufferSize - FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer);
292
293 return Buffer;
294 }
295
296 static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
297 {
298 HeapFree(GetProcessHeap(), 0, Buffer);
299 }
300
301 #define KmtVSNPrintF vsnprintf
302 #endif /* defined KMT_USER_MODE */
303
304 PKMT_RESULTBUFFER ResultBuffer = NULL;
305
306 static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
307 {
308 LONG OldLength;
309 LONG NewLength;
310
311 if (!Buffer)
312 return;
313
314 do
315 {
316 OldLength = Buffer->LogBufferLength;
317 NewLength = OldLength + (ULONG)Length;
318 if (NewLength > Buffer->LogBufferMaxLength)
319 return;
320 } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
321
322 memcpy(&Buffer->LogBuffer[OldLength], String, Length);
323 }
324
325 KMT_FORMAT(ms_printf, 5, 0)
326 static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
327 {
328 SIZE_T BufferLength = 0;
329 SIZE_T Length;
330
331 if (FileAndLine)
332 {
333 PCSTR Slash;
334 Slash = strrchr(FileAndLine, '\\');
335 if (Slash)
336 FileAndLine = Slash + 1;
337 Slash = strrchr(FileAndLine, '/');
338 if (Slash)
339 FileAndLine = Slash + 1;
340
341 Length = min(BufferMaxLength, strlen(FileAndLine));
342 memcpy(Buffer, FileAndLine, Length);
343 Buffer += Length;
344 BufferLength += Length;
345 BufferMaxLength -= Length;
346 }
347 if (Prepend)
348 {
349 Length = min(BufferMaxLength, strlen(Prepend));
350 memcpy(Buffer, Prepend, Length);
351 Buffer += Length;
352 BufferLength += Length;
353 BufferMaxLength -= Length;
354 }
355 if (Format)
356 {
357 Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
358 /* vsnprintf can return more than maxLength, we don't want to do that */
359 BufferLength += min(Length, BufferMaxLength);
360 }
361 return BufferLength;
362 }
363
364 KMT_FORMAT(ms_printf, 5, 6)
365 static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
366 {
367 SIZE_T BufferLength;
368 va_list Arguments;
369 va_start(Arguments, Format);
370 BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
371 va_end(Arguments);
372 return BufferLength;
373 }
374
375 VOID KmtFinishTest(PCSTR TestName)
376 {
377 CHAR MessageBuffer[512];
378 SIZE_T MessageLength;
379
380 if (!ResultBuffer)
381 return;
382
383 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
384 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
385 TestName,
386 ResultBuffer->Successes + ResultBuffer->Failures,
387 ResultBuffer->Failures,
388 ResultBuffer->Skipped);
389 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
390 }
391
392 BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
393 {
394 CHAR MessageBuffer[512];
395 SIZE_T MessageLength;
396
397 if (!ResultBuffer)
398 return Condition != 0;
399
400 if (Condition)
401 {
402 InterlockedIncrement(&ResultBuffer->Successes);
403
404 if (0/*KmtReportSuccess*/)
405 {
406 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
407 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
408 }
409 }
410 else
411 {
412 InterlockedIncrement(&ResultBuffer->Failures);
413 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
414 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
415 }
416
417 return Condition != 0;
418 }
419
420 BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
421 {
422 BOOLEAN Ret;
423 va_list Arguments;
424 va_start(Arguments, Format);
425 Ret = KmtVOk(Condition, FileAndLine, Format, Arguments);
426 va_end(Arguments);
427 return Ret;
428 }
429
430 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
431 {
432 CHAR MessageBuffer[512];
433 SIZE_T MessageLength;
434
435 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
436 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
437 }
438
439 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
440 {
441 va_list Arguments;
442 va_start(Arguments, Format);
443 KmtVTrace(FileAndLine, Format, Arguments);
444 va_end(Arguments);
445 }
446
447 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
448 {
449 CHAR MessageBuffer[512];
450 SIZE_T MessageLength;
451
452 if (!ResultBuffer)
453 return !Condition;
454
455 if (!Condition)
456 {
457 InterlockedIncrement(&ResultBuffer->Skipped);
458 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
459 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
460 }
461
462 return !Condition;
463 }
464
465 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
466 {
467 BOOLEAN Ret;
468 va_list Arguments;
469 va_start(Arguments, Format);
470 Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
471 va_end(Arguments);
472 return Ret;
473 }
474
475 PVOID KmtAllocateGuarded(SIZE_T SizeRequested)
476 {
477 NTSTATUS Status;
478 SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
479 PVOID VirtualMemory = NULL;
480 PCHAR StartOfBuffer;
481
482 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
483
484 if (!NT_SUCCESS(Status))
485 return NULL;
486
487 Size -= PAGE_SIZE;
488 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
489 if (!NT_SUCCESS(Status))
490 {
491 Size = 0;
492 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
493 ok_eq_hex(Status, STATUS_SUCCESS);
494 return NULL;
495 }
496
497 StartOfBuffer = VirtualMemory;
498 StartOfBuffer += Size - SizeRequested;
499
500 return StartOfBuffer;
501 }
502
503 VOID KmtFreeGuarded(PVOID Pointer)
504 {
505 NTSTATUS Status;
506 PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
507 SIZE_T Size = 0;
508
509 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
510 ok_eq_hex(Status, STATUS_SUCCESS);
511 }
512
513 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
514
515 #endif /* !defined _KMTEST_TEST_H_ */