ReactOS 0.4.16-dev-336-gb667d82
kmtest.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: Kernel-Mode Test Suite loader application
5 * COPYRIGHT: Copyright 2011-2018 Thomas Faber <thomas.faber@reactos.org>
6 */
7
8#define KMT_DEFINE_TEST_FUNCTIONS
9#include <kmt_test.h>
10
11#include "kmtest.h"
12#include <kmt_public.h>
13
14#include <assert.h>
15#include <stdio.h>
16#include <stdlib.h>
17
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"
21
22#define RESULTBUFFER_SIZE (1024 * 1024)
23
24typedef enum
25{
31
35
36static void OutputError(IN DWORD Error);
37static DWORD ListTests(IN BOOLEAN IncludeHidden);
38static PKMT_TESTFUNC FindTest(IN PCSTR TestName);
39static DWORD OutputResult(IN PCSTR TestName);
40static DWORD RunTest(IN PCSTR TestName);
41int __cdecl main(int ArgCount, char **Arguments);
42
51static
52void
55{
59 {
60 fprintf(stderr, "%s: Could not retrieve error message (error 0x%08lx). Original error: 0x%08lx\n",
62 return;
63 }
64
65 fprintf(stderr, "%s: error 0x%08lx: %s\n", ErrorFileAndLine, Error, Message);
66
68}
69
79static
80INT
82 IN PCSTR Str1,
83 IN PCSTR Str2)
84{
85 if (*Str1 == '-')
86 ++Str1;
87 if (*Str2 == '-')
88 ++Str2;
89 while (*Str1 && *Str1 == *Str2)
90 {
91 ++Str1;
92 ++Str2;
93 }
94 return *Str1 - *Str2;
95}
96
109static
110DWORD
112 IN BOOLEAN IncludeHidden)
113{
115 CHAR Buffer[1024];
117 PCSTR TestName = Buffer;
119 PCSTR NextTestName;
120
121 puts("Valid test names:");
122
123 // get test list from driver
126
127 // output test list plus user-mode tests
128 while (TestEntry->TestName || *TestName)
129 {
130 if (!TestEntry->TestName)
131 {
132 NextTestName = TestName;
133 TestName += strlen(TestName) + 1;
134 }
135 else if (!*TestName)
136 {
137 NextTestName = TestEntry->TestName;
138 ++TestEntry;
139 }
140 else
141 {
142 INT Result = CompareTestNames(TestEntry->TestName, TestName);
143
144 if (Result == 0)
145 {
146 NextTestName = TestEntry->TestName;
147 TestName += strlen(TestName) + 1;
148 ++TestEntry;
149 }
150 else if (Result < 0)
151 {
152 NextTestName = TestEntry->TestName;
153 ++TestEntry;
154 }
155 else
156 {
157 NextTestName = TestName;
158 TestName += strlen(TestName) + 1;
159 }
160 }
161
162 if (IncludeHidden && NextTestName[0] == '-')
163 ++NextTestName;
164
165 if (NextTestName[0] != '-')
166 printf(" %s\n", NextTestName);
167 }
168
169cleanup:
170 return Error;
171}
172
183static
186 IN PCSTR TestName)
187{
189
190 for (TestEntry = TestList; TestEntry->TestName; ++TestEntry)
191 {
192 PCSTR TestEntryName = TestEntry->TestName;
193
194 // skip leading '-' if present
195 if (*TestEntryName == '-')
196 ++TestEntryName;
197
198 if (!lstrcmpA(TestEntryName, TestName))
199 break;
200 }
201
202 return TestEntry->TestFunction;
203}
204
215static
216DWORD
218 IN PCSTR TestName)
219{
222 DWORD LogBufferLength;
223 DWORD Offset = 0;
224 /* A console window can't handle a single
225 * huge block of data, so split it up */
226 const DWORD BlockSize = 8 * 1024;
227
228 KmtFinishTest(TestName);
229
230 LogBufferLength = ResultBuffer->LogBufferLength;
231 for (Offset = 0; Offset < LogBufferLength; Offset += BlockSize)
232 {
233 DWORD Length = min(LogBufferLength - Offset, BlockSize);
235 error(Error);
236 }
237
238 return Error;
239}
240
251static
252DWORD
254 IN PCSTR TestName)
255{
259
260 assert(TestName != NULL);
261
262 if (!ResultBuffer)
263 {
265 if (!ResultBuffer)
269 }
270
271 // check test list
272 TestFunction = FindTest(TestName);
273
274 if (TestFunction)
275 {
276 TestFunction();
277 goto cleanup;
278 }
279
280 // not found in user-mode test list, call driver
281 Error = KmtRunKernelTest(TestName);
282
283cleanup:
284 if (!Error)
285 Error = OutputResult(TestName);
286
287 return Error;
288}
289
300int
302 int ArgCount,
303 char **Arguments)
304{
307 PCSTR AppName = "kmtest.exe";
308 PCSTR TestName = NULL;
310 BOOLEAN ShowHidden = FALSE;
311
313 if (Error)
314 goto cleanup;
315
316 if (ArgCount >= 1)
317 AppName = Arguments[0];
318
319 if (ArgCount <= 1)
320 {
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);
326 }
327 else
328 {
329 TestName = Arguments[1];
330 if (!lstrcmpA(TestName, "create"))
332 else if (!lstrcmpA(TestName, "delete"))
334 else if (!lstrcmpA(TestName, "start"))
336 else if (!lstrcmpA(TestName, "stop"))
338
339 else if (!lstrcmpA(TestName, "--list"))
341 else if (!lstrcmpA(TestName, "--list-all"))
343 else
345 }
346
347 if (Operation)
348 {
350 if (Error)
351 goto cleanup;
352
356
357 switch (Operation)
358 {
360 ShowHidden = TRUE;
361 /* fall through */
362 case KMT_LIST_TESTS:
363 Error = ListTests(ShowHidden);
364 break;
365 case KMT_RUN_TEST:
366 Error = RunTest(TestName);
367 break;
368 default:
369 assert(FALSE);
370 }
371 }
372
373cleanup:
374 if (KmtestHandle)
376
377 if (ResultBuffer)
379
381
382 if (Error)
384 else
386
387 if (Error)
388 {
390
392 }
393
394 return Status;
395}
DWORD KmtStartService(IN PCWSTR ServiceName OPTIONAL, IN OUT SC_HANDLE *ServiceHandle)
Definition: service.c:217
static void TestEntry(const ENTRY *pEntry)
static KSTART_ROUTINE RunTest
Definition: NpfsConnect.c:238
unsigned char BOOLEAN
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define __cdecl
Definition: accygwin.h:79
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:203
BOOL Error
Definition: chkdsk.c:66
Definition: bufpool.h:45
int puts(const char *string)
Definition: crtsupp.c:23
static CHAR AppName[MAX_PATH]
Definition: dem.c:252
#define ERROR_SUCCESS
Definition: deptool.c:10
BOOL WINAPI DeviceIoControl(IN HANDLE hDevice, IN DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL, IN DWORD nInBufferSize OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL, IN DWORD nOutBufferSize OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: deviceio.c:136
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define CloseHandle
Definition: compat.h:739
#define OPEN_EXISTING
Definition: compat.h:775
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GENERIC_READ
Definition: compat.h:135
static void cleanup(void)
Definition: main.c:1335
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:483
int WINAPI lstrcmpA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4195
static const WCHAR Message[]
Definition: register.c:74
#define assert(x)
Definition: debug.h:53
int main()
Definition: test.c:6
unsigned long DWORD
Definition: ntddk_ex.h:95
FP_OP Operation
Definition: fpcontrol.c:150
#define printf
Definition: freeldr.h:97
Status
Definition: gdiplustypes.h:25
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1594
#define stderr
Definition: stdio.h:100
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
#define EXIT_FAILURE
Definition: jerror.c:33
#define IOCTL_KMTEST_GET_TESTS
Definition: kmt_public.h:13
#define KMTEST_DEVICE_PATH
Definition: kmt_public.h:35
#define IOCTL_KMTEST_SET_RESULTBUFFER
Definition: kmt_public.h:19
KMT_TESTFUNC * PKMT_TESTFUNC
Definition: kmt_test.h:22
PKMT_RESULTBUFFER ResultBuffer
static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
Definition: kmt_test_user.h:30
static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T ResultBufferSize)
Definition: kmt_test_user.h:15
static DWORD ListTests(IN BOOLEAN IncludeHidden)
Definition: kmtest.c:111
static void OutputError(IN DWORD Error)
Definition: kmtest.c:53
#define RESULTBUFFER_SIZE
Definition: kmtest.c:22
KMT_OPERATION
Definition: kmtest.c:25
@ KMT_RUN_TEST
Definition: kmtest.c:29
@ KMT_LIST_TESTS
Definition: kmtest.c:27
@ KMT_LIST_ALL_TESTS
Definition: kmtest.c:28
@ KMT_DO_NOTHING
Definition: kmtest.c:26
#define SERVICE_NAME
Definition: kmtest.c:18
PCSTR ErrorFileAndLine
Definition: kmtest.c:34
static DWORD OutputResult(IN PCSTR TestName)
Definition: kmtest.c:217
HANDLE KmtestHandle
Definition: kmtest.c:32
static INT CompareTestNames(IN PCSTR Str1, IN PCSTR Str2)
Definition: kmtest.c:81
#define SERVICE_PATH
Definition: kmtest.c:19
SC_HANDLE KmtestServiceHandle
Definition: kmtest.c:33
DWORD KmtServiceCleanup(BOOLEAN IgnoreErrors)
Definition: service.c:64
DWORD KmtServiceInit(VOID)
Definition: service.c:40
DWORD KmtCloseService(IN OUT SC_HANDLE *ServiceHandle)
Definition: service.c:392
#define error_goto(Error, label)
Definition: kmtest.h:21
DWORD KmtDeleteService(IN PCWSTR ServiceName OPTIONAL, IN OUT SC_HANDLE *ServiceHandle)
Definition: service.c:356
DWORD KmtCreateService(IN PCWSTR ServiceName, IN PCWSTR ServicePath, IN PCWSTR DisplayName OPTIONAL, OUT SC_HANDLE *ServiceHandle)
Definition: service.c:92
DWORD KmtStopService(IN PCWSTR ServiceName OPTIONAL, IN OUT SC_HANDLE *ServiceHandle)
Definition: service.c:315
DWORD KmtCreateAndStartService(IN PCWSTR ServiceName, IN PCWSTR ServicePath, IN PCWSTR DisplayName OPTIONAL, OUT SC_HANDLE *ServiceHandle, IN BOOLEAN RestartIfRunning)
Definition: service.c:262
#define error(str)
Definition: mkdosfs.c:1605
#define min(a, b)
Definition: monoChain.cc:55
#define GENERIC_WRITE
Definition: nt_native.h:90
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define EXIT_SUCCESS
Definition: rdjpgcom.c:55
void TestFunction()
#define LANG_NEUTRAL
Definition: nls.h:22
#define MAKELANGID(p, s)
Definition: nls.h:15
#define SUBLANG_DEFAULT
Definition: nls.h:168
CHAR LogBuffer[ANYSIZE_ARRAY]
Definition: kmt_test.h:41
volatile LONG LogBufferLength
Definition: kmt_test.h:39
DWORD KmtRunKernelTest(IN PCSTR TestName)
Definition: support.c:95
EH_STD::__list__< TestClass, eh_allocator(TestClass) > TestList
Definition: test_list.cpp:31
char * PSTR
Definition: typedefs.h:51
int32_t INT
Definition: typedefs.h:58
const char * PCSTR
Definition: typedefs.h:52
#define IN
Definition: typedefs.h:39
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:960
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870
#define STD_OUTPUT_HANDLE
Definition: winbase.h:294
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define FORMAT_MESSAGE_IGNORE_INSERTS
Definition: winbase.h:446
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:449
#define FORMAT_MESSAGE_ALLOCATE_BUFFER
Definition: winbase.h:445
#define CreateFile
Definition: winbase.h:3774
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
char * LPSTR
Definition: xmlstorage.h:182
char CHAR
Definition: xmlstorage.h:175