blob: 3ef9d36a58e8bc577fa57c28027395b7eacd86e0 [file] [log] [blame]
// Copyright 2021 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/llcpp/memory.h>
#include <lib/fidl/llcpp/message.h>
#include <thread>
#include <fidl/llcpp/linearized/test/llcpp/fidl.h>
#include <gtest/gtest.h>
namespace fidl_linearized = ::llcpp::fidl::llcpp::linearized::test;
void RunTest(
const std::function<void(fidl::OutgoingIovecMessage*, fidl_linearized::FullyLinearizedStruct*,
fidl_linearized::InnerStruct*)>& run_test_body) {
fidl_linearized::InnerStruct inner = {.x = 1};
fidl_linearized::FullyLinearizedStruct input{.ptr = fidl::unowned_ptr(&inner)};
constexpr uint32_t kNumIovecs = 3;
zx_channel_iovec_t iovecs[kNumIovecs];
constexpr uint32_t kNumSubstitutions = 3;
fidl_iovec_substitution_t substitutions[kNumSubstitutions];
fidl::OutgoingIovecMessage iovec_message({
.iovecs = iovecs,
.iovecs_actual = 0,
.iovecs_capacity = kNumIovecs,
.substitutions = substitutions,
.substitutions_actual = 0,
.substitutions_capacity = kNumSubstitutions,
.handles = nullptr,
.handle_actual = 0,
.handle_capacity = 0,
});
iovec_message.Encode(&input);
ASSERT_EQ(ZX_OK, iovec_message.status()) << iovec_message.error();
run_test_body(&iovec_message, &input, &inner);
}
template <uint32_t N>
uint32_t Linearize(fidl::OutgoingIovecMessage* iovec_message, uint8_t (&bytes)[N]) {
uint32_t offset = 0;
for (uint32_t i = 0; i < iovec_message->iovec_actual(); i++) {
zx_channel_iovec_t iovec = iovec_message->iovecs()[i];
ZX_ASSERT(offset + iovec.capacity <= N);
memcpy(&bytes[offset], iovec.buffer, iovec.capacity);
offset += iovec.capacity;
}
return offset;
}
TEST(Iovec, Encode) {
RunTest([](fidl::OutgoingIovecMessage* iovec_message,
fidl_linearized::FullyLinearizedStruct* input, fidl_linearized::InnerStruct* inner) {
ASSERT_EQ(3u, iovec_message->iovec_actual());
EXPECT_EQ(input, iovec_message->iovecs()[0].buffer);
EXPECT_EQ(sizeof(*input), iovec_message->iovecs()[0].capacity);
EXPECT_EQ(0u, iovec_message->iovecs()[0].reserved);
EXPECT_EQ(inner, iovec_message->iovecs()[1].buffer);
EXPECT_EQ(sizeof(*inner), iovec_message->iovecs()[1].capacity);
EXPECT_EQ(0u, iovec_message->iovecs()[1].reserved);
static_assert(std::is_same<decltype(inner->x), int32_t>::value);
EXPECT_EQ(0, *reinterpret_cast<const int32_t*>(iovec_message->iovecs()[2].buffer));
EXPECT_EQ(8 - (sizeof(*inner)) % 8, iovec_message->iovecs()[2].capacity);
EXPECT_EQ(0u, iovec_message->iovecs()[2].reserved);
});
}
TEST(Iovec, Write) {
RunTest([](fidl::OutgoingIovecMessage* iovec_message,
fidl_linearized::FullyLinearizedStruct* input, fidl_linearized::InnerStruct* inner) {
zx::channel ch1, ch2;
ASSERT_EQ(ZX_OK, zx::channel::create(0, &ch1, &ch2));
iovec_message->Write(ch1);
ASSERT_EQ(ZX_OK, iovec_message->status()) << iovec_message->error();
uint8_t expected_bytes[ZX_CHANNEL_MAX_MSG_BYTES];
uint32_t expected_num_bytes = Linearize(iovec_message, expected_bytes);
uint8_t bytes[ZX_CHANNEL_MAX_MSG_BYTES];
uint32_t actual_bytes;
uint32_t actual_handles;
ch2.read(0, bytes, nullptr, sizeof(bytes), 0, &actual_bytes, &actual_handles);
EXPECT_EQ(expected_num_bytes, actual_bytes);
EXPECT_EQ(0u, actual_handles);
EXPECT_EQ(0, memcmp(expected_bytes, bytes, expected_num_bytes));
});
}
TEST(Iovec, Call) {
RunTest([](fidl::OutgoingIovecMessage* iovec_message,
fidl_linearized::FullyLinearizedStruct* input, fidl_linearized::InnerStruct* inner) {
uint8_t expected_bytes[ZX_CHANNEL_MAX_MSG_BYTES];
uint32_t expected_num_bytes = Linearize(iovec_message, expected_bytes);
zx::channel ch1, ch2;
ASSERT_EQ(ZX_OK, zx::channel::create(0, &ch1, &ch2));
std::thread thread([&ch2, &expected_num_bytes]() {
zx_signals_t signals;
zx_status_t status = ch2.wait_one(ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED,
zx::time::infinite(), &signals);
ASSERT_EQ(ZX_OK, status);
ASSERT_TRUE(signals & ZX_CHANNEL_READABLE);
uint8_t buf[ZX_CHANNEL_MAX_MSG_BYTES];
uint32_t actual_bytes;
uint32_t actual_handles;
ASSERT_EQ(ZX_OK, ch2.read(0, buf, nullptr, sizeof(buf), 0, &actual_bytes, &actual_handles));
ASSERT_EQ(expected_num_bytes, actual_bytes);
ASSERT_EQ(0u, actual_handles);
ASSERT_EQ(ZX_OK, ch2.write(0, buf, actual_bytes, nullptr, 0));
});
uint8_t bytes[ZX_CHANNEL_MAX_MSG_BYTES];
iovec_message->Call<fidl_linearized::FullyLinearizedStruct>(ch1.get(), bytes, sizeof(bytes));
ASSERT_EQ(ZX_OK, iovec_message->status()) << iovec_message->error();
auto result = reinterpret_cast<fidl_linearized::FullyLinearizedStruct*>(bytes);
EXPECT_EQ(1, result->ptr->x);
thread.join();
});
}