text: // 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/gtest/test_loop_fixture.h>
  #include <zircon/types.h>
  #include <lib/zx/channel.h>
  
  #include "gtest/gtest.h"
  #include "lib/ui/scenic/cpp/commands.h"
  #include "sdk/lib/ui/scenic/cpp/session.h"
  
  namespace {
  
  class MockScenicSession : public scenic::Session {
   public:
    MockScenicSession(fuchsia::ui::scenic::SessionPtr client) : Session(std::move(client)) {}
  
    void Flush() override {
      num_flushed_++;
      commands_.clear();
    };
  
    int64_t num_flushed_ = 0;
    size_t num_commands() { return commands_.size(); }
    int64_t num_bytes() { return commands_num_bytes_; }
    int64_t num_handles() { return commands_num_handles_; }
  };
  
  class ScenicSessionFlushTest : public ::gtest::TestLoopFixture {
   public:
    ScenicSessionFlushTest() = default;
    ~ScenicSessionFlushTest() override = default;
  
    std::unique_ptr<MockScenicSession> session_;
  
   protected:
    void SetUp() override {
      zx::channel client_end, server_end;
      zx::channel::create(0, &client_end, &server_end);
      fuchsia::ui::scenic::SessionPtr client;
      client.Bind(std::move(client_end));
      session_ = std::make_unique<MockScenicSession>(std::move(client));
    }
  
    void TearDown() override {
      session_.reset();
    }
  };
  
  TEST_F(ScenicSessionFlushTest, AddOneInputCommand) {
    fuchsia::ui::input::SendPointerInputCmd send_pointer_input_cmd;
  
    fuchsia::ui::input::Command input_cmd;
    input_cmd.set_send_pointer_input(send_pointer_input_cmd);
  
    fuchsia::ui::scenic::Command cmd;
    cmd.set_input(std::move(input_cmd));
  
    session_->Enqueue(std::move(cmd));
  
    EXPECT_EQ(session_->num_flushed_, 1);
    EXPECT_EQ(session_->num_commands(), 0u);
    EXPECT_EQ(session_->num_bytes(),
              // See commands_sizing_test.cc for details.
              scenic::kEnqueueRequestBaseNumBytes + 104u);
    EXPECT_EQ(session_->num_handles(),
              // See commands_sizing_test.cc for details.
              0u);
  }
  
  TEST_F(ScenicSessionFlushTest, AddTwoInputCommands) {
    for (int64_t i = 0; i < 2; ++i) {
      fuchsia::ui::input::SendPointerInputCmd send_pointer_input_cmd;
  
      fuchsia::ui::input::Command input_cmd;
      input_cmd.set_send_pointer_input(send_pointer_input_cmd);
  
      fuchsia::ui::scenic::Command cmd;
      cmd.set_input(std::move(input_cmd));
  
      session_->Enqueue(std::move(cmd));
    }
  
    EXPECT_EQ(session_->num_flushed_, 2);
    EXPECT_EQ(session_->num_commands(), 0u);
  
    // The overriden Flush does not reset byte and handle counts, so we accumulate each
    // command's size.
    EXPECT_EQ(session_->num_bytes(),
              // See commands_sizing_test.cc for details.
              scenic::kEnqueueRequestBaseNumBytes + 2 * 104u);
    EXPECT_EQ(session_->num_handles(),
              // See commands_sizing_test.cc for details.
              0u);
  }
  
  TEST_F(ScenicSessionFlushTest, AddTenNonInputCommandsThenOneInputCommand) {
    for (int64_t i = 0; i < 10; ++i) {
      fuchsia::ui::gfx::MemoryArgs memory_args;
  
      fuchsia::ui::gfx::ResourceArgs resource_args;
      resource_args.set_memory(std::move(memory_args));
  
      fuchsia::ui::gfx::CreateResourceCmd create_resource_cmd;
      create_resource_cmd.resource = std::move(resource_args);
  
      fuchsia::ui::gfx::Command gfx_cmd;
      gfx_cmd.set_create_resource(std::move(create_resource_cmd));
  
      fuchsia::ui::scenic::Command cmd;
      cmd.set_gfx(std::move(gfx_cmd));
  
      session_->Enqueue(std::move(cmd));
    }
  
    // We accumulate all commands (without ever flushing).
    EXPECT_EQ(session_->num_flushed_, 0u);
    EXPECT_EQ(session_->num_commands(), 10u);
    EXPECT_EQ(session_->num_bytes(),
              // See commands_sizing_test.cc for details.
              scenic::kEnqueueRequestBaseNumBytes + 10 * 104u);
    EXPECT_EQ(session_->num_handles(),
              // See commands_sizing_test.cc for details.
              10 * 1u);
  
    {
      fuchsia::ui::input::SendPointerInputCmd send_pointer_input_cmd;
  
      fuchsia::ui::input::Command input_cmd;
      input_cmd.set_send_pointer_input(send_pointer_input_cmd);
  
      fuchsia::ui::scenic::Command cmd;
      cmd.set_input(std::move(input_cmd));
  
      session_->Enqueue(std::move(cmd));
    }
  
    // Since input commands are eagerly flushed, we send all eleven commands at
    // once.
    EXPECT_EQ(session_->num_flushed_, 1u);
    EXPECT_EQ(session_->num_commands(), 0u);
    EXPECT_EQ(session_->num_bytes(),
              // See commands_sizing_test.cc for details.
              scenic::kEnqueueRequestBaseNumBytes + 11 * 104u);
    EXPECT_EQ(session_->num_handles(),
              // See commands_sizing_test.cc for details.
              10 * 1u);
  }
  
  TEST_F(ScenicSessionFlushTest, AddNonInputCommandThenPresent) {
    // Enqueue CreateResourceCmd
    {
      fuchsia::ui::gfx::MemoryArgs memory_args;
  
      fuchsia::ui::gfx::ResourceArgs resource_args;
      resource_args.set_memory(std::move(memory_args));
  
      fuchsia::ui::gfx::CreateResourceCmd create_resource_cmd;
      create_resource_cmd.resource = std::move(resource_args);
  
      fuchsia::ui::gfx::Command gfx_cmd;
      gfx_cmd.set_create_resource(std::move(create_resource_cmd));
  
      fuchsia::ui::scenic::Command cmd;
      cmd.set_gfx(std::move(gfx_cmd));
  
      session_->Enqueue(std::move(cmd));
    }
  
    // The enqueued command has not been flushed, but will be when we present.
    EXPECT_EQ(session_->num_flushed_, 0);
  
    // Present
    auto callback = [&](fuchsia::images::PresentationInfo info) {};
    session_->Present(0u, std::move(callback));
  
    // And check that we've flushed.
    EXPECT_EQ(session_->num_flushed_, 1);
  }
  
  TEST_F(ScenicSessionFlushTest, AddNonInputCommandThenPresent2) {
    // Enqueue CreateResourceCmd
    {
      fuchsia::ui::gfx::MemoryArgs memory_args;
  
      fuchsia::ui::gfx::ResourceArgs resource_args;
      resource_args.set_memory(std::move(memory_args));
  
      fuchsia::ui::gfx::CreateResourceCmd create_resource_cmd;
      create_resource_cmd.resource = std::move(resource_args);
  
      fuchsia::ui::gfx::Command gfx_cmd;
      gfx_cmd.set_create_resource(std::move(create_resource_cmd));
  
      fuchsia::ui::scenic::Command cmd;
      cmd.set_gfx(std::move(gfx_cmd));
  
      session_->Enqueue(std::move(cmd));
    }
  
    // The enqueued command has not been flushed, but will be when we present.
    EXPECT_EQ(session_->num_flushed_, 0);
  
    // Present2
    auto callback = [&](fuchsia::scenic::scheduling::FuturePresentationTimes info) {};
    session_->Present2(0u, 0u, std::move(callback));
  
    // And check that we've flushed.
    EXPECT_EQ(session_->num_flushed_, 1);
  }
  
  }  // namespace
  