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

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

Issue 8655001: views: Move table and tree directories to ui/views/controls/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: exclude native_widget_win_unittest too Created 9 years 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 | Annotate | Revision Log
« no previous file with comments | « views/controls/table/table_view_observer.h ('k') | views/controls/tree/tree_view.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 // For WinDDK ATL compatibility, these ATL headers must come first.
6
7 #include "build/build_config.h"
8
9 #if defined(OS_WIN)
10 #include <atlbase.h> // NOLINT
11 #include <atlwin.h> // NOLINT
12 #endif
13
14 #include <vector> // NOLINT
15
16 #include "base/compiler_specific.h"
17 #include "base/message_loop.h"
18 #include "base/string_number_conversions.h"
19 #include "base/utf_string_conversions.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "ui/base/models/table_model.h"
22 #include "ui/base/models/table_model_observer.h"
23 #include "ui/views/widget/widget.h"
24 #include "ui/views/widget/widget_delegate.h"
25 #include "views/controls/table/table_view.h"
26 #include "views/controls/table/table_view2.h"
27
28 // Put the tests in the views namespace to make it easier to declare them as
29 // friend classes.
30 namespace views {
31
32 // TestTableModel --------------------------------------------------------------
33
34 // Trivial TableModel implementation that is backed by a vector of vectors.
35 // Provides methods for adding/removing/changing the contents that notify the
36 // observer appropriately.
37 //
38 // Initial contents are:
39 // 0, 1
40 // 1, 1
41 // 2, 2
42 class TestTableModel : public ui::TableModel {
43 public:
44 TestTableModel();
45
46 // Adds a new row at index |row| with values |c1_value| and |c2_value|.
47 void AddRow(int row, int c1_value, int c2_value);
48
49 // Removes the row at index |row|.
50 void RemoveRow(int row);
51
52 // Changes the values of the row at |row|.
53 void ChangeRow(int row, int c1_value, int c2_value);
54
55 // ui::TableModel:
56 virtual int RowCount() OVERRIDE;
57 virtual string16 GetText(int row, int column_id) OVERRIDE;
58 virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE;
59 virtual int CompareValues(int row1, int row2, int column_id) OVERRIDE;
60
61 private:
62 ui::TableModelObserver* observer_;
63
64 // The data.
65 std::vector<std::vector<int> > rows_;
66
67 DISALLOW_COPY_AND_ASSIGN(TestTableModel);
68 };
69
70 // Same behavior as TestTableModel, except even items are in one group, while
71 // odd items are put in a different group.
72 class GroupTestTableModel : public TestTableModel {
73 virtual bool HasGroups() { return true; }
74
75 virtual Groups GetGroups() {
76 Groups groups;
77 Group group1, group2;
78 group1.title = ASCIIToUTF16("Group 1");
79 group1.id = 0;
80 group2.title = ASCIIToUTF16("Group 2");
81 group2.id = 0;
82 groups.push_back(group1);
83 groups.push_back(group2);
84 return groups;
85 }
86
87 // Return group = 0 if row is even, otherwise group = 1.
88 virtual int GetGroupID(int row) { return row % 2; }
89 };
90
91 TestTableModel::TestTableModel() : observer_(NULL) {
92 AddRow(0, 0, 1);
93 AddRow(1, 1, 1);
94 AddRow(2, 2, 2);
95 }
96
97 void TestTableModel::AddRow(int row, int c1_value, int c2_value) {
98 DCHECK(row >= 0 && row <= static_cast<int>(rows_.size()));
99 std::vector<int> new_row;
100 new_row.push_back(c1_value);
101 new_row.push_back(c2_value);
102 rows_.insert(rows_.begin() + row, new_row);
103 if (observer_)
104 observer_->OnItemsAdded(row, 1);
105 }
106 void TestTableModel::RemoveRow(int row) {
107 DCHECK(row >= 0 && row <= static_cast<int>(rows_.size()));
108 rows_.erase(rows_.begin() + row);
109 if (observer_)
110 observer_->OnItemsRemoved(row, 1);
111 }
112
113 void TestTableModel::ChangeRow(int row, int c1_value, int c2_value) {
114 DCHECK(row >= 0 && row < static_cast<int>(rows_.size()));
115 rows_[row][0] = c1_value;
116 rows_[row][1] = c2_value;
117 if (observer_)
118 observer_->OnItemsChanged(row, 1);
119 }
120
121 int TestTableModel::RowCount() {
122 return static_cast<int>(rows_.size());
123 }
124
125 string16 TestTableModel::GetText(int row, int column_id) {
126 return UTF8ToUTF16(base::IntToString(rows_[row][column_id]));
127 }
128
129 void TestTableModel::SetObserver(ui::TableModelObserver* observer) {
130 observer_ = observer;
131 }
132
133 int TestTableModel::CompareValues(int row1, int row2, int column_id) {
134 return rows_[row1][column_id] - rows_[row2][column_id];
135 }
136
137 #if defined(OS_WIN)
138
139 // TableViewTest ---------------------------------------------------------------
140
141 class TableViewTest : public testing::Test, views::WidgetDelegate {
142 public:
143 virtual void SetUp() OVERRIDE;
144 virtual void TearDown() OVERRIDE;
145
146 virtual views::View* GetContentsView() OVERRIDE {
147 return table_;
148 }
149 virtual views::Widget* GetWidget() OVERRIDE {
150 return table_->GetWidget();
151 }
152 virtual const views::Widget* GetWidget() const OVERRIDE {
153 return table_->GetWidget();
154 }
155
156 protected:
157 // Creates the model.
158 virtual TestTableModel* CreateModel();
159
160 // Verifies the view order matches that of the supplied arguments. The
161 // arguments are in terms of the model. For example, values of '1, 0' indicate
162 // the model index at row 0 is 1 and the model index at row 1 is 0.
163 void VerifyViewOrder(int first, ...);
164
165 // Verifies the selection matches the supplied arguments. The supplied
166 // arguments are in terms of this model. This uses the iterator returned by
167 // SelectionBegin.
168 void VerifySelectedRows(int first, ...);
169
170 // Configures the state for the various multi-selection tests.
171 // This selects model rows 0 and 1, and if |sort| is true the first column
172 // is sorted in descending order.
173 void SetUpMultiSelectTestState(bool sort);
174
175 scoped_ptr<TestTableModel> model_;
176
177 // The table. This is owned by the window.
178 TableView* table_;
179
180 private:
181 MessageLoopForUI message_loop_;
182 views::Widget* window_;
183 };
184
185 void TableViewTest::SetUp() {
186 OleInitialize(NULL);
187 model_.reset(CreateModel());
188 std::vector<ui::TableColumn> columns;
189 columns.resize(2);
190 columns[0].id = 0;
191 columns[1].id = 1;
192 table_ = new TableView(model_.get(), columns, views::ICON_AND_TEXT,
193 false, false, false);
194 window_ = views::Widget::CreateWindowWithBounds(
195 this,
196 gfx::Rect(100, 100, 512, 512));
197 }
198
199 void TableViewTest::TearDown() {
200 window_->Close();
201 // Temporary workaround to avoid leak of RootView::pending_paint_task_.
202 message_loop_.RunAllPending();
203 OleUninitialize();
204 }
205
206 void TableViewTest::VerifyViewOrder(int first, ...) {
207 va_list marker;
208 va_start(marker, first);
209 int value = first;
210 int index = 0;
211 for (int value = first, index = 0; value != -1; index++) {
212 ASSERT_EQ(value, table_->ViewToModel(index));
213 value = va_arg(marker, int);
214 }
215 va_end(marker);
216 }
217
218 void TableViewTest::VerifySelectedRows(int first, ...) {
219 va_list marker;
220 va_start(marker, first);
221 int value = first;
222 int index = 0;
223 TableView::iterator selection_iterator = table_->SelectionBegin();
224 for (int value = first, index = 0; value != -1; index++) {
225 ASSERT_TRUE(selection_iterator != table_->SelectionEnd());
226 ASSERT_EQ(value, *selection_iterator);
227 value = va_arg(marker, int);
228 ++selection_iterator;
229 }
230 ASSERT_TRUE(selection_iterator == table_->SelectionEnd());
231 va_end(marker);
232 }
233
234 void TableViewTest::SetUpMultiSelectTestState(bool sort) {
235 // Select two rows.
236 table_->SetSelectedState(0, true);
237 table_->SetSelectedState(1, true);
238
239 VerifySelectedRows(1, 0, -1);
240 if (!sort || HasFatalFailure())
241 return;
242
243 // Sort by first column descending.
244 TableView::SortDescriptors sd;
245 sd.push_back(TableView::SortDescriptor(0, false));
246 table_->SetSortDescriptors(sd);
247 VerifyViewOrder(2, 1, 0, -1);
248 if (HasFatalFailure())
249 return;
250
251 // Make sure the two rows are sorted.
252 // NOTE: the order changed because iteration happens over view indices.
253 VerifySelectedRows(0, 1, -1);
254 }
255
256 TestTableModel* TableViewTest::CreateModel() {
257 return new TestTableModel();
258 }
259
260 // NullModelTableViewTest ------------------------------------------------------
261
262 class NullModelTableViewTest : public TableViewTest {
263 protected:
264 // Creates the model.
265 TestTableModel* CreateModel() {
266 return NULL;
267 }
268 };
269
270 // GroupModelTableViewTest -----------------------------------------------------
271 class GroupModelTableViewTest : public TableViewTest {
272 protected:
273 TestTableModel* CreateModel() {
274 return new GroupTestTableModel();
275 }
276 };
277
278 // Tests -----------------------------------------------------------------------
279
280 // Failing: http://crbug.com/45015
281 // Tests various sorting permutations.
282 TEST_F(TableViewTest, DISABLED_Sort) {
283 // Sort by first column descending.
284 TableView::SortDescriptors sort;
285 sort.push_back(TableView::SortDescriptor(0, false));
286 table_->SetSortDescriptors(sort);
287 VerifyViewOrder(2, 1, 0, -1);
288 if (HasFatalFailure())
289 return;
290
291 // Sort by second column ascending, first column descending.
292 sort.clear();
293 sort.push_back(TableView::SortDescriptor(1, true));
294 sort.push_back(TableView::SortDescriptor(0, false));
295 sort[1].ascending = false;
296 table_->SetSortDescriptors(sort);
297 VerifyViewOrder(1, 0, 2, -1);
298 if (HasFatalFailure())
299 return;
300
301 // Clear the sort.
302 table_->SetSortDescriptors(TableView::SortDescriptors());
303 VerifyViewOrder(0, 1, 2, -1);
304 if (HasFatalFailure())
305 return;
306 }
307
308 // Failing: http://crbug.com/45015
309 // Tests changing the model while sorted.
310 TEST_F(TableViewTest, DISABLED_SortThenChange) {
311 // Sort by first column descending.
312 TableView::SortDescriptors sort;
313 sort.push_back(TableView::SortDescriptor(0, false));
314 table_->SetSortDescriptors(sort);
315 VerifyViewOrder(2, 1, 0, -1);
316 if (HasFatalFailure())
317 return;
318
319 model_->ChangeRow(0, 3, 1);
320 VerifyViewOrder(0, 2, 1, -1);
321 }
322
323 // Failing: http://crbug.com/45015
324 // Tests adding to the model while sorted.
325 TEST_F(TableViewTest, DISABLED_AddToSorted) {
326 // Sort by first column descending.
327 TableView::SortDescriptors sort;
328 sort.push_back(TableView::SortDescriptor(0, false));
329 table_->SetSortDescriptors(sort);
330 VerifyViewOrder(2, 1, 0, -1);
331 if (HasFatalFailure())
332 return;
333
334 // Add row so that it occurs first.
335 model_->AddRow(0, 5, -1);
336 VerifyViewOrder(0, 3, 2, 1, -1);
337 if (HasFatalFailure())
338 return;
339
340 // Add row so that it occurs last.
341 model_->AddRow(0, -1, -1);
342 VerifyViewOrder(1, 4, 3, 2, 0, -1);
343 }
344
345 // Failing: http://crbug.com/45015
346 // Tests selection on sort.
347 TEST_F(TableViewTest, DISABLED_PersistSelectionOnSort) {
348 // Select row 0.
349 table_->Select(0);
350
351 // Sort by first column descending.
352 TableView::SortDescriptors sort;
353 sort.push_back(TableView::SortDescriptor(0, false));
354 table_->SetSortDescriptors(sort);
355 VerifyViewOrder(2, 1, 0, -1);
356 if (HasFatalFailure())
357 return;
358
359 // Make sure 0 is still selected.
360 EXPECT_EQ(0, table_->FirstSelectedRow());
361 }
362
363 // Failing: http://crbug.com/45015
364 // Tests selection iterator with sort.
365 TEST_F(TableViewTest, DISABLED_PersistMultiSelectionOnSort) {
366 SetUpMultiSelectTestState(true);
367 }
368
369 // Failing: http://crbug.com/45015
370 // Tests selection persists after a change when sorted with iterator.
371 TEST_F(TableViewTest, DISABLED_PersistMultiSelectionOnChangeWithSort) {
372 SetUpMultiSelectTestState(true);
373 if (HasFatalFailure())
374 return;
375
376 model_->ChangeRow(0, 3, 1);
377
378 VerifySelectedRows(1, 0, -1);
379 }
380
381 // Failing: http://crbug.com/45015
382 // Tests selection persists after a remove when sorted with iterator.
383 TEST_F(TableViewTest, DISABLED_PersistMultiSelectionOnRemoveWithSort) {
384 SetUpMultiSelectTestState(true);
385 if (HasFatalFailure())
386 return;
387
388 model_->RemoveRow(0);
389
390 VerifySelectedRows(0, -1);
391 }
392
393 // Failing: http://crbug.com/45015
394 // Tests selection persists after a add when sorted with iterator.
395 TEST_F(TableViewTest, DISABLED_PersistMultiSelectionOnAddWithSort) {
396 SetUpMultiSelectTestState(true);
397 if (HasFatalFailure())
398 return;
399
400 model_->AddRow(3, 4, 4);
401
402 VerifySelectedRows(0, 1, -1);
403 }
404
405 // Failing: http://crbug.com/45015
406 // Tests selection persists after a change with iterator.
407 TEST_F(TableViewTest, DISABLED_PersistMultiSelectionOnChange) {
408 SetUpMultiSelectTestState(false);
409 if (HasFatalFailure())
410 return;
411
412 model_->ChangeRow(0, 3, 1);
413
414 VerifySelectedRows(1, 0, -1);
415 }
416
417 // Failing: http://crbug.com/45015
418 // Tests selection persists after a remove with iterator.
419 TEST_F(TableViewTest, DISABLED_PersistMultiSelectionOnRemove) {
420 SetUpMultiSelectTestState(false);
421 if (HasFatalFailure())
422 return;
423
424 model_->RemoveRow(0);
425
426 VerifySelectedRows(0, -1);
427 }
428
429 // Failing: http://crbug.com/45015
430 // Tests selection persists after a add with iterator.
431 TEST_F(TableViewTest, DISABLED_PersistMultiSelectionOnAdd) {
432 SetUpMultiSelectTestState(false);
433 if (HasFatalFailure())
434 return;
435
436 model_->AddRow(3, 4, 4);
437
438 VerifySelectedRows(1, 0, -1);
439 }
440
441 TEST_F(GroupModelTableViewTest, IndividualSelectAcrossGroups) {
442 table_->SetSelectedState(0, true);
443 table_->SetSelectedState(1, true);
444 table_->SetSelectedState(2, true);
445 VerifySelectedRows(2, 1, 0, -1);
446 }
447
448 TEST_F(GroupModelTableViewTest, ShiftSelectAcrossGroups) {
449 table_->SetSelectedState(0, true);
450 // Try to select across groups - this should fail.
451 ASSERT_FALSE(table_->SelectMultiple(1, 0));
452 VerifySelectedRows(0, -1);
453 }
454
455 TEST_F(GroupModelTableViewTest, ShiftSelectSameGroup) {
456 table_->SetSelectedState(0, true);
457 // Try to select in the same group - this should work but should only select
458 // items in the "even" group.
459 ASSERT_TRUE(table_->SelectMultiple(2, 0));
460 VerifySelectedRows(2, 0, -1);
461 }
462
463 // Crashing: http://crbug.com/45015
464 TEST_F(NullModelTableViewTest, DISABLED_NullModel) {
465 // There's nothing explicit to test. If there is a bug in TableView relating
466 // to a NULL model we'll crash.
467 }
468
469 #endif // OS_WIN
470
471 ////////////////////////////////////////////////////////////////////////////////
472 // TableView2 Tests
473
474 class TableView2Test : public testing::Test, views::WidgetDelegate {
475 public:
476 virtual void SetUp();
477 virtual void TearDown();
478
479 virtual views::View* GetContentsView() OVERRIDE {
480 return table_;
481 }
482 virtual views::Widget* GetWidget() OVERRIDE {
483 return table_->GetWidget();
484 }
485 virtual const views::Widget* GetWidget() const OVERRIDE {
486 return table_->GetWidget();
487 }
488
489 // Returns the contents of a cell in the table.
490 std::string GetCellValue(int row, int column);
491
492 protected:
493 // Creates the model.
494 TestTableModel* CreateModel();
495
496 virtual views::TableTypes GetTableType() {
497 return views::TEXT_ONLY;
498 }
499
500 scoped_ptr<TestTableModel> model_;
501
502 // The table. This is owned by the window.
503 views::TableView2* table_;
504
505 private:
506 MessageLoopForUI message_loop_;
507 views::Widget* window_;
508 };
509
510 void TableView2Test::SetUp() {
511 #if defined(OS_WIN)
512 OleInitialize(NULL);
513 #endif
514 model_.reset(CreateModel());
515 std::vector<ui::TableColumn> columns;
516 columns.resize(2);
517 columns[0].id = 0;
518 columns[1].id = 1;
519 table_ = new views::TableView2(model_.get(), columns, GetTableType(),
520 views::TableView2::NONE);
521 window_ = views::Widget::CreateWindowWithBounds(
522 this,
523 gfx::Rect(100, 100, 512, 512));
524 window_->Show();
525 }
526
527 void TableView2Test::TearDown() {
528 window_->Close();
529 // Temporary workaround to avoid leak of RootView::pending_paint_task_.
530 message_loop_.RunAllPending();
531 #if defined(OS_WIN)
532 OleUninitialize();
533 #endif
534 }
535
536 TestTableModel* TableView2Test::CreateModel() {
537 return new TestTableModel();
538 }
539
540 std::string TableView2Test::GetCellValue(int row, int column) {
541 #if defined(OS_WIN)
542 wchar_t str[128] = {0};
543 LVITEM item = {0};
544 item.mask = LVIF_TEXT;
545 item.iItem = row;
546 item.iSubItem = column;
547 item.pszText = str;
548 item.cchTextMax = 128;
549 BOOL r = ListView_GetItem(table_->GetTestingHandle(), &item);
550 DCHECK(r);
551 return WideToUTF8(str);
552 #else
553 GtkTreeModel* gtk_model =
554 gtk_tree_view_get_model(GTK_TREE_VIEW(table_->GetTestingHandle()));
555 DCHECK(gtk_model);
556 GtkTreeIter row_iter;
557 gboolean r = gtk_tree_model_iter_nth_child(gtk_model, &row_iter, NULL, row);
558 DCHECK(r);
559 gchar* text = NULL;
560 gtk_tree_model_get(gtk_model, &row_iter, column, &text, -1);
561 DCHECK(text);
562 std::string value(text);
563 g_free(text);
564 return value;
565 #endif
566 }
567
568 // Tests that the table correctly reflects changes to the model.
569 TEST_F(TableView2Test, ModelChangesTest) {
570 ASSERT_EQ(3, table_->GetRowCount());
571 EXPECT_EQ("0", GetCellValue(0, 0));
572 EXPECT_EQ("1", GetCellValue(1, 0));
573 EXPECT_EQ("2", GetCellValue(2, 1));
574
575 // Test adding rows and that OnItemsAdded works.
576 model_->AddRow(3, 3, 3);
577 model_->AddRow(4, 4, 4);
578 table_->OnItemsAdded(3, 2);
579 ASSERT_EQ(5, table_->GetRowCount());
580 EXPECT_EQ("3", GetCellValue(3, 0));
581 EXPECT_EQ("4", GetCellValue(4, 1));
582
583 // Test removing rows and that OnItemsRemoved works.
584 model_->RemoveRow(1);
585 model_->RemoveRow(1);
586 table_->OnItemsRemoved(1, 2);
587 ASSERT_EQ(3, table_->GetRowCount());
588 EXPECT_EQ("0", GetCellValue(0, 0));
589 EXPECT_EQ("3", GetCellValue(1, 0));
590 EXPECT_EQ("4", GetCellValue(2, 1));
591
592 // Test changing rows and that OnItemsChanged works.
593 model_->ChangeRow(1, 1, 1);
594 model_->ChangeRow(2, 2, 2);
595 table_->OnItemsChanged(1, 2);
596 EXPECT_EQ("0", GetCellValue(0, 0));
597 EXPECT_EQ("1", GetCellValue(1, 0));
598 EXPECT_EQ("2", GetCellValue(2, 1));
599
600 // Test adding and removing rows and using OnModelChanged.
601 model_->RemoveRow(2);
602 model_->AddRow(2, 5, 5);
603 model_->AddRow(3, 6, 6);
604 table_->OnModelChanged();
605 ASSERT_EQ(4, table_->GetRowCount());
606 EXPECT_EQ("0", GetCellValue(0, 0));
607 EXPECT_EQ("1", GetCellValue(1, 0));
608 EXPECT_EQ("5", GetCellValue(2, 1));
609 EXPECT_EQ("6", GetCellValue(3, 1));
610 }
611
612 // Test the selection on a single-selection table.
613 TEST_F(TableView2Test, SingleSelectionTest) {
614 EXPECT_EQ(0, table_->SelectedRowCount());
615 EXPECT_EQ(-1, table_->GetFirstSelectedRow());
616
617 table_->SelectRow(0);
618 EXPECT_EQ(1, table_->SelectedRowCount());
619 EXPECT_EQ(0, table_->GetFirstSelectedRow());
620
621 table_->SelectRow(2);
622 EXPECT_EQ(1, table_->SelectedRowCount());
623 EXPECT_EQ(2, table_->GetFirstSelectedRow());
624
625 table_->ClearSelection();
626 EXPECT_EQ(0, table_->SelectedRowCount());
627 EXPECT_EQ(-1, table_->GetFirstSelectedRow());
628 }
629
630 // Row focusing are not supported on Linux yet.
631 #if defined(OS_WIN)
632 // Test the row focus on a single-selection table.
633 TEST_F(TableView2Test, RowFocusTest) {
634 EXPECT_EQ(-1, table_->GetFirstFocusedRow());
635
636 table_->FocusRow(0);
637 EXPECT_EQ(0, table_->GetFirstFocusedRow());
638
639 table_->FocusRow(2);
640 EXPECT_EQ(2, table_->GetFirstFocusedRow());
641
642 table_->ClearRowFocus();
643 EXPECT_EQ(-1, table_->GetFirstSelectedRow());
644 }
645 #endif
646
647 } // namespace views
OLDNEW
« no previous file with comments | « views/controls/table/table_view_observer.h ('k') | views/controls/tree/tree_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698