7daed0d02da4d00b7b8e13c68eea0e32ff3e06b6
[platform/framework/web/crosswalk.git] / src / ui / app_list / views / apps_grid_view_unittest.cc
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
3 // found in the LICENSE file.
4
5 #include "ui/app_list/views/apps_grid_view.h"
6
7 #include <string>
8
9 #include "base/basictypes.h"
10 #include "base/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/timer/timer.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/app_list/app_list_constants.h"
18 #include "ui/app_list/app_list_folder_item.h"
19 #include "ui/app_list/app_list_item.h"
20 #include "ui/app_list/app_list_model.h"
21 #include "ui/app_list/app_list_switches.h"
22 #include "ui/app_list/pagination_model.h"
23 #include "ui/app_list/test/app_list_test_model.h"
24 #include "ui/app_list/views/app_list_item_view.h"
25 #include "ui/app_list/views/test/apps_grid_view_test_api.h"
26 #include "ui/views/test/views_test_base.h"
27
28 namespace app_list {
29 namespace test {
30
31 namespace {
32
33 const int kIconDimension = 48;
34 const int kCols = 2;
35 const int kRows = 2;
36 const int kTilesPerPage = kCols * kRows;
37
38 const int kWidth = 320;
39 const int kHeight = 240;
40
41 class PageFlipWaiter : public PaginationModelObserver {
42  public:
43   PageFlipWaiter(base::MessageLoopForUI* ui_loop, PaginationModel* model)
44       : ui_loop_(ui_loop), model_(model), wait_(false), page_changed_(false) {
45     model_->AddObserver(this);
46   }
47
48   virtual ~PageFlipWaiter() {
49     model_->RemoveObserver(this);
50   }
51
52   bool Wait(int time_out_ms) {
53     DCHECK(!wait_);
54     wait_ = true;
55     page_changed_ = false;
56
57     if (time_out_ms) {
58       wait_timer_.Stop();
59       wait_timer_.Start(FROM_HERE,
60                         base::TimeDelta::FromMilliseconds(time_out_ms),
61                         this, &PageFlipWaiter::OnWaitTimeOut);
62     }
63
64     ui_loop_->Run();
65     wait_ = false;
66     return page_changed_;
67   }
68
69  private:
70   void OnWaitTimeOut() {
71     ui_loop_->Quit();
72   }
73
74   // PaginationModelObserver overrides:
75   virtual void TotalPagesChanged() OVERRIDE {
76   }
77   virtual void SelectedPageChanged(int old_selected,
78                                    int new_selected) OVERRIDE {
79     page_changed_ = true;
80     if (wait_)
81       ui_loop_->Quit();
82   }
83   virtual void TransitionStarted() OVERRIDE {
84   }
85   virtual void TransitionChanged() OVERRIDE {
86   }
87
88   base::MessageLoopForUI* ui_loop_;
89   PaginationModel* model_;
90   bool wait_;
91   bool page_changed_;
92   base::OneShotTimer<PageFlipWaiter> wait_timer_;
93
94   DISALLOW_COPY_AND_ASSIGN(PageFlipWaiter);
95 };
96
97 }  // namespace
98
99 class AppsGridViewTest : public views::ViewsTestBase {
100  public:
101   AppsGridViewTest() {}
102   virtual ~AppsGridViewTest() {}
103
104   // testing::Test overrides:
105   virtual void SetUp() OVERRIDE {
106     views::ViewsTestBase::SetUp();
107     model_.reset(new AppListTestModel);
108     pagination_model_.reset(new PaginationModel);
109
110     apps_grid_view_.reset(new AppsGridView(NULL, pagination_model_.get()));
111     apps_grid_view_->SetLayout(kIconDimension, kCols, kRows);
112     apps_grid_view_->SetBoundsRect(gfx::Rect(gfx::Size(kWidth, kHeight)));
113     apps_grid_view_->SetModel(model_.get());
114     apps_grid_view_->SetItemList(model_->top_level_item_list());
115
116     test_api_.reset(new AppsGridViewTestApi(apps_grid_view_.get()));
117   }
118   virtual void TearDown() OVERRIDE {
119     apps_grid_view_.reset();  // Release apps grid view before models.
120     views::ViewsTestBase::TearDown();
121   }
122
123  protected:
124   AppListItemView* GetItemViewAt(int index) {
125     return static_cast<AppListItemView*>(
126         test_api_->GetViewAtModelIndex(index));
127   }
128
129   AppListItemView* GetItemViewForPoint(const gfx::Point& point) {
130     for (size_t i = 0; i < model_->top_level_item_list()->item_count(); ++i) {
131       AppListItemView* view = GetItemViewAt(i);
132       if (view->bounds().Contains(point))
133         return view;
134     }
135     return NULL;
136   }
137
138   gfx::Rect GetItemTileRectAt(int row, int col) {
139     DCHECK_GT(model_->top_level_item_list()->item_count(), 0u);
140
141     gfx::Insets insets(apps_grid_view_->GetInsets());
142     gfx::Rect rect(gfx::Point(insets.left(), insets.top()),
143                    GetItemViewAt(0)->bounds().size());
144     rect.Offset(col * rect.width(), row * rect.height());
145     return rect;
146   }
147
148   // Points are in |apps_grid_view_|'s coordinates.
149   void SimulateDrag(AppsGridView::Pointer pointer,
150                     const gfx::Point& from,
151                     const gfx::Point& to) {
152     AppListItemView* view = GetItemViewForPoint(from);
153     DCHECK(view);
154
155     gfx::Point translated_from = gfx::PointAtOffsetFromOrigin(
156         from - view->bounds().origin());
157     gfx::Point translated_to = gfx::PointAtOffsetFromOrigin(
158         to - view->bounds().origin());
159
160     ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED,
161                                  translated_from, from, 0, 0);
162     apps_grid_view_->InitiateDrag(view, pointer, pressed_event);
163
164     ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
165                               translated_to, to, 0, 0);
166     apps_grid_view_->UpdateDragFromItem(pointer, drag_event);
167   }
168
169   void SimulateKeyPress(ui::KeyboardCode key_code) {
170     ui::KeyEvent key_event(ui::ET_KEY_PRESSED, key_code, 0, false);
171     apps_grid_view_->OnKeyPressed(key_event);
172   }
173
174   scoped_ptr<AppListTestModel> model_;
175   scoped_ptr<PaginationModel> pagination_model_;
176   scoped_ptr<AppsGridView> apps_grid_view_;
177   scoped_ptr<AppsGridViewTestApi> test_api_;
178
179  private:
180   DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest);
181 };
182
183 TEST_F(AppsGridViewTest, CreatePage) {
184   // Fully populates a page.
185   const int kPages = 1;
186   model_->PopulateApps(kPages * kTilesPerPage);
187   EXPECT_EQ(kPages, pagination_model_->total_pages());
188
189   // Adds one more and gets a new page created.
190   model_->CreateAndAddItem("Extra");
191   EXPECT_EQ(kPages + 1, pagination_model_->total_pages());
192 }
193
194 TEST_F(AppsGridViewTest, EnsureHighlightedVisible) {
195   const int kPages = 3;
196   model_->PopulateApps(kPages * kTilesPerPage);
197   EXPECT_EQ(kPages, pagination_model_->total_pages());
198   EXPECT_EQ(0, pagination_model_->selected_page());
199
200   // Highlight first one and last one one first page and first page should be
201   // selected.
202   model_->HighlightItemAt(0);
203   EXPECT_EQ(0, pagination_model_->selected_page());
204   model_->HighlightItemAt(kTilesPerPage - 1);
205   EXPECT_EQ(0, pagination_model_->selected_page());
206
207   // Highlight first one on 2nd page and 2nd page should be selected.
208   model_->HighlightItemAt(kTilesPerPage + 1);
209   EXPECT_EQ(1, pagination_model_->selected_page());
210
211   // Highlight last one in the model and last page should be selected.
212   model_->HighlightItemAt(model_->top_level_item_list()->item_count() - 1);
213   EXPECT_EQ(kPages - 1, pagination_model_->selected_page());
214 }
215
216 TEST_F(AppsGridViewTest, RemoveSelectedLastApp) {
217   const int kTotalItems = 2;
218   const int kLastItemIndex = kTotalItems - 1;
219
220   model_->PopulateApps(kTotalItems);
221
222   AppListItemView* last_view = GetItemViewAt(kLastItemIndex);
223   apps_grid_view_->SetSelectedView(last_view);
224   model_->DeleteItem(model_->GetItemName(kLastItemIndex));
225
226   EXPECT_FALSE(apps_grid_view_->IsSelectedView(last_view));
227
228   // No crash happens.
229   AppListItemView* view = GetItemViewAt(0);
230   apps_grid_view_->SetSelectedView(view);
231   EXPECT_TRUE(apps_grid_view_->IsSelectedView(view));
232 }
233
234 TEST_F(AppsGridViewTest, MouseDragWithFolderDisabled) {
235   CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableFolderUI);
236   const int kTotalItems = 4;
237   model_->PopulateApps(kTotalItems);
238   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
239             model_->GetModelContent());
240
241   gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
242   gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
243
244   // Dragging changes model order.
245   SimulateDrag(AppsGridView::MOUSE, from, to);
246   apps_grid_view_->EndDrag(false);
247   EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
248             model_->GetModelContent());
249   test_api_->LayoutToIdealBounds();
250
251   // Canceling drag should keep existing order.
252   SimulateDrag(AppsGridView::MOUSE, from, to);
253   apps_grid_view_->EndDrag(true);
254   EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
255             model_->GetModelContent());
256   test_api_->LayoutToIdealBounds();
257
258   // Deleting an item keeps remaining intact.
259   SimulateDrag(AppsGridView::MOUSE, from, to);
260   model_->DeleteItem(model_->GetItemName(0));
261   apps_grid_view_->EndDrag(false);
262   EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
263             model_->GetModelContent());
264   test_api_->LayoutToIdealBounds();
265
266   // Adding a launcher item cancels the drag and respects the order.
267   SimulateDrag(AppsGridView::MOUSE, from, to);
268   model_->CreateAndAddItem("Extra");
269   apps_grid_view_->EndDrag(false);
270   EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
271             model_->GetModelContent());
272   test_api_->LayoutToIdealBounds();
273 }
274
275 TEST_F(AppsGridViewTest, MouseDragItemIntoFolder) {
276   size_t kTotalItems = 3;
277   model_->PopulateApps(kTotalItems);
278   EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
279   EXPECT_EQ(std::string("Item 0,Item 1,Item 2"), model_->GetModelContent());
280
281   gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
282   gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
283
284   // Dragging item_1 over item_0 creates a folder.
285   SimulateDrag(AppsGridView::MOUSE, from, to);
286   apps_grid_view_->EndDrag(false);
287   EXPECT_EQ(kTotalItems - 1, model_->top_level_item_list()->item_count());
288   EXPECT_EQ(AppListFolderItem::kItemType,
289             model_->top_level_item_list()->item_at(0)->GetItemType());
290   AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
291       model_->top_level_item_list()->item_at(0));
292   EXPECT_EQ(2u, folder_item->ChildItemCount());
293   AppListItem* item_0 = model_->FindItem("Item 0");
294   EXPECT_TRUE(item_0->IsInFolder());
295   EXPECT_EQ(folder_item->id(), item_0->folder_id());
296   AppListItem* item_1 = model_->FindItem("Item 1");
297   EXPECT_TRUE(item_1->IsInFolder());
298   EXPECT_EQ(folder_item->id(), item_1->folder_id());
299   std::string expected_items = folder_item->id() + ",Item 2";
300   EXPECT_EQ(expected_items, model_->GetModelContent());
301   test_api_->LayoutToIdealBounds();
302
303   // Dragging item_2 to the folder adds item_2 to the folder.
304   SimulateDrag(AppsGridView::MOUSE, from, to);
305   apps_grid_view_->EndDrag(false);
306
307   EXPECT_EQ(kTotalItems - 2, model_->top_level_item_list()->item_count());
308   EXPECT_EQ(folder_item->id(), model_->GetModelContent());
309   EXPECT_EQ(3u, folder_item->ChildItemCount());
310   item_0 = model_->FindItem("Item 0");
311   EXPECT_TRUE(item_0->IsInFolder());
312   EXPECT_EQ(folder_item->id(), item_0->folder_id());
313   item_1 = model_->FindItem("Item 1");
314   EXPECT_TRUE(item_1->IsInFolder());
315   EXPECT_EQ(folder_item->id(), item_1->folder_id());
316   AppListItem* item_2 = model_->FindItem("Item 2");
317   EXPECT_TRUE(item_2->IsInFolder());
318   EXPECT_EQ(folder_item->id(), item_2->folder_id());
319   test_api_->LayoutToIdealBounds();
320 }
321
322 TEST_F(AppsGridViewTest, MouseDragMaxItemsInFolder) {
323   // Create and add a folder with 15 items in it.
324   size_t kTotalItems = kMaxFolderItems - 1;
325   model_->CreateAndPopulateFolderWithApps(kTotalItems);
326   EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
327   EXPECT_EQ(AppListFolderItem::kItemType,
328             model_->top_level_item_list()->item_at(0)->GetItemType());
329   AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
330       model_->top_level_item_list()->item_at(0));
331   EXPECT_EQ(kTotalItems, folder_item->ChildItemCount());
332
333   // Create and add another 2 items.
334   model_->PopulateAppWithId(kTotalItems);
335   model_->PopulateAppWithId(kTotalItems + 1);
336   EXPECT_EQ(3u, model_->top_level_item_list()->item_count());
337   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
338   EXPECT_EQ(model_->GetItemName(kMaxFolderItems - 1),
339             model_->top_level_item_list()->item_at(1)->id());
340   EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
341             model_->top_level_item_list()->item_at(2)->id());
342
343   gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
344   gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
345
346   // Dragging one item into the folder, the folder should accept the item.
347   SimulateDrag(AppsGridView::MOUSE, from, to);
348   apps_grid_view_->EndDrag(false);
349   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
350   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
351   EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
352   EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
353             model_->top_level_item_list()->item_at(1)->id());
354   test_api_->LayoutToIdealBounds();
355
356   // Dragging the last item over the folder, the folder won't accept the new
357   // item, instead, it will re-order the items.
358   SimulateDrag(AppsGridView::MOUSE, from, to);
359   apps_grid_view_->EndDrag(false);
360   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
361   EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
362             model_->top_level_item_list()->item_at(0)->id());
363   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(1)->id());
364   EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
365   test_api_->LayoutToIdealBounds();
366 }
367
368 TEST_F(AppsGridViewTest, MouseDragItemReorder) {
369   size_t kTotalItems = 2;
370   model_->PopulateApps(kTotalItems);
371   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
372   EXPECT_EQ(std::string("Item 0,Item 1"), model_->GetModelContent());
373
374   gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
375   int reorder_offset = (GetItemTileRectAt(0, 1).CenterPoint() -
376                         GetItemTileRectAt(0, 0).CenterPoint()).Length() -
377                        kReorderDroppingCircleRadius -
378                        kPreferredIconDimension / 2 + 5;
379   gfx::Point to = gfx::Point(from.x() - reorder_offset, from.y());
380
381   // Dragging item_1 closing to item_0 should leads to re-ordering these two
382   // items.
383   SimulateDrag(AppsGridView::MOUSE, from, to);
384   apps_grid_view_->EndDrag(false);
385   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
386   EXPECT_EQ(std::string("Item 1,Item 0"), model_->GetModelContent());
387   test_api_->LayoutToIdealBounds();
388 }
389
390 TEST_F(AppsGridViewTest, MouseDragFolderReorder) {
391   size_t kTotalItems = 2;
392   model_->CreateAndPopulateFolderWithApps(kTotalItems);
393   model_->PopulateAppWithId(kTotalItems);
394   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
395   EXPECT_EQ(AppListFolderItem::kItemType,
396             model_->top_level_item_list()->item_at(0)->GetItemType());
397   AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
398       model_->top_level_item_list()->item_at(0));
399   EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(1)->id());
400
401   gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
402   gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
403
404   // Dragging folder over item_1 should leads to re-ordering these two
405   // items.
406   SimulateDrag(AppsGridView::MOUSE, from, to);
407   apps_grid_view_->EndDrag(false);
408   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
409   EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(0)->id());
410   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(1)->id());
411   test_api_->LayoutToIdealBounds();
412 }
413
414 TEST_F(AppsGridViewTest, MouseDragWithCancelDeleteAddItem) {
415   size_t kTotalItems = 4;
416   model_->PopulateApps(kTotalItems);
417   EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
418   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
419             model_->GetModelContent());
420
421   gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
422   gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
423
424   // Canceling drag should keep existing order.
425   SimulateDrag(AppsGridView::MOUSE, from, to);
426   apps_grid_view_->EndDrag(true);
427   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
428             model_->GetModelContent());
429   test_api_->LayoutToIdealBounds();
430
431   // Deleting an item keeps remaining intact.
432   SimulateDrag(AppsGridView::MOUSE, from, to);
433   model_->DeleteItem(model_->GetItemName(2));
434   apps_grid_view_->EndDrag(false);
435   EXPECT_EQ(std::string("Item 0,Item 1,Item 3"), model_->GetModelContent());
436   test_api_->LayoutToIdealBounds();
437
438   // Adding a launcher item cancels the drag and respects the order.
439   SimulateDrag(AppsGridView::MOUSE, from, to);
440   model_->CreateAndAddItem("Extra");
441   apps_grid_view_->EndDrag(false);
442   EXPECT_EQ(std::string("Item 0,Item 1,Item 3,Extra"),
443             model_->GetModelContent());
444   test_api_->LayoutToIdealBounds();
445 }
446
447 TEST_F(AppsGridViewTest, MouseDragFlipPage) {
448   test_api_->SetPageFlipDelay(10);
449   pagination_model_->SetTransitionDurations(10, 10);
450
451   PageFlipWaiter page_flip_waiter(message_loop(),
452                                   pagination_model_.get());
453
454   const int kPages = 3;
455   model_->PopulateApps(kPages * kTilesPerPage);
456   EXPECT_EQ(kPages, pagination_model_->total_pages());
457   EXPECT_EQ(0, pagination_model_->selected_page());
458
459   gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
460   gfx::Point to = gfx::Point(apps_grid_view_->width(),
461                              apps_grid_view_->height() / 2);
462
463   // Drag to right edge.
464   SimulateDrag(AppsGridView::MOUSE, from, to);
465
466   // Page should be flipped after sometime.
467   EXPECT_TRUE(page_flip_waiter.Wait(0));
468   EXPECT_EQ(1, pagination_model_->selected_page());
469
470   // Stay there and page should be flipped again.
471   EXPECT_TRUE(page_flip_waiter.Wait(0));
472   EXPECT_EQ(2, pagination_model_->selected_page());
473
474   // Stay there longer and no page flip happen since we are at the last page.
475   EXPECT_FALSE(page_flip_waiter.Wait(100));
476   EXPECT_EQ(2, pagination_model_->selected_page());
477
478   apps_grid_view_->EndDrag(true);
479
480   // Now drag to the left edge and test the other direction.
481   to.set_x(0);
482
483   SimulateDrag(AppsGridView::MOUSE, from, to);
484
485   EXPECT_TRUE(page_flip_waiter.Wait(0));
486   EXPECT_EQ(1, pagination_model_->selected_page());
487
488   EXPECT_TRUE(page_flip_waiter.Wait(0));
489   EXPECT_EQ(0, pagination_model_->selected_page());
490
491   EXPECT_FALSE(page_flip_waiter.Wait(100));
492   EXPECT_EQ(0, pagination_model_->selected_page());
493   apps_grid_view_->EndDrag(true);
494 }
495
496 TEST_F(AppsGridViewTest, SimultaneousDragWithFolderDisabled) {
497   CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableFolderUI);
498   const int kTotalItems = 4;
499   model_->PopulateApps(kTotalItems);
500   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
501             model_->GetModelContent());
502
503   gfx::Point mouse_from = GetItemTileRectAt(0, 0).CenterPoint();
504   gfx::Point mouse_to = GetItemTileRectAt(0, 1).CenterPoint();
505
506   gfx::Point touch_from = GetItemTileRectAt(1, 0).CenterPoint();
507   gfx::Point touch_to = GetItemTileRectAt(1, 1).CenterPoint();
508
509   // Starts a mouse drag first then a touch drag.
510   SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
511   SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
512   // Finishes the drag and mouse drag wins.
513   apps_grid_view_->EndDrag(false);
514   EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
515             model_->GetModelContent());
516   test_api_->LayoutToIdealBounds();
517
518   // Starts a touch drag first then a mouse drag.
519   SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
520   SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
521   // Finishes the drag and touch drag wins.
522   apps_grid_view_->EndDrag(false);
523   EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
524             model_->GetModelContent());
525   test_api_->LayoutToIdealBounds();
526 }
527
528 TEST_F(AppsGridViewTest, HighlightWithKeyboard) {
529   const int kPages = 3;
530   const int kItems = (kPages - 1) * kTilesPerPage + 1;
531   model_->PopulateApps(kItems);
532
533   const int first_index = 0;
534   const int last_index = kItems - 1;
535   const int last_index_on_page1_first_row = kRows - 1;
536   const int last_index_on_page1 = kTilesPerPage - 1;
537   const int first_index_on_page2 = kTilesPerPage;
538   const int first_index_on_page2_last_row = 2 * kTilesPerPage - kRows;
539   const int last_index_on_page2_last_row = 2 * kTilesPerPage - 1;
540
541   // Try moving off the item beyond the first one.
542   apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
543   SimulateKeyPress(ui::VKEY_UP);
544   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
545   SimulateKeyPress(ui::VKEY_LEFT);
546   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
547
548   // Move to the last item and try to go past it.
549   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index));
550   SimulateKeyPress(ui::VKEY_DOWN);
551   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
552   SimulateKeyPress(ui::VKEY_RIGHT);
553   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
554
555   // Move right on last item on page 1 should get to first item on page 2's last
556   // row and vice versa.
557   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
558   SimulateKeyPress(ui::VKEY_RIGHT);
559   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
560       first_index_on_page2_last_row)));
561   SimulateKeyPress(ui::VKEY_LEFT);
562   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
563       last_index_on_page1)));
564
565   // Up/down on page boundary does nothing.
566   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
567   SimulateKeyPress(ui::VKEY_DOWN);
568   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
569       last_index_on_page1)));
570   apps_grid_view_->SetSelectedView(
571       GetItemViewAt(first_index_on_page2_last_row));
572   apps_grid_view_->
573       SetSelectedView(GetItemViewAt(last_index_on_page1_first_row));
574   SimulateKeyPress(ui::VKEY_UP);
575   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
576       last_index_on_page1_first_row)));
577
578   // Page up and down should go to the same item on the next and last page.
579   apps_grid_view_->SetSelectedView(GetItemViewAt(first_index_on_page2));
580   SimulateKeyPress(ui::VKEY_PRIOR);
581   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
582       first_index)));
583   SimulateKeyPress(ui::VKEY_NEXT);
584   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
585       first_index_on_page2)));
586
587   // Moving onto a a page with too few apps to support the expected index snaps
588   // to the last available index.
589   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
590   SimulateKeyPress(ui::VKEY_RIGHT);
591   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
592       last_index)));
593   apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
594   SimulateKeyPress(ui::VKEY_NEXT);
595   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
596       last_index)));
597
598
599
600   // After page switch, arrow keys select first item on current page.
601   apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
602   pagination_model_->SelectPage(1, false);
603   SimulateKeyPress(ui::VKEY_UP);
604   EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
605       first_index_on_page2)));
606 }
607
608 TEST_F(AppsGridViewTest, ItemLabelShortNameOverride) {
609   // If the app's full name and short name differ, the title label's tooltip
610   // should always be the full name of the app.
611   std::string expected_text("xyz");
612   std::string expected_tooltip("tooltip");
613   AppListItem* item = model_->CreateAndAddItem("Item with short name");
614   model_->SetItemNameAndShortName(item, expected_tooltip, expected_text);
615
616   base::string16 actual_tooltip;
617   AppListItemView* item_view = GetItemViewAt(0);
618   ASSERT_TRUE(item_view);
619   const views::Label* title_label = item_view->title();
620   EXPECT_TRUE(title_label->GetTooltipText(
621       title_label->bounds().CenterPoint(), &actual_tooltip));
622   EXPECT_EQ(expected_tooltip, base::UTF16ToUTF8(actual_tooltip));
623   EXPECT_EQ(expected_text, base::UTF16ToUTF8(title_label->text()));
624 }
625
626 TEST_F(AppsGridViewTest, ItemLabelNoShortName) {
627   // If the app's full name and short name are the same, use the default tooltip
628   // behavior of the label (only show a tooltip if the title is truncated).
629   std::string title("a");
630   AppListItem* item = model_->CreateAndAddItem(title);
631   model_->SetItemNameAndShortName(item, title, "");
632
633   base::string16 actual_tooltip;
634   AppListItemView* item_view = GetItemViewAt(0);
635   ASSERT_TRUE(item_view);
636   const views::Label* title_label = item_view->title();
637   EXPECT_FALSE(title_label->GetTooltipText(
638       title_label->bounds().CenterPoint(), &actual_tooltip));
639   EXPECT_EQ(title, base::UTF16ToUTF8(title_label->text()));
640 }
641
642 }  // namespace test
643 }  // namespace app_list