// 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 "src/bringup/bin/virtcon/session-manager.h"

#include <fuchsia/hardware/pty/llcpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>

#include <memory>

#include <zxtest/zxtest.h>

#include "src/bringup/bin/virtcon/vc.h"

// These are necessary because vc-device.cc calls these functions and they need to be
// mocked out for testing. Ideally these files can be refactored to follow C++ patterns.
bool is_primary_bound() { return false; }
bool g_vc_owns_display = false;
void vc_gfx_invalidate_status(vc_gfx_t* gfx) {}
void vc_gfx_invalidate_all(vc_gfx_t* gfx, vc_t* vc) {}
void vc_gfx_invalidate(vc_gfx_t* gfx, vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) {}
void vc_gfx_draw_char(vc_gfx_t* gfx, vc_t* vc, vc_char_t ch, unsigned x, unsigned y, bool invert) {}
void vc_attach_to_main_display(vc_t* vc) {}
void vc_toggle_framebuffer() {}

TEST(VirtconSessionManager, LifeTimeTest) {
  async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
  virtcon::SessionManager sessions(loop.dispatcher(), false, &color_schemes[kDefaultColorScheme]);
  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
  ASSERT_EQ(ZX_OK, endpoints.status_value());
  auto [local, remote] = *std::move(endpoints);
  ASSERT_EQ(ZX_OK, sessions.CreateSession(std::move(remote)).status_value());

  loop.Shutdown();
}

TEST(VirtconSessionManager, TestWriting) {
  async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
  virtcon::SessionManager sessions(loop.dispatcher(), false, &color_schemes[kDefaultColorScheme]);
  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
  ASSERT_EQ(ZX_OK, endpoints.status_value());
  auto [local, remote] = *std::move(endpoints);

  vc_t* session = nullptr;
  {
    auto response = sessions.CreateSession(std::move(remote));
    ASSERT_EQ(ZX_OK, response.status_value());
    session = std::move(response.value());
  }

  auto pty = fidl::Client(std::move(local), loop.dispatcher());

  char output[] = "Testing!";
  auto result = pty->Write_Sync(
      fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(output), sizeof(output)));
  ASSERT_EQ(result.status(), ZX_OK);
  ASSERT_EQ(result->s, ZX_OK);
  ASSERT_EQ(result->actual, sizeof(output));

  loop.RunUntilIdle();

  // Check characters up to -1 since text_buf isn't null terminated.
  for (size_t i = 0; i < sizeof(output) - 1; i++) {
    ASSERT_EQ(vc_char_get_char(session->text_buf[i]), output[i], "index %ld : %c != %c", i,
              vc_char_get_char(session->text_buf[i]), output[i]);
  }
  loop.Shutdown();
}

