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

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: docs 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
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/run_loop.h"
10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h"
12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "testing/gtest/include/gtest/gtest.h"
13 #include "ui/events/event_utils.h" 14 #include "ui/events/event_utils.h"
15 #include "ui/events/test/event_generator.h"
14 #include "ui/views/controls/table/table_grouper.h" 16 #include "ui/views/controls/table/table_grouper.h"
15 #include "ui/views/controls/table/table_header.h" 17 #include "ui/views/controls/table/table_header.h"
16 #include "ui/views/controls/table/table_view_observer.h" 18 #include "ui/views/controls/table/table_view_observer.h"
19 #include "ui/views/test/views_test_base.h"
17 20
18 // Put the tests in the views namespace to make it easier to declare them as 21 // Put the tests in the views namespace to make it easier to declare them as
19 // friend classes. 22 // friend classes.
20 namespace views { 23 namespace views {
21 24
22 class TableViewTestHelper { 25 class TableViewTestHelper {
23 public: 26 public:
24 explicit TableViewTestHelper(TableView* table) : table_(table) {} 27 explicit TableViewTestHelper(TableView* table) : table_(table) {}
25 28
26 std::string GetPaintRegion(const gfx::Rect& bounds) { 29 std::string GetPaintRegion(const gfx::Rect& bounds) {
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 // Overriden so key processing works. 199 // Overriden so key processing works.
197 return true; 200 return true;
198 } 201 }
199 202
200 private: 203 private:
201 DISALLOW_COPY_AND_ASSIGN(TestTableView); 204 DISALLOW_COPY_AND_ASSIGN(TestTableView);
202 }; 205 };
203 206
204 } // namespace 207 } // namespace
205 208
206 class TableViewTest : public testing::Test { 209 class TableViewTest : public ViewsTestBase {
207 public: 210 public:
208 TableViewTest() : table_(NULL) {} 211 TableViewTest() : table_(NULL) {}
209 212
210 void SetUp() override { 213 void SetUp() override {
214 ViewsTestBase::SetUp();
215
211 model_.reset(new TestTableModel2); 216 model_.reset(new TestTableModel2);
212 std::vector<ui::TableColumn> columns(2); 217 std::vector<ui::TableColumn> columns(2);
213 columns[0].title = base::ASCIIToUTF16("Title Column 0"); 218 columns[0].title = base::ASCIIToUTF16("Title Column 0");
214 columns[0].sortable = true; 219 columns[0].sortable = true;
215 columns[1].title = base::ASCIIToUTF16("Title Column 1"); 220 columns[1].title = base::ASCIIToUTF16("Title Column 1");
216 columns[1].id = 1; 221 columns[1].id = 1;
217 columns[1].sortable = true; 222 columns[1].sortable = true;
218 table_ = new TestTableView(model_.get(), columns); 223 table_ = new TestTableView(model_.get(), columns);
219 parent_.reset(table_->CreateParentIfNecessary()); 224 View* parent = table_->CreateParentIfNecessary();
220 parent_->SetBounds(0, 0, 10000, 10000); 225 parent->SetBounds(0, 0, 10000, 10000);
221 parent_->Layout(); 226 parent->Layout();
222 helper_.reset(new TableViewTestHelper(table_)); 227 helper_.reset(new TableViewTestHelper(table_));
228
229 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
230 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
231 params.bounds = gfx::Rect(0, 0, 650, 650);
232 widget_.reset(new Widget);
233 widget_->Init(params);
234 widget_->GetContentsView()->AddChildView(parent);
235 widget_->Show();
236 }
237
238 void TearDown() override {
239 widget_.reset();
240 ViewsTestBase::TearDown();
223 } 241 }
224 242
225 void ClickOnRow(int row, int flags) { 243 void ClickOnRow(int row, int flags) {
226 const int y = row * table_->row_height(); 244 ui::test::EventGenerator generator(widget_->GetNativeWindow());
227 const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(0, y), 245 generator.set_flags(flags);
228 gfx::Point(0, y), ui::EventTimeForNow(), 246 generator.set_current_location(GetPointForRow(row));
229 ui::EF_LEFT_MOUSE_BUTTON | flags, 247 generator.PressLeftButton();
230 ui::EF_LEFT_MOUSE_BUTTON);
231 table_->OnMousePressed(pressed);
232 } 248 }
233 249
234 void TapOnRow(int row) { 250 void TapOnRow(int row) {
235 const int y = row * table_->row_height(); 251 ui::test::EventGenerator generator(widget_->GetNativeWindow());
236 const ui::GestureEventDetails event_details(ui::ET_GESTURE_TAP); 252 generator.GestureTapAt(GetPointForRow(row));
237 ui::GestureEvent tap(0, y, 0, base::TimeTicks(), event_details);
238 table_->OnGestureEvent(&tap);
239 } 253 }
240 254
241 // Returns the state of the selection model as a string. The format is: 255 // Returns the state of the selection model as a string. The format is:
242 // 'active=X anchor=X selection=X X X...'. 256 // 'active=X anchor=X selection=X X X...'.
243 std::string SelectionStateAsString() const { 257 std::string SelectionStateAsString() const {
244 const ui::ListSelectionModel& model(table_->selection_model()); 258 const ui::ListSelectionModel& model(table_->selection_model());
245 std::string result = "active=" + base::IntToString(model.active()) + 259 std::string result = "active=" + base::IntToString(model.active()) +
246 " anchor=" + base::IntToString(model.anchor()) + 260 " anchor=" + base::IntToString(model.anchor()) +
247 " selection="; 261 " selection=";
248 const ui::ListSelectionModel::SelectedIndices& selection( 262 const ui::ListSelectionModel::SelectedIndices& selection(
249 model.selected_indices()); 263 model.selected_indices());
250 for (size_t i = 0; i < selection.size(); ++i) { 264 for (size_t i = 0; i < selection.size(); ++i) {
251 if (i != 0) 265 if (i != 0)
252 result += " "; 266 result += " ";
253 result += base::IntToString(selection[i]); 267 result += base::IntToString(selection[i]);
254 } 268 }
255 return result; 269 return result;
256 } 270 }
257 271
258 void PressKey(ui::KeyboardCode code) { 272 void PressKey(ui::KeyboardCode code) {
259 ui::KeyEvent event(ui::ET_KEY_PRESSED, code, ui::EF_NONE); 273 ui::test::EventGenerator generator(widget_->GetNativeWindow());
260 table_->OnKeyPressed(event); 274 generator.PressKey(code, ui::EF_NONE);
261 } 275 }
262 276
263 protected: 277 protected:
264 std::unique_ptr<TestTableModel2> model_; 278 std::unique_ptr<TestTableModel2> model_;
265 279
266 // Owned by |parent_|. 280 // Owned by |parent_|.
267 TableView* table_; 281 TableView* table_;
268 282
269 std::unique_ptr<TableViewTestHelper> helper_; 283 std::unique_ptr<TableViewTestHelper> helper_;
270 284
271 private: 285 private:
272 std::unique_ptr<View> parent_; 286 gfx::Point GetPointForRow(int row) {
287 const int y = row * table_->row_height();
288 return table_->GetBoundsInScreen().origin() + gfx::Vector2d(5, y);
289 }
290
291 std::unique_ptr<Widget> widget_;
273 292
274 DISALLOW_COPY_AND_ASSIGN(TableViewTest); 293 DISALLOW_COPY_AND_ASSIGN(TableViewTest);
275 }; 294 };
276 295
277 // Verifies GetPaintRegion. 296 // Verifies GetPaintRegion.
278 TEST_F(TableViewTest, GetPaintRegion) { 297 TEST_F(TableViewTest, GetPaintRegion) {
279 // Two columns should be visible. 298 // Two columns should be visible.
280 EXPECT_EQ(2u, helper_->visible_col_count()); 299 EXPECT_EQ(2u, helper_->visible_col_count());
281 300
282 EXPECT_EQ("rows=0 4 cols=0 2", helper_->GetPaintRegion(table_->bounds())); 301 EXPECT_EQ("rows=0 4 cols=0 2", helper_->GetPaintRegion(table_->bounds()));
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after
759 ranges.push_back(2); 778 ranges.push_back(2);
760 grouper.SetRanges(ranges); 779 grouper.SetRanges(ranges);
761 table_->SetGrouper(&grouper); 780 table_->SetGrouper(&grouper);
762 781
763 TableViewObserverImpl observer; 782 TableViewObserverImpl observer;
764 table_->set_observer(&observer); 783 table_->set_observer(&observer);
765 784
766 // Initially no selection. 785 // Initially no selection.
767 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString()); 786 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString());
768 787
769 PressKey(ui::VKEY_DOWN); 788 // Focus selects the first row.
789 table_->RequestFocus();
790 EXPECT_EQ(0, observer.GetChangedCountAndClear());
791 // ... after a delay.
792 base::RunLoop().RunUntilIdle();
770 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 793 EXPECT_EQ(1, observer.GetChangedCountAndClear());
771 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString()); 794 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
772 795
773 PressKey(ui::VKEY_DOWN); 796 PressKey(ui::VKEY_DOWN);
774 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 797 EXPECT_EQ(1, observer.GetChangedCountAndClear());
775 EXPECT_EQ("active=1 anchor=1 selection=0 1", SelectionStateAsString()); 798 EXPECT_EQ("active=1 anchor=1 selection=0 1", SelectionStateAsString());
776 799
777 PressKey(ui::VKEY_DOWN); 800 PressKey(ui::VKEY_DOWN);
778 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 801 EXPECT_EQ(1, observer.GetChangedCountAndClear());
779 EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString()); 802 EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString());
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
886 std::vector<int> ranges; 909 std::vector<int> ranges;
887 ranges.push_back(2); 910 ranges.push_back(2);
888 ranges.push_back(1); 911 ranges.push_back(1);
889 ranges.push_back(2); 912 ranges.push_back(2);
890 grouper.SetRanges(ranges); 913 grouper.SetRanges(ranges);
891 table_->SetGrouper(&grouper); 914 table_->SetGrouper(&grouper);
892 915
893 TableViewObserverImpl observer; 916 TableViewObserverImpl observer;
894 table_->set_observer(&observer); 917 table_->set_observer(&observer);
895 918
896 // Initially no selection. 919 // Focus selects the first row.
897 EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString()); 920 table_->RequestFocus();
921 EXPECT_EQ(0, observer.GetChangedCountAndClear());
922 // ... after a delay.
923 base::RunLoop().RunUntilIdle();
924 EXPECT_EQ(1, observer.GetChangedCountAndClear());
925 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
898 926
899 PressKey(ui::VKEY_HOME); 927 PressKey(ui::VKEY_HOME);
900 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 928 EXPECT_EQ(0, observer.GetChangedCountAndClear());
901 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString()); 929 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
902 930
903 PressKey(ui::VKEY_END); 931 PressKey(ui::VKEY_END);
904 EXPECT_EQ(1, observer.GetChangedCountAndClear()); 932 EXPECT_EQ(1, observer.GetChangedCountAndClear());
905 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString()); 933 EXPECT_EQ("active=4 anchor=4 selection=3 4", SelectionStateAsString());
906 934
935 PressKey(ui::VKEY_HOME);
936 EXPECT_EQ(1, observer.GetChangedCountAndClear());
937 EXPECT_EQ("active=0 anchor=0 selection=0 1", SelectionStateAsString());
938
907 table_->set_observer(NULL); 939 table_->set_observer(NULL);
908 } 940 }
909 941
910 // Verifies multiple selection gestures work (control-click, shift-click ...). 942 // Verifies multiple selection gestures work (control-click, shift-click ...).
911 TEST_F(TableViewTest, Multiselection) { 943 TEST_F(TableViewTest, Multiselection) {
912 // Configure the grouper so that there are three groups: 944 // Configure the grouper so that there are three groups:
913 // A 0 945 // A 0
914 // 1 946 // 1
915 // B 5 947 // B 5
916 // C 2 948 // C 2
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1019 new_selection.set_active(0); 1051 new_selection.set_active(0);
1020 new_selection.set_anchor(0); 1052 new_selection.set_anchor(0);
1021 helper_->SetSelectionModel(new_selection); 1053 helper_->SetSelectionModel(new_selection);
1022 model_->RemoveRow(0); 1054 model_->RemoveRow(0);
1023 helper_->OnFocus(); 1055 helper_->OnFocus();
1024 } 1056 }
1025 1057
1026 // Tests that focusing the table will activate the first row, but only if 1058 // Tests that focusing the table will activate the first row, but only if
1027 // there's no active row. 1059 // there's no active row.
1028 TEST_F(TableViewTest, InitialFocusActivatesFirstRow) { 1060 TEST_F(TableViewTest, InitialFocusActivatesFirstRow) {
1061 // Focus selects the first row if there's nothing selected.
1029 EXPECT_EQ(-1, table_->selection_model().active()); 1062 EXPECT_EQ(-1, table_->selection_model().active());
1030 helper_->OnFocus(); 1063 helper_->OnFocus();
1064 base::RunLoop().RunUntilIdle();
1031 EXPECT_EQ(0, table_->selection_model().active()); 1065 EXPECT_EQ(0, table_->selection_model().active());
1032 1066
1067 // Focus does not affect selection if something's already selected.
1033 ui::ListSelectionModel new_selection; 1068 ui::ListSelectionModel new_selection;
1034 new_selection.set_active(1); 1069 new_selection.set_active(1);
1035 helper_->SetSelectionModel(new_selection); 1070 helper_->SetSelectionModel(new_selection);
1036 EXPECT_EQ(1, table_->selection_model().active()); 1071 EXPECT_EQ(1, table_->selection_model().active());
1037 helper_->OnFocus(); 1072 helper_->OnFocus();
1073 base::RunLoop().RunUntilIdle();
1074 EXPECT_EQ(1, table_->selection_model().active());
1075
1076 // Focus does not affect selection if something gets selected synchronously
1077 // after focus is taken.
1078 new_selection.Clear();
1079 helper_->SetSelectionModel(new_selection);
1080 EXPECT_EQ(-1, table_->selection_model().active());
1081 helper_->OnFocus();
1082 new_selection.set_active(1);
1083 helper_->SetSelectionModel(new_selection);
1084 EXPECT_EQ(1, table_->selection_model().active());
1085 base::RunLoop().RunUntilIdle();
1038 EXPECT_EQ(1, table_->selection_model().active()); 1086 EXPECT_EQ(1, table_->selection_model().active());
1039 1087
1040 // Remove all rows; focusing should not activate a non existent first row. 1088 // Remove all rows; focusing should not activate a non existent first row.
1041 while (model_->RowCount()) 1089 while (model_->RowCount())
1042 model_->RemoveRow(0); 1090 model_->RemoveRow(0);
1043 1091
1044 new_selection.set_active(-1); 1092 new_selection.set_active(-1);
1045 helper_->SetSelectionModel(new_selection); 1093 helper_->SetSelectionModel(new_selection);
1046 helper_->OnFocus(); 1094 helper_->OnFocus();
1047 EXPECT_EQ(-1, table_->selection_model().active()); 1095 EXPECT_EQ(-1, table_->selection_model().active());
1048 } 1096 }
1049 1097
1050 } // namespace views 1098 } // namespace views
OLDNEW
« ui/views/controls/table/table_view.cc ('K') | « 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