Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Side by Side Diff: ui/views/controls/table/table_view_unittest.cc

Issue 2780833004: Improve TableView unit tests and fix bugs that were uncovered. (Closed)
Patch Set: disable for now on mac Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/views/controls/table/table_view.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/table/table_view.h" 5 #include "ui/views/controls/table/table_view.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include "base/macros.h" 9 #include "base/macros.h"
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.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/events/event_utils.h" 13 #include "ui/events/event_utils.h"
14 #include "ui/events/test/event_generator.h"
14 #include "ui/views/controls/table/table_grouper.h" 15 #include "ui/views/controls/table/table_grouper.h"
15 #include "ui/views/controls/table/table_header.h" 16 #include "ui/views/controls/table/table_header.h"
16 #include "ui/views/controls/table/table_view_observer.h" 17 #include "ui/views/controls/table/table_view_observer.h"
18 #include "ui/views/test/views_test_base.h"
17 19
18 // Put the tests in the views namespace to make it easier to declare them as 20 // Put the tests in the views namespace to make it easier to declare them as
19 // friend classes. 21 // friend classes.
20 namespace views { 22 namespace views {
21 23
22 class TableViewTestHelper { 24 class TableViewTestHelper {
23 public: 25 public:
24 explicit TableViewTestHelper(TableView* table) : table_(table) {} 26 explicit TableViewTestHelper(TableView* table) : table_(table) {}
25 27
26 std::string GetPaintRegion(const gfx::Rect& bounds) { 28 std::string GetPaintRegion(const gfx::Rect& bounds) {
27 TableView::PaintRegion region(table_->GetPaintRegion(bounds)); 29 TableView::PaintRegion region(table_->GetPaintRegion(bounds));
28 return "rows=" + base::IntToString(region.min_row) + " " + 30 return "rows=" + base::IntToString(region.min_row) + " " +
29 base::IntToString(region.max_row) + " cols=" + 31 base::IntToString(region.max_row) + " cols=" +
30 base::IntToString(region.min_column) + " " + 32 base::IntToString(region.min_column) + " " +
31 base::IntToString(region.max_column); 33 base::IntToString(region.max_column);
32 } 34 }
33 35
34 size_t visible_col_count() { 36 size_t visible_col_count() {
35 return table_->visible_columns().size(); 37 return table_->visible_columns().size();
36 } 38 }
37 39
38 TableHeader* header() { return table_->header_; } 40 TableHeader* header() { return table_->header_; }
39 41
40 void SetSelectionModel(const ui::ListSelectionModel& new_selection) { 42 void SetSelectionModel(const ui::ListSelectionModel& new_selection) {
41 table_->SetSelectionModel(new_selection); 43 table_->SetSelectionModel(new_selection);
42 } 44 }
43 45
44 void OnFocus() {
45 table_->OnFocus();
46 }
47
48 private: 46 private:
49 TableView* table_; 47 TableView* table_;
50 48
51 DISALLOW_COPY_AND_ASSIGN(TableViewTestHelper); 49 DISALLOW_COPY_AND_ASSIGN(TableViewTestHelper);
52 }; 50 };
53 51
54 namespace { 52 namespace {
55 53
56 // TestTableModel2 ------------------------------------------------------------- 54 // TestTableModel2 -------------------------------------------------------------
57 55
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 result += ", "; // Comma between each value in the row. 175 result += ", "; // Comma between each value in the row.
178 176
179 result += base::UTF16ToUTF8( 177 result += base::UTF16ToUTF8(
180 table->model()->GetText(table->ViewToModel(i), column.id)); 178 table->model()->GetText(table->ViewToModel(i), column.id));
181 } 179 }
182 result += "]"; 180 result += "]";
183 } 181 }
184 return result; 182 return result;
185 } 183 }
186 184
187 class TestTableView : public TableView {
188 public:
189 TestTableView(ui::TableModel* model,
190 const std::vector<ui::TableColumn>& columns)
191 : TableView(model, columns, TEXT_ONLY, false) {
192 }
193
194 // View overrides:
195 bool HasFocus() const override {
196 // Overriden so key processing works.
197 return true;
198 }
199
200 private:
201 DISALLOW_COPY_AND_ASSIGN(TestTableView);
202 };
203
204 } // namespace 185 } // namespace
205 186
206 class TableViewTest : public testing::Test { 187 class TableViewTest : public ViewsTestBase {
207 public: 188 public:
208 TableViewTest() : table_(NULL) {} 189 TableViewTest() : table_(NULL) {}
209 190
210 void SetUp() override { 191 void SetUp() override {
192 ViewsTestBase::SetUp();
193
211 model_.reset(new TestTableModel2); 194 model_.reset(new TestTableModel2);
212 std::vector<ui::TableColumn> columns(2); 195 std::vector<ui::TableColumn> columns(2);
213 columns[0].title = base::ASCIIToUTF16("Title Column 0"); 196 columns[0].title = base::ASCIIToUTF16("Title Column 0");
214 columns[0].sortable = true; 197 columns[0].sortable = true;
215 columns[1].title = base::ASCIIToUTF16("Title Column 1"); 198 columns[1].title = base::ASCIIToUTF16("Title Column 1");
216 columns[1].id = 1; 199 columns[1].id = 1;
217 columns[1].sortable = true; 200 columns[1].sortable = true;
218 table_ = new TestTableView(model_.get(), columns); 201 table_ = new TableView(model_.get(), columns, TEXT_ONLY, false);
219 parent_.reset(table_->CreateParentIfNecessary()); 202 View* parent = table_->CreateParentIfNecessary();
220 parent_->SetBounds(0, 0, 10000, 10000); 203 parent->SetBounds(0, 0, 10000, 10000);
221 parent_->Layout(); 204 parent->Layout();
222 helper_.reset(new TableViewTestHelper(table_)); 205 helper_.reset(new TableViewTestHelper(table_));
206
207 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
208 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
209 params.bounds = gfx::Rect(0, 0, 650, 650);
210 widget_.reset(new Widget);
211 widget_->Init(params);
212 widget_->GetContentsView()->AddChildView(parent);
213 widget_->Show();
214 }
215
216 void TearDown() override {
217 widget_.reset();
218 ViewsTestBase::TearDown();
223 } 219 }
224 220
225 void ClickOnRow(int row, int flags) { 221 void ClickOnRow(int row, int flags) {
226 const int y = row * table_->row_height(); 222 ui::test::EventGenerator generator(widget_->GetNativeWindow());
227 const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(0, y), 223 generator.set_flags(flags);
228 gfx::Point(0, y), ui::EventTimeForNow(), 224 generator.set_current_location(GetPointForRow(row));
229 ui::EF_LEFT_MOUSE_BUTTON | flags, 225 generator.PressLeftButton();
230 ui::EF_LEFT_MOUSE_BUTTON);
231 table_->OnMousePressed(pressed);
232 } 226 }
233 227
234 void TapOnRow(int row) { 228 void TapOnRow(int row) {
235 const int y = row * table_->row_height(); 229 ui::test::EventGenerator generator(widget_->GetNativeWindow());
236 const ui::GestureEventDetails event_details(ui::ET_GESTURE_TAP); 230 generator.GestureTapAt(GetPointForRow(row));
237 ui::GestureEvent tap(0, y, 0, base::TimeTicks(), event_details);
238 table_->OnGestureEvent(&tap);
239 } 231 }
240 232
241 // Returns the state of the selection model as a string. The format is: 233 // Returns the state of the selection model as a string. The format is:
242 // 'active=X anchor=X selection=X X X...'. 234 // 'active=X anchor=X selection=X X X...'.
243 std::string SelectionStateAsString() const { 235 std::string SelectionStateAsString() const {
244 const ui::ListSelectionModel& model(table_->selection_model()); 236 const ui::ListSelectionModel& model(table_->selection_model());
245 std::string result = "active=" + base::IntToString(model.active()) + 237 std::string result = "active=" + base::IntToString(model.active()) +
246 " anchor=" + base::IntToString(model.anchor()) + 238 " anchor=" + base::IntToString(model.anchor()) +
247 " selection="; 239 " selection=";
248 const ui::ListSelectionModel::SelectedIndices& selection( 240 const ui::ListSelectionModel::SelectedIndices& selection(
249 model.selected_indices()); 241 model.selected_indices());
250 for (size_t i = 0; i < selection.size(); ++i) { 242 for (size_t i = 0; i < selection.size(); ++i) {
251 if (i != 0) 243 if (i != 0)
252 result += " "; 244 result += " ";
253 result += base::IntToString(selection[i]); 245 result += base::IntToString(selection[i]);
254 } 246 }
255 return result; 247 return result;
256 } 248 }
257 249
258 void PressKey(ui::KeyboardCode code) { 250 void PressKey(ui::KeyboardCode code) {
259 ui::KeyEvent event(ui::ET_KEY_PRESSED, code, ui::EF_NONE); 251 ui::test::EventGenerator generator(widget_->GetNativeWindow());
260 table_->OnKeyPressed(event); 252 generator.PressKey(code, ui::EF_NONE);
261 } 253 }
262 254
263 protected: 255 protected:
264 std::unique_ptr<TestTableModel2> model_; 256 std::unique_ptr<TestTableModel2> model_;
265 257
266 // Owned by |parent_|. 258 // Owned by |parent_|.
267 TableView* table_; 259 TableView* table_;
268 260
269 std::unique_ptr<TableViewTestHelper> helper_; 261 std::unique_ptr<TableViewTestHelper> helper_;
270 262
271 private: 263 private:
272 std::unique_ptr<View> parent_; 264 gfx::Point GetPointForRow(int row) {
265 const int y = (row + 0.5) * table_->row_height();
266 return table_->GetBoundsInScreen().origin() + gfx::Vector2d(5, y);
267 }
268
269 std::unique_ptr<Widget> widget_;
273 270
274 DISALLOW_COPY_AND_ASSIGN(TableViewTest); 271 DISALLOW_COPY_AND_ASSIGN(TableViewTest);
275 }; 272 };
276 273
277 // Verifies GetPaintRegion. 274 // Verifies GetPaintRegion.
278 TEST_F(TableViewTest, GetPaintRegion) { 275 TEST_F(TableViewTest, GetPaintRegion) {
279 // Two columns should be visible. 276 // Two columns should be visible.
280 EXPECT_EQ(2u, helper_->visible_col_count()); 277 EXPECT_EQ(2u, helper_->visible_col_count());
281 278
282 EXPECT_EQ("rows=0 4 cols=0 2", helper_->GetPaintRegion(table_->bounds())); 279 EXPECT_EQ("rows=0 4 cols=0 2", helper_->GetPaintRegion(table_->bounds()));
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after
720 EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString()); 717 EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString());
721 718
722 // Remove the selected row. 719 // Remove the selected row.
723 model_->RemoveRow(0); 720 model_->RemoveRow(0);
724 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 721 EXPECT_EQ(1, observer.GetChangedCountAndClear());
725 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString()); 722 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
726 723
727 table_->set_observer(nullptr); 724 table_->set_observer(nullptr);
728 } 725 }
729 726
727 // No touch on desktop Mac. Tracked in http://crbug.com/445520.
728 #if !defined(OS_MACOSX)
730 // Verifies selection works by way of a gesture. 729 // Verifies selection works by way of a gesture.
731 TEST_F(TableViewTest, SelectOnTap) { 730 TEST_F(TableViewTest, SelectOnTap) {
732 // Initially no selection. 731 // Initially no selection.
733 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString()); 732 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
734 733
735 TableViewObserverImpl observer; 734 TableViewObserverImpl observer;
736 table_->set_observer(&observer); 735 table_->set_observer(&observer);
737 736
738 // Click on the first row, should select it. 737 // Tap on the first row, should select it.
739 TapOnRow(0); 738 TapOnRow(0);
740 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 739 EXPECT_EQ(1, observer.GetChangedCountAndClear());
741 EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString()); 740 EXPECT_EQ("active=0 anchor=0 selection=0", SelectionStateAsString());
742 741
743 table_->set_observer(NULL); 742 table_->set_observer(NULL);
744 } 743 }
744 #endif
745 745
746 // Verifies up/down correctly navigates through groups. 746 // Verifies up/down correctly navigates through groups.
747 TEST_F(TableViewTest, KeyUpDown) { 747 TEST_F(TableViewTest, KeyUpDown) {
748 // Configure the grouper so that there are three groups: 748 // Configure the grouper so that there are three groups:
749 // A 0 749 // A 0
750 // 1 750 // 1
751 // B 5 751 // B 5
752 // C 2 752 // C 2
753 // 3 753 // 3
754 model_->AddRow(2, 5, 0); 754 model_->AddRow(2, 5, 0);
755 TableGrouperImpl grouper; 755 TableGrouperImpl grouper;
756 std::vector<int> ranges; 756 std::vector<int> ranges;
757 ranges.push_back(2); 757 ranges.push_back(2);
758 ranges.push_back(1); 758 ranges.push_back(1);
759 ranges.push_back(2); 759 ranges.push_back(2);
760 grouper.SetRanges(ranges); 760 grouper.SetRanges(ranges);
761 table_->SetGrouper(&grouper); 761 table_->SetGrouper(&grouper);
762 762
763 TableViewObserverImpl observer; 763 TableViewObserverImpl observer;
764 table_->set_observer(&observer); 764 table_->set_observer(&observer);
765 table_->RequestFocus();
765 766
766 // Initially no selection. 767 // Initially no selection.
767 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString()); 768 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
768 769
769 PressKey(ui::VKEY_DOWN); 770 PressKey(ui::VKEY_DOWN);
770 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 771 EXPECT_EQ(1, observer.GetChangedCountAndClear());
771 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString()); 772 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
772 773
773 PressKey(ui::VKEY_DOWN); 774 PressKey(ui::VKEY_DOWN);
774 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 775 EXPECT_EQ(1, observer.GetChangedCountAndClear());
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
885 TableGrouperImpl grouper; 886 TableGrouperImpl grouper;
886 std::vector<int> ranges; 887 std::vector<int> ranges;
887 ranges.push_back(2); 888 ranges.push_back(2);
888 ranges.push_back(1); 889 ranges.push_back(1);
889 ranges.push_back(2); 890 ranges.push_back(2);
890 grouper.SetRanges(ranges); 891 grouper.SetRanges(ranges);
891 table_->SetGrouper(&grouper); 892 table_->SetGrouper(&grouper);
892 893
893 TableViewObserverImpl observer; 894 TableViewObserverImpl observer;
894 table_->set_observer(&observer); 895 table_->set_observer(&observer);
896 table_->RequestFocus();
895 897
896 // Initially no selection. 898 // Initially no selection.
897 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString()); 899 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
898 900
899 PressKey(ui::VKEY_HOME); 901 PressKey(ui::VKEY_HOME);
900 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 902 EXPECT_EQ(1, observer.GetChangedCountAndClear());
901 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString()); 903 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
902 904
903 PressKey(ui::VKEY_END); 905 PressKey(ui::VKEY_END);
904 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 906 EXPECT_EQ(1, observer.GetChangedCountAndClear());
905 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString()); 907 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
906 908
909 PressKey(ui::VKEY_HOME);
910 EXPECT_EQ(1, observer.GetChangedCountAndClear());
911 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
912
907 table_->set_observer(NULL); 913 table_->set_observer(NULL);
908 } 914 }
909 915
916 // TODO(tapted): enable these tests on Mac.
917 #if !defined(OS_MACOSX)
910 // Verifies multiple selection gestures work (control-click, shift-click ...). 918 // Verifies multiple selection gestures work (control-click, shift-click ...).
911 TEST_F(TableViewTest, Multiselection) { 919 TEST_F(TableViewTest, Multiselection) {
912 // Configure the grouper so that there are three groups: 920 // Configure the grouper so that there are three groups:
913 // A 0 921 // A 0
914 // 1 922 // 1
915 // B 5 923 // B 5
916 // C 2 924 // C 2
917 // 3 925 // 3
918 model_->AddRow(2, 5, 0); 926 model_->AddRow(2, 5, 0);
919 TableGrouperImpl grouper; 927 TableGrouperImpl grouper;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
1000 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 1008 EXPECT_EQ(1, observer.GetChangedCountAndClear());
1001 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString()); 1009 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
1002 1010
1003 // Extend selection to first row. 1011 // Extend selection to first row.
1004 ClickOnRow(0, ui::EF_SHIFT_DOWN); 1012 ClickOnRow(0, ui::EF_SHIFT_DOWN);
1005 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 1013 EXPECT_EQ(1, observer.GetChangedCountAndClear());
1006 EXPECT_EQ("active=2 anchor=4 selection=2 3 4", SelectionStateAsString()); 1014 EXPECT_EQ("active=2 anchor=4 selection=2 3 4", SelectionStateAsString());
1007 1015
1008 table_->set_observer(NULL); 1016 table_->set_observer(NULL);
1009 } 1017 }
1018 #endif
1010 1019
1011 // Verifies we don't crash after removing the selected row when there is 1020 // Verifies we don't crash after removing the selected row when there is
1012 // sorting and the anchor/active index also match the selected row. 1021 // sorting and the anchor/active index also match the selected row.
1013 TEST_F(TableViewTest, FocusAfterRemovingAnchor) { 1022 TEST_F(TableViewTest, FocusAfterRemovingAnchor) {
1014 table_->ToggleSortOrder(0); 1023 table_->ToggleSortOrder(0);
1015 1024
1016 ui::ListSelectionModel new_selection; 1025 ui::ListSelectionModel new_selection;
1017 new_selection.AddIndexToSelection(0); 1026 new_selection.AddIndexToSelection(0);
1018 new_selection.AddIndexToSelection(1); 1027 new_selection.AddIndexToSelection(1);
1019 new_selection.set_active(0); 1028 new_selection.set_active(0);
1020 new_selection.set_anchor(0); 1029 new_selection.set_anchor(0);
1021 helper_->SetSelectionModel(new_selection); 1030 helper_->SetSelectionModel(new_selection);
1022 model_->RemoveRow(0); 1031 model_->RemoveRow(0);
1023 helper_->OnFocus(); 1032 table_->RequestFocus();
1024 }
1025
1026 // Tests that focusing the table will activate the first row, but only if
1027 // there's no active row.
1028 TEST_F(TableViewTest, InitialFocusActivatesFirstRow) {
1029 EXPECT_EQ(-1, table_->selection_model().active());
1030 helper_->OnFocus();
1031 EXPECT_EQ(0, table_->selection_model().active());
1032
1033 ui::ListSelectionModel new_selection;
1034 new_selection.set_active(1);
1035 helper_->SetSelectionModel(new_selection);
1036 EXPECT_EQ(1, table_->selection_model().active());
1037 helper_->OnFocus();
1038 EXPECT_EQ(1, table_->selection_model().active());
1039
1040 // Remove all rows; focusing should not activate a non existent first row.
1041 while (model_->RowCount())
1042 model_->RemoveRow(0);
1043
1044 new_selection.set_active(-1);
1045 helper_->SetSelectionModel(new_selection);
1046 helper_->OnFocus();
1047 EXPECT_EQ(-1, table_->selection_model().active());
1048 } 1033 }
1049 1034
1050 } // namespace views 1035 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/table/table_view.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698