Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/controls/tabbed_pane/tabbed_pane.h" | 5 #include "ui/views/controls/tabbed_pane/tabbed_pane.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 #include "ui/accessibility/ax_action_data.h" | |
| 14 #include "ui/accessibility/ax_enums.h" | |
| 13 #include "ui/events/keycodes/keyboard_code_conversion.h" | 15 #include "ui/events/keycodes/keyboard_code_conversion.h" |
| 16 #include "ui/views/accessibility/native_view_accessibility.h" | |
| 14 #include "ui/views/test/views_test_base.h" | 17 #include "ui/views/test/views_test_base.h" |
| 18 #include "ui/views/widget/widget.h" | |
| 15 | 19 |
| 16 using base::ASCIIToUTF16; | 20 using base::ASCIIToUTF16; |
| 17 | 21 |
| 18 namespace views { | 22 namespace views { |
| 19 | 23 |
| 20 // A view for testing that takes a fixed preferred size upon construction. | 24 // A view for testing that takes a fixed preferred size upon construction. |
| 21 class FixedSizeView : public View { | 25 class FixedSizeView : public View { |
| 22 public: | 26 public: |
| 23 explicit FixedSizeView(const gfx::Size& size) | 27 explicit FixedSizeView(const gfx::Size& size) |
| 24 : size_(size) {} | 28 : size_(size) {} |
| 25 | 29 |
| 26 // Overridden from View: | 30 // Overridden from View: |
| 27 gfx::Size GetPreferredSize() const override { return size_; } | 31 gfx::Size GetPreferredSize() const override { return size_; } |
| 28 | 32 |
| 29 private: | 33 private: |
| 30 const gfx::Size size_; | 34 const gfx::Size size_; |
| 31 | 35 |
| 32 DISALLOW_COPY_AND_ASSIGN(FixedSizeView); | 36 DISALLOW_COPY_AND_ASSIGN(FixedSizeView); |
| 33 }; | 37 }; |
| 34 | 38 |
| 39 base::string16 kTabTitle = ASCIIToUTF16("tab"); | |
|
tapted
2017/01/06 04:25:12
This will make a static initializer, which will ge
Patti Lor
2017/01/09 22:39:28
Done.
| |
| 40 | |
| 35 typedef ViewsTestBase TabbedPaneTest; | 41 typedef ViewsTestBase TabbedPaneTest; |
|
tapted
2017/01/06 04:25:12
I think it's time to upgrade this to a proper test
Patti Lor
2017/01/09 22:39:28
Done.
| |
| 36 | 42 |
| 37 // Tests TabbedPane::GetPreferredSize() and TabbedPane::Layout(). | 43 // Tests TabbedPane::GetPreferredSize() and TabbedPane::Layout(). |
| 38 TEST_F(TabbedPaneTest, SizeAndLayout) { | 44 TEST_F(TabbedPaneTest, SizeAndLayout) { |
| 39 std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); | 45 std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); |
| 40 View* child1 = new FixedSizeView(gfx::Size(20, 10)); | 46 View* child1 = new FixedSizeView(gfx::Size(20, 10)); |
| 41 tabbed_pane->AddTab(ASCIIToUTF16("tab1"), child1); | 47 tabbed_pane->AddTab(ASCIIToUTF16("tab1"), child1); |
| 42 View* child2 = new FixedSizeView(gfx::Size(5, 5)); | 48 View* child2 = new FixedSizeView(gfx::Size(5, 5)); |
| 43 tabbed_pane->AddTab(ASCIIToUTF16("tab2"), child2); | 49 tabbed_pane->AddTab(ASCIIToUTF16("tab2"), child2); |
| 44 tabbed_pane->SelectTabAt(0); | 50 tabbed_pane->SelectTabAt(0); |
| 45 | 51 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 62 EXPECT_GT(bounds.height(), 0); | 68 EXPECT_GT(bounds.height(), 0); |
| 63 EXPECT_LT(bounds.height(), 200); | 69 EXPECT_LT(bounds.height(), 200); |
| 64 | 70 |
| 65 // If we switch to the other tab, it should get assigned the same bounds. | 71 // If we switch to the other tab, it should get assigned the same bounds. |
| 66 tabbed_pane->SelectTabAt(1); | 72 tabbed_pane->SelectTabAt(1); |
| 67 EXPECT_EQ(bounds, child2->bounds()); | 73 EXPECT_EQ(bounds, child2->bounds()); |
| 68 } | 74 } |
| 69 | 75 |
| 70 TEST_F(TabbedPaneTest, AddAndSelect) { | 76 TEST_F(TabbedPaneTest, AddAndSelect) { |
| 71 std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); | 77 std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); |
| 72 // Add several tabs; only the first should be a selected automatically. | 78 // Add several tabs; only the first should be selected automatically. |
| 73 for (int i = 0; i < 3; ++i) { | 79 for (int i = 0; i < 3; ++i) { |
| 74 View* tab = new View(); | 80 View* tab = new View(); |
| 75 tabbed_pane->AddTab(ASCIIToUTF16("tab"), tab); | 81 tabbed_pane->AddTab(kTabTitle, tab); |
| 76 EXPECT_EQ(i + 1, tabbed_pane->GetTabCount()); | 82 EXPECT_EQ(i + 1, tabbed_pane->GetTabCount()); |
| 77 EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); | 83 EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); |
| 78 } | 84 } |
| 79 | 85 |
| 80 // Select each tab. | 86 // Select each tab. |
| 81 for (int i = 0; i < tabbed_pane->GetTabCount(); ++i) { | 87 for (int i = 0; i < tabbed_pane->GetTabCount(); ++i) { |
| 82 tabbed_pane->SelectTabAt(i); | 88 tabbed_pane->SelectTabAt(i); |
| 83 EXPECT_EQ(i, tabbed_pane->GetSelectedTabIndex()); | 89 EXPECT_EQ(i, tabbed_pane->GetSelectedTabIndex()); |
| 84 } | 90 } |
| 85 | 91 |
| 86 // Add a tab at index 0, it should not be selected automatically. | 92 // Add a tab at index 0, it should not be selected automatically. |
| 87 View* tab0 = new View(); | 93 View* tab0 = new View(); |
| 88 tabbed_pane->AddTabAtIndex(0, ASCIIToUTF16("tab0"), tab0); | 94 tabbed_pane->AddTabAtIndex(0, ASCIIToUTF16("tab0"), tab0); |
| 89 EXPECT_NE(tab0, tabbed_pane->GetSelectedTabContentView()); | 95 EXPECT_NE(tab0, tabbed_pane->GetSelectedTabContentView()); |
| 90 EXPECT_NE(0, tabbed_pane->GetSelectedTabIndex()); | 96 EXPECT_NE(0, tabbed_pane->GetSelectedTabIndex()); |
| 91 } | 97 } |
| 92 | 98 |
| 93 ui::KeyEvent MakeKeyPressedEvent(ui::KeyboardCode keyboard_code, int flags) { | 99 ui::KeyEvent MakeKeyPressedEvent(ui::KeyboardCode keyboard_code, int flags) { |
| 94 return ui::KeyEvent(ui::ET_KEY_PRESSED, keyboard_code, | 100 return ui::KeyEvent(ui::ET_KEY_PRESSED, keyboard_code, |
| 95 ui::UsLayoutKeyboardCodeToDomCode(keyboard_code), flags); | 101 ui::UsLayoutKeyboardCodeToDomCode(keyboard_code), flags); |
| 96 } | 102 } |
| 97 | 103 |
| 98 TEST_F(TabbedPaneTest, ArrowKeyBindings) { | 104 TEST_F(TabbedPaneTest, ArrowKeyBindings) { |
| 99 std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); | 105 std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); |
| 100 // Add several tabs; only the first should be a selected automatically. | 106 // Add several tabs; only the first should be selected automatically. |
| 101 for (int i = 0; i < 3; ++i) { | 107 for (int i = 0; i < 3; ++i) { |
| 102 View* tab = new View(); | 108 View* tab = new View(); |
| 103 tabbed_pane->AddTab(ASCIIToUTF16("tab"), tab); | 109 tabbed_pane->AddTab(kTabTitle, tab); |
| 104 EXPECT_EQ(i + 1, tabbed_pane->GetTabCount()); | 110 EXPECT_EQ(i + 1, tabbed_pane->GetTabCount()); |
| 105 } | 111 } |
| 106 | 112 |
| 107 EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); | 113 EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); |
| 108 | 114 |
| 109 // Right arrow should select tab 1: | 115 // Right arrow should select tab 1: |
| 110 tabbed_pane->GetSelectedTab()->OnKeyPressed( | 116 tabbed_pane->GetSelectedTab()->OnKeyPressed( |
| 111 MakeKeyPressedEvent(ui::VKEY_RIGHT, 0)); | 117 MakeKeyPressedEvent(ui::VKEY_RIGHT, 0)); |
| 112 EXPECT_EQ(1, tabbed_pane->GetSelectedTabIndex()); | 118 EXPECT_EQ(1, tabbed_pane->GetSelectedTabIndex()); |
| 113 | 119 |
| 114 // Left arrow should select tab 0: | 120 // Left arrow should select tab 0: |
| 115 tabbed_pane->GetSelectedTab()->OnKeyPressed( | 121 tabbed_pane->GetSelectedTab()->OnKeyPressed( |
| 116 MakeKeyPressedEvent(ui::VKEY_LEFT, 0)); | 122 MakeKeyPressedEvent(ui::VKEY_LEFT, 0)); |
| 117 EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); | 123 EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); |
| 118 | 124 |
| 119 // Left arrow again should wrap to tab 2: | 125 // Left arrow again should wrap to tab 2: |
| 120 tabbed_pane->GetSelectedTab()->OnKeyPressed( | 126 tabbed_pane->GetSelectedTab()->OnKeyPressed( |
| 121 MakeKeyPressedEvent(ui::VKEY_LEFT, 0)); | 127 MakeKeyPressedEvent(ui::VKEY_LEFT, 0)); |
| 122 EXPECT_EQ(2, tabbed_pane->GetSelectedTabIndex()); | 128 EXPECT_EQ(2, tabbed_pane->GetSelectedTabIndex()); |
| 123 | 129 |
| 124 // Right arrow again should wrap to tab 0: | 130 // Right arrow again should wrap to tab 0: |
| 125 tabbed_pane->GetSelectedTab()->OnKeyPressed( | 131 tabbed_pane->GetSelectedTab()->OnKeyPressed( |
| 126 MakeKeyPressedEvent(ui::VKEY_RIGHT, 0)); | 132 MakeKeyPressedEvent(ui::VKEY_RIGHT, 0)); |
| 127 EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); | 133 EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); |
| 128 } | 134 } |
| 129 | 135 |
| 136 // Use TabbedPane::HandleAccessibleAction() to select tabs and make sure their | |
| 137 // a11y information is correct. | |
| 138 TEST_F(TabbedPaneTest, SelectTabWithAccessibleAction) { | |
| 139 // Testing accessibility information requires the View to have a Widget. | |
| 140 Widget* widget = new Widget; | |
| 141 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); | |
| 142 widget->Init(params); | |
| 143 TabbedPane* tabbed_pane = new TabbedPane(); | |
| 144 widget->GetContentsView()->AddChildView(tabbed_pane); | |
| 145 widget->Show(); | |
| 146 | |
| 147 const int num_tabs = 2; | |
|
tapted
2017/01/06 04:25:12
constexpr int kNumTabs = 2;
(constexpr helps guar
Patti Lor
2017/01/09 22:39:28
Done, thanks I didn't know about constexpr.
| |
| 148 std::vector<Tab*> tab_list; | |
| 149 for (int i = 0; i <= num_tabs; ++i) { | |
|
tapted
2017/01/06 04:25:12
this ends up making 3 tabs, which I see is intenti
Patti Lor
2017/01/09 22:39:28
Done.
| |
| 150 tabbed_pane->AddTab(kTabTitle, new View()); | |
| 151 tabbed_pane->SelectTabAt(i); | |
| 152 tab_list.push_back(tabbed_pane->GetSelectedTab()); | |
| 153 } | |
| 154 // Check the last tab added is selected. | |
| 155 EXPECT_EQ(num_tabs, tabbed_pane->GetSelectedTabIndex()); | |
| 156 | |
| 157 // Check the a11y information for each tab. | |
| 158 for (int i = 0; i <= num_tabs; ++i) { | |
| 159 ui::AXNodeData data = | |
| 160 NativeViewAccessibility::Create(tab_list[i])->GetData(); | |
| 161 SCOPED_TRACE(testing::Message() << "Tab at index: " << i); | |
| 162 EXPECT_EQ(ui::AX_ROLE_TAB, data.role); | |
| 163 EXPECT_EQ(kTabTitle, data.GetString16Attribute(ui::AX_ATTR_NAME)); | |
| 164 EXPECT_TRUE(data.HasStateFlag(ui::AX_STATE_SELECTABLE)); | |
| 165 EXPECT_EQ(i == num_tabs, data.HasStateFlag(ui::AX_STATE_SELECTED)); | |
|
tapted
2017/01/06 04:25:12
e.g. i == kNumTabs - 1
Patti Lor
2017/01/09 22:39:28
Done.
| |
| 166 } | |
| 167 | |
| 168 ui::AXActionData action; | |
| 169 action.action = ui::AX_ACTION_SET_SELECTION; | |
| 170 // Select the first tab. | |
| 171 NativeViewAccessibility::Create(tab_list[0]) | |
|
tapted
2017/01/06 04:25:12
I think this is leaked. It's possible you are actu
Patti Lor
2017/01/09 22:39:28
Yep, I am - I think this change might land first t
| |
| 172 ->AccessibilityPerformAction(action); | |
| 173 EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); | |
| 174 | |
| 175 // Select the second tab. | |
| 176 NativeViewAccessibility::Create(tab_list[1]) | |
| 177 ->AccessibilityPerformAction(action); | |
| 178 EXPECT_EQ(1, tabbed_pane->GetSelectedTabIndex()); | |
| 179 // Select the second tab again. | |
| 180 NativeViewAccessibility::Create(tab_list[1]) | |
| 181 ->AccessibilityPerformAction(action); | |
| 182 EXPECT_EQ(1, tabbed_pane->GetSelectedTabIndex()); | |
| 183 | |
| 184 widget->Close(); | |
|
tapted
2017/01/06 04:25:12
nit: CloseNow()
Patti Lor
2017/01/09 22:39:28
Done.
| |
| 185 } | |
| 186 | |
| 130 } // namespace views | 187 } // namespace views |
| OLD | NEW |