From 8c09da5559b124f97fd5f24540c25b28009562f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Tue, 20 Jan 2015 18:39:36 +0100 Subject: ntoskrnl.exe/tests: Add kernel compliant test functions. --- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +- dlls/ntoskrnl.exe/tests/driver.sys/Makefile.in | 3 +- dlls/ntoskrnl.exe/tests/driver.sys/driver.c | 65 ++++++--- dlls/ntoskrnl.exe/tests/driver.sys/driver.h | 11 +- dlls/ntoskrnl.exe/tests/driver.sys/test.c | 195 +++++++++++++++++++++++++ dlls/ntoskrnl.exe/tests/driver.sys/test.h | 158 ++++++++++++++++++++ dlls/ntoskrnl.exe/tests/driver.sys/util.h | 47 ++++++ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 36 ++--- include/wine/test.h | 39 ++++- 9 files changed, 509 insertions(+), 47 deletions(-) create mode 100644 dlls/ntoskrnl.exe/tests/driver.sys/test.c create mode 100644 dlls/ntoskrnl.exe/tests/driver.sys/test.h create mode 100644 dlls/ntoskrnl.exe/tests/driver.sys/util.h diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 25649c9b3b6..99c5749c6cf 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1427,7 +1427,7 @@ @ cdecl -private _strrev(str) msvcrt._strrev @ cdecl -private _strset(str long) msvcrt._strset @ cdecl -private _strupr(str) msvcrt._strupr -@ cdecl -private _vsnprintf(ptr long str ptr) msvcrt._vsnprintf +@ cdecl _vsnprintf(ptr long str ptr) msvcrt._vsnprintf @ cdecl -private _vsnwprintf(ptr long wstr ptr) msvcrt._vsnwprintf @ cdecl -private _wcsicmp(wstr wstr) msvcrt._wcsicmp @ cdecl -private _wcslwr(wstr) msvcrt._wcslwr diff --git a/dlls/ntoskrnl.exe/tests/driver.sys/Makefile.in b/dlls/ntoskrnl.exe/tests/driver.sys/Makefile.in index 1c49b2bd5cd..b200eec7e95 100644 --- a/dlls/ntoskrnl.exe/tests/driver.sys/Makefile.in +++ b/dlls/ntoskrnl.exe/tests/driver.sys/Makefile.in @@ -8,4 +8,5 @@ CROSSFLAGS = -nostartfiles -nostdlib -nodefaultlibs \ -Wl,-entry,_DriverEntry@8 C_SRCS = \ - driver.c + driver.c \ + test.c diff --git a/dlls/ntoskrnl.exe/tests/driver.sys/driver.c b/dlls/ntoskrnl.exe/tests/driver.sys/driver.c index 35f78d1ab2f..78fb55a961c 100644 --- a/dlls/ntoskrnl.exe/tests/driver.sys/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.sys/driver.c @@ -30,6 +30,9 @@ #include "winioctl.h" #include "ddk/wdm.h" +#define WINE_KERNEL +#include "util.h" +#include "test.h" #include "driver.h" const WCHAR driver_device[] = {'\\','D','e','v','i','c','e', @@ -37,24 +40,25 @@ const WCHAR driver_device[] = {'\\','D','e','v','i','c','e', const WCHAR driver_link[] = {'\\','D','o','s','D','e','v','i','c','e','s', '\\','W','i','n','e','T','e','s','t','D','r','i','v','e','r',0}; +/* In each kernel testcase the following variables are available: + * + * device - DEVICE_OBJECT used for ioctl + * irp - IRP pointer passed to ioctl + * __state - used internally for test macros + */ -static NTSTATUS test_basic_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) +KERNEL_TESTCASE(PsGetCurrentProcessId) { - const char str[] = "Wine is not an emulator"; - ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; - char *buffer = irp->AssociatedIrp.SystemBuffer; - int i; - - if (!buffer) - return STATUS_ACCESS_VIOLATION; - - if (length < sizeof(str)-1) - return STATUS_BUFFER_TOO_SMALL; - - for (i = 0; i < sizeof(str)-1; i++) - buffer[i] = str[i]; + struct test_PsGetCurrentProcessId *test = (void *)&__state->userdata; + test->pid = (DWORD)(ULONG_PTR)PsGetCurrentProcessId(); + ok(test->pid, "Expected processid to be non zero\n"); + return STATUS_SUCCESS; +} - *info = sizeof(str)-1; +KERNEL_TESTCASE(PsGetCurrentThread) +{ + PETHREAD thread = PsGetCurrentThread(); + todo_wine ok(thread != NULL, "Expected thread to be non-NULL\n"); return STATUS_SUCCESS; } @@ -69,19 +73,44 @@ static NTSTATUS WINAPI driver_Create(DEVICE_OBJECT *device, IRP *irp) static NTSTATUS WINAPI driver_IoControl(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + struct kernel_test_state *state = irp->AssociatedIrp.SystemBuffer; NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG_PTR information = 0; + if (!state) + { + status = STATUS_ACCESS_VIOLATION; + goto done; + } + + if (stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(*state) || + stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*state)) + { + status = STATUS_BUFFER_TOO_SMALL; + goto done; + } + + kernel_memset(&state->temp, 0, sizeof(state->temp)); + kernel_memset(&state->output, 0, sizeof(state->output)); + +#define DECLARE_TEST(name) \ + case WINE_IOCTL_##name: status = test_##name(device, irp, state); break; + switch (stack->Parameters.DeviceIoControl.IoControlCode) { - case IOCTL_WINETEST_BASIC_IOCTL: - status = test_basic_ioctl(irp, stack, &information); - break; + DECLARE_TEST(PsGetCurrentProcessId); + DECLARE_TEST(PsGetCurrentThread); default: break; } +#undef DECLARE_TEST + + kernel_memset(&state->temp, 0, sizeof(state->temp)); + if (status == STATUS_SUCCESS) information = sizeof(*state); + +done: irp->IoStatus.Status = status; irp->IoStatus.Information = information; IoCompleteRequest(irp, IO_NO_INCREMENT); diff --git a/dlls/ntoskrnl.exe/tests/driver.sys/driver.h b/dlls/ntoskrnl.exe/tests/driver.sys/driver.h index 372e9080896..1af2dcec249 100644 --- a/dlls/ntoskrnl.exe/tests/driver.sys/driver.h +++ b/dlls/ntoskrnl.exe/tests/driver.sys/driver.h @@ -20,9 +20,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "test.h" -/* - * All custom IOCTLs need to have a function value >= 0x800. - */ +#define WINE_IOCTL_PsGetCurrentProcessId WINE_TEST_IOCTL(0) +#define WINE_IOCTL_PsGetCurrentThread WINE_TEST_IOCTL(1) -#define IOCTL_WINETEST_BASIC_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) +struct test_PsGetCurrentProcessId +{ + DWORD pid; +}; diff --git a/dlls/ntoskrnl.exe/tests/driver.sys/test.c b/dlls/ntoskrnl.exe/tests/driver.sys/test.c new file mode 100644 index 00000000000..01adf609371 --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver.sys/test.c @@ -0,0 +1,195 @@ +/* + * ntoskrnl.exe testing framework + * + * Copyright 2015 Michael Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/wdm.h" + +#define WINE_KERNEL +#include "util.h" +#include "test.h" + +extern int CDECL _vsnprintf(char *buffer, size_t count, const char *format, __ms_va_list argptr); + +static void safe_vsnprintf(struct kernel_test_state *state, const char *msg, __ms_va_list args) +{ + int remaining; + int length; + + if (state->output.overflow) + return; + + if (state->output.offset >= sizeof(state->output.debug) - 1) + { + state->output.overflow = TRUE; + return; + } + + remaining = (sizeof(state->output.debug) - 1) - state->output.offset; + length = _vsnprintf(&state->output.debug[state->output.offset], remaining, msg, args); + if (length < 0) + { + state->output.debug[state->output.offset] = 0; + state->output.overflow = TRUE; + return; + } + + state->output.offset += length; +} + +static void __cdecl safe_snprintf(struct kernel_test_state *state, const char *msg, ...) +{ + __ms_va_list valist; + + __ms_va_start(valist, msg); + safe_vsnprintf(state, msg, valist); + __ms_va_end(valist); +} + +void winetest_set_location(struct kernel_test_state *state, const char *file, int line) +{ + state->temp.file = kernel_strrchr(file, '/'); + if (state->temp.file == NULL) + state->temp.file = kernel_strrchr(file, '\\'); + if (state->temp.file == NULL) + state->temp.file = file; + else + state->temp.file++; + state->temp.line = line; +} + +int winetest_vok(struct kernel_test_state *state, int condition, const char *msg, __ms_va_list args) +{ + if (state->temp.todo_level) + { + if (condition) + { + safe_snprintf( state, "%s:%d: Test succeeded inside todo block: ", + state->temp.file, state->temp.line ); + safe_vsnprintf(state, msg, args); + state->output.todo_failures++; + return 0; + } + else + { + if (state->input.debug_level > 0) + { + safe_snprintf( state, "%s:%d: Test marked todo: ", + state->temp.file, state->temp.line ); + safe_vsnprintf(state, msg, args); + } + state->output.todo_successes++; + return 1; + } + } + else + { + if (!condition) + { + safe_snprintf( state, "%s:%d: Test failed: ", + state->temp.file, state->temp.line ); + safe_vsnprintf(state, msg, args); + state->output.failures++; + return 0; + } + else + { + if (state->input.report_success) + safe_snprintf( state, "%s:%d: Test succeeded\n", + state->temp.file, state->temp.line); + state->output.successes++; + return 1; + } + } +} + +void __cdecl winetest_ok(struct kernel_test_state *state, int condition, const char *msg, ...) +{ + __ms_va_list valist; + + __ms_va_start(valist, msg); + winetest_vok(state, condition, msg, valist); + __ms_va_end(valist); +} + +void __cdecl winetest_trace(struct kernel_test_state *state, const char *msg, ...) +{ + __ms_va_list valist; + + if (state->input.debug_level > 0) + { + safe_snprintf( state, "%s:%d: ", state->temp.file, state->temp.line ); + __ms_va_start(valist, msg); + safe_vsnprintf(state, msg, valist); + __ms_va_end(valist); + } +} + +void winetest_vskip(struct kernel_test_state *state, const char *msg, __ms_va_list args) +{ + safe_snprintf( state, "%s:%d: Tests skipped: ", state->temp.file, state->temp.line ); + safe_vsnprintf(state, msg, args); + state->output.skipped++; +} + +void __cdecl winetest_skip(struct kernel_test_state *state, const char *msg, ...) +{ + __ms_va_list valist; + __ms_va_start(valist, msg); + winetest_vskip(state, msg, valist); + __ms_va_end(valist); +} + +void __cdecl winetest_win_skip(struct kernel_test_state *state, const char *msg, ...) +{ + __ms_va_list valist; + __ms_va_start(valist, msg); + if (!state->input.windows) + winetest_vskip(state, msg, valist); + else + winetest_vok(state, 0, msg, valist); + __ms_va_end(valist); +} + +void winetest_start_todo(struct kernel_test_state *state, int windows) +{ + if (state->input.windows == windows) + state->temp.todo_level++; + state->temp.todo_do_loop=1; +} + +int winetest_loop_todo(struct kernel_test_state *state) +{ + int do_loop=state->temp.todo_do_loop; + state->temp.todo_do_loop=0; + return do_loop; +} + +void winetest_end_todo(struct kernel_test_state *state, int windows) +{ + if (state->input.windows == windows) + state->temp.todo_level--; +} diff --git a/dlls/ntoskrnl.exe/tests/driver.sys/test.h b/dlls/ntoskrnl.exe/tests/driver.sys/test.h new file mode 100644 index 00000000000..65d08c0d645 --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver.sys/test.h @@ -0,0 +1,158 @@ +/* + * ntoskrnl.exe testing framework + * + * Copyright 2015 Michael Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _WINE_KERNEL_TEST_ +#define _WINE_KERNEL_TEST_ + +struct kernel_test_state +{ + char userdata[1024]; + struct + { + int debug_level; + int report_success; + BOOL windows; + } input; + struct + { + const char *file; + int line; + int todo_level; + int todo_do_loop; + } temp; + struct + { + LONG failures; + LONG successes; + LONG todo_failures; + LONG todo_successes; + LONG skipped; + + BOOL overflow; + DWORD offset; + char debug[4096]; + } output; +}; + +#define WINE_TEST_IOCTL(index) CTL_CODE(FILE_DEVICE_UNKNOWN, (index) + 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#ifdef WINE_KERNEL + +#ifdef __GNUC__ +void __cdecl winetest_ok(struct kernel_test_state *state, int condition, const char *msg, ...) __attribute__((format (printf,3,4) )); +void __cdecl winetest_skip(struct kernel_test_state *state, const char *msg, ...) __attribute__((format (printf,2,3))); +void __cdecl winetest_win_skip(struct kernel_test_state *state, const char *msg, ...) __attribute__((format (printf,2,3))); +void __cdecl winetest_trace(struct kernel_test_state *state, const char *msg, ...) __attribute__((format (printf,2,3))); +#else +void __cdecl winetest_ok(struct kernel_test_state *state, int condition, const char *msg, ...); +void __cdecl winetest_skip(struct kernel_test_state *state, const char *msg, ...); +void __cdecl winetest_win_skip(struct kernel_test_state *state, const char *msg, ...); +void __cdecl winetest_trace(struct kernel_test_state *state, const char *msg, ...); +#endif /* __GNUC__ */ + +void winetest_set_location(struct kernel_test_state *state, const char* file, int line); +void winetest_start_todo(struct kernel_test_state *state, int windows); +int winetest_loop_todo(struct kernel_test_state *state); +void winetest_end_todo(struct kernel_test_state *state, int windows); + +#define ok_(file, line) (winetest_set_location(__state, file, line), 0) ? (void)0 : winetest_ok +#define skip_(file, line) (winetest_set_location(__state, file, line), 0) ? (void)0 : winetest_skip +#define win_skip_(file, line) (winetest_set_location(__state, file, line), 0) ? (void)0 : winetest_win_skip +#define trace_(file, line) (winetest_set_location(__state, file, line), 0) ? (void)0 : winetest_trace + +#define _ok ok_(__FILE__, __LINE__) +#define _skip skip_(__FILE__, __LINE__) +#define _win_skip win_skip_(__FILE__, __LINE__) +#define _trace trace_(__FILE__, __LINE__) + +/* Variadic Macros */ +#define ok(...) _ok(__state, __VA_ARGS__) +#define skip(...) _skip(__state, __VA_ARGS__) +#define win_skip(...) _win_skip(__state, __VA_ARGS__) +#define trace(...) _trace(__state, __VA_ARGS__) + +#define todo(windows) for (winetest_start_todo(__state, windows); \ + winetest_loop_todo(__state); \ + winetest_end_todo(__state, windows)) +#define todo_wine todo(0) + +#define KERNEL_TESTCASE(name) \ + static NTSTATUS test_##name(DEVICE_OBJECT *device, IRP *irp, \ + struct kernel_test_state *__state) + +#else + +#include + +#define wine_run_kernel_test(device_path, ioctl, state) \ + __wine_run_kernel_test(__FILE__, __LINE__, device_path, ioctl, state) + +static void __wine_run_kernel_test(const char *file, int line, const char *device_path, + DWORD ioctl, struct kernel_test_state *state) +{ + struct kernel_test_state temp_state; + DWORD returned; + HANDLE device; + BOOL ret; + + device = CreateFileA(device_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + ok_(file, line)(device != INVALID_HANDLE_VALUE, "CreateFileA failed with error %u\n", GetLastError()); + if (device == INVALID_HANDLE_VALUE) return; + + if (!state) + { + state = &temp_state; + memset(state, 0, sizeof(*state)); + } + + state->input.debug_level = winetest_get_debug(); + state->input.report_success = winetest_get_report_success(); + state->input.windows = !strcmp(winetest_platform, "windows"); + + ret = DeviceIoControl(device, ioctl, state, sizeof(*state), state, sizeof(*state), &returned, NULL); + ok_(file, line)(ret, "DeviceIoControl failed with error %u\n", GetLastError()); + ok_(file, line)(returned == sizeof(*state), "DeviceIoControl returned %u bytes\n", returned); + + if (state->output.offset >= sizeof(state->output.debug)) + state->output.offset = sizeof(state->output.debug) - 1; + + if (state->output.offset) + { + state->output.debug[state->output.offset] = 0; + fprintf(stdout, "%s", state->output.debug); + if (state->output.debug[state->output.offset - 1] != '\n') + fprintf(stdout, "\n"); + } + + if (state->output.overflow) + skip_(file, line)("Buffer was too small, kernel debug output is truncated!\n"); + + winetest_add_failures(state->output.failures); + winetest_add_successes(state->output.successes); + winetest_add_todo_failures(state->output.todo_failures); + winetest_add_todo_successes(state->output.todo_successes); + winetest_add_skipped(state->output.skipped); + + CloseHandle(device); +} + +#endif + +#endif /* _WINE_KERNEL_TEST_ */ diff --git a/dlls/ntoskrnl.exe/tests/driver.sys/util.h b/dlls/ntoskrnl.exe/tests/driver.sys/util.h new file mode 100644 index 00000000000..881a4a2952f --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver.sys/util.h @@ -0,0 +1,47 @@ +/* + * ntoskrnl.exe testing framework + * + * Copyright 2015 Sebastian Lackner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +static inline const char* kernel_strrchr(const char *str, int character) +{ + const char *ret = NULL; + for (; *str; str++) + { + if (*str == character) + ret = str; + } + return ret; +} + +static inline void* kernel_memcpy(void *destination, const void *source, size_t num) +{ + const char *src = source; + char *dst = destination; + while (num--) *dst++ = *src++; + return destination; +} + +static inline void* kernel_memset(void *ptr, int value, size_t num) +{ + char *dst = ptr; + while (num--) *dst++ = value; + return ptr; +} diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 9b8a6a7c5b0..6f020101b4c 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -25,6 +25,7 @@ #include "winioctl.h" #include "wine/test.h" +#include "driver.sys/test.h" #include "driver.sys/driver.h" static const char driver_name[] = "WineTestDriver"; @@ -184,29 +185,21 @@ err: return NULL; } -static void test_basic_ioctl(void) +static void test_PsGetCurrentProcessId(void) { - const char str[] = "Wine is not an emulator"; - DWORD bytes_returned; - char buf[32]; - HANDLE file; - BOOL res; + struct kernel_test_state state; + struct test_PsGetCurrentProcessId *test = (void *)&state.userdata; - file = CreateFileA(device_path, GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); - if (file == INVALID_HANDLE_VALUE) - { - ok(0, "Connecting to driver failed with %x\n", GetLastError()); - return; - } - - res = DeviceIoControl(file, IOCTL_WINETEST_BASIC_IOCTL, NULL, 0, buf, - sizeof(buf), &bytes_returned, NULL); - ok(res, "DeviceIoControl failed with %x\n", GetLastError()); - ok(bytes_returned == sizeof(str)-1, "Unexpected number of bytes\n"); - ok(!memcmp(buf, str, sizeof(str)-1), "Unexpected response data\n"); + memset(&state, 0, sizeof(state)); + trace("Running tests for PsGetCurrentProcessId\n"); + wine_run_kernel_test(device_path, WINE_IOCTL_PsGetCurrentProcessId, &state); + ok(test->pid == GetCurrentProcessId(), "Expected pid %u, got %u\n", GetCurrentProcessId(), test->pid); +} - CloseHandle(file); +static void test_PsGetCurrentThread(void) +{ + trace("Running tests for PsGetCurrentThread\n"); + wine_run_kernel_test(device_path, WINE_IOCTL_PsGetCurrentThread, NULL); } START_TEST(ntoskrnl) @@ -220,7 +213,8 @@ START_TEST(ntoskrnl) return; } - test_basic_ioctl(); + test_PsGetCurrentProcessId(); + test_PsGetCurrentThread(); unload_driver(service, filename); } diff --git a/include/wine/test.h b/include/wine/test.h index af602c0fac0..e7d7961f2a9 100644 --- a/include/wine/test.h +++ b/include/wine/test.h @@ -61,7 +61,13 @@ extern int winetest_loop_todo(void); extern void winetest_end_todo(void); extern int winetest_get_mainargs( char*** pargv ); extern LONG winetest_get_failures(void); +extern int winetest_get_report_success(void); +extern int winetest_get_debug(void); extern void winetest_add_failures( LONG new_failures ); +extern void winetest_add_successes( LONG new_successes ); +extern void winetest_add_todo_failures( LONG new_todo_failures ); +extern void winetest_add_todo_successes( LONG new_todo_successes ); +extern void winetest_add_skipped( LONG new_skipped ); extern void winetest_wait_child_process( HANDLE process ); extern const char *wine_dbgstr_wn( const WCHAR *str, int n ); @@ -429,10 +435,39 @@ LONG winetest_get_failures(void) return failures; } +int winetest_get_report_success(void) +{ + return report_success; +} + +int winetest_get_debug(void) +{ + return winetest_debug; +} + void winetest_add_failures( LONG new_failures ) { - while (new_failures-- > 0) - InterlockedIncrement( &failures ); + InterlockedExchangeAdd( &failures, new_failures ); +} + +void winetest_add_successes( LONG new_successes ) +{ + InterlockedExchangeAdd( &successes, new_successes ); +} + +void winetest_add_todo_failures( LONG new_todo_failures ) +{ + InterlockedExchangeAdd( &todo_failures, new_todo_failures ); +} + +void winetest_add_todo_successes( LONG new_todo_successes ) +{ + InterlockedExchangeAdd( &todo_successes, new_todo_successes ); +} + +void winetest_add_skipped( LONG new_skipped ) +{ + InterlockedExchangeAdd( &skipped, new_skipped ); } void winetest_wait_child_process( HANDLE process ) -- 2.13.1