// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/fake_iasync_operation_win.h"
#include <asyncinfo.h>
#include <wrl/event.h>
#include <wrl/implements.h>
#include "base/test/async_results_test_values_win.h"
#include "testing/gtest/include/gtest/gtest-spi.h"
#include "testing/gtest/include/gtest/gtest.h"
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::IAsyncOperationCompletedHandler;
using Microsoft::WRL::Callback;
using Microsoft::WRL::Make;
namespace base {
namespace win {
namespace {
constexpr HRESULT kTestError = 0x87654321;
}
template <typename T>
class FakeIAsyncOperationTest : public ::testing::Test {};
TYPED_TEST_SUITE_P(FakeIAsyncOperationTest);
TYPED_TEST_P(FakeIAsyncOperationTest, MultipleCompletedHandlers) {
auto operation = Make<FakeIAsyncOperation<TypeParam>>();
auto handler = Callback<IAsyncOperationCompletedHandler<TypeParam>>(
[](auto async_operation, AsyncStatus async_status) { return S_OK; });
ASSERT_HRESULT_SUCCEEDED(operation->put_Completed(handler.Get()));
EXPECT_NONFATAL_FAILURE(
ASSERT_HRESULT_SUCCEEDED(operation->put_Completed(handler.Get()));
, "put_Completed");
}
TYPED_TEST_P(FakeIAsyncOperationTest, MultipleCompletions) {
auto operation = Make<FakeIAsyncOperation<TypeParam>>();
base::test::AsyncResultsTestValues<TypeParam> test_values;
ASSERT_NO_FATAL_FAILURE(
operation->CompleteWithResults(test_values.GetTestValue_T()));
// EXPECT_FATAL_FAILURE() can only reference globals and statics.
// https://github.com/google/googletest/blob/main/docs/advanced.md#catching-failures
static auto test_value_t = test_values.GetTestValue_T();
static auto& static_operation = operation;
EXPECT_FATAL_FAILURE(static_operation->CompleteWithResults(test_value_t),
"already completed");
operation = Make<FakeIAsyncOperation<TypeParam>>();
static_operation = operation;
ASSERT_NO_FATAL_FAILURE(operation->CompleteWithError(E_FAIL));
EXPECT_FATAL_FAILURE(static_operation->CompleteWithError(E_FAIL),
"already completed");
operation = Make<FakeIAsyncOperation<TypeParam>>();
static_operation = operation;
ASSERT_NO_FATAL_FAILURE(operation->CompleteWithError(E_FAIL));
EXPECT_FATAL_FAILURE(static_operation->CompleteWithResults(test_value_t),
"already completed");
operation = Make<FakeIAsyncOperation<TypeParam>>();
static_operation = operation;
ASSERT_NO_FATAL_FAILURE(
operation->CompleteWithResults(test_values.GetTestValue_T()));
EXPECT_FATAL_FAILURE(static_operation->CompleteWithError(E_FAIL),
"already completed");
}
TYPED_TEST_P(FakeIAsyncOperationTest, CompleteWithResults_WithHandler) {
auto operation = Make<FakeIAsyncOperation<TypeParam>>();
bool completed_handler_called = false;
ASSERT_HRESULT_SUCCEEDED(operation->put_Completed(
Callback<IAsyncOperationCompletedHandler<TypeParam>>(
[operation, &completed_handler_called](auto async_operation,
AsyncStatus async_status) {
completed_handler_called = true;
EXPECT_EQ(operation.Get(), async_operation);
EXPECT_EQ(async_status, AsyncStatus::Completed);
return S_OK;
})
.Get()));
ASSERT_FALSE(completed_handler_called);
AsyncStatus async_status;
ASSERT_HRESULT_SUCCEEDED(operation->get_Status(&async_status));
ASSERT_EQ(async_status, AsyncStatus::Started);
HRESULT error_code;
ASSERT_HRESULT_SUCCEEDED(operation->get_ErrorCode(&error_code));
ASSERT_EQ(error_code, S_OK);
base::test::AsyncResultsTestValues<TypeParam> test_values;
auto results = test_values.GetDefaultValue_AsyncResultsT();
EXPECT_NONFATAL_FAILURE(
ASSERT_HRESULT_FAILED(operation->GetResults(&results)), "GetResults");
operation->CompleteWithResults(test_values.GetTestValue_AsyncResultsT());
ASSERT_TRUE(completed_handler_called);
ASSERT_HRESULT_SUCCEEDED(operation->get_Status(&async_status));
ASSERT_EQ(async_status, AsyncStatus::Completed);
ASSERT_HRESULT_SUCCEEDED(operation->get_ErrorCode(&error_code));
ASSERT_EQ(error_code, S_OK);
ASSERT_HRESULT_SUCCEEDED(operation->GetResults(&results));
ASSERT_EQ(results, test_values.GetTestValue_AsyncResultsT());
}
TYPED_TEST_P(FakeIAsyncOperationTest, CompleteWithResults_WithoutHandler) {
auto operation = Make<FakeIAsyncOperation<TypeParam>>();
AsyncStatus async_status;
ASSERT_HRESULT_SUCCEEDED(operation->get_Status(&async_status));
ASSERT_EQ(async_status, AsyncStatus::Started);
HRESULT error_code;
ASSERT_HRESULT_SUCCEEDED(operation->get_ErrorCode(&error_code));
ASSERT_EQ(error_code, S_OK);
base::test::AsyncResultsTestValues<TypeParam> test_values;
auto results = test_values.GetDefaultValue_AsyncResultsT();
EXPECT_NONFATAL_FAILURE(
ASSERT_HRESULT_FAILED(operation->GetResults(&results)), "GetResults");
operation->CompleteWithResults(test_values.GetTestValue_AsyncResultsT());
ASSERT_HRESULT_SUCCEEDED(operation->get_Status(&async_status));
ASSERT_EQ(async_status, AsyncStatus::Completed);
ASSERT_HRESULT_SUCCEEDED(operation->get_ErrorCode(&error_code));
ASSERT_EQ(error_code, S_OK);
ASSERT_HRESULT_SUCCEEDED(operation->GetResults(&results));
ASSERT_EQ(results, test_values.GetTestValue_AsyncResultsT());
}
TYPED_TEST_P(FakeIAsyncOperationTest, CompleteWithError_WithHandler) {
auto operation = Make<FakeIAsyncOperation<TypeParam>>();
bool completed_handler_called = false;
ASSERT_HRESULT_SUCCEEDED(operation->put_Completed(
Callback<IAsyncOperationCompletedHandler<TypeParam>>(
[operation, &completed_handler_called](auto async_operation,
AsyncStatus async_status) {
completed_handler_called = true;
EXPECT_EQ(operation.Get(), async_operation);
EXPECT_EQ(async_status, AsyncStatus::Error);
return S_OK;
})
.Get()));
ASSERT_FALSE(completed_handler_called);
AsyncStatus async_status;
ASSERT_HRESULT_SUCCEEDED(operation->get_Status(&async_status));
ASSERT_EQ(async_status, AsyncStatus::Started);
HRESULT error_code;
ASSERT_HRESULT_SUCCEEDED(operation->get_ErrorCode(&error_code));
ASSERT_EQ(error_code, S_OK);
base::test::AsyncResultsTestValues<TypeParam> test_values;
auto results = test_values.GetDefaultValue_AsyncResultsT();
EXPECT_NONFATAL_FAILURE(
ASSERT_HRESULT_FAILED(operation->GetResults(&results)), "GetResults");
operation->CompleteWithError(kTestError);
ASSERT_TRUE(completed_handler_called);
ASSERT_HRESULT_SUCCEEDED(operation->get_Status(&async_status));
ASSERT_EQ(async_status, AsyncStatus::Error);
ASSERT_HRESULT_SUCCEEDED(operation->get_ErrorCode(&error_code));
ASSERT_EQ(error_code, kTestError);
ASSERT_HRESULT_FAILED(operation->GetResults(&results));
}
TYPED_TEST_P(FakeIAsyncOperationTest, CompleteWithError_WithoutHandler) {
auto operation = Make<FakeIAsyncOperation<TypeParam>>();
AsyncStatus async_status;
ASSERT_HRESULT_SUCCEEDED(operation->get_Status(&async_status));
ASSERT_EQ(async_status, AsyncStatus::Started);
HRESULT error_code;
ASSERT_HRESULT_SUCCEEDED(operation->get_ErrorCode(&error_code));
ASSERT_EQ(error_code, S_OK);
base::test::AsyncResultsTestValues<TypeParam> test_values;
auto results = test_values.GetDefaultValue_AsyncResultsT();
EXPECT_NONFATAL_FAILURE(
ASSERT_HRESULT_FAILED(operation->GetResults(&results)), "GetResults");
operation->CompleteWithError(kTestError);
ASSERT_HRESULT_SUCCEEDED(operation->get_Status(&async_status));
ASSERT_EQ(async_status, AsyncStatus::Error);
ASSERT_HRESULT_SUCCEEDED(operation->get_ErrorCode(&error_code));
ASSERT_EQ(error_code, kTestError);
ASSERT_HRESULT_FAILED(operation->GetResults(&results));
}
REGISTER_TYPED_TEST_SUITE_P(FakeIAsyncOperationTest,
MultipleCompletedHandlers,
MultipleCompletions,
CompleteWithResults_WithHandler,
CompleteWithResults_WithoutHandler,
CompleteWithError_WithHandler,
CompleteWithError_WithoutHandler);
INSTANTIATE_TYPED_TEST_SUITE_P(Win,
FakeIAsyncOperationTest,
base::test::AsyncResultsTestValuesTypes);
} // namespace win
} // namespace base