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 return E_NOTIMPL; 67 } GetResults(internal::AsyncOperationAbi<T> * results)68 IFACEMETHODIMP GetResults(internal::AsyncOperationAbi<T>* results) final { 69 if (!is_complete_) { 70 ADD_FAILURE() << "GetResults called on incomplete IAsyncOperation."; 71 return E_PENDING; 72 } 73 if (status_ != AsyncStatus::Completed && !results_includes_failure_) 74 return E_UNEXPECTED; 75 return base::win::internal::CopyTo(results_, results); 76 } 77 78 // ABI::Windows::Foundation::IAsyncInfo: get_Id(uint32_t * id)79 IFACEMETHODIMP get_Id(uint32_t* id) final { 80 NOTREACHED(); 81 return E_NOTIMPL; 82 } get_Status(AsyncStatus * status)83 IFACEMETHODIMP get_Status(AsyncStatus* status) final { 84 *status = status_; 85 return S_OK; 86 } get_ErrorCode(HRESULT * error_code)87 IFACEMETHODIMP get_ErrorCode(HRESULT* error_code) final { 88 EXPECT_FALSE(results_includes_failure_) 89 << "get_ErrorCode called on IAsyncOperation whose failure is expected " 90 "to be expressed through the results instead. If a case arises " 91 "where this is actually intended this check can be removed, but is " 92 "most likely an indication of incorrectly assuming the error_code " 93 "can be used in place of get_Status or GetResults for this kind of " 94 "IAsyncOperation."; 95 *error_code = error_code_; 96 return S_OK; 97 } Cancel()98 IFACEMETHODIMP Cancel() final { 99 NOTREACHED(); 100 return E_NOTIMPL; 101 } Close()102 IFACEMETHODIMP Close() final { 103 NOTREACHED(); 104 return E_NOTIMPL; 105 } 106 107 // Completes the operation with |error_code|. 108 // 109 // The get_ErrorCode API will be set to return |error_code|, the remainder of 110 // the APIs will be set to represent an error state, and the CompletedHandler 111 // (if defined) will be run. CompleteWithError(HRESULT error_code)112 void CompleteWithError(HRESULT error_code) { 113 error_code_ = error_code; 114 status_ = AsyncStatus::Error; 115 InvokeCompletedHandler(); 116 } 117 118 // Completes the operation with |results|, but with an AsyncStatus of Error. 119 // This is an uncommon combination only appropriate when |results| includes 120 // the failure information. 121 // 122 // The GetResults API will be set to return |results| and the get_ErrorCode 123 // API will be set to return S_OK, but the get_Status API will be set to 124 // return AsyncStatus::Error. Then the CompletedHandler (if defined) will be 125 // run. CompleteWithErrorResult(internal::AsyncOperationStorage<T> results)126 void CompleteWithErrorResult(internal::AsyncOperationStorage<T> results) { 127 error_code_ = S_OK; 128 results_ = std::move(results); 129 results_includes_failure_ = true; 130 status_ = AsyncStatus::Error; 131 InvokeCompletedHandler(); 132 } 133 134 // Completes the operation with |results|. 135 // 136 // The GetResults API will be set to return |results|, the remainder of the 137 // APIs will be set to represent a successfully completed state, and the 138 // CompletedHandler (if defined) will be run. CompleteWithResults(internal::AsyncOperationStorage<T> results)139 void CompleteWithResults(internal::AsyncOperationStorage<T> results) { 140 error_code_ = S_OK; 141 results_ = std::move(results); 142 status_ = AsyncStatus::Completed; 143 InvokeCompletedHandler(); 144 } 145 146 private: InvokeCompletedHandler()147 void InvokeCompletedHandler() { 148 ASSERT_FALSE(is_complete_) 149 << "Attempted to invoke completion on an already " 150 "completed IAsyncOperation."; 151 is_complete_ = true; 152 if (handler_) 153 handler_->Invoke(this, status_); 154 } 155 156 HRESULT error_code_ = S_OK; 157 Microsoft::WRL::ComPtr< 158 ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>> 159 handler_; 160 bool is_complete_ = false; 161 internal::AsyncOperationOptionalStorage<T> results_; 162 bool results_includes_failure_ = false; 163 AsyncStatus status_ = AsyncStatus::Started; 164 }; 165 166 } // namespace win 167 } // namespace base 168 169 #endif // BASE_TEST_FAKE_IASYNC_OPERATION_WIN_H_ 170