// Copyright 2022 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 <fuchsia/logger/cpp/fidl.h>
#include <fuchsia/sdk/examples/fidl/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/default.h>
#include <lib/async/dispatcher.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fidl/cpp/string.h>
#include <lib/fit/function.h>
#include <lib/sys/component/cpp/testing/realm_builder.h>
#include <zircon/status.h>

#include <memory>

#include <gtest/gtest.h>

constexpr static char kGreetingService[] = "greeting_service";

// Create a test fixture to manage the async loop required by Realm Builder.
class RealmBuilderTest : public ::testing::Test {
 protected:
  RealmBuilderTest() : loop_(&kAsyncLoopConfigAttachToCurrentThread) {}

  async_dispatcher_t* dispatcher() { return loop_.dispatcher(); }

  void RunLoop() {
    loop_.Run();
    loop_.ResetQuit();
  }

  void QuitLoop() { loop_.Quit(); }

  fit::closure QuitLoopClosure() {
    return [this] { loop_.Quit(); };
  }

 private:
  async::Loop loop_;
};

// This first test constructs a realm with a single component and tests that the
// component correctly implements the
// fuchsia.sdk.examples.fidl.GreetingService protocol.
TEST_F(RealmBuilderTest, RoutesFromComponent) {
  // Component URL of the component to test.
  static constexpr char kGreetingServiceServerUrl[] = "#meta/greeting_service.cm";

  // Use Realm::Builder factory method to initiate builder object.
  auto realm_builder = component_testing::RealmBuilder::Create();

  // Add the Greeting Service component as child of the Realm.
  realm_builder.AddChild(kGreetingService, kGreetingServiceServerUrl);

  // Route the fuchsia.logger.LogSink protocol from the test to the
  // Greeting Service component.
  realm_builder.AddRoute(component_testing::Route{
      .capabilities = {component_testing::Protocol{fuchsia::logger::LogSink::Name_}},
      .source = component_testing::ParentRef(),
      .targets = {component_testing::ChildRef{kGreetingService}}});

  // Route the fuchsia.sdk.examples.fidl.GreetingService protocol from
  // the Greeting Service component to this component.
  realm_builder.AddRoute(
      component_testing::Route{.capabilities = {component_testing::Protocol{
                                   fuchsia::sdk::examples::fidl::GreetingService::Name_}},
                               .source = component_testing::ChildRef{kGreetingService},
                               .targets = {component_testing::ParentRef()}});

  // Build the realm once the topology has been determined.
  auto realm = realm_builder.Build(dispatcher());

  // Since we routed the fuchsia.sdk.examples.fidl.GreetingService
  // protocol to this component, we should be able to connect to it through
  // the exposed directory of the created Realm.
  auto greeting_service = realm.ConnectSync<fuchsia::sdk::examples::fidl::GreetingService>();
  auto greeting = fuchsia::sdk::examples::fidl::Greeting::New();

  static constexpr char kGreeting[] = "Hello World!";
  greeting->text = kGreeting;
  fuchsia::sdk::examples::fidl::GreetingPtr reply = nullptr;
  ASSERT_EQ(greeting_service->Greet(std::move(greeting), &reply), ZX_OK);
  ASSERT_NE(reply, nullptr);
  EXPECT_EQ(reply->text, kGreeting);
}

