1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/views/controls/button/radio_button.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/strings/utf_string_conversions.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/events/base_event_utils.h"
13 #include "ui/views/test/views_test_base.h"
14 
15 namespace {
16 // Group ID of the test radio buttons.
17 constexpr int kGroup = 1;
18 }  // namespace
19 
20 namespace views {
21 
22 class RadioButtonTest : public ViewsTestBase {
23  public:
24   RadioButtonTest() = default;
25 
SetUp()26   void SetUp() override {
27     ViewsTestBase::SetUp();
28 
29     // Create a Widget so the radio buttons can find their group siblings.
30     widget_ = std::make_unique<Widget>();
31     Widget::InitParams params =
32         CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
33     params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
34     widget_->Init(std::move(params));
35     widget_->Show();
36 
37     button_container_ = widget_->SetContentsView(std::make_unique<View>());
38   }
39 
TearDown()40   void TearDown() override {
41     button_container_ = nullptr;
42     widget_.reset();
43     ViewsTestBase::TearDown();
44   }
45 
46  protected:
button_container()47   View& button_container() { return *button_container_; }
48 
49  private:
50   View* button_container_ = nullptr;
51   std::unique_ptr<Widget> widget_;
52 
53   DISALLOW_COPY_AND_ASSIGN(RadioButtonTest);
54 };
55 
TEST_F(RadioButtonTest,Basics)56 TEST_F(RadioButtonTest, Basics) {
57   RadioButton* button1 = new RadioButton(base::ASCIIToUTF16("Blah"), kGroup);
58   button_container().AddChildView(button1);
59   RadioButton* button2 = new RadioButton(base::ASCIIToUTF16("Blah"), kGroup);
60   button_container().AddChildView(button2);
61 
62   button1->SetChecked(true);
63   EXPECT_TRUE(button1->GetChecked());
64   EXPECT_FALSE(button2->GetChecked());
65 
66   button2->SetChecked(true);
67   EXPECT_FALSE(button1->GetChecked());
68   EXPECT_TRUE(button2->GetChecked());
69 }
70 
TEST_F(RadioButtonTest,Focus)71 TEST_F(RadioButtonTest, Focus) {
72   RadioButton* button1 = new RadioButton(base::ASCIIToUTF16("Blah"), kGroup);
73   button_container().AddChildView(button1);
74   RadioButton* button2 = new RadioButton(base::ASCIIToUTF16("Blah"), kGroup);
75   button_container().AddChildView(button2);
76 
77   // Tabbing through only focuses the checked button.
78   button1->SetChecked(true);
79   auto* focus_manager = button_container().GetFocusManager();
80   ui::KeyEvent pressed_tab(ui::ET_KEY_PRESSED, ui::VKEY_TAB, ui::EF_NONE);
81   focus_manager->OnKeyEvent(pressed_tab);
82   EXPECT_EQ(button1, focus_manager->GetFocusedView());
83   focus_manager->OnKeyEvent(pressed_tab);
84   EXPECT_EQ(button1, focus_manager->GetFocusedView());
85 
86   // The checked button can be moved using arrow keys.
87   focus_manager->OnKeyEvent(
88       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_DOWN, ui::EF_NONE));
89   EXPECT_EQ(button2, focus_manager->GetFocusedView());
90   EXPECT_FALSE(button1->GetChecked());
91   EXPECT_TRUE(button2->GetChecked());
92 
93   focus_manager->OnKeyEvent(
94       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_UP, ui::EF_NONE));
95   EXPECT_EQ(button1, focus_manager->GetFocusedView());
96   EXPECT_TRUE(button1->GetChecked());
97   EXPECT_FALSE(button2->GetChecked());
98 }
99 
TEST_F(RadioButtonTest,FocusOnClick)100 TEST_F(RadioButtonTest, FocusOnClick) {
101   RadioButton* button1 = new RadioButton(base::string16(), kGroup);
102   button1->SetSize(gfx::Size(10, 10));
103   button_container().AddChildView(button1);
104   button1->SetChecked(true);
105   RadioButton* button2 = new RadioButton(base::string16(), kGroup);
106   button2->SetSize(gfx::Size(10, 10));
107   button_container().AddChildView(button2);
108 
109   const gfx::Point point(1, 1);
110   const ui::MouseEvent event(ui::ET_MOUSE_PRESSED, point, point,
111                              ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
112                              ui::EF_LEFT_MOUSE_BUTTON);
113   button2->OnMousePressed(event);
114   button2->OnMouseReleased(event);
115 
116   EXPECT_TRUE(button2->GetChecked());
117   auto* focus_manager = button_container().GetFocusManager();
118   // No focus on click.
119   EXPECT_EQ(nullptr, focus_manager->GetFocusedView());
120 
121   ui::KeyEvent pressed_tab(ui::ET_KEY_PRESSED, ui::VKEY_TAB, ui::EF_NONE);
122   focus_manager->OnKeyEvent(pressed_tab);
123   EXPECT_EQ(button2, focus_manager->GetFocusedView());
124 
125   button1->OnMousePressed(event);
126   button1->OnMouseReleased(event);
127   // Button 1 gets focus on click because button 2 already had it.
128   EXPECT_TRUE(button1->GetChecked());
129   EXPECT_EQ(button1, focus_manager->GetFocusedView());
130 }
131 
132 }  // namespace views
133