chromium/chrome/browser/ui/webui/ash/mako/mako_rewrite_view_unittest.cc

// Copyright 2023 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/ui/webui/ash/mako/mako_rewrite_view.h"

#include <memory>

#include "ash/constants/ash_features.h"
#include "base/memory/weak_ptr.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ui/webui/top_chrome/webui_contents_wrapper.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/views/chrome_views_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"

namespace ash {
namespace {

class TestWebUIContentsWrapper final : public WebUIContentsWrapper {
 public:
  explicit TestWebUIContentsWrapper(Profile* profile)
      : WebUIContentsWrapper(GURL(""),
                             profile,
                             /*task_manager_string_id=*/0,
                             /*webui_resizes_host=*/true,
                             /*esc_closes_ui=*/false,
                             /*supports_draggable_regions=*/false,
                             /*webui_name=*/"Test") {}
  TestWebUIContentsWrapper(const TestWebUIContentsWrapper&) = delete;
  TestWebUIContentsWrapper& operator=(const TestWebUIContentsWrapper&) = delete;
  ~TestWebUIContentsWrapper() override = default;

  // WebUIContentsWrapper:
  void ReloadWebContents() override {}
  base::WeakPtr<WebUIContentsWrapper> GetWeakPtr() override {
    return weak_ptr_factory_.GetWeakPtr();
  }

 private:
  base::WeakPtrFactory<TestWebUIContentsWrapper> weak_ptr_factory_{this};
};

class MakoRewriteViewTest : public ChromeViewsTestBase {
 public:
  void SetUp() override {
    feature_list_.InitAndEnableFeature(features::kOrcaResizingSupport);
    ChromeViewsTestBase::SetUp();
  }

