Update path of checkdeps to buildtools checkout
[chromium-blink-merge.git] / ui / app_list / views / app_list_main_view_unittest.cc
blob4007e902d06bf9202a3476964866019ea8613255
1 // Copyright 2013 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.
5 #include "ui/app_list/views/app_list_main_view.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/time/time.h"
10 #include "base/timer/timer.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/app_list/pagination_model.h"
13 #include "ui/app_list/test/app_list_test_model.h"
14 #include "ui/app_list/test/app_list_test_view_delegate.h"
15 #include "ui/app_list/views/app_list_folder_view.h"
16 #include "ui/app_list/views/app_list_item_view.h"
17 #include "ui/app_list/views/apps_container_view.h"
18 #include "ui/app_list/views/apps_grid_view.h"
19 #include "ui/app_list/views/contents_view.h"
20 #include "ui/app_list/views/test/apps_grid_view_test_api.h"
21 #include "ui/views/test/views_test_base.h"
22 #include "ui/views/view_model.h"
23 #include "ui/views/widget/widget.h"
25 namespace app_list {
26 namespace test {
28 namespace {
30 const int kInitialItems = 2;
32 class GridViewVisibleWaiter {
33 public:
34 explicit GridViewVisibleWaiter(AppsGridView* grid_view)
35 : grid_view_(grid_view) {}
36 ~GridViewVisibleWaiter() {}
38 void Wait() {
39 if (grid_view_->visible())
40 return;
42 check_timer_.Start(FROM_HERE,
43 base::TimeDelta::FromMilliseconds(50),
44 base::Bind(&GridViewVisibleWaiter::OnTimerCheck,
45 base::Unretained(this)));
46 run_loop_.reset(new base::RunLoop);
47 run_loop_->Run();
48 check_timer_.Stop();
51 private:
52 void OnTimerCheck() {
53 if (grid_view_->visible())
54 run_loop_->Quit();
57 AppsGridView* grid_view_;
58 scoped_ptr<base::RunLoop> run_loop_;
59 base::RepeatingTimer<GridViewVisibleWaiter> check_timer_;
61 DISALLOW_COPY_AND_ASSIGN(GridViewVisibleWaiter);
64 class AppListMainViewTest : public views::ViewsTestBase {
65 public:
66 AppListMainViewTest()
67 : widget_(NULL),
68 main_view_(NULL) {}
70 virtual ~AppListMainViewTest() {}
72 // testing::Test overrides:
73 virtual void SetUp() OVERRIDE {
74 views::ViewsTestBase::SetUp();
75 delegate_.reset(new AppListTestViewDelegate);
77 main_view_ =
78 new AppListMainView(delegate_.get(), &pagination_model_, GetContext());
79 main_view_->SetPaintToLayer(true);
81 widget_ = new views::Widget;
82 views::Widget::InitParams params =
83 CreateParams(views::Widget::InitParams::TYPE_POPUP);
84 params.bounds.set_size(main_view_->GetPreferredSize());
85 widget_->Init(params);
87 widget_->SetContentsView(main_view_);
90 virtual void TearDown() OVERRIDE {
91 widget_->Close();
92 views::ViewsTestBase::TearDown();
93 delegate_.reset();
96 // |point| is in |grid_view|'s coordinates.
97 AppListItemView* GetItemViewAtPointInGrid(AppsGridView* grid_view,
98 const gfx::Point& point) {
99 const views::ViewModel* view_model = grid_view->view_model_for_test();
100 for (int i = 0; i < view_model->view_size(); ++i) {
101 views::View* view = view_model->view_at(i);
102 if (view->bounds().Contains(point)) {
103 return static_cast<AppListItemView*>(view);
107 return NULL;
110 void SimulateClick(views::View* view) {
111 gfx::Point center = view->GetLocalBounds().CenterPoint();
112 view->OnMousePressed(ui::MouseEvent(ui::ET_MOUSE_PRESSED,
113 center,
114 center,
115 ui::EF_LEFT_MOUSE_BUTTON,
116 ui::EF_LEFT_MOUSE_BUTTON));
117 view->OnMouseReleased(ui::MouseEvent(ui::ET_MOUSE_RELEASED,
118 center,
119 center,
120 ui::EF_LEFT_MOUSE_BUTTON,
121 ui::EF_LEFT_MOUSE_BUTTON));
124 // |point| is in |grid_view|'s coordinates.
125 AppListItemView* SimulateInitiateDrag(AppsGridView* grid_view,
126 AppsGridView::Pointer pointer,
127 const gfx::Point& point) {
128 AppListItemView* view = GetItemViewAtPointInGrid(grid_view, point);
129 DCHECK(view);
131 gfx::Point translated =
132 gfx::PointAtOffsetFromOrigin(point - view->bounds().origin());
133 ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, translated, point, 0, 0);
134 grid_view->InitiateDrag(view, pointer, pressed_event);
135 return view;
138 // |point| is in |grid_view|'s coordinates.
139 void SimulateUpdateDrag(AppsGridView* grid_view,
140 AppsGridView::Pointer pointer,
141 AppListItemView* drag_view,
142 const gfx::Point& point) {
143 DCHECK(drag_view);
144 gfx::Point translated =
145 gfx::PointAtOffsetFromOrigin(point - drag_view->bounds().origin());
146 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, translated, point, 0, 0);
147 grid_view->UpdateDragFromItem(pointer, drag_event);
150 AppsGridView* RootGridView() {
151 return main_view_->contents_view()->apps_container_view()->apps_grid_view();
154 AppListFolderView* FolderView() {
155 return main_view_->contents_view()
156 ->apps_container_view()
157 ->app_list_folder_view();
160 AppsGridView* FolderGridView() { return FolderView()->items_grid_view(); }
162 const views::ViewModel* RootViewModel() {
163 return RootGridView()->view_model_for_test();
166 const views::ViewModel* FolderViewModel() {
167 return FolderGridView()->view_model_for_test();
170 protected:
171 views::Widget* widget_; // Owned by native window.
172 AppListMainView* main_view_; // Owned by |widget_|.
173 PaginationModel pagination_model_;
174 scoped_ptr<AppListTestViewDelegate> delegate_;
176 private:
177 DISALLOW_COPY_AND_ASSIGN(AppListMainViewTest);
180 } // namespace
182 // Tests changing the AppListModel when switching profiles.
183 TEST_F(AppListMainViewTest, ModelChanged) {
184 delegate_->GetTestModel()->PopulateApps(kInitialItems);
185 EXPECT_EQ(kInitialItems, RootViewModel()->view_size());
187 // The model is owned by a profile keyed service, which is never destroyed
188 // until after profile switching.
189 scoped_ptr<AppListModel> old_model(delegate_->ReleaseTestModel());
191 const int kReplacementItems = 5;
192 delegate_->ReplaceTestModel(kReplacementItems);
193 main_view_->ModelChanged();
194 EXPECT_EQ(kReplacementItems, RootViewModel()->view_size());
197 // Tests dragging an item out of a single item folder and drop it at the last
198 // slot.
199 TEST_F(AppListMainViewTest, DragLastItemFromFolderAndDropAtLastSlot) {
200 // Prepare single folder with a single item in it.
201 AppListFolderItem* folder_item =
202 delegate_->GetTestModel()->CreateSingleItemFolder("single_item_folder",
203 "single");
204 EXPECT_EQ(folder_item,
205 delegate_->GetTestModel()->FindFolderItem("single_item_folder"));
206 EXPECT_EQ(AppListFolderItem::kItemType, folder_item->GetItemType());
208 EXPECT_EQ(1, RootViewModel()->view_size());
209 AppListItemView* folder_item_view =
210 static_cast<AppListItemView*>(RootViewModel()->view_at(0));
211 EXPECT_EQ(folder_item_view->item(), folder_item);
212 const gfx::Rect first_slot_tile = folder_item_view->bounds();
214 // Click on the folder to open it.
215 EXPECT_FALSE(FolderView()->visible());
216 SimulateClick(folder_item_view);
217 base::RunLoop().RunUntilIdle();
218 EXPECT_TRUE(FolderView()->visible());
220 #if defined(OS_WIN)
221 AppsGridViewTestApi folder_grid_view_test_api(FolderGridView());
222 folder_grid_view_test_api.DisableSynchronousDrag();
223 #endif
225 // Start to drag the item in folder.
226 EXPECT_EQ(1, FolderViewModel()->view_size());
227 views::View* item_view = FolderViewModel()->view_at(0);
228 gfx::Point point = item_view->bounds().CenterPoint();
229 AppListItemView* dragged =
230 SimulateInitiateDrag(FolderGridView(), AppsGridView::MOUSE, point);
231 EXPECT_EQ(item_view, dragged);
232 EXPECT_FALSE(RootGridView()->visible());
233 EXPECT_TRUE(FolderView()->visible());
235 // Drag it to top left corner.
236 point = gfx::Point(0, 0);
237 // Two update drags needed to actually drag the view. The first changes state
238 // and the 2nd one actually moves the view. The 2nd call can be removed when
239 // UpdateDrag is fixed.
240 SimulateUpdateDrag(FolderGridView(), AppsGridView::MOUSE, dragged, point);
241 SimulateUpdateDrag(FolderGridView(), AppsGridView::MOUSE, dragged, point);
242 base::RunLoop().RunUntilIdle();
244 // Wait until the folder view is invisible and root grid view shows up.
245 GridViewVisibleWaiter(RootGridView()).Wait();
246 EXPECT_TRUE(RootGridView()->visible());
247 EXPECT_EQ(0, FolderView()->layer()->opacity());
249 // Drop it to the slot on the right of first slot.
250 gfx::Rect drop_target_tile(first_slot_tile);
251 drop_target_tile.Offset(first_slot_tile.width(), 0);
252 point = drop_target_tile.CenterPoint();
253 SimulateUpdateDrag(FolderGridView(), AppsGridView::MOUSE, dragged, point);
254 SimulateUpdateDrag(FolderGridView(), AppsGridView::MOUSE, dragged, point);
255 base::RunLoop().RunUntilIdle();
257 // Drop it.
258 FolderGridView()->EndDrag(false);
259 base::RunLoop().RunUntilIdle();
261 // Folder icon view should be gone and there is only one item view.
262 EXPECT_EQ(1, RootViewModel()->view_size());
263 EXPECT_EQ(AppListItemView::kViewClassName,
264 RootViewModel()->view_at(0)->GetClassName());
266 // The item view should be in slot 1 instead of slot 2 where it is dropped.
267 AppsGridViewTestApi root_grid_view_test_api(RootGridView());
268 root_grid_view_test_api.LayoutToIdealBounds();
269 EXPECT_EQ(first_slot_tile, RootViewModel()->view_at(0)->bounds());
271 // Single item folder should be auto removed.
272 EXPECT_EQ(NULL,
273 delegate_->GetTestModel()->FindFolderItem("single_item_folder"));
276 } // namespace test
277 } // namespace app_list