chromium/extensions/browser/api/cec_private/cec_private_lacros_apitest.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>

#include "base/memory/raw_ptr.h"
#include "chromeos/crosapi/mojom/cec_private.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "extensions/common/features/feature_session_type.h"
#include "extensions/common/mojom/feature_session_type.mojom.h"
#include "extensions/common/switches.h"
#include "extensions/shell/test/shell_apitest.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"

namespace extensions {

namespace {

constexpr char kTestAppId[] = "jabiebdnficieldhmegebckfhpfidfla";

class FakeCecPrivate : public crosapi::mojom::CecPrivate {
 public:
  FakeCecPrivate() = default;
  ~FakeCecPrivate() override = default;
  FakeCecPrivate(const FakeCecPrivate&) = delete;
  FakeCecPrivate& operator=(const FakeCecPrivate&) = delete;

  mojo::PendingRemote<crosapi::mojom::CecPrivate> BindNewPipeAndPassRemote() {
    return receiver_.BindNewPipeAndPassRemote();
  }

  // mojom::CecPrivate overrides
  void SendStandBy(SendStandByCallback callback) override {
    stand_by_call_count_++;
    UpdateDisplayPowerStates(crosapi::mojom::PowerState::kStandBy);
    std::move(callback).Run();
  }

  void SendWakeUp(SendWakeUpCallback callback) override {
    wake_up_call_count_++;
    UpdateDisplayPowerStates(crosapi::mojom::PowerState::kOn);
    std::move(callback).Run();
  }
  void QueryDisplayCecPowerState(
      QueryDisplayCecPowerStateCallback callback) override {
    std::move(callback).Run(power_states_);
  }

  int stand_by_call_count() const { return stand_by_call_count_; }
  int wake_up_call_count() const { return wake_up_call_count_; }

  void set_power_states(
      const std::vector<crosapi::mojom::PowerState>& power_states) {
    power_states_ = power_states;
  }

  void UpdateDisplayPowerStates(crosapi::mojom::PowerState new_state) {
    for (size_t i = 0; i < power_states_.size(); i++) {
      power_states_[i] = new_state;
    }
  }

 private:
  mojo::Receiver<crosapi::mojom::CecPrivate> receiver_{this};
  int stand_by_call_count_ = 0;
  int wake_up_call_count_ = 0;
  std::vector<crosapi::mojom::PowerState> power_states_;
};

class CecPrivateKioskApiTest : public ShellApiTest {
 public:
  CecPrivateKioskApiTest()
      : session_type_(ScopedCurrentFeatureSessionType(
            mojom::FeatureSessionType::kKiosk)) {}

  CecPrivateKioskApiTest(const CecPrivateKioskApiTest&) = delete;
  CecPrivateKioskApiTest& operator=(const CecPrivateKioskApiTest&) = delete;

  ~CecPrivateKioskApiTest() override = default;

  void SetUpOnMainThread() override {
    ShellApiTest::SetUpOnMainThread();
    chromeos::LacrosService::Get()->InjectRemoteForTesting(
        receiver_.BindNewPipeAndPassRemote());
  }

  void SetUpCommandLine(base::CommandLine* command_line) override {
    command_line->AppendSwitchASCII(
        extensions::switches::kAllowlistedExtensionID, kTestAppId);
    ShellApiTest::SetUpCommandLine(command_line);
  }

 protected:
  FakeCecPrivate fake_cec_private_;

 private:
  std::unique_ptr<base::AutoReset<mojom::FeatureSessionType>> session_type_;
  mojo::Receiver<crosapi::mojom::CecPrivate> receiver_{&fake_cec_private_};
};

using CecPrivateNonKioskApiTest = ShellApiTest;

}  // namespace

IN_PROC_BROWSER_TEST_F(CecPrivateKioskApiTest, TestLacrosServiceAccess) {
  auto* service = chromeos::LacrosService::Get();
  EXPECT_NE(service, nullptr);
}

IN_PROC_BROWSER_TEST_F(CecPrivateKioskApiTest, TestCanFake) {
  EXPECT_TRUE(
      chromeos::LacrosService::Get()->IsAvailable<crosapi::mojom::CecPrivate>())
      << "the fake CecPrivate didn't really bind";
  EXPECT_NE(chromeos::LacrosService::Get()
                ->GetRemote<crosapi::mojom::CecPrivate>()
                .get(),
            nullptr);
}

IN_PROC_BROWSER_TEST_F(CecPrivateKioskApiTest, TestAllApiFunctions) {
  fake_cec_private_.set_power_states(
      {crosapi::mojom::PowerState::kOn, crosapi::mojom::PowerState::kOn});
  extensions::ResultCatcher catcher;
  ExtensionTestMessageListener standby_call_count("standby_call_count",
                                                  ReplyBehavior::kWillReply);
  ExtensionTestMessageListener wakeup_call_count("wakeup_call_count",
                                                 ReplyBehavior::kWillReply);

  ASSERT_TRUE(LoadApp("api_test/cec_private/api"));

  ASSERT_TRUE(standby_call_count.WaitUntilSatisfied())
      << standby_call_count.message();
  standby_call_count.Reply(fake_cec_private_.stand_by_call_count());

  ASSERT_TRUE(wakeup_call_count.WaitUntilSatisfied())
      << wakeup_call_count.message();
  wakeup_call_count.Reply(fake_cec_private_.wake_up_call_count());

  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}

IN_PROC_BROWSER_TEST_F(CecPrivateNonKioskApiTest, TestCecPrivateNotAvailable) {
  ASSERT_TRUE(RunAppTest("api_test/cec_private/non_kiosk_api_not_available"))
      << message_;
}

}  // namespace extensions