123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- // 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>";
- }
- };
- #ifdef NTDDI_WIN10_VB // Windows 10.0.19041
- // Specialization templates that used to be in windows.foundation.h, removed in
- // the 10.0.19041.0 SDK, so placed here instead.
- template <>
- struct __declspec(uuid("968b9665-06ed-5774-8f53-8edeabd5f7b5"))
- IAsyncOperation<int> : IAsyncOperation_impl<int> {};
- template <>
- struct __declspec(uuid("d60cae9d-88cb-59f1-8576-3fba44796be8"))
- IAsyncOperationCompletedHandler<int>
- : IAsyncOperationCompletedHandler_impl<int> {};
- #endif
- } // 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
|