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