Partial merge of condrv_restructure branch r65657.
[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 <thomas.faber@reactos.org>
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 #ifndef KMT_STANDALONE_DRIVER
42
43 /* usermode call-back mechanism */
44
45 /* list of supported operations */
46 typedef enum _KMT_CALLBACK_INFORMATION_CLASS
47 {
48 QueryVirtualMemory
49 } KMT_CALLBACK_INFORMATION_CLASS, *PKMT_CALLBACK_INFORMATION_CLASS;
50
51 /* TODO: "response" is a little generic */
52 typedef union _KMT_RESPONSE
53 {
54 MEMORY_BASIC_INFORMATION MemInfo;
55 } KMT_RESPONSE, *PKMT_RESPONSE;
56
57 /* this struct is sent from driver to usermode */
58 typedef struct _KMT_CALLBACK_REQUEST_PACKET
59 {
60 ULONG RequestId;
61 KMT_CALLBACK_INFORMATION_CLASS OperationClass;
62 PVOID Parameters;
63 } KMT_CALLBACK_REQUEST_PACKET, *PKMT_CALLBACK_REQUEST_PACKET;
64
65 PKMT_RESPONSE KmtUserModeCallback(KMT_CALLBACK_INFORMATION_CLASS Operation, PVOID Parameters);
66 VOID KmtFreeCallbackResponse(PKMT_RESPONSE Response);
67
68 //macro to simplify using the mechanism
69 #define Test_NtQueryVirtualMemory(BaseAddress, Size, AllocationType, ProtectionType) \
70 do { \
71 PKMT_RESPONSE NtQueryTest = KmtUserModeCallback(QueryVirtualMemory, BaseAddress); \
72 if (NtQueryTest != NULL) \
73 { \
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); \
78 } \
79 } while (0) \
80
81 #endif
82
83 #ifdef KMT_STANDALONE_DRIVER
84 #define KMT_KERNEL_MODE
85
86 typedef NTSTATUS (KMT_IRP_HANDLER)(
87 IN PDEVICE_OBJECT DeviceObject,
88 IN PIRP Irp,
89 IN PIO_STACK_LOCATION IoStackLocation);
90 typedef KMT_IRP_HANDLER *PKMT_IRP_HANDLER;
91
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);
94
95 typedef NTSTATUS (KMT_MESSAGE_HANDLER)(
96 IN PDEVICE_OBJECT DeviceObject,
97 IN ULONG ControlCode,
98 IN PVOID Buffer OPTIONAL,
99 IN SIZE_T InLength,
100 IN OUT PSIZE_T OutLength);
101 typedef KMT_MESSAGE_HANDLER *PKMT_MESSAGE_HANDLER;
102
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);
105
106 typedef enum
107 {
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 } KMT_TESTENTRY_FLAGS;
113
114 NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryPath, OUT PCWSTR *DeviceName, IN OUT INT *Flags);
115 VOID TestUnload(IN PDRIVER_OBJECT DriverObject);
116 #endif /* defined KMT_STANDALONE_DRIVER */
117
118 #ifdef KMT_KERNEL_MODE
119 /* Device Extension layout */
120 typedef struct
121 {
122 PKMT_RESULTBUFFER ResultBuffer;
123 PMDL Mdl;
124 } KMT_DEVICE_EXTENSION, *PKMT_DEVICE_EXTENSION;
125
126 extern BOOLEAN KmtIsCheckedBuild;
127 extern BOOLEAN KmtIsMultiProcessorBuild;
128 extern PCSTR KmtMajorFunctionNames[];
129 extern PDRIVER_OBJECT KmtDriverObject;
130
131 VOID KmtSetIrql(IN KIRQL NewIrql);
132 BOOLEAN KmtAreInterruptsEnabled(VOID);
133 ULONG KmtGetPoolTag(PVOID Memory);
134 USHORT KmtGetPoolType(PVOID Memory);
135 PKTHREAD KmtStartThread(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext OPTIONAL);
136 VOID KmtFinishThread(IN PKTHREAD Thread OPTIONAL, IN PKEVENT Event OPTIONAL);
137 #elif defined KMT_USER_MODE
138 DWORD KmtRunKernelTest(IN PCSTR TestName);
139
140 VOID KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
141 VOID KmtUnloadDriver(VOID);
142 VOID KmtOpenDriver(VOID);
143 VOID KmtCloseDriver(VOID);
144
145 DWORD KmtSendToDriver(IN DWORD ControlCode);
146 DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
147 DWORD KmtSendWStringToDriver(IN DWORD ControlCode, IN PCWSTR String);
148 DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer OPTIONAL, IN DWORD InLength, IN OUT PDWORD OutLength);
149 #else /* if !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
150 #error either KMT_KERNEL_MODE or KMT_USER_MODE must be defined
151 #endif /* !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
152
153 extern PKMT_RESULTBUFFER ResultBuffer;
154
155 #ifdef __GNUC__
156 /* TODO: GCC doesn't understand %wZ :( */
157 #define KMT_FORMAT(type, fmt, first) /*__attribute__((__format__(type, fmt, first)))*/
158 #elif !defined __GNUC__
159 #define KMT_FORMAT(type, fmt, first)
160 #endif /* !defined __GNUC__ */
161
162 #define START_TEST(name) VOID Test_##name(VOID)
163
164 #ifndef KMT_STRINGIZE
165 #define KMT_STRINGIZE(x) #x
166 #endif /* !defined KMT_STRINGIZE */
167 #define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
168 #define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
169 #define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__)
170
171 #define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
172 #define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
173 #define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
174
175 BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
176 BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
177 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 2, 0);
178 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 2, 3);
179 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
180 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
181 PVOID KmtAllocateGuarded(SIZE_T SizeRequested);
182 VOID KmtFreeGuarded(PVOID Pointer);
183
184 #ifdef KMT_KERNEL_MODE
185 #define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
186 #endif /* defined KMT_KERNEL_MODE */
187 #define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
188 #define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
189 #define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
190 #define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
191 #define ok_eq_long(value, expected) ok_eq_print(value, expected, "%ld")
192 #define ok_eq_ulong(value, expected) ok_eq_print(value, expected, "%lu")
193 #define ok_eq_longlong(value, expected) ok_eq_print(value, expected, "%I64d")
194 #define ok_eq_ulonglong(value, expected) ok_eq_print(value, expected, "%I64u")
195 #define ok_eq_char(value, expected) ok_eq_print(value, expected, "%c")
196 #define ok_eq_wchar(value, expected) ok_eq_print(value, expected, "%C")
197 #ifndef _WIN64
198 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%lu")
199 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%ld")
200 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%lu")
201 #elif defined _WIN64
202 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%I64u")
203 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%I64d")
204 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%I64u")
205 #endif /* defined _WIN64 */
206 #define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
207 #define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
208 #define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
209 #define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
210 (value) ? "TRUE" : "FALSE", \
211 (expected) ? "TRUE" : "FALSE")
212 #define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
213 #define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
214 #define ok_eq_tag(value, expected) ok_eq_print(value, expected, "0x%08lx")
215
216 #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
217 0xC00 + (ControlCode), \
218 METHOD_BUFFERED, \
219 FILE_ANY_ACCESS)
220
221 #define MICROSECOND 10
222 #define MILLISECOND (1000 * MICROSECOND)
223 #define SECOND (1000 * MILLISECOND)
224
225 /* See apitests/include/apitest.h */
226 #define KmtInvalidPointer ((PVOID)0x5555555555555555ULL)
227
228 #define KmtStartSeh() \
229 { \
230 NTSTATUS ExceptionStatus = STATUS_SUCCESS; \
231 _SEH2_TRY \
232 {
233
234 #define KmtEndSeh(ExpectedStatus) \
235 } \
236 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) \
237 { \
238 ExceptionStatus = _SEH2_GetExceptionCode(); \
239 } \
240 _SEH2_END; \
241 ok_eq_hex(ExceptionStatus, (ExpectedStatus)); \
242 }
243
244 #if defined KMT_DEFINE_TEST_FUNCTIONS
245
246 #if defined KMT_KERNEL_MODE
247 #include "kmt_test_kernel.h"
248 #elif defined KMT_USER_MODE
249 #include "kmt_test_user.h"
250 #endif /* defined KMT_USER_MODE */
251
252 PKMT_RESULTBUFFER ResultBuffer = NULL;
253
254 static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
255 {
256 LONG OldLength;
257 LONG NewLength;
258
259 if (!Buffer)
260 return;
261
262 do
263 {
264 OldLength = Buffer->LogBufferLength;
265 NewLength = OldLength + (ULONG)Length;
266 if (NewLength > Buffer->LogBufferMaxLength)
267 return;
268 } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
269
270 memcpy(&Buffer->LogBuffer[OldLength], String, Length);
271 }
272
273 KMT_FORMAT(ms_printf, 5, 0)
274 static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
275 {
276 SIZE_T BufferLength = 0;
277 SIZE_T Length;
278
279 if (FileAndLine)
280 {
281 PCSTR Slash;
282 Slash = strrchr(FileAndLine, '\\');
283 if (Slash)
284 FileAndLine = Slash + 1;
285 Slash = strrchr(FileAndLine, '/');
286 if (Slash)
287 FileAndLine = Slash + 1;
288
289 Length = min(BufferMaxLength, strlen(FileAndLine));
290 memcpy(Buffer, FileAndLine, Length);
291 Buffer += Length;
292 BufferLength += Length;
293 BufferMaxLength -= Length;
294 }
295 if (Prepend)
296 {
297 Length = min(BufferMaxLength, strlen(Prepend));
298 memcpy(Buffer, Prepend, Length);
299 Buffer += Length;
300 BufferLength += Length;
301 BufferMaxLength -= Length;
302 }
303 if (Format)
304 {
305 Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
306 /* vsnprintf can return more than maxLength, we don't want to do that */
307 BufferLength += min(Length, BufferMaxLength);
308 }
309 return BufferLength;
310 }
311
312 KMT_FORMAT(ms_printf, 5, 6)
313 static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
314 {
315 SIZE_T BufferLength;
316 va_list Arguments;
317 va_start(Arguments, Format);
318 BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
319 va_end(Arguments);
320 return BufferLength;
321 }
322
323 VOID KmtFinishTest(PCSTR TestName)
324 {
325 CHAR MessageBuffer[512];
326 SIZE_T MessageLength;
327
328 if (!ResultBuffer)
329 return;
330
331 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
332 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
333 TestName,
334 ResultBuffer->Successes + ResultBuffer->Failures,
335 ResultBuffer->Failures,
336 ResultBuffer->Skipped);
337 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
338 }
339
340 BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
341 {
342 CHAR MessageBuffer[512];
343 SIZE_T MessageLength;
344
345 if (!ResultBuffer)
346 return Condition != 0;
347
348 if (Condition)
349 {
350 InterlockedIncrement(&ResultBuffer->Successes);
351
352 if (0/*KmtReportSuccess*/)
353 {
354 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
355 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
356 }
357 }
358 else
359 {
360 InterlockedIncrement(&ResultBuffer->Failures);
361 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
362 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
363 }
364
365 return Condition != 0;
366 }
367
368 BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
369 {
370 BOOLEAN Ret;
371 va_list Arguments;
372 va_start(Arguments, Format);
373 Ret = KmtVOk(Condition, FileAndLine, Format, Arguments);
374 va_end(Arguments);
375 return Ret;
376 }
377
378 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
379 {
380 CHAR MessageBuffer[512];
381 SIZE_T MessageLength;
382
383 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
384 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
385 }
386
387 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
388 {
389 va_list Arguments;
390 va_start(Arguments, Format);
391 KmtVTrace(FileAndLine, Format, Arguments);
392 va_end(Arguments);
393 }
394
395 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
396 {
397 CHAR MessageBuffer[512];
398 SIZE_T MessageLength;
399
400 if (!ResultBuffer)
401 return !Condition;
402
403 if (!Condition)
404 {
405 InterlockedIncrement(&ResultBuffer->Skipped);
406 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
407 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
408 }
409
410 return !Condition;
411 }
412
413 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
414 {
415 BOOLEAN Ret;
416 va_list Arguments;
417 va_start(Arguments, Format);
418 Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
419 va_end(Arguments);
420 return Ret;
421 }
422
423 PVOID KmtAllocateGuarded(SIZE_T SizeRequested)
424 {
425 NTSTATUS Status;
426 SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
427 PVOID VirtualMemory = NULL;
428 PCHAR StartOfBuffer;
429
430 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
431
432 if (!NT_SUCCESS(Status))
433 return NULL;
434
435 Size -= PAGE_SIZE;
436 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
437 if (!NT_SUCCESS(Status))
438 {
439 Size = 0;
440 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
441 ok_eq_hex(Status, STATUS_SUCCESS);
442 return NULL;
443 }
444
445 StartOfBuffer = VirtualMemory;
446 StartOfBuffer += Size - SizeRequested;
447
448 return StartOfBuffer;
449 }
450
451 VOID KmtFreeGuarded(PVOID Pointer)
452 {
453 NTSTATUS Status;
454 PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
455 SIZE_T Size = 0;
456
457 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
458 ok_eq_hex(Status, STATUS_SUCCESS);
459 }
460
461 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
462
463 #endif /* !defined _KMTEST_TEST_H_ */