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