910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/glic/widget/application_hotkey_delegate.h"

#include <memory>

#include "base/memory/weak_ptr.h"
#include "base/test/metrics/user_action_tester.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/glic/test_support/mock_local_hotkey_panel.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/browser_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/views/focus/focus_manager.h"

namespace glic {

namespace {

class MockAcceleratorTarget : public ui::AcceleratorTarget {
 public:
  MOCK_METHOD(bool,
              AcceleratorPressed,
              (const ui::Accelerator& accelerator),
              (override));
  MOCK_METHOD(bool, CanHandleAccelerators, (), (const, override));

  base::WeakPtr<MockAcceleratorTarget> GetWeakPtr() {
    return weak_factory_.GetWeakPtr();
  }

 private:
  base::WeakPtrFactory<MockAcceleratorTarget> weak_factory_{this};
};

class ApplicationHotkeyDelegateTest : public InProcessBrowserTest {
 protected:
  void SetUpOnMainThread() override {
    InProcessBrowserTest::SetUpOnMainThread();
    delegate_.emplace(mock_panel_.GetWeakPtr());
  }

  BrowserView* GetBrowserView() {
    return BrowserView::GetBrowserViewForBrowser(browser());
  }

  BrowserView* GetBrowserViewForBrowser(Browser* b) {
    return BrowserView::GetBrowserViewForBrowser(b);
  }

  MockLocalHotkeyPanel mock_panel_;
  std::optional<ApplicationHotkeyDelegate> delegate_;
  base::UserActionTester user_action_tester_;
};

}  // namespace

IN_PROC_BROWSER_TEST_F(ApplicationHotkeyDelegateTest, GetSupportedHotkeys) {
  CHECK(g_browser_process);
  auto supported = delegate_->GetSupportedHotkeys();
  // kFocusToggle is the only supported hotkey for application-wide scope.
  EXPECT_THAT(supported,
              testing::ElementsAre(LocalHotkeyManager::Hotkey::kFocusToggle));
}

IN_PROC_BROWSER_TEST_F(ApplicationHotkeyDelegateTest,
                       AcceleratorPressedFocusToggle) {
  EXPECT_CALL(mock_panel_, FocusIfOpen()).Times(1);

  EXPECT_TRUE(
      delegate_->AcceleratorPressed(LocalHotkeyManager::Hotkey::kFocusToggle));
  EXPECT_EQ(1, user_action_tester_.GetActionCount("Glic.FocusHotKey"));
}

IN_PROC_BROWSER_TEST_F(ApplicationHotkeyDelegateTest,
                       AcceleratorPressedControllerNull) {
  // Create a delegate with an invalidated controller WeakPtr.
  auto panel = std::make_unique<MockLocalHotkeyPanel>();
  auto delegate_with_null_controller =
      std::make_unique<ApplicationHotkeyDelegate>(panel->GetWeakPtr());
  panel.reset();  // Invalidate the WeakPtr

  EXPECT_FALSE(delegate_with_null_controller->AcceleratorPressed(
      LocalHotkeyManager::Hotkey::kFocusToggle));
  EXPECT_EQ(0, user_action_tester_.GetActionCount("Glic.FocusHotKey"));
}

IN_PROC_BROWSER_TEST_F(ApplicationHotkeyDelegateTest,
                       CreateScopedHotkeyRegistration) {
  ui::Accelerator test_accel(ui::VKEY_A, ui::EF_NONE);
  MockAcceleratorTarget mock_target;

  ASSERT_TRUE(GetBrowserView()) << "BrowserView not available";
  views::FocusManager* focus_manager = GetBrowserView()->GetFocusManager();
  ASSERT_TRUE(focus_manager) << "FocusManager not available";

  EXPECT_FALSE(focus_manager->IsAcceleratorRegistered(test_accel));

  auto registration = delegate_->CreateScopedHotkeyRegistration(
      test_accel, mock_target.GetWeakPtr());
  ASSERT_TRUE(registration);

  // Verify registration with the first browser.
  EXPECT_TRUE(focus_manager->IsAcceleratorRegistered(test_accel));

  // Test adding a new browser after registration.
  Browser* browser2 = CreateBrowser(browser()->profile());
  BrowserView* browser_view2 = GetBrowserViewForBrowser(browser2);
  ASSERT_TRUE(browser_view2);
  views::FocusManager* focus_manager2 = nullptr;

  focus_manager2 = browser_view2->GetFocusManager();
  ASSERT_TRUE(focus_manager2);

  EXPECT_TRUE(focus_manager2->IsAcceleratorRegistered(test_accel));

  registration.reset();

  EXPECT_FALSE(focus_manager->IsAcceleratorRegistered(test_accel));
  EXPECT_FALSE(focus_manager2->IsAcceleratorRegistered(test_accel));

  // BrowserList will take care of cleaning up browser2.
}

IN_PROC_BROWSER_TEST_F(ApplicationHotkeyDelegateTest,
                       MakeApplicationHotkeyManager) {
  auto manager = MakeApplicationHotkeyManager(mock_panel_.GetWeakPtr());
  EXPECT_TRUE(manager);
}

}  // namespace glic