blob: 762c45bbad94110564b69212c0656122150cf9f8 [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/wait.h>
#include <lib/fidl-async/cpp/bind.h>
#include <lib/fidl/llcpp/memory.h>
#include <lib/fidl/llcpp/server.h>
#include <lib/fidl/llcpp/vector_view.h>
#include <lib/zx/object.h>
#include <zircon/errors.h>
#include <zircon/fidl.h>
#include <zircon/status.h>
#include <zircon/syscalls/object.h>
#include <cstdint>
#include <gtest/gtest.h>
#include <llcpptest/handles/test/llcpp/fidl.h>
namespace test = ::llcpp::llcpptest::handles::test;
// All the tests in this file check that when a result is freed, all the handles inside the result
// are closed.
namespace {
class HandleChecker {
public:
HandleChecker() = default;
size_t size() const { return events_.size(); }
void AddEvent(const zx::event& event) {
ASSERT_TRUE(event.is_valid());
zx::event new_event;
ASSERT_EQ(event.duplicate(ZX_RIGHT_SAME_RIGHTS, &new_event), ZX_OK);
events_.emplace_back(std::move(new_event));
}
void CheckEvents() {
for (size_t i = 0; i < events_.size(); ++i) {
zx_info_handle_count_t info = {};
auto status =
events_[i].get_info(ZX_INFO_HANDLE_COUNT, &info, sizeof(info), nullptr, nullptr);
ZX_ASSERT(status == ZX_OK);
EXPECT_EQ(info.handle_count, 1U) << "Handle not freed " << (i + 1) << '/' << events_.size();
}
}
private:
std::vector<zx::event> events_;
};
} // namespace
class HandleCloseProviderServer : public test::HandleProvider::Interface {
public:
void GetHandle(GetHandleCompleter::Sync& completer) override {
zx::event e;
zx::event::create(0, &e);
completer.Reply(std::move(e));
}
void GetHandleStruct(GetHandleStructCompleter::Sync& completer) override {
test::HandleStruct s;
zx::event::create(0, &s.h);
completer.Reply(std::move(s));
}
void GetHandleStructStruct(GetHandleStructStructCompleter::Sync& completer) override {
test::HandleStructStruct s;
zx::event::create(0, &s.s.h);
completer.Reply(std::move(s));
}
void GetMultiFieldStruct(GetMultiFieldStructCompleter::Sync& completer) override {
test::MultiFieldStruct s;
zx::event::create(0, &s.h1);
zx::event::create(0, &s.s.h);
zx::event::create(0, &s.h2);
completer.Reply(std::move(s));
}
void GetMultiArgs(GetMultiArgsCompleter::Sync& completer) override {
zx::event h1;
zx::event::create(0, &h1);
test::HandleStruct s;
zx::event::create(0, &s.h);
zx::event h2;
zx::event::create(0, &h2);
completer.Reply(std::move(h1), std::move(s), std::move(h2));
}
void GetVectorStruct(uint32_t count, GetVectorStructCompleter::Sync& completer) override {
std::vector<test::HandleStruct> v(count);
for (auto& s : v) {
zx::event::create(0, &s.h);
}
test::VectorStruct s;
s.v = fidl::unowned_vec(v);
completer.Reply(std::move(s));
}
void GetArrayStruct(GetArrayStructCompleter::Sync& completer) override {
test::ArrayStruct s;
for (size_t i = 0; i < s.a.size(); ++i) {
zx::event::create(0, &s.a[i].h);
}
completer.Reply(std::move(s));
}
void GetHandleUnion(int32_t field, GetHandleUnionCompleter::Sync& completer) override {
test::HandleUnion u;
test::HandleStruct s;
zx::event e;
zx::event::create(0, &e);
if (field == 1) {
u = test::HandleUnion::WithH1(fidl::unowned_ptr(&e));
} else if (field == 2) {
s.h = std::move(e);
u = test::HandleUnion::WithH2(fidl::unowned_ptr(&s));
}
completer.Reply(std::move(u));
}
void GetHandleUnionStruct(int32_t field,
GetHandleUnionStructCompleter::Sync& completer) override {
test::HandleUnionStruct u;
test::HandleStruct s;
zx::event e;
zx::event::create(0, &e);
if (field == 1) {
u.u = test::HandleUnion::WithH1(fidl::unowned_ptr(&e));
} else if (field == 2) {
s.h = std::move(e);
u.u = test::HandleUnion::WithH2(fidl::unowned_ptr(&s));
}
completer.Reply(std::move(u));
}
void GetHandleTable(uint32_t fields, GetHandleTableCompleter::Sync& completer) override {
zx::event e;
test::HandleStruct s;
test::HandleTable::Builder builder(std::make_unique<test::HandleTable::Frame>());
if ((fields & 1) != 0) {
zx::event::create(0, &e);
builder.set_h1(std::make_unique<zx::event>(std::move(e)));
}
if ((fields & 2) != 0) {
zx::event::create(0, &s.h);
builder.set_h2(std::make_unique<test::HandleStruct>(std::move(s)));
}
test::HandleTable t = builder.build();
completer.Reply(std::move(t));
}
void GetHandleTableStruct(uint32_t fields,
GetHandleTableStructCompleter::Sync& completer) override {
zx::event e;
test::HandleStruct s;
test::HandleTable::Builder builder(std::make_unique<test::HandleTable::Frame>());
if ((fields & 1) != 0) {
zx::event::create(0, &e);
builder.set_h1(std::make_unique<zx::event>(std::move(e)));
}
if ((fields & 2) != 0) {
zx::event::create(0, &s.h);
builder.set_h2(std::make_unique<test::HandleStruct>(std::move(s)));
}
test::HandleTableStruct reply;
reply.t = builder.build();
completer.Reply(std::move(reply));
}
void GetOptionalHandleStruct(bool defined,
GetOptionalHandleStructCompleter::Sync& completer) override {
if (defined) {
test::HandleStruct s;
zx::event::create(0, &s.h);
completer.Reply(fidl::unowned_ptr(&s));
} else {
completer.Reply(nullptr);
}
}
void GetOptionalHandleUnion(int32_t field,
GetOptionalHandleUnionCompleter::Sync& completer) override {
test::HandleUnion u;
test::HandleStruct s;
zx::event e;
zx::event::create(0, &e);
if (field == 1) {
u = test::HandleUnion::WithH1(fidl::unowned_ptr(&e));
} else if (field == 2) {
s.h = std::move(e);
u = test::HandleUnion::WithH2(fidl::unowned_ptr(&s));
}
completer.Reply(std::move(u));
}
void GetOptionalHandleUnionStruct(
bool defined, int32_t field,
GetOptionalHandleUnionStructCompleter::Sync& completer) override {
if (defined) {
test::HandleUnionStruct u;
test::HandleStruct s;
zx::event e;
zx::event::create(0, &e);
if (field == 1) {
u.u = test::HandleUnion::WithH1(fidl::unowned_ptr(&e));
} else if (field == 2) {
s.h = std::move(e);
u.u = test::HandleUnion::WithH2(fidl::unowned_ptr(&s));
}
completer.Reply(fidl::unowned_ptr(&u));
} else {
completer.Reply(nullptr);
}
}
void GetOptionalHandleTableStruct(
bool defined, uint32_t fields,
GetOptionalHandleTableStructCompleter::Sync& completer) override {
if (defined) {
zx::event e;
test::HandleStruct s;
test::HandleTable::Builder builder(std::make_unique<test::HandleTable::Frame>());
if ((fields & 1) != 0) {
zx::event::create(0, &e);
builder.set_h1(std::make_unique<zx::event>(std::move(e)));
}
if ((fields & 2) != 0) {
zx::event::create(0, &s.h);
builder.set_h2(std::make_unique<test::HandleStruct>(std::move(s)));
}
test::HandleTableStruct reply;
reply.t = builder.build();
completer.Reply(fidl::unowned_ptr(&reply));
} else {
completer.Reply(nullptr);
}
}
void GetHandleStructOptionalStruct(
bool defined, GetHandleStructOptionalStructCompleter::Sync& completer) override {
test::HandleStructOptionalStruct reply;
test::HandleStruct s;
if (defined) {
zx::event::create(0, &s.h);
reply.s = fidl::unowned_ptr(&s);
}
completer.Reply(std::move(reply));
}
void GetHandleUnionOptionalStruct(
bool defined, int32_t field,
GetHandleUnionOptionalStructCompleter::Sync& completer) override {
test::HandleUnionOptionalStruct reply;
test::HandleUnion u;
test::HandleStruct s;
zx::event e;
if (defined) {
zx::event::create(0, &e);
if (field == 1) {
u = test::HandleUnion::WithH1(fidl::unowned_ptr(&e));
} else if (field == 2) {
s.h = std::move(e);
u = test::HandleUnion::WithH2(fidl::unowned_ptr(&s));
}
reply.u = std::move(u);
}
completer.Reply(std::move(reply));
}
void GetVectorOfHandle(uint32_t count, GetVectorOfHandleCompleter::Sync& completer) override {
std::vector<zx::event> v(count);
for (auto& item : v) {
zx::event::create(0, &item);
}
completer.Reply(fidl::unowned_vec(v));
}
void GetVectorOfVectorOfHandle(uint32_t count1, uint32_t count2,
GetVectorOfVectorOfHandleCompleter::Sync& completer) override {
std::vector<fidl::VectorView<zx::event>> v(count1);
for (uint32_t i1 = 0; i1 < count1; ++i1) {
v[i1] = fidl::VectorView(
fidl::tracking_ptr<zx::event[]>(std::make_unique<zx::event[]>(count2)), count2);
for (uint32_t i2 = 0; i2 < count2; ++i2) {
zx::event::create(0, &v[i1][i2]);
}
}
completer.Reply(fidl::unowned_vec(v));
}
void GetVectorOfVectorOfVectorOfHandle(
uint32_t count1, uint32_t count2, uint32_t count3,
GetVectorOfVectorOfVectorOfHandleCompleter::Sync& completer) override {
std::vector<fidl::VectorView<fidl::VectorView<zx::event>>> v(count1);
for (uint32_t i1 = 0; i1 < count1; ++i1) {
v[i1] = fidl::VectorView(fidl::tracking_ptr<fidl::VectorView<zx::event>[]>(
std::make_unique<fidl::VectorView<zx::event>[]>(count2)),
count2);
for (uint32_t i2 = 0; i2 < count2; ++i2) {
v[i1][i2] = fidl::VectorView(
fidl::tracking_ptr<zx::event[]>(std::make_unique<zx::event[]>(count3)), count3);
for (uint32_t i3 = 0; i3 < count3; ++i3) {
zx::event::create(0, &v[i1][i2][i3]);
}
}
}
completer.Reply(fidl::unowned_vec(v));
}
void GetVectorOfHandleStruct(uint32_t count,
GetVectorOfHandleStructCompleter::Sync& completer) override {
std::vector<test::HandleStruct> v(count);
for (auto& item : v) {
zx::event::create(0, &item.h);
}
completer.Reply(fidl::unowned_vec(v));
}
void GetVectorOfVectorOfHandleStruct(
uint32_t count1, uint32_t count2,
GetVectorOfVectorOfHandleStructCompleter::Sync& completer) override {
std::vector<fidl::VectorView<test::HandleStruct>> v(count1);
for (uint32_t i1 = 0; i1 < count1; ++i1) {
v[i1] = fidl::VectorView(
fidl::tracking_ptr<test::HandleStruct[]>(std::make_unique<test::HandleStruct[]>(count2)),
count2);
for (uint32_t i2 = 0; i2 < count2; ++i2) {
zx::event::create(0, &v[i1][i2].h);
}
}
completer.Reply(fidl::unowned_vec(v));
}
void GetVectorOfVectorOfVectorOfHandleStruct(
uint32_t count1, uint32_t count2, uint32_t count3,
GetVectorOfVectorOfVectorOfHandleStructCompleter::Sync& completer) override {
std::vector<fidl::VectorView<fidl::VectorView<test::HandleStruct>>> v(count1);
for (uint32_t i1 = 0; i1 < count1; ++i1) {
v[i1] =
fidl::VectorView(fidl::tracking_ptr<fidl::VectorView<test::HandleStruct>[]>(
std::make_unique<fidl::VectorView<test::HandleStruct>[]>(count2)),
count2);
for (uint32_t i2 = 0; i2 < count2; ++i2) {
v[i1][i2] = fidl::VectorView(fidl::tracking_ptr<test::HandleStruct[]>(
std::make_unique<test::HandleStruct[]>(count3)),
count3);
for (uint32_t i3 = 0; i3 < count3; ++i3) {
zx::event::create(0, &v[i1][i2][i3].h);
}
}
}
completer.Reply(fidl::unowned_vec(v));
}
void GetArrayOfHandle(GetArrayOfHandleCompleter::Sync& completer) override {
fidl::Array<zx::event, 2> a;
for (auto& item : a) {
zx::event::create(0, &item);
}
completer.Reply(std::move(a));
}
void GetArrayOfArrayOfHandle(GetArrayOfArrayOfHandleCompleter::Sync& completer) override {
fidl::Array<fidl::Array<zx::event, 2>, 3> a;
for (auto& item1 : a) {
for (auto& item2 : item1) {
zx::event::create(0, &item2);
}
}
completer.Reply(std::move(a));
}
void GetArrayOfArrayOfArrayOfHandle(
GetArrayOfArrayOfArrayOfHandleCompleter::Sync& completer) override {
fidl::Array<fidl::Array<fidl::Array<zx::event, 2>, 3>, 4> a;
for (auto& item1 : a) {
for (auto& item2 : item1) {
for (auto& item3 : item2) {
zx::event::create(0, &item3);
}
}
}
completer.Reply(std::move(a));
}
void GetArrayOfHandleStruct(GetArrayOfHandleStructCompleter::Sync& completer) override {
fidl::Array<test::HandleStruct, 2> a;
for (auto& item : a) {
zx::event::create(0, &item.h);
}
completer.Reply(std::move(a));
}
void GetArrayOfArrayOfHandleStruct(
GetArrayOfArrayOfHandleStructCompleter::Sync& completer) override {
fidl::Array<fidl::Array<test::HandleStruct, 2>, 3> a;
for (auto& item1 : a) {
for (auto& item2 : item1) {
zx::event::create(0, &item2.h);
}
}
completer.Reply(std::move(a));
}
void GetArrayOfArrayOfArrayOfHandleStruct(
GetArrayOfArrayOfArrayOfHandleStructCompleter::Sync& completer) override {
fidl::Array<fidl::Array<fidl::Array<test::HandleStruct, 2>, 3>, 4> a;
for (auto& item1 : a) {
for (auto& item2 : item1) {
for (auto& item3 : item2) {
zx::event::create(0, &item3.h);
}
}
}
completer.Reply(std::move(a));
}
void GetMixed1(uint32_t count, GetMixed1Completer::Sync& completer) override {
fidl::Array<fidl::VectorView<zx::event>, 2> a;
for (auto& item1 : a) {
item1 = fidl::VectorView(
fidl::tracking_ptr<zx::event[]>(std::make_unique<zx::event[]>(count)), count);
for (auto& item2 : item1) {
zx::event::create(0, &item2);
}
}
completer.Reply(std::move(a));
}
void GetMixed2(uint32_t count, GetMixed2Completer::Sync& completer) override {
std::vector<fidl::Array<zx::event, 2>> v(count);
for (auto& item1 : v) {
for (auto& item2 : item1) {
zx::event::create(0, &item2);
}
}
completer.Reply(fidl::unowned_vec(v));
}
};
class HandleCloseTest : public ::testing::Test {
protected:
virtual void SetUp() {
loop_ = std::make_unique<async::Loop>(&kAsyncLoopConfigAttachToCurrentThread);
ASSERT_EQ(loop_->StartThread("test_llcpp_handle_server"), ZX_OK);
zx::channel server_end;
ASSERT_EQ(zx::channel::create(0, &client_end_, &server_end), ZX_OK);
server_ = std::make_unique<HandleCloseProviderServer>();
fidl::BindSingleInFlightOnly(loop_->dispatcher(), std::move(server_end), server_.get());
}
test::HandleProvider::SyncClient TakeClient() {
EXPECT_TRUE(client_end_.is_valid());
return test::HandleProvider::SyncClient(std::move(client_end_));
}
private:
std::unique_ptr<async::Loop> loop_;
std::unique_ptr<HandleCloseProviderServer> server_;
zx::channel client_end_;
};
TEST_F(HandleCloseTest, Handle) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandle();
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleStruct();
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleStructStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleStructStruct();
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.s.h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, MultiFieldStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetMultiFieldStruct();
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.h1);
checker.AddEvent(result->value.s.h);
checker.AddEvent(result->value.h2);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, MultiArgs) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetMultiArgs();
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->h1);
checker.AddEvent(result->s.h);
checker.AddEvent(result->h2);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, VectorStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetVectorStruct(4);
ASSERT_TRUE(result.ok()) << result.error();
for (uint32_t i = 0; i < result->value.v.count(); ++i) {
checker.AddEvent(result->value.v[i].h);
}
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, ArrayStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetArrayStruct();
ASSERT_TRUE(result.ok()) << result.error();
for (size_t i = 0; i < result->value.a.size(); ++i) {
checker.AddEvent(result->value.a[i].h);
}
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleUnion1) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleUnion(1);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value.is_h1());
checker.AddEvent(result->value.h1());
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleUnion2) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleUnion(2);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value.is_h2());
checker.AddEvent(result->value.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleUnionStruct1) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleUnionStruct(1);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value.u.is_h1());
checker.AddEvent(result->value.u.h1());
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleUnionStruct2) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleUnionStruct(2);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value.u.is_h2());
checker.AddEvent(result->value.u.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleTableNone) {
// Only checks that the destructions won't crash.
auto client = TakeClient();
{
auto result = client.GetHandleTable(0);
ASSERT_TRUE(result.ok()) << result.error();
}
}
TEST_F(HandleCloseTest, HandleTableEvent) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleTable(1);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.h1());
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleTableHandleStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleTable(2);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleTableAll) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleTable(3);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.h1());
checker.AddEvent(result->value.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleTableStructNone) {
// Only checks that the destructions won't crash.
auto client = TakeClient();
{
auto result = client.GetHandleTableStruct(0);
ASSERT_TRUE(result.ok()) << result.error();
}
}
TEST_F(HandleCloseTest, HandleTableStructEvent) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleTableStruct(1);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.t.h1());
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleTableStructHandleStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleTableStruct(2);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.t.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleTableStructAll) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleTableStruct(3);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.t.h1());
checker.AddEvent(result->value.t.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, OptionalHandleStructNotDefined) {
// Only checks that the destructions won't crash.
auto client = TakeClient();
{
auto result = client.GetOptionalHandleStruct(false);
ASSERT_TRUE(result.ok()) << result.error();
}
}
TEST_F(HandleCloseTest, OptionalHandleStructDefined) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetOptionalHandleStruct(true);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value->h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, OptionalHandleUnionNone) {
// Only checks that the destructions won't crash.
auto client = TakeClient();
{
auto result = client.GetOptionalHandleUnion(0);
ASSERT_TRUE(result.ok()) << result.error();
}
}
TEST_F(HandleCloseTest, OptionalHandleUnion1) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetOptionalHandleUnion(1);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value.is_h1());
checker.AddEvent(result->value.h1());
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, OptionalHandleUnion2) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetOptionalHandleUnion(2);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value.is_h2());
checker.AddEvent(result->value.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, OptionalHandleUnionStructNotDefined) {
// Only checks that the destructions won't crash.
auto client = TakeClient();
{
auto result = client.GetOptionalHandleUnionStruct(false, 0);
ASSERT_TRUE(result.ok()) << result.error();
}
}
TEST_F(HandleCloseTest, OptionalHandleUnionStruct1) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetOptionalHandleUnionStruct(true, 1);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value->u.is_h1());
checker.AddEvent(result->value->u.h1());
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, OptionalHandleUnionStruct2) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetOptionalHandleUnionStruct(true, 2);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value->u.is_h2());
checker.AddEvent(result->value->u.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, OptionalHandleTableStructNotDefined) {
// Only checks that the destructions won't crash.
auto client = TakeClient();
{
auto result = client.GetOptionalHandleTableStruct(false, 0);
ASSERT_TRUE(result.ok()) << result.error();
}
}
TEST_F(HandleCloseTest, OptionalHandleTableStructNone) {
// Only checks that the destructions won't crash.
auto client = TakeClient();
{
auto result = client.GetOptionalHandleTableStruct(true, 0);
ASSERT_TRUE(result.ok()) << result.error();
}
}
TEST_F(HandleCloseTest, OptionalHandleTableStructEvent) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetOptionalHandleTableStruct(true, 1);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value->t.h1());
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, OptionalHandleTableStructHandleStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetOptionalHandleTableStruct(true, 2);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value->t.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, OptionalHandleTableStructAll) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetOptionalHandleTableStruct(true, 3);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value->t.h1());
checker.AddEvent(result->value->t.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleStructOptionalStructNotDefined) {
// Only checks that the destructions won't crash.
auto client = TakeClient();
{
auto result = client.GetHandleStructOptionalStruct(false);
ASSERT_TRUE(result.ok()) << result.error();
}
}
TEST_F(HandleCloseTest, HandleStructOptionalStructDefined) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleStructOptionalStruct(true);
ASSERT_TRUE(result.ok()) << result.error();
checker.AddEvent(result->value.s->h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleUnionOptionalStructNotDefined) {
// Only checks that the destructions won't crash.
auto client = TakeClient();
{
auto result = client.GetHandleUnionOptionalStruct(false, 0);
ASSERT_TRUE(result.ok()) << result.error();
}
}
TEST_F(HandleCloseTest, HandleUnionOptionalStruct1) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleUnionOptionalStruct(true, 1);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value.u.is_h1());
checker.AddEvent(result->value.u.h1());
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, HandleUnionOptionalStruct2) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetHandleUnionOptionalStruct(true, 2);
ASSERT_TRUE(result.ok()) << result.error();
ASSERT_TRUE(result->value.u.is_h2());
checker.AddEvent(result->value.u.h2().h);
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, VectorOfHandle) {
constexpr size_t kNumHandle = 5;
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetVectorOfHandle(kNumHandle);
ASSERT_TRUE(result.ok()) << result.error();
for (uint32_t i = 0; i < result->value.count(); ++i) {
checker.AddEvent(result->value[i]);
}
}
ASSERT_EQ(checker.size(), kNumHandle);
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, VectorOfVectorOfHandle) {
constexpr size_t kNumVector = 4;
constexpr size_t kNumHandle = 5;
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetVectorOfVectorOfHandle(kNumVector, kNumHandle);
ASSERT_TRUE(result.ok()) << result.error();
for (uint32_t i = 0; i < result->value.count(); ++i) {
for (uint32_t j = 0; j < result->value[i].count(); ++j) {
checker.AddEvent(result->value[i][j]);
}
}
}
ASSERT_EQ(checker.size(), kNumVector * kNumHandle);
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, VectorOfVectorOfVectorOfHandle) {
constexpr size_t kNumVector1 = 3;
constexpr size_t kNumVector2 = 4;
constexpr size_t kNumHandle = 5;
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetVectorOfVectorOfVectorOfHandle(kNumVector1, kNumVector2, kNumHandle);
ASSERT_TRUE(result.ok()) << result.error();
for (uint32_t i = 0; i < result->value.count(); ++i) {
for (uint32_t j = 0; j < result->value[i].count(); ++j) {
for (uint32_t k = 0; k < result->value[i][j].count(); ++k) {
checker.AddEvent(result->value[i][j][k]);
}
}
}
}
ASSERT_EQ(checker.size(), kNumVector1 * kNumVector2 * kNumHandle);
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, VectorOfHandleStruct) {
constexpr size_t kNumHandle = 5;
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetVectorOfHandleStruct(kNumHandle);
ASSERT_TRUE(result.ok()) << result.error();
for (uint32_t i = 0; i < result->value.count(); ++i) {
checker.AddEvent(result->value[i].h);
}
}
ASSERT_EQ(checker.size(), kNumHandle);
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, VectorOfVectorOfHandleStruct) {
constexpr size_t kNumVector = 4;
constexpr size_t kNumHandle = 5;
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetVectorOfVectorOfHandleStruct(kNumVector, kNumHandle);
ASSERT_TRUE(result.ok()) << result.error();
for (uint32_t i = 0; i < result->value.count(); ++i) {
for (uint32_t j = 0; j < result->value[i].count(); ++j) {
checker.AddEvent(result->value[i][j].h);
}
}
}
ASSERT_EQ(checker.size(), kNumVector * kNumHandle);
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, VectorOfVectorOfVectorOfHandleStruct) {
constexpr size_t kNumVector1 = 3;
constexpr size_t kNumVector2 = 4;
constexpr size_t kNumHandle = 5;
HandleChecker checker;
auto client = TakeClient();
{
auto result =
client.GetVectorOfVectorOfVectorOfHandleStruct(kNumVector1, kNumVector2, kNumHandle);
ASSERT_TRUE(result.ok()) << result.error();
for (uint32_t i = 0; i < result->value.count(); ++i) {
for (uint32_t j = 0; j < result->value[i].count(); ++j) {
for (uint32_t k = 0; k < result->value[i][j].count(); ++k) {
checker.AddEvent(result->value[i][j][k].h);
}
}
}
}
ASSERT_EQ(checker.size(), kNumVector1 * kNumVector2 * kNumHandle);
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, ArrayOfHandle) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetArrayOfHandle();
ASSERT_TRUE(result.ok()) << result.error();
for (auto& item : result->value) {
checker.AddEvent(item);
}
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, ArrayOfArrayOfHandle) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetArrayOfArrayOfHandle();
ASSERT_TRUE(result.ok()) << result.error();
for (auto& item1 : result->value) {
for (const auto& item2 : item1) {
checker.AddEvent(item2);
}
}
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, ArrayOfArrayOfArrayOfHandle) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetArrayOfArrayOfArrayOfHandle();
ASSERT_TRUE(result.ok()) << result.error();
for (auto& item1 : result->value) {
for (const auto& item2 : item1) {
for (const auto& item3 : item2) {
checker.AddEvent(item3);
}
}
}
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, ArrayOfHandleStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetArrayOfHandleStruct();
ASSERT_TRUE(result.ok()) << result.error();
for (auto& item : result->value) {
checker.AddEvent(item.h);
}
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, ArrayOfArrayOfHandleStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetArrayOfArrayOfHandleStruct();
ASSERT_TRUE(result.ok()) << result.error();
for (auto& item1 : result->value) {
for (const auto& item2 : item1) {
checker.AddEvent(item2.h);
}
}
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, ArrayOfArrayOfArrayOfHandleStruct) {
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetArrayOfArrayOfArrayOfHandleStruct();
ASSERT_TRUE(result.ok()) << result.error();
for (auto& item1 : result->value) {
for (const auto& item2 : item1) {
for (const auto& item3 : item2) {
checker.AddEvent(item3.h);
}
}
}
}
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, Mixed1) {
constexpr size_t kNumHandle = 5;
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetMixed1(kNumHandle);
ASSERT_TRUE(result.ok()) << result.error();
for (auto& item1 : result->value) {
for (const auto& item2 : item1) {
checker.AddEvent(item2);
}
}
}
ASSERT_EQ(checker.size(), kNumHandle * 2);
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}
TEST_F(HandleCloseTest, Mixed2) {
constexpr size_t kNumHandle = 5;
HandleChecker checker;
auto client = TakeClient();
{
auto result = client.GetMixed2(kNumHandle);
ASSERT_TRUE(result.ok()) << result.error();
for (auto& item1 : result->value) {
for (const auto& item2 : item1) {
checker.AddEvent(item2);
}
}
}
ASSERT_EQ(checker.size(), kNumHandle * 2);
// After the destruction of the result, each handle in dupes should have only one link.
checker.CheckEvents();
}