| // 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 <fidl/fuchsia.hardware.pty/cpp/wire_test_base.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/fit/thread_safety.h> |
| #include <lib/zx/eventpair.h> |
| #include <lib/zxio/zxio.h> |
| |
| #include <zxtest/zxtest.h> |
| |
| class WindowSizeTtyServer : public fidl::testing::WireTestBase<fuchsia_hardware_pty::Device> { |
| public: |
| void Init() { |
| ASSERT_OK(zx::eventpair::create(0, &event0_, &event1_)) << "failed to allocate eventpair"; |
| } |
| |
| void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) final { |
| ADD_FAILURE() << "unexpected message received: " << name; |
| completer.Close(ZX_ERR_NOT_SUPPORTED); |
| } |
| |
| void Close(CloseCompleter::Sync& completer) final { |
| completer.ReplySuccess(); |
| // After the reply, we should close the connection. |
| completer.Close(ZX_OK); |
| } |
| |
| void Query(QueryCompleter::Sync& completer) final { |
| const std::string_view kProtocol = fidl::DiscoverableProtocolName<fuchsia_hardware_pty::Device>; |
| // TODO(https://fxbug.dev/42052765): avoid the const cast. |
| uint8_t* data = reinterpret_cast<uint8_t*>(const_cast<char*>(kProtocol.data())); |
| completer.Reply(fidl::VectorView<uint8_t>::FromExternal(data, kProtocol.size())); |
| } |
| |
| void Describe(DescribeCompleter::Sync& completer) final { |
| zx::eventpair event; |
| zx_status_t status = event1_.duplicate(ZX_RIGHT_SAME_RIGHTS, &event); |
| if (status != ZX_OK) { |
| ADD_FAILURE() << "failed to duplicate event: " << zx_status_get_string(status); |
| completer.Close(status); |
| return; |
| } |
| fidl::Arena alloc; |
| completer.Reply(fuchsia_hardware_pty::wire::DeviceDescribeResponse::Builder(alloc) |
| .event(std::move(event)) |
| .Build()); |
| } |
| |
| void SetWindowSize(SetWindowSizeRequestView request, |
| SetWindowSizeCompleter::Sync& completer) final { |
| std::lock_guard guard(lock_); |
| size_ = request->size; |
| completer.Reply(ZX_OK); |
| } |
| |
| void GetWindowSize(GetWindowSizeCompleter::Sync& completer) final { |
| std::lock_guard guard(lock_); |
| completer.Reply(ZX_OK, size_); |
| } |
| |
| using Size = fuchsia_hardware_pty::wire::WindowSize; |
| |
| void set_size(Size size) { |
| std::lock_guard guard(lock_); |
| size_ = size; |
| } |
| |
| Size size() { |
| std::lock_guard g(lock_); |
| return size_; |
| } |
| |
| private: |
| zx::eventpair event0_, event1_; |
| std::mutex lock_; |
| Size size_ FIT_GUARDED(lock_); |
| }; |
| |
| TEST(Tty, Basic) { |
| auto [device_client, device_server] = fidl::Endpoints<fuchsia_hardware_pty::Device>::Create(); |
| |
| async::Loop device_control_loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| WindowSizeTtyServer server; |
| ASSERT_NO_FATAL_FAILURE(server.Init()); |
| fidl::BindServer(device_control_loop.dispatcher(), std::move(device_server), &server); |
| device_control_loop.StartThread("device_control_thread"); |
| |
| zxio_storage_t storage; |
| ASSERT_OK(zxio_create(device_client.TakeChannel().release(), &storage)); |
| zxio_t* io = &storage.io; |
| |
| bool tty = false; |
| EXPECT_OK(zxio_isatty(io, &tty)); |
| EXPECT_TRUE(tty); |
| |
| EXPECT_OK(zxio_set_window_size(io, 42, 57)); |
| |
| fuchsia_hardware_pty::wire::WindowSize server_size = server.size(); |
| EXPECT_EQ(42, server_size.width); |
| EXPECT_EQ(57, server_size.height); |
| |
| uint32_t width = 0; |
| uint32_t height = 0; |
| EXPECT_OK(zxio_get_window_size(io, &width, &height)); |
| |
| EXPECT_EQ(42, width); |
| EXPECT_EQ(57, height); |
| |
| ASSERT_OK(zxio_close(io, /*should_wait=*/true)); |
| |
| device_control_loop.Shutdown(); |
| } |