From: Rémi Bernon rbernon@codeweavers.com
--- .../tests/application.c | 16 + dlls/windows.applicationmodel/tests/model.c | 52 ++ .../tests/winrt_test.h | 477 ++++++++++++++++++ 3 files changed, 545 insertions(+) create mode 100644 dlls/windows.applicationmodel/tests/winrt_test.h
diff --git a/dlls/windows.applicationmodel/tests/application.c b/dlls/windows.applicationmodel/tests/application.c index d437e225587..06530b32fec 100644 --- a/dlls/windows.applicationmodel/tests/application.c +++ b/dlls/windows.applicationmodel/tests/application.c @@ -22,8 +22,24 @@
#include "windef.h" #include "winbase.h" +#include "initguid.h" +#include "winstring.h" + +#include "roapi.h" + +#include "winrt_test.h"
int main( int argc, char const *argv[] ) { + HRESULT hr; + + if (!winrt_test_init()) return -1; + + hr = RoInitialize( RO_INIT_MULTITHREADED ); + ok( hr == S_OK, "RoInitialize failed, hr %#lx\n", hr ); + + RoUninitialize(); + + winrt_test_exit(); return 0; } diff --git a/dlls/windows.applicationmodel/tests/model.c b/dlls/windows.applicationmodel/tests/model.c index b15024f6ca9..ca1da5daded 100644 --- a/dlls/windows.applicationmodel/tests/model.c +++ b/dlls/windows.applicationmodel/tests/model.c @@ -37,6 +37,7 @@ #include "windows.management.deployment.h"
#include "wine/test.h" +#include "winrt_test.h"
#define DEFINE_ASYNC_COMPLETED_HANDLER( name, iface_type, async_type ) \ struct name \ @@ -192,6 +193,9 @@ static void check_async_info_( int line, void *async, AsyncStatus expect_status,
DEFINE_ASYNC_COMPLETED_HANDLER( async_deployment_result_handler, IAsyncOperationWithProgressCompletedHandler_DeploymentResult_DeploymentProgress, IAsyncOperationWithProgress_DeploymentResult_DeploymentProgress ) +DEFINE_ASYNC_COMPLETED_HANDLER( async_applist_handler, IAsyncOperationCompletedHandler_IVectorView_AppListEntry, + IAsyncOperation_IVectorView_AppListEntry ) +DEFINE_ASYNC_COMPLETED_HANDLER( async_boolean_handler, IAsyncOperationCompletedHandler_boolean, IAsyncOperation_boolean )
static HRESULT uri_create( const WCHAR *uri, IUriRuntimeClass **out ) { @@ -371,6 +375,53 @@ static void test_remove_package( IPackageManager *manager, IPackage *package ) IAsyncOperationWithProgress_DeploymentResult_DeploymentProgress_Release( operation ); }
+static void test_execute_package( IPackage *package ) +{ + IAsyncOperation_IVectorView_AppListEntry *async_list; + IAsyncOperation_boolean *async_launch; + IVectorView_AppListEntry *list; + IAppListEntry *app_entry; + IPackage3 *package3; + boolean launched; + HRESULT hr; + UINT res; + + if (!winrt_test_init()) return; + + hr = IPackage_QueryInterface( package, &IID_IPackage3, (void **)&package3 ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + + hr = IPackage3_GetAppListEntriesAsync( package3, &async_list ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + res = await_IAsyncOperation_IVectorView_AppListEntry( async_list, 5000 ); + ok( res == 0, "await_IAsyncOperation_IVectorView_AppListEntry returned %#x.\n", res ); + check_async_info( async_list, Completed, S_OK ); + hr = IAsyncOperation_IVectorView_AppListEntry_GetResults( async_list, &list ); + ok( hr == S_OK, "GetResults returned %#lx\n", hr ); + IAsyncOperation_IVectorView_AppListEntry_Release( async_list ); + + hr = IVectorView_AppListEntry_GetAt( list, 0, &app_entry ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + IVectorView_AppListEntry_Release( list ); + + IPackage3_Release( package3 ); + + + hr = IAppListEntry_LaunchAsync( app_entry, &async_launch ); + ok( hr == S_OK, "got hr %#lx.\n", hr ); + res = await_IAsyncOperation_boolean( async_launch, 5000 ); + ok( res == 0, "await_IAsyncOperation_boolean returned %#x.\n", res ); + check_async_info( async_launch, Completed, S_OK ); + + hr = IAsyncOperation_boolean_GetResults( async_launch, &launched ); + ok( hr == S_OK, "GetResults returned %#lx\n", hr ); + ok( launched == TRUE, "got launched %u.\n", launched ); + + IAppListEntry_Release( app_entry ); + + winrt_test_exit(); +} + static void test_PackageManager(void) { static const WCHAR *statics_name = RuntimeClass_Windows_Management_Deployment_PackageManager; @@ -442,6 +493,7 @@ static void test_PackageManager(void)
if (SUCCEEDED(test_register_package( manager, &package ))) { + test_execute_package( package ); test_remove_package( manager, package ); IPackage_Release( package ); } diff --git a/dlls/windows.applicationmodel/tests/winrt_test.h b/dlls/windows.applicationmodel/tests/winrt_test.h new file mode 100644 index 00000000000..fb1bb02d2e7 --- /dev/null +++ b/dlls/windows.applicationmodel/tests/winrt_test.h @@ -0,0 +1,477 @@ +/* + * Copyright 2023 Rémi Bernon for CodeWeavers + * + * 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_WINRT_TEST_H +#define __WINE_WINRT_TEST_H + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" + +/* desktop/winrt shared data */ +struct winetest_shared_data +{ + BOOL running_under_wine; + BOOL winetest_report_success; + BOOL winetest_debug; + LONG failures; + LONG todo_failures; +}; + +static HANDLE winrt_section; +static HANDLE winrt_okfile; +static HANDLE winrt_event; + +#define winrt_test_init() winrt_test_init_( __FILE__, __LINE__ ) +#define winrt_test_exit() winrt_test_exit_( __FILE__, __LINE__ ) + +#ifdef __WINE_WINE_TEST_H + +static BOOL winrt_test_init_( const char *file, int line ) +{ + struct winetest_shared_data *data; + + winrt_section = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(*data), + L"winetest_winrt_section" ); + if (!winrt_section && GetLastError() == ERROR_ACCESS_DENIED) + { + win_skip_(file, line)( "Skipping WinRT tests: failed to create mapping.\n" ); + return FALSE; + } + ok_(file, line)( !!winrt_section, "got error %lu\n", GetLastError() ); + + data = MapViewOfFile( winrt_section, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024 ); + ok_(file, line)( !!data, "MapViewOfFile failed, error %lu\n", GetLastError() ); + data->running_under_wine = !strcmp( winetest_platform, "wine" ); + data->winetest_report_success = winetest_report_success; + data->winetest_debug = winetest_debug; + UnmapViewOfFile( data ); + + winrt_okfile = CreateFileW( L"C:\Users\Public\Documents\winetest_winrt_okfile", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL ); + ok_(file, line)( winrt_okfile != INVALID_HANDLE_VALUE, "failed to create file, error %lu\n", GetLastError() ); + + winrt_event = CreateEventW( 0, FALSE, FALSE, L"winetest_winrt_event" ); + ok_(file, line)( !!winrt_event, "got error %lu\n", GetLastError() ); + + subtest_(file, line)( "application" ); + return TRUE; +} + +static void winrt_test_exit_( const char *file, int line ) +{ + struct winetest_shared_data *data; + char buffer[512]; + DWORD size, res; + + res = WaitForSingleObject( winrt_event, 5000 ); + ok_(file, line)( !res, "WaitForSingleObject returned %#lx\n", res ); + CloseHandle( winrt_event ); + + SetFilePointer( winrt_okfile, 0, NULL, FILE_BEGIN ); + do + { + ReadFile( winrt_okfile, buffer, sizeof(buffer), &size, NULL ); + printf( "%.*s", (int)size, buffer ); + } while (size == sizeof(buffer)); + SetFilePointer( winrt_okfile, 0, NULL, FILE_BEGIN ); + SetEndOfFile( winrt_okfile ); + CloseHandle( winrt_okfile ); + DeleteFileW( L"C:\Users\Public\Documents\winetest_winrt_okfile" ); + + data = MapViewOfFile( winrt_section, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024 ); + ok_(file, line)( !!data, "MapViewOfFile failed, error %lu\n", GetLastError() ); + winetest_add_failures( InterlockedExchange( &data->failures, 0 ) ); + winetest_add_failures( InterlockedExchange( &data->todo_failures, 0 ) ); + UnmapViewOfFile( data ); + CloseHandle( winrt_section ); +} + +#else /* __WINE_WINE_TEST_H */ + +#ifdef __MINGW32__ +#define __WINE_PRINTF_ATTR( fmt, args ) __attribute__((format( printf, fmt, args ))) +#else +#define __WINE_PRINTF_ATTR( fmt, args ) +#endif + +static LONG successes; +static LONG failures; +static LONG skipped; +static LONG todo_successes; +static LONG todo_failures; +static LONG muted_traces; +static LONG muted_skipped; +static LONG muted_todo_successes; + +static int running_under_wine; +static int winetest_debug; +static int winetest_report_success; + +/* silence todos and skips above this threshold */ +static int winetest_mute_threshold = 42; + +/* counts how many times a given line printed a message */ +static LONG line_counters[16384]; + +/* The following data must be kept track of on a per-thread basis */ +struct tls_data +{ + const char *current_file; /* file of current check */ + int current_line; /* line of current check */ + unsigned int todo_level; /* current todo nesting level */ + int todo_do_loop; + char *str_pos; /* position in debug buffer */ + char strings[2000]; /* buffer for debug strings */ + char context[8][128]; /* data to print before messages */ + unsigned int context_count; /* number of context prefixes */ +}; + +static DWORD tls_index; + +static inline struct tls_data *get_tls_data(void) +{ + struct tls_data *data; + + if (!(data = TlsGetValue( tls_index ))) + { + data = calloc( 1, sizeof(*data) ); + data->str_pos = data->strings; + TlsSetValue( tls_index, data ); + } + + return data; +} + +static inline void winetest_set_location( const char *file, int line ) +{ + struct tls_data *data = get_tls_data(); + data->current_file = strrchr( file, '/' ); + if (data->current_file == NULL) data->current_file = strrchr( file, '\' ); + if (data->current_file == NULL) data->current_file = file; + else data->current_file++; + data->current_line = line; +} + +static inline void kvprintf( const char *format, va_list ap ) +{ + struct tls_data *data = get_tls_data(); + DWORD written; + int len = vsnprintf( data->str_pos, sizeof(data->strings) - (data->str_pos - data->strings), format, ap ); + data->str_pos += len; + + if (len && data->str_pos[-1] == '\n') + { + WriteFile( winrt_okfile, data->strings, strlen( data->strings ), &written, NULL ); + data->str_pos = data->strings; + } +} + +static inline void WINAPIV kprintf( const char *format, ... ) __WINE_PRINTF_ATTR( 1, 2 ); +static inline void WINAPIV kprintf( const char *format, ... ) +{ + va_list valist; + + va_start( valist, format ); + kvprintf( format, valist ); + va_end( valist ); +} + +static inline void WINAPIV winetest_printf( const char *msg, ... ) __WINE_PRINTF_ATTR( 1, 2 ); +static inline void WINAPIV winetest_printf( const char *msg, ... ) +{ + struct tls_data *data = get_tls_data(); + va_list valist; + + kprintf( "%s:%d: ", data->current_file, data->current_line ); + va_start( valist, msg ); + kvprintf( msg, valist ); + va_end( valist ); +} + +static inline void winetest_print_context( const char *msgtype ) +{ + struct tls_data *data = get_tls_data(); + unsigned int i; + + winetest_printf( "%s", msgtype ); + for (i = 0; i < data->context_count; ++i) kprintf( "%s: ", data->context[i] ); +} + +static inline LONG winetest_add_line(void) +{ + struct tls_data *data; + int index, count; + + if (winetest_debug > 1) return 0; + + data = get_tls_data(); + index = data->current_line % ARRAY_SIZE(line_counters); + count = InterlockedIncrement( line_counters + index ) - 1; + if (count == winetest_mute_threshold) + winetest_printf( "Line has been silenced after %d occurrences\n", winetest_mute_threshold ); + + return count; +} + +static inline int winetest_vok( int condition, const char *msg, va_list args ) +{ + struct tls_data *data = get_tls_data(); + + if (data->todo_level) + { + if (condition) + { + winetest_print_context( "Test succeeded inside todo block: " ); + kvprintf( msg, args ); + InterlockedIncrement( &todo_failures ); + return 0; + } + else + { + if (!winetest_debug || winetest_add_line() < winetest_mute_threshold) + { + if (winetest_debug > 0) + { + winetest_print_context( "Test marked todo: " ); + kvprintf( msg, args ); + } + InterlockedIncrement( &todo_successes ); + } + else InterlockedIncrement( &muted_todo_successes ); + return 1; + } + } + else + { + if (!condition) + { + winetest_print_context( "Test failed: " ); + kvprintf( msg, args ); + InterlockedIncrement( &failures ); + return 0; + } + else + { + if (winetest_report_success) winetest_printf( "Test succeeded\n" ); + InterlockedIncrement( &successes ); + return 1; + } + } +} + +static inline void WINAPIV winetest_ok( int condition, const char *msg, ... ) __WINE_PRINTF_ATTR( 2, 3 ); +static inline void WINAPIV winetest_ok( int condition, const char *msg, ... ) +{ + va_list args; + va_start( args, msg ); + winetest_vok( condition, msg, args ); + va_end( args ); +} + +static inline void winetest_vskip( const char *msg, va_list args ) +{ + if (winetest_add_line() < winetest_mute_threshold) + { + winetest_print_context( "Driver tests skipped: " ); + kvprintf( msg, args ); + InterlockedIncrement( &skipped ); + } + else InterlockedIncrement( &muted_skipped ); +} + +static inline void WINAPIV winetest_skip( const char *msg, ... ) __WINE_PRINTF_ATTR( 1, 2 ); +static inline void WINAPIV winetest_skip( const char *msg, ... ) +{ + va_list args; + va_start( args, msg ); + winetest_vskip( msg, args ); + va_end( args ); +} + +static inline void WINAPIV winetest_win_skip( const char *msg, ... ) __WINE_PRINTF_ATTR( 1, 2 ); +static inline void WINAPIV winetest_win_skip( const char *msg, ... ) +{ + va_list args; + va_start( args, msg ); + if (!running_under_wine) winetest_vskip( msg, args ); + else winetest_vok( 0, msg, args ); + va_end( args ); +} + +static inline void WINAPIV winetest_trace( const char *msg, ... ) __WINE_PRINTF_ATTR( 1, 2 ); +static inline void WINAPIV winetest_trace( const char *msg, ... ) +{ + va_list args; + + if (!winetest_debug) return; + if (winetest_add_line() < winetest_mute_threshold) + { + winetest_print_context( "" ); + va_start( args, msg ); + kvprintf( msg, args ); + va_end( args ); + } + else InterlockedIncrement( &muted_traces ); +} + +static inline void winetest_start_todo( int is_todo ) +{ + struct tls_data *data = get_tls_data(); + data->todo_level = (data->todo_level << 1) | (is_todo != 0); + data->todo_do_loop = 1; +} + +static inline int winetest_loop_todo(void) +{ + struct tls_data *data = get_tls_data(); + int do_loop = data->todo_do_loop; + data->todo_do_loop = 0; + return do_loop; +} + +static inline void winetest_end_todo(void) +{ + struct tls_data *data = get_tls_data(); + data->todo_level >>= 1; +} + +static inline void WINAPIV winetest_push_context( const char *fmt, ... ) __WINE_PRINTF_ATTR( 1, 2 ); +static inline void WINAPIV winetest_push_context( const char *fmt, ... ) +{ + struct tls_data *data = get_tls_data(); + va_list valist; + + if (data->context_count < ARRAY_SIZE(data->context)) + { + va_start( valist, fmt ); + vsnprintf( data->context[data->context_count], sizeof(data->context[data->context_count]), fmt, valist ); + va_end( valist ); + data->context[data->context_count][sizeof(data->context[data->context_count]) - 1] = 0; + } + ++data->context_count; +} + +static inline void winetest_pop_context(void) +{ + struct tls_data *data = get_tls_data(); + + if (data->context_count) --data->context_count; +} + +static inline int broken( int condition ) +{ + return !running_under_wine && condition; +} + +#ifdef WINETEST_NO_LINE_NUMBERS +# define subtest_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_subtest +# define ignore_exceptions_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_ignore_exceptions +# define ok_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_ok +# define skip_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_skip +# define win_skip_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_win_skip +# define trace_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_trace +# define wait_child_process_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_wait_child_process +#else +# define subtest_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_subtest +# define ignore_exceptions_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_ignore_exceptions +# define ok_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_ok +# define skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_skip +# define win_skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_win_skip +# define trace_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_trace +# define wait_child_process_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_wait_child_process +#endif + +#define ok ok_(__FILE__, __LINE__) +#define skip skip_(__FILE__, __LINE__) +#define trace trace_(__FILE__, __LINE__) +#define win_skip win_skip_(__FILE__, __LINE__) + +#define todo_if(is_todo) for (winetest_start_todo(is_todo); \ + winetest_loop_todo(); \ + winetest_end_todo()) +#define todo_wine todo_if(running_under_wine) +#define todo_wine_if(is_todo) todo_if((is_todo) && running_under_wine) + +static inline BOOL winrt_test_init_( const char *file, int line ) +{ + const struct winetest_shared_data *data; + + tls_index = TlsAlloc(); + + winrt_okfile = CreateFileW( L"C:\Users\Public\Documents\winetest_winrt_okfile", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); + if (!winrt_okfile) return FALSE; + + winrt_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, L"winetest_winrt_event" ); + ok_(file, line)( !!winrt_event, "OpenEventW failed, error %lu\n", GetLastError() ); + + winrt_section = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, L"winetest_winrt_section" ); + ok_(file, line)( !!winrt_section, "OpenFileMappingW failed, error %lu\n", GetLastError() ); + + data = MapViewOfFile( winrt_section, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024 ); + ok_(file, line)( !!data, "MapViewOfFile failed, error %lu\n", GetLastError() ); + running_under_wine = data->running_under_wine; + winetest_debug = data->winetest_debug; + winetest_report_success = data->winetest_report_success; + UnmapViewOfFile( data ); + + return TRUE; +} + +static inline void winrt_test_exit_( const char *file, int line ) +{ + char test_name[MAX_PATH], *tmp; + struct winetest_shared_data *data; + const char *source_file; + + source_file = strrchr( file, '/' ); + if (!source_file) source_file = strrchr( file, '\' ); + if (!source_file) source_file = file; + else source_file++; + + strcpy( test_name, source_file ); + if ((tmp = strrchr( test_name, '.' ))) *tmp = 0; + + data = MapViewOfFile( winrt_section, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024 ); + ok_(file, line)( !!data, "MapViewOfFile failed, error %lu\n", GetLastError() ); + InterlockedExchangeAdd( &data->failures, failures ); + InterlockedExchangeAdd( &data->todo_failures, todo_failures ); + UnmapViewOfFile( data ); + CloseHandle( winrt_section ); + + if (winetest_debug) + { + kprintf( "%04lx:%s: %ld tests executed (%ld marked as todo, 0 as flaky, %ld %s), %ld skipped.\n", + (DWORD)(DWORD_PTR)GetCurrentProcessId(), test_name, + successes + failures + todo_successes + todo_failures, todo_successes, failures + todo_failures, + (failures + todo_failures != 1) ? "failures" : "failure", skipped ); + } + CloseHandle( winrt_okfile ); + + SetEvent( winrt_event ); + CloseHandle( winrt_event ); +} + +#endif /* __WINE_WINE_TEST_H */ + +#endif /* __WINE_WINRT_TEST_H */