blob: d1d636746ea3a8ec0031f9a1a5193f77cff1a82e [file] [log] [blame]
// 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/views/toolbar/toolbar_controller.h"
#include <gtest/gtest.h>
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/test/views/chrome_views_test_base.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/flex_layout_types.h"
#include "ui/views/view_class_properties.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_utils.h"
namespace {
// Toolbar button size is ~34dp.
constexpr gfx::Size kButtonSize(34, 34);
constexpr int kElementFlexOrderStart = 1;
} // namespace
class ToolbarControllerUnitTest : public ChromeViewsTestBase {
public:
ToolbarControllerUnitTest() = default;
ToolbarControllerUnitTest(const ToolbarControllerUnitTest&) = delete;
ToolbarControllerUnitTest& operator=(const ToolbarControllerUnitTest&) =
delete;
~ToolbarControllerUnitTest() override = default;
void SetUp() override {
ChromeViewsTestBase::SetUp();
widget_ = CreateTestWidget();
widget_->Show();
std::unique_ptr<views::View> toolbar_container_view =
std::make_unique<views::View>();
toolbar_container_view
->SetLayoutManager(std::make_unique<views::FlexLayout>())
->SetOrientation(views::LayoutOrientation::kHorizontal)
.SetCrossAxisAlignment(views::LayoutAlignment::kCenter)
.SetDefault(views::kFlexBehaviorKey,
views::FlexSpecification(
views::LayoutOrientation::kHorizontal,
views::MinimumFlexSizeRule::kPreferredSnapToZero,
views::MaximumFlexSizeRule::kPreferred));
toolbar_container_view_ =
widget_->SetContentsView(std::move(toolbar_container_view));
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kDummyButton1);
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kDummyButton2);
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kDummyButton3);
std::vector<ui::ElementIdentifier> element_ids = {
kDummyButton1, kDummyButton2, kDummyButton3};
InitToolbarContainerViewWithTestButtons(element_ids);
auto overflow_button = std::make_unique<OverflowButton>();
overflow_button_ =
toolbar_container_view_->AddChildView(std::move(overflow_button));
overflow_button_->SetVisible(false);
toolbar_controller_ = std::make_unique<ToolbarController>(
element_ids, kElementFlexOrderStart, toolbar_container_view_,
overflow_button_);
overflow_button_->set_create_menu_model_callback(
base::BindRepeating(&ToolbarController::CreateOverflowMenuModel,
base::Unretained(toolbar_controller_.get())));
event_generator_ = std::make_unique<ui::test::EventGenerator>(
views::GetRootWindow(widget_.get()));
}
// Add test buttons with `ids` to `toolbar_container_view_`.
void InitToolbarContainerViewWithTestButtons(
std::vector<ui::ElementIdentifier> ids) {
for (size_t i = 0; i < ids.size(); ++i) {
auto button = std::make_unique<views::View>();
button->SetProperty(views::kElementIdentifierKey, ids[i]);
button->SetPreferredSize(kButtonSize);
button->SetAccessibleName(
base::StrCat({u"DummyButton", base::NumberToString16(i)}));
button->SetVisible(true);
test_buttons_.emplace_back(
toolbar_container_view_->AddChildView(std::move(button)));
}
}
void TearDown() override {
overflow_button_ = nullptr;
toolbar_container_view_ = nullptr;
event_generator_.reset();
toolbar_controller_.reset();
widget_.reset();
ChromeViewsTestBase::TearDown();
}
views::Widget* widget() { return widget_.get(); }
ToolbarController* toolbar_controller() { return toolbar_controller_.get(); }
ui::test::EventGenerator* event_generator() { return event_generator_.get(); }
const views::View* overflow_button() { return overflow_button_; }
const std::vector<views::View*>& test_buttons() { return test_buttons_; }
const ui::SimpleMenuModel* overflow_menu() {
return overflow_button_->menu_model_for_testing();
}
std::vector<const views::View*> GetOverflowedElements() {
return toolbar_controller()->GetOverflowedElements();
}
private:
std::unique_ptr<views::Widget> widget_;
std::unique_ptr<ToolbarController> toolbar_controller_;
std::unique_ptr<ui::test::EventGenerator> event_generator_;
raw_ptr<views::View> toolbar_container_view_;
raw_ptr<OverflowButton> overflow_button_;
// Buttons being tested.
std::vector<views::View*> test_buttons_;
};
TEST_F(ToolbarControllerUnitTest, OverflowButtonVisibility) {
// Initialize widget width with total width of all test buttons.
// Should not see overflowed buttons.
widget()->SetSize(gfx::Size(kButtonSize.width() * test_buttons().size(),
kButtonSize.height()));
EXPECT_EQ(GetOverflowedElements().size(), size_t(0));
toolbar_controller()->SetOverflowButtonVisible(
toolbar_controller()->ShouldShowOverflowButton());
EXPECT_FALSE(overflow_button()->GetVisible());
// Shrink widget width with one button width smaller.
widget()->SetSize(gfx::Size(kButtonSize.width() * (test_buttons().size() - 1),
kButtonSize.height()));
EXPECT_EQ(GetOverflowedElements().size(), size_t(1));
toolbar_controller()->SetOverflowButtonVisible(
toolbar_controller()->ShouldShowOverflowButton());
EXPECT_TRUE(overflow_button()->GetVisible());
}
TEST_F(ToolbarControllerUnitTest, OverflowedButtonsMatchMenu) {
widget()->SetSize(gfx::Size(kButtonSize.width() * (test_buttons().size() - 1),
kButtonSize.height()));
toolbar_controller()->SetOverflowButtonVisible(
toolbar_controller()->ShouldShowOverflowButton());
EXPECT_TRUE(overflow_button()->GetVisible());
widget()->LayoutRootViewIfNecessary();
event_generator()->MoveMouseTo(
overflow_button()->GetBoundsInScreen().CenterPoint());
event_generator()->PressLeftButton();
const ui::SimpleMenuModel* menu = overflow_menu();
std::vector<const views::View*> overflowed_buttons = GetOverflowedElements();
// Overflowed buttons should match overflow menu.
EXPECT_TRUE(menu);
EXPECT_EQ(overflowed_buttons.size(), menu->GetItemCount());
for (size_t i = 0; i < overflowed_buttons.size(); ++i) {
EXPECT_EQ(overflowed_buttons[i]->GetAccessibleName(), menu->GetLabelAt(i));
}
}