 private:
  base::test::ScopedFeatureList feature_list_;
};

TEST_F(MakoRewriteViewTest, ResizesToWebViewSize) {
  TestingProfile profile;
  TestWebUIContentsWrapper contents_wrapper(&profile);

  auto mako_rewrite_view = std::make_unique<MakoRewriteView>(
      &contents_wrapper, /*caret_bounds=*/gfx::Rect(20, 20),
      /*can_fallback_to_center_position=*/false);
  auto* mako_rewrite_view_ptr = mako_rewrite_view.get();
  views::BubbleDialogDelegateView::CreateBubble(std::move(mako_rewrite_view));

  constexpr gfx::Size kWebViewSize(440, 343);
  mako_rewrite_view_ptr->ShowUI();

  EXPECT_EQ(mako_rewrite_view_ptr->GetBoundsInScreen().size(), kWebViewSize);
}

TEST_F(MakoRewriteViewTest, DefaultBoundsAtBottomLeftOfCaret) {
  TestingProfile profile;
  TestWebUIContentsWrapper contents_wrapper(&profile);

  constexpr gfx::Rect kCaretBounds(30, 40, 0, 10);
  auto mako_rewrite_view = std::make_unique<MakoRewriteView>(
      &contents_wrapper, kCaretBounds,
      /*can_fallback_to_center_position=*/false);
  auto* mako_rewrite_view_ptr = mako_rewrite_view.get();
  views::BubbleDialogDelegateView::CreateBubble(std::move(mako_rewrite_view));

  mako_rewrite_view_ptr->ShowUI();

  // Should be left aligned and below the caret.
  EXPECT_EQ(mako_rewrite_view_ptr->GetBoundsInScreen().x(), kCaretBounds.x());
  EXPECT_GE(mako_rewrite_view_ptr->GetBoundsInScreen().y(),
            kCaretBounds.bottom());
}

TEST_F(MakoRewriteViewTest, AtTopLeftOfCaretForCaretAtScreenBottom) {
  TestingProfile profile;
  TestWebUIContentsWrapper contents_wrapper(&profile);

  const int screen_bottom =
      display::Screen::GetScreen()->GetPrimaryDisplay().work_area().bottom();
  const gfx::Rect caret_bounds(30, screen_bottom - 20, 0, 10);
  auto mako_rewrite_view = std::make_unique<MakoRewriteView>(
      &contents_wrapper, caret_bounds,
      /*can_fallback_to_center_position=*/false);
  auto* mako_rewrite_view_ptr = mako_rewrite_view.get();
  views::BubbleDialogDelegateView::CreateBubble(std::move(mako_rewrite_view));

  mako_rewrite_view_ptr->ShowUI();

  // Should be left aligned and above the caret.
  EXPECT_EQ(mako_rewrite_view_ptr->GetBoundsInScreen().x(), caret_bounds.x());
  EXPECT_LE(mako_rewrite_view_ptr->GetBoundsInScreen().bottom(),
            caret_bounds.y());
}

TEST_F(MakoRewriteViewTest, OnScreenWithoutOverlapForSmallSelection) {
  TestingProfile profile;
  TestWebUIContentsWrapper contents_wrapper(&profile);

  constexpr gfx::Rect kSelectionBounds(100, 40, 200, 100);
  auto mako_rewrite_view = std::make_unique<MakoRewriteView>(
      &contents_wrapper, kSelectionBounds,
      /*can_fallback_to_center_position=*/false);
  auto* mako_rewrite_view_ptr = mako_rewrite_view.get();
  views::BubbleDialogDelegateView::CreateBubble(std::move(mako_rewrite_view));

  mako_rewrite_view_ptr->ShowUI();

  EXPECT_TRUE(
      display::Screen::GetScreen()->GetPrimaryDisplay().work_area().Contains(
          mako_rewrite_view_ptr->GetBoundsInScreen()));
  EXPECT_FALSE(
      mako_rewrite_view_ptr->GetBoundsInScreen().Intersects(kSelectionBounds));
}

TEST_F(MakoRewriteViewTest, OnScreenForLargeSelection) {
  TestingProfile profile;
  TestWebUIContentsWrapper contents_wrapper(&profile);

  const gfx::Rect selection_bounds =
      display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
  auto mako_rewrite_view = std::make_unique<MakoRewriteView>(
      &contents_wrapper, selection_bounds,
      /*can_fallback_to_center_position=*/false);
  auto* mako_rewrite_view_ptr = mako_rewrite_view.get();
  views::BubbleDialogDelegateView::CreateBubble(std::move(mako_rewrite_view));

  mako_rewrite_view_ptr->ShowUI();

  EXPECT_TRUE(
      display::Screen::GetScreen()->GetPrimaryDisplay().work_area().Contains(
          mako_rewrite_view_ptr->GetBoundsInScreen()));
}

TEST_F(MakoRewriteViewTest, FallbackToScreenCenterIfCaretBoundsAreEmpty) {
  TestingProfile profile;
  TestWebUIContentsWrapper contents_wrapper(&profile);

  // Simulate a situation when the client fails to report selection bounds.
  constexpr gfx::Size kWebViewSize(440, 343);
  constexpr gfx::Rect kSelectionBounds(0, 0, 0, 0);
  auto mako_rewrite_view = std::make_unique<MakoRewriteView>(
      &contents_wrapper, kSelectionBounds,
      /*can_fallback_to_center_position=*/true);
  auto* mako_rewrite_view_ptr = mako_rewrite_view.get();
  views::BubbleDialogDelegateView::CreateBubble(std::move(mako_rewrite_view));

  mako_rewrite_view_ptr->ShowUI();

  gfx::Rect work_area =
      display::Screen::GetScreen()->GetPrimaryDisplay().work_area();

  EXPECT_EQ(mako_rewrite_view_ptr->GetBoundsInScreen().x(),
            work_area.x() + work_area.width() / 2 - kWebViewSize.width() / 2);
}

TEST_F(MakoRewriteViewTest, FallbackToScreenCenterIfCaretBoundsAreInvalid) {
  TestingProfile profile;
  TestWebUIContentsWrapper contents_wrapper(&profile);

  // Simulate a situation when the client reports invalid bounds
  constexpr gfx::Size kWebViewSize(440, 343);
  constexpr gfx::Rect kSelectionBounds(0, -10000, 100, 100);
  auto mako_rewrite_view = std::make_unique<MakoRewriteView>(
      &contents_wrapper, kSelectionBounds,
      /*can_fallback_to_center_position=*/true);
  auto* mako_rewrite_view_ptr = mako_rewrite_view.get();
  views::BubbleDialogDelegateView::CreateBubble(std::move(mako_rewrite_view));

  mako_rewrite_view_ptr->ShowUI();

  gfx::Rect work_area =
      display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
  EXPECT_EQ(mako_rewrite_view_ptr->GetBoundsInScreen().x(),
            work_area.x() + work_area.width() / 2 - kWebViewSize.width() / 2);
}

}  // namespace
}  // namespace ash