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