blob: 88f7ab0f4a11d06df7ad7782153f9cbbdb6e3b12 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/controls/button/toggle_button.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/animation/ink_drop.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget_utils.h"
namespace views {
class TestToggleButton : public ToggleButton {
public:
explicit TestToggleButton(int* counter) : counter_(counter) {}
TestToggleButton(const TestToggleButton&) = delete;
TestToggleButton& operator=(const TestToggleButton&) = delete;
~TestToggleButton() override {
// TODO(pbos): Revisit explicit removal of InkDrop for classes that override
// Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't
// access the non-override versions in ~View.
views::InkDrop::Remove(this);
}
void AddLayerBeneathView(ui::Layer* layer) override {
++(*counter_);
ToggleButton::AddLayerBeneathView(layer);
}
void RemoveLayerBeneathView(ui::Layer* layer) override {
--(*counter_);
ToggleButton::RemoveLayerBeneathView(layer);
}
using View::Focus;
private:
const raw_ptr<int> counter_;
};
class ToggleButtonTest : public ViewsTestBase {
public:
ToggleButtonTest() = default;
ToggleButtonTest(const ToggleButtonTest&) = delete;
ToggleButtonTest& operator=(const ToggleButtonTest&) = delete;
~ToggleButtonTest() override = default;
void SetUp() override {
ViewsTestBase::SetUp();
// Create a widget so that the ToggleButton can query the hover state
// correctly.
widget_ = std::make_unique<Widget>();
Widget::InitParams params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(0, 0, 650, 650);
widget_->Init(std::move(params));
widget_->Show();
button_ =
widget_->SetContentsView(std::make_unique<TestToggleButton>(&counter_));
}
void TearDown() override {
widget_.reset();
ViewsTestBase::TearDown();
}
protected:
int counter() const { return counter_; }
Widget* widget() { return widget_.get(); }
TestToggleButton* button() { return button_; }
private:
std::unique_ptr<Widget> widget_;
raw_ptr<TestToggleButton> button_ = nullptr;
int counter_ = 0;
};
// Starts ink drop animation on a ToggleButton and destroys the button.
// The test verifies that the ink drop layer is removed properly when the
// ToggleButton gets destroyed.
TEST_F(ToggleButtonTest, ToggleButtonDestroyed) {
EXPECT_EQ(0, counter());
gfx::Point center(10, 10);
button()->OnMousePressed(ui::MouseEvent(
ui::ET_MOUSE_PRESSED, center, center, ui::EventTimeForNow(),
ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
EXPECT_EQ(1, counter());
delete button();
EXPECT_EQ(0, counter());
}
// Make sure nothing bad happens when the widget is destroyed while the
// ToggleButton has focus (and is showing a ripple).
TEST_F(ToggleButtonTest, ShutdownWithFocus) {
button()->RequestFocus();
EXPECT_EQ(1, counter());
}
// Verify that ToggleButton::accepts_events_ works as expected.
TEST_F(ToggleButtonTest, AcceptEvents) {
EXPECT_FALSE(button()->GetIsOn());
ui::test::EventGenerator generator(GetRootWindow(widget()));
generator.MoveMouseTo(widget()->GetClientAreaBoundsInScreen().CenterPoint());
// Clicking toggles.
generator.ClickLeftButton();
EXPECT_TRUE(button()->GetIsOn());
generator.ClickLeftButton();
EXPECT_FALSE(button()->GetIsOn());
// Spacebar toggles.
button()->RequestFocus();
generator.PressKey(ui::VKEY_SPACE, ui::EF_NONE);
generator.ReleaseKey(ui::VKEY_SPACE, ui::EF_NONE);
EXPECT_TRUE(button()->GetIsOn());
generator.PressKey(ui::VKEY_SPACE, ui::EF_NONE);
generator.ReleaseKey(ui::VKEY_SPACE, ui::EF_NONE);
EXPECT_FALSE(button()->GetIsOn());
// Spacebar and clicking do nothing when not accepting events, but focus is
// not affected.
button()->SetAcceptsEvents(false);
EXPECT_TRUE(button()->HasFocus());
generator.PressKey(ui::VKEY_SPACE, ui::EF_NONE);
generator.ReleaseKey(ui::VKEY_SPACE, ui::EF_NONE);
EXPECT_FALSE(button()->GetIsOn());
generator.ClickLeftButton();
EXPECT_FALSE(button()->GetIsOn());
// Re-enable events and clicking and spacebar resume working.
button()->SetAcceptsEvents(true);
generator.PressKey(ui::VKEY_SPACE, ui::EF_NONE);
generator.ReleaseKey(ui::VKEY_SPACE, ui::EF_NONE);
EXPECT_TRUE(button()->GetIsOn());
generator.ClickLeftButton();
EXPECT_FALSE(button()->GetIsOn());
}
} // namespace views