blob: 32d5531609350cf7172039d847ab21e237040adc [file] [log] [blame]
// Copyright 2019 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/fidl/cpp/comparison.h>
#include <lib/fidl/cpp/test/test_util.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <vector>
#include <fidl/test/unionmigration/cpp/fidl.h>
#include <gtest/gtest.h>
namespace {
class HandleChecker {
public:
HandleChecker() = default;
size_t size() const { return events_.size(); }
void AddEvent(zx_handle_t event) {
zx_handle_t new_event;
ASSERT_EQ(zx_handle_duplicate(event, ZX_RIGHT_SAME_RIGHTS, &new_event), ZX_OK);
events_.emplace_back(zx::event(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
// TODO(fxbug.dev/60033): These tests can be moved to GIDL once handles are
// supported on host
namespace fidl {
namespace {
// Tests that decoding unknown handles for a non-resource type fails, and closes
// handles.
TEST(XUnion, UnknownHandlesValue) {
using fidl::test::unionmigration::BasicXUnionStruct;
std::vector<uint8_t> bytes = {
0x11, 0xba, 0x5e, 0xba, 0x00, 0x00, 0x00, 0x00, // invalid ordinal + padding
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // envelope: 8 bytes, 3 handles
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope: data is present
0xde, 0xad, 0xbe, 0xef, 0x5c, 0xa1, 0xab, 0x1e, // fake out-of-line dat
};
zx_handle_t h1, h2, h3;
ASSERT_EQ(ZX_OK, zx_event_create(0, &h1));
ASSERT_EQ(ZX_OK, zx_event_create(0, &h2));
ASSERT_EQ(ZX_OK, zx_event_create(0, &h3));
std::vector<zx_handle_t> handles = {h1, h2, h3};
HandleChecker checker;
checker.AddEvent(h1);
checker.AddEvent(h2);
checker.AddEvent(h3);
Message message(BytePart(bytes.data(), bytes.size(), bytes.size()),
HandlePart(handles.data(), handles.size(), handles.size()));
const char* error;
auto status = message.Decode(BasicXUnionStruct::FidlType, &error);
ASSERT_EQ(status, ZX_ERR_INVALID_ARGS);
ASSERT_STREQ(error, "received unknown handles for a non-resource type");
checker.CheckEvents();
}
// Tests that decoding unknown bytes for a resource type succeeds
TEST(XUnion, UnknownBytesResource) {
using fidl::test::unionmigration::BasicResourceXUnion;
using fidl::test::unionmigration::BasicResourceXUnionStruct;
std::vector<uint8_t> bytes = {
0x11, 0xba, 0x5e, 0xba, 0x00, 0x00, 0x00, 0x00, // invalid ordinal + padding
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope: 8 bytes, 0 handles
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope: data is present
0xde, 0xad, 0xbe, 0xef, 0x5c, 0xa1, 0xab, 0x1e, // fake out-of-line dat
};
Message message(BytePart(bytes.data(), bytes.size(), bytes.size()), HandlePart());
auto status = message.Decode(BasicResourceXUnionStruct::FidlType, nullptr);
ASSERT_EQ(status, ZX_OK);
fidl::Decoder decoder(std::move(message));
BasicResourceXUnionStruct result;
BasicResourceXUnionStruct::Decode(&decoder, &result, 0);
const BasicResourceXUnion& xu = result.val;
auto actual_bytes = xu.UnknownBytes();
auto unknown_data = std::vector<uint8_t>(bytes.cbegin() + sizeof(fidl_xunion_t), bytes.cend());
EXPECT_TRUE(fidl::test::util::cmp_payload(actual_bytes->data(), actual_bytes->size(),
unknown_data.data(), unknown_data.size()));
}
// Tests that decoding unknown bytes for a value type succeeds
TEST(XUnion, UnknownBytesValue) {
using fidl::test::unionmigration::BasicXUnion;
using fidl::test::unionmigration::BasicXUnionStruct;
std::vector<uint8_t> bytes = {
0x11, 0xba, 0x5e, 0xba, 0x00, 0x00, 0x00, 0x00, // invalid ordinal + padding
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope: 8 bytes, 0 handles
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope: data is present
0xde, 0xad, 0xbe, 0xef, 0x5c, 0xa1, 0xab, 0x1e, // fake out-of-line dat
};
Message message(BytePart(bytes.data(), bytes.size(), bytes.size()), HandlePart());
auto status = message.Decode(BasicXUnionStruct::FidlType, nullptr);
ASSERT_EQ(status, ZX_OK);
fidl::Decoder decoder(std::move(message));
BasicXUnionStruct result;
BasicXUnionStruct::Decode(&decoder, &result, 0);
const BasicXUnion& xu = result.val;
auto actual_bytes = xu.UnknownBytes();
auto unknown_data = std::vector<uint8_t>(bytes.cbegin() + sizeof(fidl_xunion_t), bytes.cend());
EXPECT_TRUE(fidl::test::util::cmp_payload(actual_bytes->data(), actual_bytes->size(),
unknown_data.data(), unknown_data.size()));
}
// Tests that decoding and re-encoding unknown handles for a resource type succeeds
TEST(XUnion, UnknownHandlesResource) {
using fidl::test::unionmigration::BasicResourceXUnion;
using fidl::test::unionmigration::BasicResourceXUnionStruct;
std::vector<uint8_t> bytes = {
0x11, 0xba, 0x5e, 0xba, 0x00, 0x00, 0x00, 0x00, // invalid ordinal + padding
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // envelope: 8 bytes, 3 handles
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope: data is present
0xde, 0xad, 0xbe, 0xef, 0x5c, 0xa1, 0xab, 0x1e, // fake out-of-line dat
};
auto unknown_data = std::vector<uint8_t>(bytes.cbegin() + sizeof(fidl_xunion_t), bytes.cend());
zx_handle_t h1, h2, h3;
ASSERT_EQ(ZX_OK, zx_event_create(0, &h1));
ASSERT_EQ(ZX_OK, zx_event_create(0, &h2));
ASSERT_EQ(ZX_OK, zx_event_create(0, &h3));
std::vector<zx_handle_t> handles = {h1, h2, h3};
auto result = test::util::DecodedBytes<BasicResourceXUnionStruct>(bytes, handles);
const BasicResourceXUnion& xu = result.val;
// compare
auto actual_bytes = xu.UnknownBytes();
EXPECT_TRUE(test::util::cmp_payload(actual_bytes->data(), actual_bytes->size(),
unknown_data.data(), unknown_data.size()));
auto actual_handles = xu.UnknownHandles();
ASSERT_EQ(actual_handles->size(), 3ul);
for (int i = 0; i < 3; ++i) {
EXPECT_EQ(handles[i], (*actual_handles)[i].get());
}
EXPECT_TRUE(test::util::ValueToBytes(std::move(result), bytes, handles));
}
} // namespace
} // namespace fidl