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