[KMTESTS]
[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 <stdarg.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_KERNEL_MODE
42 /* Device Extension layout */
43 typedef struct
44 {
45 PKMT_RESULTBUFFER ResultBuffer;
46 PMDL Mdl;
47 } KMT_DEVICE_EXTENSION, *PKMT_DEVICE_EXTENSION;
48 #elif defined KMT_USER_MODE
49 VOID KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
50 VOID KmtUnloadDriver(VOID);
51 VOID KmtOpenDriver(VOID);
52 VOID KmtCloseDriver(VOID);
53
54 DWORD KmtSendToDriver(IN DWORD ControlCode);
55 DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
56 DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer, IN OUT PDWORD Length);
57 #endif /* defined KMT_USER_MODE */
58
59 extern PKMT_RESULTBUFFER ResultBuffer;
60
61 #ifdef __GNUC__
62 #define KMT_FORMAT(type, fmt, first) __attribute__((__format__(type, fmt, first)))
63 #elif !defined __GNUC__
64 #define KMT_FORMAT(type, fmt, first)
65 #endif /* !defined __GNUC__ */
66
67 #define START_TEST(name) VOID Test_##name(VOID)
68
69 #ifndef KMT_STRINGIZE
70 #define KMT_STRINGIZE(x) #x
71 #endif /* !defined KMT_STRINGIZE */
72 #define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
73 #define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
74 #define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__)
75
76 #define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
77 #define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
78 #define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
79
80 VOID KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
81 VOID KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
82 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 2, 0);
83 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 2, 3);
84 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
85 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
86
87 #ifdef KMT_KERNEL_MODE
88 #define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
89 #endif /* defined KMT_KERNEL_MODE */
90 #define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
91 #define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
92 #define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
93 #define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
94 #define ok_eq_long(value, expected) ok_eq_print(value, expected, "%ld")
95 #define ok_eq_ulong(value, expected) ok_eq_print(value, expected, "%lu")
96 #define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
97 #define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
98 #define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
99 #define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
100 (value) ? "TRUE" : "FALSE", \
101 (expected) ? "TRUE" : "FALSE")
102 #define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
103 #define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
104
105 #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
106 0xA00 + (ControlCode), \
107 METHOD_BUFFERED, \
108 FILE_ANY_ACCESS)
109
110 #if defined KMT_DEFINE_TEST_FUNCTIONS
111 PKMT_RESULTBUFFER ResultBuffer = NULL;
112
113 #if defined KMT_USER_MODE
114 static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T LogBufferMaxLength)
115 {
116 PKMT_RESULTBUFFER Buffer = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer[LogBufferMaxLength]));
117
118 Buffer->Successes = 0;
119 Buffer->Failures = 0;
120 Buffer->Skipped = 0;
121 Buffer->LogBufferLength = 0;
122 Buffer->LogBufferMaxLength = LogBufferMaxLength;
123
124 return Buffer;
125 }
126
127 static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
128 {
129 HeapFree(GetProcessHeap(), 0, Buffer);
130 }
131 #endif /* defined KMT_USER_MODE */
132
133 static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
134 {
135 LONG OldLength;
136 LONG NewLength;
137
138 if (!Buffer)
139 return;
140
141 do
142 {
143 OldLength = Buffer->LogBufferLength;
144 NewLength = OldLength + Length;
145 if (NewLength > Buffer->LogBufferMaxLength)
146 {
147 /* TODO: indicate failure somehow */
148 __debugbreak();
149 return;
150 }
151 } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
152
153 memcpy(&Buffer->LogBuffer[OldLength], String, Length);
154 }
155
156 #ifdef KMT_KERNEL_MODE
157 INT __cdecl KmtVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
158 #elif defined KMT_USER_MODE
159 #define KmtVSNPrintF vsnprintf
160 #endif /* defined KMT_USER_MODE */
161
162 KMT_FORMAT(ms_printf, 5, 0)
163 static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
164 {
165 SIZE_T BufferLength = 0;
166 SIZE_T Length;
167
168 if (FileAndLine)
169 {
170 PCSTR Slash;
171 Slash = strrchr(FileAndLine, '\\');
172 if (Slash)
173 FileAndLine = Slash + 1;
174 Slash = strrchr(FileAndLine, '/');
175 if (Slash)
176 FileAndLine = Slash + 1;
177
178 Length = min(BufferMaxLength, strlen(FileAndLine));
179 memcpy(Buffer, FileAndLine, Length);
180 Buffer += Length;
181 BufferLength += Length;
182 BufferMaxLength -= Length;
183 }
184 if (Prepend)
185 {
186 Length = min(BufferMaxLength, strlen(Prepend));
187 memcpy(Buffer, Prepend, Length);
188 Buffer += Length;
189 BufferLength += Length;
190 BufferMaxLength -= Length;
191 }
192 if (Format)
193 {
194 Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
195 /* vsnprintf can return more than maxLength, we don't want to do that */
196 BufferLength += min(Length, BufferMaxLength);
197 }
198 return BufferLength;
199 }
200
201 KMT_FORMAT(ms_printf, 5, 6)
202 static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
203 {
204 SIZE_T BufferLength;
205 va_list Arguments;
206 va_start(Arguments, Format);
207 BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
208 va_end(Arguments);
209 return BufferLength;
210 }
211
212 VOID KmtFinishTest(PCSTR TestName)
213 {
214 CHAR MessageBuffer[512];
215 SIZE_T MessageLength;
216
217 if (!ResultBuffer)
218 return;
219
220 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
221 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
222 TestName,
223 ResultBuffer->Successes + ResultBuffer->Failures,
224 ResultBuffer->Failures,
225 ResultBuffer->Skipped);
226 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
227 }
228
229 VOID KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
230 {
231 CHAR MessageBuffer[512];
232 SIZE_T MessageLength;
233
234 if (!ResultBuffer)
235 return;
236
237 if (Condition)
238 {
239 InterlockedIncrement(&ResultBuffer->Successes);
240
241 if (0/*KmtReportSuccess*/)
242 {
243 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
244 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
245 }
246 }
247 else
248 {
249 InterlockedIncrement(&ResultBuffer->Failures);
250 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
251 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
252 }
253 }
254
255 VOID KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
256 {
257 va_list Arguments;
258 va_start(Arguments, Format);
259 KmtVOk(Condition, FileAndLine, Format, Arguments);
260 va_end(Arguments);
261 }
262
263 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
264 {
265 CHAR MessageBuffer[512];
266 SIZE_T MessageLength;
267
268 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
269 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
270 }
271
272 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
273 {
274 va_list Arguments;
275 va_start(Arguments, Format);
276 KmtVTrace(FileAndLine, Format, Arguments);
277 va_end(Arguments);
278 }
279
280 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
281 {
282 CHAR MessageBuffer[512];
283 SIZE_T MessageLength;
284
285 if (!ResultBuffer)
286 return !Condition;
287
288 if (!Condition)
289 {
290 InterlockedIncrement(&ResultBuffer->Skipped);
291 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
292 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
293 }
294
295 return !Condition;
296 }
297
298 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
299 {
300 BOOLEAN Ret;
301 va_list Arguments;
302 va_start(Arguments, Format);
303 Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
304 va_end(Arguments);
305 return Ret;
306 }
307
308 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
309
310 #endif /* !defined _KMTEST_TEST_H_ */