TEST(VirtconSessionManager, TestWritingMultipleClients) {
  async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
  virtcon::SessionManager sessions(loop.dispatcher(), false, &color_schemes[kDefaultColorScheme]);
  auto endpoints1 = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
  ASSERT_EQ(ZX_OK, endpoints1.status_value());
  auto [local1, remote1] = *std::move(endpoints1);
  vc_t* session_one = nullptr;
  {
    auto response = sessions.CreateSession(std::move(remote1));
    ASSERT_EQ(ZX_OK, response.status_value());
    session_one = std::move(response.value());
  }
  auto pty_one = fidl::Client(std::move(local1), loop.dispatcher());

  auto endpoints2 = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
  ASSERT_EQ(ZX_OK, endpoints2.status_value());
  auto [local2, remote2] = *std::move(endpoints2);
  vc_t* session_two = nullptr;
  {
    auto response = sessions.CreateSession(std::move(remote2));
    ASSERT_EQ(ZX_OK, response.status_value());
    session_two = std::move(response.value());
  }
  auto pty_two = fidl::Client(std::move(local2), loop.dispatcher());

  // Write pty_one.
  char output_one[] = "Testing One!";
  {
    auto result = pty_one->Write_Sync(fidl::VectorView<uint8_t>::FromExternal(
        reinterpret_cast<uint8_t*>(output_one), sizeof(output_one)));
    ASSERT_EQ(result.status(), ZX_OK);
    ASSERT_EQ(result->s, ZX_OK);
    ASSERT_EQ(result->actual, sizeof(output_one));
  }

  // Write pty_two.
  char output_two[] = "Testing One!";
  {
    auto result = pty_two->Write_Sync(fidl::VectorView<uint8_t>::FromExternal(
        reinterpret_cast<uint8_t*>(output_two), sizeof(output_two)));
    ASSERT_EQ(result.status(), ZX_OK);
    ASSERT_EQ(result->s, ZX_OK);
    ASSERT_EQ(result->actual, sizeof(output_two));
  }

  loop.RunUntilIdle();

  // Check output_one.
  // Check characters up to -1 since text_buf isn't null terminated.
  for (size_t i = 0; i < sizeof(output_one) - 1; i++) {
    ASSERT_EQ(vc_char_get_char(session_one->text_buf[i]), output_one[i], "index %ld : %c != %c", i,
              vc_char_get_char(session_one->text_buf[i]), output_one[i]);
  }

  // Check output_two.
  // Check characters up to -1 since text_buf isn't null terminated.
  for (size_t i = 0; i < sizeof(output_two) - 1; i++) {
    ASSERT_EQ(vc_char_get_char(session_two->text_buf[i]), output_two[i], "index %ld : %c != %c", i,
              vc_char_get_char(session_two->text_buf[i]), output_two[i]);
  }
  loop.Shutdown();
}

// Test that the log stays active with keep-log-visible.
TEST(VirtconSessionManager, KeepLogVisibleSessionStaysActive) {
  async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);

  zx::debuglog fake_log;
  ASSERT_EQ(log_start(loop.dispatcher(), std::move(fake_log), &color_schemes[kDefaultColorScheme]),
            0);

  virtcon::SessionManager sessions(loop.dispatcher(), true, &color_schemes[kDefaultColorScheme]);

  // Create the first session and check that it's not active.
  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
  ASSERT_EQ(ZX_OK, endpoints.status_value());
  auto [local_one, remote] = *std::move(endpoints);

  vc_t* vc_one;
  {
    auto result = sessions.CreateSession(std::move(remote));
    ASSERT_TRUE(result.is_ok());
    vc_one = std::move(result.value());
  }
  ASSERT_TRUE(g_log_vc->active);
  ASSERT_FALSE(vc_one->active);

  log_delete_vc(g_log_vc);

  loop.Shutdown();
}

// Test that when we aren't keeping the log visible that the second session we create becomes
// the active one.
TEST(VirtconSessionManager, DontKeepLogVisibleSessionActivity) {
  async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);

  zx::debuglog fake_log;
  ASSERT_EQ(log_start(loop.dispatcher(), std::move(fake_log), &color_schemes[kDefaultColorScheme]),
            0);

  virtcon::SessionManager sessions(loop.dispatcher(), false, &color_schemes[kDefaultColorScheme]);

  // Create the first session and check that it's active.
  auto endpoints_one = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
  ASSERT_EQ(ZX_OK, endpoints_one.status_value());
  auto [local_one, remote_one] = *std::move(endpoints_one);

  vc_t* vc_one;
  {
    auto result = sessions.CreateSession(std::move(remote_one));
    ASSERT_TRUE(result.is_ok());
    vc_one = std::move(result.value());
  }
  ASSERT_FALSE(g_log_vc->active);
  ASSERT_TRUE(vc_one->active);

  // Create the second session and check that it's not active.
  auto endpoints_two = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
  ASSERT_EQ(ZX_OK, endpoints_two.status_value());
  auto [local_two, remote_two] = *std::move(endpoints_two);
  vc_t* vc_two;
  {
    auto result = sessions.CreateSession(std::move(remote_two));
    ASSERT_TRUE(result.is_ok());
    vc_two = std::move(result.value());
  }
  ASSERT_FALSE(g_log_vc->active);
  ASSERT_TRUE(vc_one->active);
  ASSERT_FALSE(vc_two->active);

  log_delete_vc(g_log_vc);

  loop.Shutdown();
}
