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 <thomas.faber@reactos.org>
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 #ifndef KMT_STANDALONE_DRIVER
43 /* usermode call-back mechanism */
45 /* list of supported operations */
46 typedef enum _KMT_CALLBACK_INFORMATION_CLASS
49 } KMT_CALLBACK_INFORMATION_CLASS
, *PKMT_CALLBACK_INFORMATION_CLASS
;
51 /* TODO: "response" is a little generic */
52 typedef union _KMT_RESPONSE
54 MEMORY_BASIC_INFORMATION MemInfo
;
55 } KMT_RESPONSE
, *PKMT_RESPONSE
;
57 /* this struct is sent from driver to usermode */
58 typedef struct _KMT_CALLBACK_REQUEST_PACKET
61 KMT_CALLBACK_INFORMATION_CLASS OperationClass
;
63 } KMT_CALLBACK_REQUEST_PACKET
, *PKMT_CALLBACK_REQUEST_PACKET
;
65 PKMT_RESPONSE
KmtUserModeCallback(KMT_CALLBACK_INFORMATION_CLASS Operation
, PVOID Parameters
);
66 VOID
KmtFreeCallbackResponse(PKMT_RESPONSE Response
);
68 //macro to simplify using the mechanism
69 #define Test_NtQueryVirtualMemory(BaseAddress, Size, AllocationType, ProtectionType) \
71 PKMT_RESPONSE NtQueryTest = KmtUserModeCallback(QueryVirtualMemory, BaseAddress); \
72 if (NtQueryTest != NULL) \
74 ok_eq_hex(NtQueryTest->MemInfo.Protect, ProtectionType); \
75 ok_eq_hex(NtQueryTest->MemInfo.State, AllocationType); \
76 ok_eq_size(NtQueryTest->MemInfo.RegionSize, Size); \
77 KmtFreeCallbackResponse(NtQueryTest); \
83 #ifdef KMT_STANDALONE_DRIVER
84 #define KMT_KERNEL_MODE
86 typedef NTSTATUS (KMT_IRP_HANDLER
)(
87 IN PDEVICE_OBJECT DeviceObject
,
89 IN PIO_STACK_LOCATION IoStackLocation
);
90 typedef KMT_IRP_HANDLER
*PKMT_IRP_HANDLER
;
92 NTSTATUS
KmtRegisterIrpHandler(IN UCHAR MajorFunction
, IN PDEVICE_OBJECT DeviceObject OPTIONAL
, IN PKMT_IRP_HANDLER IrpHandler
);
93 NTSTATUS
KmtUnregisterIrpHandler(IN UCHAR MajorFunction
, IN PDEVICE_OBJECT DeviceObject OPTIONAL
, IN PKMT_IRP_HANDLER IrpHandler
);
95 typedef NTSTATUS (KMT_MESSAGE_HANDLER
)(
96 IN PDEVICE_OBJECT DeviceObject
,
98 IN PVOID Buffer OPTIONAL
,
100 IN OUT PSIZE_T OutLength
);
101 typedef KMT_MESSAGE_HANDLER
*PKMT_MESSAGE_HANDLER
;
103 NTSTATUS
KmtRegisterMessageHandler(IN ULONG ControlCode OPTIONAL
, IN PDEVICE_OBJECT DeviceObject OPTIONAL
, IN PKMT_MESSAGE_HANDLER MessageHandler
);
104 NTSTATUS
KmtUnregisterMessageHandler(IN ULONG ControlCode OPTIONAL
, IN PDEVICE_OBJECT DeviceObject OPTIONAL
, IN PKMT_MESSAGE_HANDLER MessageHandler
);
108 TESTENTRY_NO_CREATE_DEVICE
= 1,
109 TESTENTRY_NO_REGISTER_DISPATCH
= 2,
110 TESTENTRY_NO_REGISTER_UNLOAD
= 4,
111 TESTENTRY_NO_EXCLUSIVE_DEVICE
= 8,
112 TESTENTRY_NO_READONLY_DEVICE
= 16,
113 TESTENTRY_BUFFERED_IO_DEVICE
= 32,
114 } KMT_TESTENTRY_FLAGS
;
116 NTSTATUS
TestEntry(IN PDRIVER_OBJECT DriverObject
, IN PCUNICODE_STRING RegistryPath
, OUT PCWSTR
*DeviceName
, IN OUT INT
*Flags
);
117 VOID
TestUnload(IN PDRIVER_OBJECT DriverObject
);
118 #endif /* defined KMT_STANDALONE_DRIVER */
120 #ifdef KMT_KERNEL_MODE
121 /* Device Extension layout */
124 PKMT_RESULTBUFFER ResultBuffer
;
126 } KMT_DEVICE_EXTENSION
, *PKMT_DEVICE_EXTENSION
;
128 extern BOOLEAN KmtIsCheckedBuild
;
129 extern BOOLEAN KmtIsMultiProcessorBuild
;
130 extern PCSTR KmtMajorFunctionNames
[];
131 extern PDRIVER_OBJECT KmtDriverObject
;
133 VOID
KmtSetIrql(IN KIRQL NewIrql
);
134 BOOLEAN
KmtAreInterruptsEnabled(VOID
);
135 ULONG
KmtGetPoolTag(PVOID Memory
);
136 USHORT
KmtGetPoolType(PVOID Memory
);
137 PVOID
KmtGetSystemRoutineAddress(IN PCWSTR RoutineName
);
138 PKTHREAD
KmtStartThread(IN PKSTART_ROUTINE StartRoutine
, IN PVOID StartContext OPTIONAL
);
139 VOID
KmtFinishThread(IN PKTHREAD Thread OPTIONAL
, IN PKEVENT Event OPTIONAL
);
140 #elif defined KMT_USER_MODE
141 DWORD
KmtRunKernelTest(IN PCSTR TestName
);
143 VOID
KmtLoadDriver(IN PCWSTR ServiceName
, IN BOOLEAN RestartIfRunning
);
144 VOID
KmtUnloadDriver(VOID
);
145 VOID
KmtOpenDriver(VOID
);
146 VOID
KmtCloseDriver(VOID
);
148 DWORD
KmtSendToDriver(IN DWORD ControlCode
);
149 DWORD
KmtSendStringToDriver(IN DWORD ControlCode
, IN PCSTR String
);
150 DWORD
KmtSendWStringToDriver(IN DWORD ControlCode
, IN PCWSTR String
);
151 DWORD
KmtSendUlongToDriver(IN DWORD ControlCode
, IN DWORD Value
);
152 DWORD
KmtSendBufferToDriver(IN DWORD ControlCode
, IN OUT PVOID Buffer OPTIONAL
, IN DWORD InLength
, IN OUT PDWORD OutLength
);
153 #else /* if !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
154 #error either KMT_KERNEL_MODE or KMT_USER_MODE must be defined
155 #endif /* !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
157 extern PKMT_RESULTBUFFER ResultBuffer
;
160 /* TODO: GCC doesn't understand %wZ :( */
161 #define KMT_FORMAT(type, fmt, first) /*__attribute__((__format__(type, fmt, first)))*/
162 #elif !defined __GNUC__
163 #define KMT_FORMAT(type, fmt, first)
164 #endif /* !defined __GNUC__ */
166 #define START_TEST(name) VOID Test_##name(VOID)
168 #ifndef KMT_STRINGIZE
169 #define KMT_STRINGIZE(x) #x
170 #endif /* !defined KMT_STRINGIZE */
171 #define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
172 #define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
173 #define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__)
175 #define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
176 #define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
177 #define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
179 BOOLEAN
KmtVOk(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, va_list Arguments
) KMT_FORMAT(ms_printf
, 3, 0);
180 BOOLEAN
KmtOk(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, ...) KMT_FORMAT(ms_printf
, 3, 4);
181 VOID
KmtVTrace(PCSTR FileAndLine
, PCSTR Format
, va_list Arguments
) KMT_FORMAT(ms_printf
, 2, 0);
182 VOID
KmtTrace(PCSTR FileAndLine
, PCSTR Format
, ...) KMT_FORMAT(ms_printf
, 2, 3);
183 BOOLEAN
KmtVSkip(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, va_list Arguments
) KMT_FORMAT(ms_printf
, 3, 0);
184 BOOLEAN
KmtSkip(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, ...) KMT_FORMAT(ms_printf
, 3, 4);
185 PVOID
KmtAllocateGuarded(SIZE_T SizeRequested
);
186 VOID
KmtFreeGuarded(PVOID Pointer
);
188 #ifdef KMT_KERNEL_MODE
189 #define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
190 #endif /* defined KMT_KERNEL_MODE */
191 #define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
192 #define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
193 #define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
194 #define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
195 #define ok_eq_long(value, expected) ok_eq_print(value, expected, "%ld")
196 #define ok_eq_ulong(value, expected) ok_eq_print(value, expected, "%lu")
197 #define ok_eq_longlong(value, expected) ok_eq_print(value, expected, "%I64d")
198 #define ok_eq_ulonglong(value, expected) ok_eq_print(value, expected, "%I64u")
199 #define ok_eq_char(value, expected) ok_eq_print(value, expected, "%c")
200 #define ok_eq_wchar(value, expected) ok_eq_print(value, expected, "%C")
202 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%lu")
203 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%ld")
204 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%lu")
206 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%I64u")
207 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%I64d")
208 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%I64u")
209 #endif /* defined _WIN64 */
210 #define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
211 #define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
212 #define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
213 #define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
214 (value) ? "TRUE" : "FALSE", \
215 (expected) ? "TRUE" : "FALSE")
216 #define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
217 #define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
218 #define ok_eq_tag(value, expected) ok_eq_print(value, expected, "0x%08lx")
220 #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
221 0xC00 + (ControlCode), \
225 #define MICROSECOND 10
226 #define MILLISECOND (1000 * MICROSECOND)
227 #define SECOND (1000 * MILLISECOND)
229 /* See apitests/include/apitest.h */
230 #define KmtInvalidPointer ((PVOID)0x5555555555555555ULL)
232 #define KmtStartSeh() \
234 NTSTATUS ExceptionStatus = STATUS_SUCCESS; \
238 #define KmtEndSeh(ExpectedStatus) \
240 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) \
242 ExceptionStatus = _SEH2_GetExceptionCode(); \
245 ok_eq_hex(ExceptionStatus, (ExpectedStatus)); \
248 #define KmtGetSystemOrEmbeddedRoutineAddress(RoutineName) \
249 p##RoutineName = KmtGetSystemRoutineAddress(L ## #RoutineName); \
250 if (!p##RoutineName) \
252 p##RoutineName = RoutineName; \
253 trace("Using embedded routine for " #RoutineName "\n"); \
256 trace("Using system routine for " #RoutineName "\n");
258 #if defined KMT_DEFINE_TEST_FUNCTIONS
260 #if defined KMT_KERNEL_MODE
261 #include "kmt_test_kernel.h"
262 #elif defined KMT_USER_MODE
263 #include "kmt_test_user.h"
264 #endif /* defined KMT_USER_MODE */
266 PKMT_RESULTBUFFER ResultBuffer
= NULL
;
268 static VOID
KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer
, PCSTR String
, SIZE_T Length
)
278 OldLength
= Buffer
->LogBufferLength
;
279 NewLength
= OldLength
+ (ULONG
)Length
;
280 if (NewLength
> Buffer
->LogBufferMaxLength
)
282 } while (InterlockedCompareExchange(&Buffer
->LogBufferLength
, NewLength
, OldLength
) != OldLength
);
284 memcpy(&Buffer
->LogBuffer
[OldLength
], String
, Length
);
287 KMT_FORMAT(ms_printf
, 5, 0)
288 static SIZE_T
KmtXVSNPrintF(PSTR Buffer
, SIZE_T BufferMaxLength
, PCSTR FileAndLine
, PCSTR Prepend
, PCSTR Format
, va_list Arguments
)
290 SIZE_T BufferLength
= 0;
296 Slash
= strrchr(FileAndLine
, '\\');
298 FileAndLine
= Slash
+ 1;
299 Slash
= strrchr(FileAndLine
, '/');
301 FileAndLine
= Slash
+ 1;
303 Length
= min(BufferMaxLength
, strlen(FileAndLine
));
304 memcpy(Buffer
, FileAndLine
, Length
);
306 BufferLength
+= Length
;
307 BufferMaxLength
-= Length
;
311 Length
= min(BufferMaxLength
, strlen(Prepend
));
312 memcpy(Buffer
, Prepend
, Length
);
314 BufferLength
+= Length
;
315 BufferMaxLength
-= Length
;
319 Length
= KmtVSNPrintF(Buffer
, BufferMaxLength
, Format
, Arguments
);
320 /* vsnprintf can return more than maxLength, we don't want to do that */
321 BufferLength
+= min(Length
, BufferMaxLength
);
326 KMT_FORMAT(ms_printf
, 5, 6)
327 static SIZE_T
KmtXSNPrintF(PSTR Buffer
, SIZE_T BufferMaxLength
, PCSTR FileAndLine
, PCSTR Prepend
, PCSTR Format
, ...)
331 va_start(Arguments
, Format
);
332 BufferLength
= KmtXVSNPrintF(Buffer
, BufferMaxLength
, FileAndLine
, Prepend
, Format
, Arguments
);
337 VOID
KmtFinishTest(PCSTR TestName
)
339 CHAR MessageBuffer
[512];
340 SIZE_T MessageLength
;
345 MessageLength
= KmtXSNPrintF(MessageBuffer
, sizeof MessageBuffer
, NULL
, NULL
,
346 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
348 ResultBuffer
->Successes
+ ResultBuffer
->Failures
,
349 ResultBuffer
->Failures
,
350 ResultBuffer
->Skipped
);
351 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
354 BOOLEAN
KmtVOk(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, va_list Arguments
)
356 CHAR MessageBuffer
[512];
357 SIZE_T MessageLength
;
360 return Condition
!= 0;
364 InterlockedIncrement(&ResultBuffer
->Successes
);
366 if (0/*KmtReportSuccess*/)
368 MessageLength
= KmtXSNPrintF(MessageBuffer
, sizeof MessageBuffer
, FileAndLine
, ": Test succeeded\n", NULL
);
369 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
374 InterlockedIncrement(&ResultBuffer
->Failures
);
375 MessageLength
= KmtXVSNPrintF(MessageBuffer
, sizeof MessageBuffer
, FileAndLine
, ": Test failed: ", Format
, Arguments
);
376 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
379 return Condition
!= 0;
382 BOOLEAN
KmtOk(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, ...)
386 va_start(Arguments
, Format
);
387 Ret
= KmtVOk(Condition
, FileAndLine
, Format
, Arguments
);
392 VOID
KmtVTrace(PCSTR FileAndLine
, PCSTR Format
, va_list Arguments
)
394 CHAR MessageBuffer
[512];
395 SIZE_T MessageLength
;
397 MessageLength
= KmtXVSNPrintF(MessageBuffer
, sizeof MessageBuffer
, FileAndLine
, ": ", Format
, Arguments
);
398 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
401 VOID
KmtTrace(PCSTR FileAndLine
, PCSTR Format
, ...)
404 va_start(Arguments
, Format
);
405 KmtVTrace(FileAndLine
, Format
, Arguments
);
409 BOOLEAN
KmtVSkip(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, va_list Arguments
)
411 CHAR MessageBuffer
[512];
412 SIZE_T MessageLength
;
419 InterlockedIncrement(&ResultBuffer
->Skipped
);
420 MessageLength
= KmtXVSNPrintF(MessageBuffer
, sizeof MessageBuffer
, FileAndLine
, ": Tests skipped: ", Format
, Arguments
);
421 KmtAddToLogBuffer(ResultBuffer
, MessageBuffer
, MessageLength
);
427 BOOLEAN
KmtSkip(INT Condition
, PCSTR FileAndLine
, PCSTR Format
, ...)
431 va_start(Arguments
, Format
);
432 Ret
= KmtVSkip(Condition
, FileAndLine
, Format
, Arguments
);
437 PVOID
KmtAllocateGuarded(SIZE_T SizeRequested
)
440 SIZE_T Size
= PAGE_ROUND_UP(SizeRequested
+ PAGE_SIZE
);
441 PVOID VirtualMemory
= NULL
;
444 Status
= ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory
, 0, &Size
, MEM_RESERVE
, PAGE_NOACCESS
);
446 if (!NT_SUCCESS(Status
))
450 Status
= ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory
, 0, &Size
, MEM_COMMIT
, PAGE_READWRITE
);
451 if (!NT_SUCCESS(Status
))
454 Status
= ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory
, &Size
, MEM_RELEASE
);
455 ok_eq_hex(Status
, STATUS_SUCCESS
);
459 StartOfBuffer
= VirtualMemory
;
460 StartOfBuffer
+= Size
- SizeRequested
;
462 return StartOfBuffer
;
465 VOID
KmtFreeGuarded(PVOID Pointer
)
468 PVOID VirtualMemory
= (PVOID
)PAGE_ROUND_DOWN((SIZE_T
)Pointer
);
471 Status
= ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory
, &Size
, MEM_RELEASE
);
472 ok_eq_hex(Status
, STATUS_SUCCESS
);
475 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
477 #endif /* !defined _KMTEST_TEST_H_ */