| // Copyright 2018 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/win/async_operation.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "base/test/gtest_util.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace WRL = Microsoft::WRL; | 
 |  | 
 | using ABI::Windows::Foundation::IAsyncOperation; | 
 | using ABI::Windows::Foundation::IAsyncOperationCompletedHandler; | 
 |  | 
 | // In order to exercise the interface logic of AsyncOperation we define an empty | 
 | // dummy interface, its implementation, and the necessary boilerplate to hook it | 
 | // up with IAsyncOperation and IAsyncOperationCompletedHandler. | 
 | namespace { | 
 |  | 
 | // Chosen by fair `uuidgen` invocation. Also applies to the UUIDs below. | 
 | MIDL_INTERFACE("756358C7-8083-4D78-9D27-9278B76096d4") | 
 | IFooBar : public IInspectable{}; | 
 |  | 
 | class FooBar | 
 |     : public WRL::RuntimeClass< | 
 |           WRL::RuntimeClassFlags<WRL::WinRt | WRL::InhibitRoOriginateError>, | 
 |           IFooBar> {}; | 
 |  | 
 | }  // namespace | 
 |  | 
 | namespace ABI { | 
 | namespace Windows { | 
 | namespace Foundation { | 
 |  | 
 | // Provide the required template specializations to register | 
 | // IAsyncOperation<Foobar*> as an AggregateType. This is similar to how it is | 
 | // done for UWP classes. | 
 | template <> | 
 | struct DECLSPEC_UUID("124858e4-f97e-409c-86ae-418c4781144c") | 
 |     IAsyncOperation<FooBar*> | 
 |     : IAsyncOperation_impl<Internal::AggregateType<FooBar*, IFooBar*>> { | 
 |   static const wchar_t* z_get_rc_name_impl() { | 
 |     return L"Windows.Foundation.IAsyncOperation<FooBar>"; | 
 |   } | 
 | }; | 
 |  | 
 | template <> | 
 | struct DECLSPEC_UUID("9e49373c-200c-4715-abd7-4214ba669c81") | 
 |     IAsyncOperationCompletedHandler<FooBar*> | 
 |     : IAsyncOperationCompletedHandler_impl< | 
 |           Internal::AggregateType<FooBar*, IFooBar*>> { | 
 |   static const wchar_t* z_get_rc_name_impl() { | 
 |     return L"Windows.Foundation.AsyncOperationCompletedHandler<FooBar>"; | 
 |   } | 
 | }; | 
 |  | 
 | }  // namespace Foundation | 
 | }  // namespace Windows | 
 | }  // namespace ABI | 
 |  | 
 | namespace base { | 
 | namespace win { | 
 |  | 
 | namespace { | 
 |  | 
 | // Utility method to add a completion callback to |async_op|. |*called_cb| will | 
 | // be set to true once the callback is invoked. | 
 | template <typename T> | 
 | void PutCallback(AsyncOperation<T>* async_op, bool* called_cb) { | 
 |   async_op->put_Completed( | 
 |       WRL::Callback<IAsyncOperationCompletedHandler<T>>( | 
 |           [=](IAsyncOperation<T>* iasync_op, AsyncStatus status) { | 
 |             EXPECT_EQ(async_op, iasync_op); | 
 |             *called_cb = true; | 
 |             return S_OK; | 
 |           }) | 
 |           .Get()); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | TEST(AsyncOperationTest, TestInt) { | 
 |   bool called_cb = false; | 
 |  | 
 |   auto int_op = WRL::Make<AsyncOperation<int>>(); | 
 |   PutCallback(int_op.Get(), &called_cb); | 
 |  | 
 |   int results; | 
 |   EXPECT_TRUE(FAILED(int_op->GetResults(&results))); | 
 |   EXPECT_FALSE(called_cb); | 
 |   int_op->callback().Run(123); | 
 |  | 
 |   EXPECT_TRUE(called_cb); | 
 |   EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); | 
 |   EXPECT_EQ(123, results); | 
 |  | 
 |   // GetResults should be idempotent. | 
 |   EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); | 
 |   EXPECT_EQ(123, results); | 
 | } | 
 |  | 
 | TEST(AsyncOperationTest, TestBool) { | 
 |   bool called_cb = false; | 
 |  | 
 |   auto bool_op = WRL::Make<AsyncOperation<bool>>(); | 
 |   PutCallback(bool_op.Get(), &called_cb); | 
 |  | 
 |   // AsyncOperation<bool> is an aggregate of bool and boolean, and requires a | 
 |   // pointer to the latter to get the results. | 
 |   boolean results; | 
 |   EXPECT_TRUE(FAILED(bool_op->GetResults(&results))); | 
 |   EXPECT_FALSE(called_cb); | 
 |   bool_op->callback().Run(true); | 
 |  | 
 |   EXPECT_TRUE(called_cb); | 
 |   EXPECT_TRUE(SUCCEEDED(bool_op->GetResults(&results))); | 
 |   EXPECT_TRUE(results); | 
 | } | 
 |  | 
 | TEST(AsyncOperationTest, TestInterface) { | 
 |   bool called_cb = false; | 
 |  | 
 |   auto foobar_op = WRL::Make<AsyncOperation<FooBar*>>(); | 
 |   PutCallback(foobar_op.Get(), &called_cb); | 
 |  | 
 |   // AsyncOperation<FooBar*> is an aggregate of FooBar* and IFooBar*. | 
 |   WRL::ComPtr<IFooBar> results; | 
 |   EXPECT_TRUE(FAILED(foobar_op->GetResults(&results))); | 
 |   EXPECT_FALSE(called_cb); | 
 |  | 
 |   auto foobar = WRL::Make<FooBar>(); | 
 |   IFooBar* foobar_ptr = foobar.Get(); | 
 |   foobar_op->callback().Run(std::move(foobar)); | 
 |  | 
 |   EXPECT_TRUE(called_cb); | 
 |   EXPECT_TRUE(SUCCEEDED(foobar_op->GetResults(&results))); | 
 |   EXPECT_EQ(foobar_ptr, results.Get()); | 
 | } | 
 |  | 
 | TEST(AsyncOperationTest, TestIdempotence) { | 
 |   bool called_cb = false; | 
 |  | 
 |   auto int_op = WRL::Make<AsyncOperation<int>>(); | 
 |   PutCallback(int_op.Get(), &called_cb); | 
 |  | 
 |   int results; | 
 |   EXPECT_TRUE(FAILED(int_op->GetResults(&results))); | 
 |   EXPECT_FALSE(called_cb); | 
 |   // Calling GetResults twice shouldn't change the result. | 
 |   EXPECT_TRUE(FAILED(int_op->GetResults(&results))); | 
 |   EXPECT_FALSE(called_cb); | 
 |  | 
 |   int_op->callback().Run(42); | 
 |  | 
 |   EXPECT_TRUE(called_cb); | 
 |   EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); | 
 |   EXPECT_EQ(42, results); | 
 |   // Calling GetResults twice shouldn't change the result. | 
 |   EXPECT_TRUE(SUCCEEDED(int_op->GetResults(&results))); | 
 |   EXPECT_EQ(42, results); | 
 | } | 
 |  | 
 | TEST(AsyncOperationTest, DoubleCallbackFails) { | 
 |   auto int_op = WRL::Make<AsyncOperation<int>>(); | 
 |   auto cb = int_op->callback(); | 
 |  | 
 |   // Obtaining another callback should result in a DCHECK failure. | 
 |   EXPECT_DCHECK_DEATH(int_op->callback()); | 
 | } | 
 |  | 
 | }  // namespace win | 
 | }  // namespace base |