// This test is the same as the one above, except that the implementation
// of fuchsia.sdk.examples.fidl.GreetingService comes from a
// legacy (CMX) component.
TEST_F(RealmBuilderTest, RoutesFromLegacyComponent) {
  static constexpr char kGreetingServiceServerLegacyUrl[] =
      "fuchsia-pkg://fuchsia.com/greeting_service#meta/greeting_service.cmx";

  auto realm_builder = component_testing::RealmBuilder::Create();
  realm_builder.AddLegacyChild(kGreetingService, kGreetingServiceServerLegacyUrl);
  realm_builder.AddRoute(component_testing::Route{
      .capabilities = {component_testing::Protocol{fuchsia::logger::LogSink::Name_}},
      .source = component_testing::ParentRef(),
      .targets = {component_testing::ChildRef{kGreetingService}}});
  realm_builder.AddRoute(
      component_testing::Route{.capabilities = {component_testing::Protocol{
                                   fuchsia::sdk::examples::fidl::GreetingService::Name_}},
                               .source = component_testing::ChildRef{kGreetingService},
                               .targets = {component_testing::ParentRef()}});

  auto realm = realm_builder.Build(dispatcher());

  auto greeting_service = realm.ConnectSync<fuchsia::sdk::examples::fidl::GreetingService>();
  auto greeting = fuchsia::sdk::examples::fidl::Greeting::New();

  static constexpr char kGreeting[] = "Hello World!";
  greeting->text = kGreeting;
  fuchsia::sdk::examples::fidl::GreetingPtr reply = nullptr;
  ASSERT_EQ(greeting_service->Greet(std::move(greeting), &reply), ZX_OK);
  ASSERT_NE(reply, nullptr);
  EXPECT_EQ(reply->text, kGreeting);
}

// The next test mocks a component in the Realm instead of using a prebuilt one.
// When component_manager issues a Start request for this component, the
// `Start` method will be called.
class MockGreetingServiceServer : public component_testing::LocalComponent,
                                  public fuchsia::sdk::examples::fidl::GreetingService {
 public:
  MockGreetingServiceServer(async_dispatcher_t* dispatcher)
      : dispatcher_(dispatcher), called_(false) {}

  void Greet(std::unique_ptr<fuchsia::sdk::examples::fidl::Greeting> value,
             GreetCallback callback) override {
    called_ = true;
    callback(std::move(value));
  }

  void Start(std::unique_ptr<component_testing::LocalComponentHandles> mock_handles) override {
    mock_handles_ = std::move(mock_handles);
    ASSERT_EQ(mock_handles_->outgoing()->AddPublicService(bindings_.GetHandler(this, dispatcher_)),
              ZX_OK);
  }

  bool WasCalled() const { return called_; }

 private:
  async_dispatcher_t* dispatcher_;
  fidl::BindingSet<fuchsia::sdk::examples::fidl::GreetingService> bindings_;
  bool called_;
  std::unique_ptr<component_testing::LocalComponentHandles> mock_handles_;
};

// This test differs from the other two in that instead of using a prebuilt
// component added to this test's package, it mocks an implementation inside
// a local C++ class via the overridden `Start` method.
TEST_F(RealmBuilderTest, RoutesFromMockComponent) {
  auto realm_builder = component_testing::RealmBuilder::Create();

  MockGreetingServiceServer mock_server(dispatcher());
  realm_builder.AddLocalChild(kGreetingService, &mock_server);
  realm_builder.AddRoute(
      component_testing::Route{.capabilities = {component_testing::Protocol{
                                   fuchsia::sdk::examples::fidl::GreetingService::Name_}},
                               .source = component_testing::ChildRef{kGreetingService},
                               .targets = {component_testing::ParentRef()}});

  auto realm = realm_builder.Build(dispatcher());

  fuchsia::sdk::examples::fidl::GreetingServicePtr greeting_service;
  ASSERT_EQ(realm.Connect(greeting_service.NewRequest()), ZX_OK);
  auto greeting = fuchsia::sdk::examples::fidl::Greeting::New();
  greeting->text = "hello";
  greeting_service->Greet(std::move(greeting),
                          [&](fuchsia::sdk::examples::fidl::GreetingPtr response) {
                            // Use EXPECT here so the loop can still quit if the test fails
                            EXPECT_EQ(response->text, "hello");
                            QuitLoop();
                          });

  // Wait for async callback to complete
  RunLoop();

  EXPECT_TRUE(mock_server.WasCalled());
}