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>
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
13 #ifndef _KMTEST_TEST_H_
14 #define _KMTEST_TEST_H_
16 #include <kmt_platform.h>
18 typedef VOID
KMT_TESTFUNC(VOID
);
19 typedef KMT_TESTFUNC
*PKMT_TESTFUNC
;
24 KMT_TESTFUNC
*TestFunction
;
25 } KMT_TEST
, *PKMT_TEST
;
27 typedef const KMT_TEST CKMT_TEST
, *PCKMT_TEST
;
29 extern const KMT_TEST TestList
[];
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
;
41 #ifdef KMT_STANDALONE_DRIVER
42 #define KMT_KERNEL_MODE
44 typedef NTSTATUS (KMT_IRP_HANDLER
)(
45 IN PDEVICE_OBJECT DeviceObject
,
47 IN PIO_STACK_LOCATION IoStackLocation
);
48 typedef KMT_IRP_HANDLER
*PKMT_IRP_HANDLER
;
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
);
53 typedef NTSTATUS (KMT_MESSAGE_HANDLER
)(
54 IN PDEVICE_OBJECT DeviceObject
,
56 IN PVOID Buffer OPTIONAL
,
58 IN OUT PSIZE_T OutLength
);
59 typedef KMT_MESSAGE_HANDLER
*PKMT_MESSAGE_HANDLER
;
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
);
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
;
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 */
76 #ifdef KMT_KERNEL_MODE
77 /* Device Extension layout */
80 PKMT_RESULTBUFFER ResultBuffer
;
82 } KMT_DEVICE_EXTENSION
, *PKMT_DEVICE_EXTENSION
;
84 extern BOOLEAN KmtIsCheckedBuild
;
85 extern BOOLEAN KmtIsMultiProcessorBuild
;
86 extern PCSTR KmtMajorFunctionNames
[];
87 extern PDRIVER_OBJECT KmtDriverObject
;
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
);
95 VOID
KmtLoadDriver(IN PCWSTR ServiceName
, IN BOOLEAN RestartIfRunning
);
96 VOID
KmtUnloadDriver(VOID
);
97 VOID
KmtOpenDriver(VOID
);
98 VOID
KmtCloseDriver(VOID
);
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 */
108 extern PKMT_RESULTBUFFER ResultBuffer
;
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__ */
117 #define START_TEST(name) VOID Test_##name(VOID)
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__)
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__)
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
);
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")
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")
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")
169 #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
170 0xC00 + (ControlCode), \
174 #define MICROSECOND 10
175 #define MILLISECOND (1000 * MICROSECOND)
176 #define SECOND (1000 * MILLISECOND)
178 #define KmtInvalidPointer ((PVOID)0x5555555555555555ULL)
180 #define KmtStartSeh() \
181 ExceptionStatus = STATUS_SUCCESS; \
184 #define KmtEndSeh(ExpectedStatus) \
186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) \
188 ExceptionStatus = _SEH2_GetExceptionCode(); \
190 ok_eq_hex(ExceptionStatus, ExpectedStatus)
192 #if defined KMT_DEFINE_TEST_FUNCTIONS
194 #if defined KMT_KERNEL_MODE
195 BOOLEAN KmtIsCheckedBuild
;
196 BOOLEAN KmtIsMultiProcessorBuild
;
197 PCSTR KmtMajorFunctionNames
[] =
209 "QueryVolumeInformation",
210 "SetVolumeInformation",
214 "InternalDeviceControl/Scsi",
229 VOID
KmtSetIrql(IN KIRQL NewIrql
)
231 KIRQL Irql
= KeGetCurrentIrql();
233 KeLowerIrql(NewIrql
);
234 else if (Irql
< NewIrql
)
235 KeRaiseIrql(NewIrql
, &Irql
);
238 BOOLEAN
KmtAreInterruptsEnabled(VOID
)
240 return (__readeflags() & (1 << 9)) != 0;
243 typedef struct _POOL_HEADER
250 USHORT PreviousSize
:8;
255 USHORT PreviousSize
:9;
269 PEPROCESS ProcessBilled
;
275 USHORT AllocatorBackTraceIndex
;
279 } POOL_HEADER
, *PPOOL_HEADER
;
281 ULONG
KmtGetPoolTag(PVOID Memory
)
285 /* it's not so easy for allocations of PAGE_SIZE */
286 if (((ULONG_PTR
)Memory
& (PAGE_SIZE
- 1)) == 0)
292 return Header
->PoolTag
;
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
)
299 PKMT_RESULTBUFFER Buffer
= HeapAlloc(GetProcessHeap(), 0, ResultBufferSize
);
303 Buffer
->Successes
= 0;
304 Buffer
->Failures
= 0;
306 Buffer
->LogBufferLength
= 0;
307 Buffer
->LogBufferMaxLength
= (ULONG
)ResultBufferSize
- FIELD_OFFSET(KMT_RESULTBUFFER
, LogBuffer
);
312 static VOID
KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer
)
314 HeapFree(GetProcessHeap(), 0, Buffer
);
317 #define KmtVSNPrintF vsnprintf
318 #endif /* defined KMT_USER_MODE */
320 PKMT_RESULTBUFFER ResultBuffer
= NULL
;
322 static VOID
KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer
, PCSTR String
, SIZE_T Length
)
332 OldLength
= Buffer
->LogBufferLength
;
333 NewLength
= OldLength
+ (ULONG
)Length
;
334 if (NewLength
> Buffer
->LogBufferMaxLength
)
336 } while (InterlockedCompareExchange(&Buffer
->LogBufferLength
, NewLength
, OldLength
) != OldLength
);
338 memcpy(&Buffer
->LogBuffer
[OldLength
], String
, Length
);
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
)
344 SIZE_T BufferLength
= 0;
350 Slash
= strrchr(FileAndLine
, '\\');
352 FileAndLine
= Slash
+ 1;
353 Slash
= strrchr(FileAndLine
, '/');
355 FileAndLine
= Slash
+ 1;
357 Length
= min(BufferMaxLength
, strlen(FileAndLine
));
358 memcpy(Buffer
, FileAndLine
, Length
);
360 BufferLength
+= Length
;
361 BufferMaxLength
-= Length
;
365 Length
= min(BufferMaxLength
, strlen(Prepend
));
366 memcpy(Buffer
, Prepend
, Length
);
368 BufferLength
+= Length
;
369 BufferMaxLength
-= Length
;
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
);
380 KMT_FORMAT(ms_printf
, 5, 6)
381 static SIZE_T
KmtXSNPrintF(PSTR Buffer
, SIZE_T BufferMaxLength
, PCSTR FileAndLine
, PCSTR Prepend
, PCSTR Format
, ...)
385 va_start(Arguments
, Format
);
386 BufferLength
= KmtXVSNPrintF(Buffer
, BufferMaxLength
, FileAndLine
, Prepend
, Format
, Arguments
);
391 VOID
KmtFinishTest(PCSTR TestName
)
393 CHAR MessageBuffer
[512];
394 SIZE_T MessageLength
;
399 MessageLength
= KmtXSNPrintF(MessageBuffer
, sizeof MessageBuffer
, NULL
, NULL
,
400 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
402 ResultBuffer
->Successes
+ ResultBuffer
->Failures
,
403 ResultBuffer
->Failures
,
404 ResultBuffer
->Skipped
);
405 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
408 BOOLEAN
KmtVOk(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, va_list Arguments
)
410 CHAR MessageBuffer
[512];
411 SIZE_T MessageLength
;
414 return Condition
!= 0;
418 InterlockedIncrement(&ResultBuffer
->Successes
);
420 if (0/*KmtReportSuccess*/)
422 MessageLength
= KmtXSNPrintF(MessageBuffer
, sizeof MessageBuffer
, FileAndLine
, ": Test succeeded\n", NULL
);
423 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
428 InterlockedIncrement(&ResultBuffer
->Failures
);
429 MessageLength
= KmtXVSNPrintF(MessageBuffer
, sizeof MessageBuffer
, FileAndLine
, ": Test failed: ", Format
, Arguments
);
430 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
433 return Condition
!= 0;
436 BOOLEAN
KmtOk(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, ...)
440 va_start(Arguments
, Format
);
441 Ret
= KmtVOk(Condition
, FileAndLine
, Format
, Arguments
);
446 VOID
KmtVTrace(PCSTR FileAndLine
, PCSTR Format
, va_list Arguments
)
448 CHAR MessageBuffer
[512];
449 SIZE_T MessageLength
;
451 MessageLength
= KmtXVSNPrintF(MessageBuffer
, sizeof MessageBuffer
, FileAndLine
, ": ", Format
, Arguments
);
452 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
455 VOID
KmtTrace(PCSTR FileAndLine
, PCSTR Format
, ...)
458 va_start(Arguments
, Format
);
459 KmtVTrace(FileAndLine
, Format
, Arguments
);
463 BOOLEAN
KmtVSkip(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, va_list Arguments
)
465 CHAR MessageBuffer
[512];
466 SIZE_T MessageLength
;
473 InterlockedIncrement(&ResultBuffer
->Skipped
);
474 MessageLength
= KmtXVSNPrintF(MessageBuffer
, sizeof MessageBuffer
, FileAndLine
, ": Tests skipped: ", Format
, Arguments
);
475 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
481 BOOLEAN
KmtSkip(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, ...)
485 va_start(Arguments
, Format
);
486 Ret
= KmtVSkip(Condition
, FileAndLine
, Format
, Arguments
);
491 PVOID
KmtAllocateGuarded(SIZE_T SizeRequested
)
494 SIZE_T Size
= PAGE_ROUND_UP(SizeRequested
+ PAGE_SIZE
);
495 PVOID VirtualMemory
= NULL
;
498 Status
= ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory
, 0, &Size
, MEM_RESERVE
, PAGE_NOACCESS
);
500 if (!NT_SUCCESS(Status
))
504 Status
= ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory
, 0, &Size
, MEM_COMMIT
, PAGE_READWRITE
);
505 if (!NT_SUCCESS(Status
))
508 Status
= ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory
, &Size
, MEM_RELEASE
);
509 ok_eq_hex(Status
, STATUS_SUCCESS
);
513 StartOfBuffer
= VirtualMemory
;
514 StartOfBuffer
+= Size
- SizeRequested
;
516 return StartOfBuffer
;
519 VOID
KmtFreeGuarded(PVOID Pointer
)
522 PVOID VirtualMemory
= (PVOID
)PAGE_ROUND_DOWN((SIZE_T
)Pointer
);
525 Status
= ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory
, &Size
, MEM_RELEASE
);
526 ok_eq_hex(Status
, STATUS_SUCCESS
);
529 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
531 #endif /* !defined _KMTEST_TEST_H_ */