| // 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. |
| |
| #ifndef BASE_TEST_FAKE_IASYNC_OPERATION_WIN_H_ |
| #define BASE_TEST_FAKE_IASYNC_OPERATION_WIN_H_ |
| |
| #include <wrl/client.h> |
| #include <wrl/implements.h> |
| |
| #include "base/notreached.h" |
| #include "base/win/winrt_foundation_helpers.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace base { |
| namespace win { |
| |
| namespace internal { |
| |
| // Templates used to allow easy reference to the correct types. |
| // See base/win/winrt_foundation_helpers.h for explanation. |
| template <typename T> |
| using AsyncOperationComplex = |
| typename ABI::Windows::Foundation::IAsyncOperation<T>::TResult_complex; |
| |
| template <typename T> |
| using AsyncOperationAbi = AbiType<AsyncOperationComplex<T>>; |
| |
| template <typename T> |
| using AsyncOperationOptionalStorage = |
| OptionalStorageType<AsyncOperationComplex<T>>; |
| |
| template <typename T> |
| using AsyncOperationStorage = StorageType<AsyncOperationComplex<T>>; |
| |
| } // namespace internal |
| |
| // Provides an implementation of Windows::Foundation::IAsyncOperation for |
| // use in GTests. |
| template <typename T> |
| class FakeIAsyncOperation final |
| : public Microsoft::WRL::RuntimeClass< |
| Microsoft::WRL::RuntimeClassFlags< |
| Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, |
| ABI::Windows::Foundation::IAsyncOperation<T>, |
| ABI::Windows::Foundation::IAsyncInfo> { |
| public: |
| FakeIAsyncOperation() = default; |
| FakeIAsyncOperation(const FakeIAsyncOperation&) = delete; |
| FakeIAsyncOperation& operator=(const FakeIAsyncOperation&) = delete; |
| |
| // ABI::Windows::Foundation::IAsyncOperation: |
| IFACEMETHODIMP put_Completed( |
| ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>* handler) |
| final { |
| EXPECT_EQ(nullptr, handler_) |
| << "put_Completed called on IAsyncOperation with a CompletedHandler " |
| "already defined."; |
| handler_ = handler; |
| return S_OK; |
| } |
| IFACEMETHODIMP get_Completed( |
| ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>** handler) |
| final { |
| NOTREACHED(); |
| return E_NOTIMPL; |
| } |
| IFACEMETHODIMP GetResults(internal::AsyncOperationAbi<T>* results) final { |
| if (!is_complete_) { |
| ADD_FAILURE() << "GetResults called on incomplete IAsyncOperation."; |
| return E_PENDING; |
| } |
| if (status_ != AsyncStatus::Completed && !results_includes_failure_) |
| return E_UNEXPECTED; |
| return base::win::internal::CopyTo(results_, results); |
| } |
| |
| // ABI::Windows::Foundation::IAsyncInfo: |
| IFACEMETHODIMP get_Id(uint32_t* id) final { |
| NOTREACHED(); |
| return E_NOTIMPL; |
| } |
| IFACEMETHODIMP get_Status(AsyncStatus* status) final { |
| *status = status_; |
| return S_OK; |
| } |
| IFACEMETHODIMP get_ErrorCode(HRESULT* error_code) final { |
| EXPECT_FALSE(results_includes_failure_) |
| << "get_ErrorCode called on IAsyncOperation whose failure is expected " |
| "to be expressed through the results instead. If a case arises " |
| "where this is actually intended this check can be removed, but is " |
| "most likely an indication of incorrectly assuming the error_code " |
| "can be used in place of get_Status or GetResults for this kind of " |
| "IAsyncOperation."; |
| *error_code = error_code_; |
| return S_OK; |
| } |
| IFACEMETHODIMP Cancel() final { |
| NOTREACHED(); |
| return E_NOTIMPL; |
| } |
| IFACEMETHODIMP Close() final { |
| NOTREACHED(); |
| return E_NOTIMPL; |
| } |
| |
| // Completes the operation with |error_code|. |
| // |
| // The get_ErrorCode API will be set to return |error_code|, the remainder of |
| // the APIs will be set to represent an error state, and the CompletedHandler |
| // (if defined) will be run. |
| void CompleteWithError(HRESULT error_code) { |
| error_code_ = error_code; |
| status_ = AsyncStatus::Error; |
| InvokeCompletedHandler(); |
| } |
| |
| // Completes the operation with |results|, but with an AsyncStatus of Error. |
| // This is an uncommon combination only appropriate when |results| includes |
| // the failure information. |
| // |
| // The GetResults API will be set to return |results| and the get_ErrorCode |
| // API will be set to return S_OK, but the get_Status API will be set to |
| // return AsyncStatus::Error. Then the CompletedHandler (if defined) will be |
| // run. |
| void CompleteWithErrorResult(internal::AsyncOperationStorage<T> results) { |
| error_code_ = S_OK; |
| results_ = std::move(results); |
| results_includes_failure_ = true; |
| status_ = AsyncStatus::Error; |
| InvokeCompletedHandler(); |
| } |
| |
| // Completes the operation with |results|. |
| // |
| // The GetResults API will be set to return |results|, the remainder of the |
| // APIs will be set to represent a successfully completed state, and the |
| // CompletedHandler (if defined) will be run. |
| void CompleteWithResults(internal::AsyncOperationStorage<T> results) { |
| error_code_ = S_OK; |
| results_ = std::move(results); |
| status_ = AsyncStatus::Completed; |
| InvokeCompletedHandler(); |
| } |
| |
| private: |
| void InvokeCompletedHandler() { |
| ASSERT_FALSE(is_complete_) |
| << "Attempted to invoke completion on an already " |
| "completed IAsyncOperation."; |
| is_complete_ = true; |
| if (handler_) |
| handler_->Invoke(this, status_); |
| } |
| |
| HRESULT error_code_ = S_OK; |
| Microsoft::WRL::ComPtr< |
| ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>> |
| handler_; |
| bool is_complete_ = false; |
| internal::AsyncOperationOptionalStorage<T> results_; |
| bool results_includes_failure_ = false; |
| AsyncStatus status_ = AsyncStatus::Started; |
| }; |
| |
| } // namespace win |
| } // namespace base |
| |
| #endif // BASE_TEST_FAKE_IASYNC_OPERATION_WIN_H_ |