1 // Copyright 2020 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TEST_FAKE_IASYNC_OPERATION_WIN_H_ 6 #define BASE_TEST_FAKE_IASYNC_OPERATION_WIN_H_ 7 8 #include <wrl/client.h> 9 #include <wrl/implements.h> 10 11 #include "base/notreached.h" 12 #include "base/win/winrt_foundation_helpers.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 namespace base { 16 namespace win { 17 18 namespace internal { 19 20 // Templates used to allow easy reference to the correct types. 21 // See base/win/winrt_foundation_helpers.h for explanation. 22 template <typename T> 23 using AsyncOperationComplex = 24 typename ABI::Windows::Foundation::IAsyncOperation<T>::TResult_complex; 25 26 template <typename T> 27 using AsyncOperationAbi = AbiType<AsyncOperationComplex<T>>; 28 29 template <typename T> 30 using AsyncOperationOptionalStorage = 31 OptionalStorageType<AsyncOperationComplex<T>>; 32 33 template <typename T> 34 using AsyncOperationStorage = StorageType<AsyncOperationComplex<T>>; 35 36 } // namespace internal 37 38 // Provides an implementation of Windows::Foundation::IAsyncOperation for 39 // use in GTests. 40 template <typename T> 41 class FakeIAsyncOperation final 42 : public Microsoft::WRL::RuntimeClass< 43 Microsoft::WRL::RuntimeClassFlags< 44 Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, 45 ABI::Windows::Foundation::IAsyncOperation<T>, 46 ABI::Windows::Foundation::IAsyncInfo> { 47 public: 48 FakeIAsyncOperation() = default; 49 FakeIAsyncOperation(const FakeIAsyncOperation&) = delete; 50 FakeIAsyncOperation& operator=(const FakeIAsyncOperation&) = delete; 51 52 // ABI::Windows::Foundation::IAsyncOperation: put_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T> * handler)53 IFACEMETHODIMP put_Completed( 54 ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>* handler) 55 final { 56 EXPECT_EQ(nullptr, handler_) 57 << "put_Completed called on IAsyncOperation with a CompletedHandler " 58 "already defined."; 59 handler_ = handler; 60 return S_OK; 61 } get_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T> ** handler)62 IFACEMETHODIMP get_Completed( 63 ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>** handler) 64 final { 65 NOTREACHED(); 66 } GetResults(internal::AsyncOperationAbi<T> * results)67 IFACEMETHODIMP GetResults(internal::AsyncOperationAbi<T>* results) final { 68 if (!is_complete_) { 69 ADD_FAILURE() << "GetResults called on incomplete IAsyncOperation."; 70 return E_PENDING; 71 } 72 if (status_ != AsyncStatus::Completed && !results_includes_failure_) 73 return E_UNEXPECTED; 74 return base::win::internal::CopyTo(results_, results); 75 } 76 77 // ABI::Windows::Foundation::IAsyncInfo: get_Id(uint32_t * id)78 IFACEMETHODIMP get_Id(uint32_t* id) final { NOTREACHED(); } get_Status(AsyncStatus * status)79 IFACEMETHODIMP get_Status(AsyncStatus* status) final { 80 *status = status_; 81 return S_OK; 82 } get_ErrorCode(HRESULT * error_code)83 IFACEMETHODIMP get_ErrorCode(HRESULT* error_code) final { 84 EXPECT_FALSE(results_includes_failure_) 85 << "get_ErrorCode called on IAsyncOperation whose failure is expected " 86 "to be expressed through the results instead. If a case arises " 87 "where this is actually intended this check can be removed, but is " 88 "most likely an indication of incorrectly assuming the error_code " 89 "can be used in place of get_Status or GetResults for this kind of " 90 "IAsyncOperation."; 91 *error_code = error_code_; 92 return S_OK; 93 } Cancel()94 IFACEMETHODIMP Cancel() final { NOTREACHED(); } Close()95 IFACEMETHODIMP Close() final { NOTREACHED(); } 96 97 // Completes the operation with |error_code|. 98 // 99 // The get_ErrorCode API will be set to return |error_code|, the remainder of 100 // the APIs will be set to represent an error state, and the CompletedHandler 101 // (if defined) will be run. CompleteWithError(HRESULT error_code)102 void CompleteWithError(HRESULT error_code) { 103 error_code_ = error_code; 104 status_ = AsyncStatus::Error; 105 InvokeCompletedHandler(); 106 } 107 108 // Completes the operation with |results|, but with an AsyncStatus of Error. 109 // This is an uncommon combination only appropriate when |results| includes 110 // the failure information. 111 // 112 // The GetResults API will be set to return |results| and the get_ErrorCode 113 // API will be set to return S_OK, but the get_Status API will be set to 114 // return AsyncStatus::Error. Then the CompletedHandler (if defined) will be 115 // run. CompleteWithErrorResult(internal::AsyncOperationStorage<T> results)116 void CompleteWithErrorResult(internal::AsyncOperationStorage<T> results) { 117 error_code_ = S_OK; 118 results_ = std::move(results); 119 results_includes_failure_ = true; 120 status_ = AsyncStatus::Error; 121 InvokeCompletedHandler(); 122 } 123 124 // Completes the operation with |results|. 125 // 126 // The GetResults API will be set to return |results|, the remainder of the 127 // APIs will be set to represent a successfully completed state, and the 128 // CompletedHandler (if defined) will be run. CompleteWithResults(internal::AsyncOperationStorage<T> results)129 void CompleteWithResults(internal::AsyncOperationStorage<T> results) { 130 error_code_ = S_OK; 131 results_ = std::move(results); 132 status_ = AsyncStatus::Completed; 133 InvokeCompletedHandler(); 134 } 135 136 private: InvokeCompletedHandler()137 void InvokeCompletedHandler() { 138 ASSERT_FALSE(is_complete_) 139 << "Attempted to invoke completion on an already " 140 "completed IAsyncOperation."; 141 is_complete_ = true; 142 if (handler_) 143 handler_->Invoke(this, status_); 144 } 145 146 HRESULT error_code_ = S_OK; 147 Microsoft::WRL::ComPtr< 148 ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>> 149 handler_; 150 bool is_complete_ = false; 151 internal::AsyncOperationOptionalStorage<T> results_; 152 bool results_includes_failure_ = false; 153 AsyncStatus status_ = AsyncStatus::Started; 154 }; 155 156 } // namespace win 157 } // namespace base 158 159 #endif // BASE_TEST_FAKE_IASYNC_OPERATION_WIN_H_ 160