#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;
namespace {
MIDL_INTERFACE("756358C7-8083-4D78-9D27-9278B76096d4")
IFooBar : public IInspectable{};
class FooBar
: public WRL::RuntimeClass<
WRL::RuntimeClassFlags<WRL::WinRt | WRL::InhibitRoOriginateError>,
IFooBar> {};
}
namespace ABI {
namespace Windows {
namespace Foundation {
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
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 base {
namespace win {
namespace {
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());
}
}
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);
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);
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);
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);
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);
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();
EXPECT_DCHECK_DEATH(int_op->callback());
}
}
}