2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Loader Application
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
8 #define KMT_DEFINE_TEST_FUNCTIONS
12 #include <kmt_public.h>
18 #define SERVICE_NAME L"Kmtest"
19 #define SERVICE_PATH L"kmtest_drv.sys"
20 #define SERVICE_DESCRIPTION L"ReactOS Kernel-Mode Test Suite Driver"
22 #define RESULTBUFFER_SIZE (1024 * 1024)
33 SC_HANDLE KmtestServiceHandle
;
34 PCSTR ErrorFileAndLine
= "No error";
36 static void OutputError(IN DWORD Error
);
37 static DWORD
ListTests(IN BOOLEAN IncludeHidden
);
38 static PKMT_TESTFUNC
FindTest(IN PCSTR TestName
);
39 static DWORD
OutputResult(IN PCSTR TestName
);
40 static DWORD
RunTest(IN PCSTR TestName
);
41 int __cdecl
main(int ArgCount
, char **Arguments
);
46 * Output an error message to the console.
57 if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
| FORMAT_MESSAGE_ALLOCATE_BUFFER
,
58 NULL
, Error
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), (LPSTR
)&Message
, 0, NULL
))
60 fprintf(stderr
, "%s: Could not retrieve error message (error 0x%08lx). Original error: 0x%08lx\n",
61 ErrorFileAndLine
, GetLastError(), Error
);
65 fprintf(stderr
, "%s: error 0x%08lx: %s\n", ErrorFileAndLine
, Error
, Message
);
71 * @name CompareTestNames
73 * strcmp that skips a leading '-' on either string if present
89 while (*Str1
&& *Str1
== *Str2
)
100 * Output the list of tests to the console.
101 * The list will comprise tests as listed by the driver
102 * in addition to user-mode tests in TestList.
104 * @param IncludeHidden
105 * TRUE to include "hidden" tests prefixed with a '-'
107 * @return Win32 error code
112 IN BOOLEAN IncludeHidden
)
114 DWORD Error
= ERROR_SUCCESS
;
117 PCSTR TestName
= Buffer
;
118 PCKMT_TEST TestEntry
= TestList
;
121 puts("Valid test names:");
123 // get test list from driver
124 if (!DeviceIoControl(KmtestHandle
, IOCTL_KMTEST_GET_TESTS
, NULL
, 0, Buffer
, sizeof Buffer
, &BytesRead
, NULL
))
125 error_goto(Error
, cleanup
);
127 // output test list plus user-mode tests
128 while (TestEntry
->TestName
|| *TestName
)
130 if (!TestEntry
->TestName
)
132 NextTestName
= TestName
;
133 TestName
+= strlen(TestName
) + 1;
137 NextTestName
= TestEntry
->TestName
;
142 INT Result
= CompareTestNames(TestEntry
->TestName
, TestName
);
146 NextTestName
= TestEntry
->TestName
;
147 TestName
+= strlen(TestName
) + 1;
152 NextTestName
= TestEntry
->TestName
;
157 NextTestName
= TestName
;
158 TestName
+= strlen(TestName
) + 1;
162 if (IncludeHidden
&& NextTestName
[0] == '-')
165 if (NextTestName
[0] != '-')
166 printf(" %s\n", NextTestName
);
176 * Find a test in TestList by name.
179 * Name of the test to look for. Case sensitive
181 * @return pointer to test function, or NULL if not found
188 PCKMT_TEST TestEntry
= TestList
;
190 for (TestEntry
= TestList
; TestEntry
->TestName
; ++TestEntry
)
192 PCSTR TestEntryName
= TestEntry
->TestName
;
194 // skip leading '-' if present
195 if (*TestEntryName
== '-')
198 if (!lstrcmpA(TestEntryName
, TestName
))
202 return TestEntry
->TestFunction
;
208 * Output the test results in ResultBuffer to the console.
211 * Name of the test whose result is to be printed
213 * @return Win32 error code
220 DWORD Error
= ERROR_SUCCESS
;
222 DWORD LogBufferLength
;
224 /* A console window can't handle a single
225 * huge block of data, so split it up */
226 const DWORD BlockSize
= 8 * 1024;
228 KmtFinishTest(TestName
);
230 LogBufferLength
= ResultBuffer
->LogBufferLength
;
231 for (Offset
= 0; Offset
< LogBufferLength
; Offset
+= BlockSize
)
233 DWORD Length
= min(LogBufferLength
- Offset
, BlockSize
);
234 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE
), ResultBuffer
->LogBuffer
+ Offset
, Length
, &BytesWritten
, NULL
))
244 * Run the named test and output its results.
247 * Name of the test to run. Case sensitive
249 * @return Win32 error code
256 DWORD Error
= ERROR_SUCCESS
;
257 PKMT_TESTFUNC TestFunction
;
260 assert(TestName
!= NULL
);
264 ResultBuffer
= KmtAllocateResultBuffer(RESULTBUFFER_SIZE
);
266 error_goto(Error
, cleanup
);
267 if (!DeviceIoControl(KmtestHandle
, IOCTL_KMTEST_SET_RESULTBUFFER
, ResultBuffer
, RESULTBUFFER_SIZE
, NULL
, 0, &BytesRead
, NULL
))
268 error_goto(Error
, cleanup
);
272 TestFunction
= FindTest(TestName
);
280 // not found in user-mode test list, call driver
281 Error
= KmtRunKernelTest(TestName
);
285 Error
= OutputResult(TestName
);
293 * Program entry point
298 * @return EXIT_SUCCESS on success, EXIT_FAILURE on failure
305 INT Status
= EXIT_SUCCESS
;
306 DWORD Error
= ERROR_SUCCESS
;
307 PCSTR AppName
= "kmtest.exe";
308 PCSTR TestName
= NULL
;
309 KMT_OPERATION Operation
= KMT_DO_NOTHING
;
310 BOOLEAN ShowHidden
= FALSE
;
312 Error
= KmtServiceInit();
317 AppName
= Arguments
[0];
321 printf("Usage: %s <test_name> - run the specified test (creates/starts the driver(s) as appropriate)\n", AppName
);
322 printf(" %s --list - list available tests\n", AppName
);
323 printf(" %s --list-all - list available tests, including hidden\n", AppName
);
324 printf(" %s <create|delete|start|stop> - manage the kmtest driver\n\n", AppName
);
325 Operation
= KMT_LIST_TESTS
;
329 TestName
= Arguments
[1];
330 if (!lstrcmpA(TestName
, "create"))
331 Error
= KmtCreateService(SERVICE_NAME
, SERVICE_PATH
, SERVICE_DESCRIPTION
, &KmtestServiceHandle
);
332 else if (!lstrcmpA(TestName
, "delete"))
333 Error
= KmtDeleteService(SERVICE_NAME
, &KmtestServiceHandle
);
334 else if (!lstrcmpA(TestName
, "start"))
335 Error
= KmtStartService(SERVICE_NAME
, &KmtestServiceHandle
);
336 else if (!lstrcmpA(TestName
, "stop"))
337 Error
= KmtStopService(SERVICE_NAME
, &KmtestServiceHandle
);
339 else if (!lstrcmpA(TestName
, "--list"))
340 Operation
= KMT_LIST_TESTS
;
341 else if (!lstrcmpA(TestName
, "--list-all"))
342 Operation
= KMT_LIST_ALL_TESTS
;
344 Operation
= KMT_RUN_TEST
;
349 Error
= KmtCreateAndStartService(SERVICE_NAME
, SERVICE_PATH
, SERVICE_DESCRIPTION
, &KmtestServiceHandle
, FALSE
);
353 KmtestHandle
= CreateFile(KMTEST_DEVICE_PATH
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
354 if (KmtestHandle
== INVALID_HANDLE_VALUE
)
355 error_goto(Error
, cleanup
);
359 case KMT_LIST_ALL_TESTS
:
363 Error
= ListTests(ShowHidden
);
366 Error
= RunTest(TestName
);
375 CloseHandle(KmtestHandle
);
378 KmtFreeResultBuffer(ResultBuffer
);
380 KmtCloseService(&KmtestServiceHandle
);
383 KmtServiceCleanup(TRUE
);
385 Error
= KmtServiceCleanup(FALSE
);
391 Status
= EXIT_FAILURE
;