Signed-off-by: Bernhard Kölbl besentv@gmail.com --- v4: Fix races in tests, leaks and implement stubs. + Some rework. --- dlls/windows.media.speech/tests/speech.c | 136 +++++++++++++++++++---- 1 file changed, 112 insertions(+), 24 deletions(-)
diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index ef75178f8c1..7fca3fa6179 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -239,8 +239,8 @@ struct compilation_handler IAsyncHandler_Compilation IAsyncHandler_Compilation_iface; LONG ref;
+ HANDLE event_block; HANDLE event_finished; - BOOLEAN sleeping; DWORD thread_id; };
@@ -290,7 +290,9 @@ HRESULT WINAPI compilation_handler_Invoke( IAsyncHandler_Compilation *iface, trace("Iface %p, info %p, status %d.\n", iface, info, status); trace("Caller thread id %lu callback thread id %lu.\n", impl->thread_id, id);
- ok(status != Started, "Got unexpected status %#x.\n", status); + /* Block handler until event is set. */ + if (impl->event_block) WaitForSingleObject(impl->event_block, INFINITE); + /* Signal finishing of the handler. */ if (impl->event_finished) SetEvent(impl->event_finished);
return S_OK; @@ -813,6 +815,39 @@ static void test_VoiceInformation(void) RoUninitialize(); }
+struct async_operation_block_param +{ + IAsyncOperationCompletedHandler_SpeechRecognitionCompilationResult *handler; + IAsyncOperation_SpeechRecognitionCompilationResult *operation; +}; + +static DWORD WINAPI async_operation_block_thread(void *arg) +{ + struct async_operation_block_param *param = arg; + HRESULT hr; + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(param->operation, param->handler); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + return 0; +} + +struct async_operation_close_param +{ + IAsyncInfo *info; +}; + +static DWORD WINAPI async_operation_close_thread(void *arg) +{ + struct async_operation_close_param *param = arg; + HRESULT hr; + + hr = IAsyncInfo_Close(param->info); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + return 0; +} + static void test_SpeechRecognizer(void) { static const WCHAR *speech_recognition_name = L"Windows.Media.SpeechRecognition.SpeechRecognizer"; @@ -824,21 +859,24 @@ static void test_SpeechRecognizer(void) ISpeechRecognizerFactory *sr_factory = NULL; ISpeechRecognizerStatics *sr_statics = NULL; ISpeechRecognizerStatics2 *sr_statics2 = NULL; - ISpeechRecognizer *recognizer = NULL; + ISpeechRecognizer *recognizer = NULL, *recognizer_2 = NULL; ISpeechRecognizer2 *recognizer2 = NULL; IActivationFactory *factory = NULL; - IInspectable *inspectable = NULL; + IInspectable *inspectable = NULL, *inspectable_2 = NULL; IClosable *closable = NULL; ILanguage *language = NULL; IAsyncInfo *info = NULL; + struct compilation_handler compilation_handler, compilation_handler2, compilation_handler3; struct completed_event_handler completed_handler; struct recognition_result_handler result_handler; - struct compilation_handler compilation_handler; - struct compilation_handler compilation_handler2; + struct async_operation_block_param block_param; + struct async_operation_close_param close_param; SpeechRecognitionResultStatus result_status; EventRegistrationToken token = { .value = 0 }; + HANDLE close_thread, blocked_thread; AsyncStatus async_status; HSTRING hstr, hstr_lang; + DWORD thread_status; HRESULT hr; UINT32 id; LONG ref; @@ -945,6 +983,7 @@ static void test_SpeechRecognizer(void) ok(ref == 1, "Got unexpected ref %lu.\n", ref);
compilation_handler_create_static(&compilation_handler); + compilation_handler.event_block = NULL; compilation_handler.event_finished = CreateEventW(NULL, FALSE, FALSE, NULL); compilation_handler.thread_id = GetCurrentThreadId();
@@ -965,9 +1004,8 @@ static void test_SpeechRecognizer(void)
hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, &compilation_handler.IAsyncHandler_Compilation_iface); todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine check_refcount(&compilation_handler.IAsyncHandler_Compilation_iface, 1);
- WaitForSingleObject(compilation_handler.event_finished, INFINITE); + todo_wine ok(!WaitForSingleObject(compilation_handler.event_finished, 1000), "Wait for event_finished failed.\n"); CloseHandle(compilation_handler.event_finished);
hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, NULL); @@ -976,7 +1014,7 @@ static void test_SpeechRecognizer(void) handler = (void*)0xdeadbeef; hr = IAsyncOperation_SpeechRecognitionCompilationResult_get_Completed(operation, &handler); todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(handler == NULL, "Handler had value %p.\n", handler); + todo_wine ok(handler == NULL || broken(handler != NULL), "Handler had value %p.\n", handler); /* Broken on Win10 1507 x32... */
hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); @@ -1048,7 +1086,7 @@ static void test_SpeechRecognizer(void) compilation_handler2.event_finished = CreateEventW(NULL, FALSE, FALSE, NULL); compilation_handler2.thread_id = GetCurrentThreadId();
- ok(compilation_handler2.event_finished != NULL, "Finished event wasn't created.\n"); + todo_wine ok(compilation_handler2.event_finished != NULL, "Finished event wasn't created.\n");
hr = ISpeechRecognizer_CompileConstraintsAsync(recognizer, &operation); todo_wine ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); @@ -1057,23 +1095,10 @@ static void test_SpeechRecognizer(void) hr = IAsyncOperation_SpeechRecognitionCompilationResult_QueryInterface(operation, &IID_IAsyncInfo, (void **)&info); todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
- /* This one can fail, if the async operation had already finished */ - compilation_result = (void*)0xdeadbeef; - hr = IAsyncOperation_SpeechRecognitionCompilationResult_GetResults(operation, &compilation_result); - todo_wine ok(hr == E_ILLEGAL_METHOD_CALL, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(compilation_result == (void*)0xdeadbeef, "Compilation result had value %p.\n", compilation_result); - - async_status = 0xdeadbeef; - hr = IAsyncInfo_get_Status(info, &async_status); - todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); - todo_wine ok(async_status == Started || async_status == Completed, "Status was %#x.\n", async_status); - - IAsyncInfo_Release(info); - hr = IAsyncOperation_SpeechRecognitionCompilationResult_put_Completed(operation, &compilation_handler2.IAsyncHandler_Compilation_iface); todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
- WaitForSingleObject(compilation_handler2.event_finished, INFINITE); + todo_wine ok(!WaitForSingleObject(compilation_handler2.event_finished, 1000), "Wait for event_finished failed.\n"); CloseHandle(compilation_handler2.event_finished);
async_status = 0xdeadbeef; @@ -1081,10 +1106,73 @@ static void test_SpeechRecognizer(void) todo_wine ok(hr == S_OK, "IAsyncInfo_get_Status failed, hr %#lx.\n", hr); todo_wine ok(async_status == Completed, "Status was %#x.\n", async_status);
+ ref = IAsyncInfo_Release(info); + todo_wine ok(ref == 1, "Got unexpected ref %lu.\n", ref); + ref = IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); + todo_wine ok(!ref, "Got unexpected ref %lu.\n", ref); + + /* Test if AsyncInfo_Close waits for the handler to finish. */ + hr = RoActivateInstance(hstr, &inspectable_2); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = IInspectable_QueryInterface(inspectable_2, &IID_ISpeechRecognizer, (void **)&recognizer_2); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + compilation_handler_create_static(&compilation_handler3); + compilation_handler3.event_block = CreateEventW(NULL, FALSE, FALSE, NULL); + compilation_handler3.event_finished = CreateEventW(NULL, FALSE, FALSE, NULL); + compilation_handler3.thread_id = GetCurrentThreadId(); + + todo_wine ok(compilation_handler3.event_finished != NULL, "Finished event wasn't created.\n"); + + hr = ISpeechRecognizer_CompileConstraintsAsync(recognizer_2, &operation); + todo_wine ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); + + block_param.handler = &compilation_handler3.IAsyncHandler_Compilation_iface; + block_param.operation = operation; + blocked_thread = CreateThread(NULL, 0, async_operation_block_thread, &block_param, 0, NULL); + thread_status = WaitForSingleObject(blocked_thread, 1000); + todo_wine ok(thread_status == WAIT_TIMEOUT || broken(thread_status == WAIT_OBJECT_0), "Wait for block_thread didn't time out.\n"); /* Broken on Win10 1507 x32... */ + + if (thread_status == WAIT_TIMEOUT) + { + todo_wine ok(compilation_handler3.ref == 3, "Got unexpected ref %lu.\n", compilation_handler3.ref); + todo_wine check_refcount(operation, 3); + + hr = IAsyncOperation_SpeechRecognitionCompilationResult_QueryInterface(operation, &IID_IAsyncInfo, (void **)&info); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + close_param.info = info; + close_thread = CreateThread(NULL, 0, async_operation_close_thread, &close_param, 0, NULL); + todo_wine ok(!WaitForSingleObject(close_thread, 100), "Wait for close_thread failed.\n"); + + CloseHandle(close_thread); + } + + SetEvent(compilation_handler3.event_block); + todo_wine ok(!WaitForSingleObject(compilation_handler3.event_finished, 500), "Wait for event_finished failed.\n"); + todo_wine ok(!WaitForSingleObject(blocked_thread, 1000), "Wait for block_thread failed.\n"); + + CloseHandle(blocked_thread); + CloseHandle(compilation_handler3.event_block); + CloseHandle(compilation_handler3.event_finished); + + ref = IAsyncInfo_Release(info); + todo_wine ok(ref == 1, "Got unexpected ref %lu.\n", ref); + skip_operation: ref = IAsyncOperation_SpeechRecognitionCompilationResult_Release(operation); ok(!ref, "Got unexpected ref %lu.\n", ref);
+ if (recognizer_2) + { + ref = ISpeechRecognizer_Release(recognizer_2); + ok(ref == 1, "Got unexpected ref %lu.\n", ref); + + ref = IInspectable_Release(inspectable_2); + ok(!ref, "Got unexpected ref %lu.\n", ref); + } + ref = ISpeechContinuousRecognitionSession_Release(session); ok(ref == 1, "Got unexpected ref %lu.\n", ref);