1 // Copyright 2018 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 #include "base/win/async_operation.h" 6 7 #include <utility> 8 9 #include "base/test/gtest_util.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace WRL = Microsoft::WRL; 13 14 using ABI::Windows::Foundation::IAsyncOperation; 15 using ABI::Windows::Foundation::IAsyncOperationCompletedHandler; 16 17 // In order to exercise the interface logic of AsyncOperation we define an empty 18 // dummy interface, its implementation, and the necessary boilerplate to hook it 19 // up with IAsyncOperation and IAsyncOperationCompletedHandler. 20 namespace { 21 22 // Chosen by fair `uuidgen` invocation. Also applies to the UUIDs below. 23 MIDL_INTERFACE("756358C7-8083-4D78-9D27-9278B76096d4") 24 IFooBar : public IInspectable{}; 25 26 class FooBar 27 : public WRL::RuntimeClass< 28 WRL::RuntimeClassFlags<WRL::WinRt | WRL::InhibitRoOriginateError>, 29 IFooBar> {}; 30 31 } // namespace 32 33 namespace ABI { 34 namespace Windows { 35 namespace Foundation { 36 37 // Provide the required template specializations to register 38 // IAsyncOperation<Foobar*> as an AggregateType. This is similar to how it is 39 // done for UWP classes. 40 template <> 41 struct DECLSPEC_UUID("124858e4-f97e-409c-86ae-418c4781144c") 42 IAsyncOperation<FooBar*> 43 : IAsyncOperation_impl<Internal::AggregateType<FooBar*, IFooBar*>> { 44 static const wchar_t* z_get_rc_name_impl() { 45 return L"Windows.Foundation.IAsyncOperation<FooBar>"; 46 } 47 }; 48 49 template <> 50 struct DECLSPEC_UUID("9e49373c-200c-4715-abd7-4214ba669c81") 51 IAsyncOperationCompletedHandler<FooBar*> 52 : IAsyncOperationCompletedHandler_impl< 53 Internal::AggregateType<FooBar*, IFooBar*>> { 54 static const wchar_t* z_get_rc_name_impl() { 55 return L"Windows.Foundation.AsyncOperationCompletedHandler<FooBar>"; 56 } 57 }; 58 59 #ifdef NTDDI_WIN10_VB // Windows 10.0.19041 60 // Specialization templates that used to be in windows.foundation.h, removed in 61 // the 10.0.19041.0 SDK, so placed here instead. 62 template <> 63 struct __declspec(uuid("968b9665-06ed-5774-8f53-8edeabd5f7b5")) 64 IAsyncOperation<int> : IAsyncOperation_impl<int> {}; 65 66 template <> 67 struct __declspec(uuid("d60cae9d-88cb-59f1-8576-3fba44796be8")) 68 IAsyncOperationCompletedHandler<int> 69 : IAsyncOperationCompletedHandler_impl<int> {}; 70 #endif 71 72 } // namespace Foundation 73 } // namespace Windows 74 } // namespace ABI 75 76 namespace base { 77 namespace win { 78 79 namespace { 80 81 // Utility method to add a completion callback to |async_op|. |*called_cb| will 82 // be set to true once the callback is invoked. 83 template <typename T> 84 void PutCallback(AsyncOperation<T>* async_op, bool* called_cb) { 85 async_op->put_Completed( 86 WRL::Callback<IAsyncOperationCompletedHandler<T>>( 87 [=](IAsyncOperation<T>* iasync_op, AsyncStatus status) { 88 EXPECT_EQ(async_op, iasync_op); 89 *called_cb = true; 90 return S_OK; 91 }) 92 .Get()); 93 } 94 95 } // namespace 96 97 TEST(AsyncOperationTest, TestInt) { 98 bool called_cb = false; 99 100 auto int_op = WRL::Make<AsyncOperation<int>>(); 101 PutCallback(int_op.Get(), &called_cb); 102 103 int results; 104 EXPECT_TRUE(FAILED(int_op->GetResults(&results))); 105 EXPECT_FALSE(called_cb); 106 int_op->callback().Run(123); 107 108 EXPECT_TRUE(called_cb); 109 EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); 110 EXPECT_EQ(123, results); 111 112 // GetResults should be idempotent. 113 EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); 114 EXPECT_EQ(123, results); 115 } 116 117 TEST(AsyncOperationTest, TestBool) { 118 bool called_cb = false; 119 120 auto bool_op = WRL::Make<AsyncOperation<bool>>(); 121 PutCallback(bool_op.Get(), &called_cb); 122 123 // AsyncOperation<bool> is an aggregate of bool and boolean, and requires a 124 // pointer to the latter to get the results. 125 boolean results; 126 EXPECT_TRUE(FAILED(bool_op->GetResults(&results))); 127 EXPECT_FALSE(called_cb); 128 bool_op->callback().Run(true); 129 130 EXPECT_TRUE(called_cb); 131 EXPECT_TRUE(SUCCEEDED(bool_op->GetResults(&results))); 132 EXPECT_TRUE(results); 133 } 134 135 TEST(AsyncOperationTest, TestInterface) { 136 bool called_cb = false; 137 138 auto foobar_op = WRL::Make<AsyncOperation<FooBar*>>(); 139 PutCallback(foobar_op.Get(), &called_cb); 140 141 // AsyncOperation<FooBar*> is an aggregate of FooBar* and IFooBar*. 142 WRL::ComPtr<IFooBar> results; 143 EXPECT_TRUE(FAILED(foobar_op->GetResults(&results))); 144 EXPECT_FALSE(called_cb); 145 146 auto foobar = WRL::Make<FooBar>(); 147 IFooBar* foobar_ptr = foobar.Get(); 148 foobar_op->callback().Run(std::move(foobar)); 149 150 EXPECT_TRUE(called_cb); 151 EXPECT_TRUE(SUCCEEDED(foobar_op->GetResults(&results))); 152 EXPECT_EQ(foobar_ptr, results.Get()); 153 } 154 155 TEST(AsyncOperationTest, TestIdempotence) { 156 bool called_cb = false; 157 158 auto int_op = WRL::Make<AsyncOperation<int>>(); 159 PutCallback(int_op.Get(), &called_cb); 160 161 int results; 162 EXPECT_TRUE(FAILED(int_op->GetResults(&results))); 163 EXPECT_FALSE(called_cb); 164 // Calling GetResults twice shouldn't change the result. 165 EXPECT_TRUE(FAILED(int_op->GetResults(&results))); 166 EXPECT_FALSE(called_cb); 167 168 int_op->callback().Run(42); 169 170 EXPECT_TRUE(called_cb); 171 EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); 172 EXPECT_EQ(42, results); 173 // Calling GetResults twice shouldn't change the result. 174 EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); 175 EXPECT_EQ(42, results); 176 } 177 178 TEST(AsyncOperationTest, DoubleCallbackFails) { 179 auto int_op = WRL::Make<AsyncOperation<int>>(); 180 auto cb = int_op->callback(); 181 182 // Obtaining another callback should result in a DCHECK failure. 183 EXPECT_DCHECK_DEATH(int_op->callback()); 184 } 185 186 } // namespace win 187 } // namespace base 188