apps_grid_controller_unittest.mm revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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.
4
5#include "base/memory/scoped_nsobject.h"
6#import "testing/gtest_mac.h"
7#include "ui/app_list/app_list_item_model.h"
8#import "ui/app_list/cocoa/apps_collection_view_drag_manager.h"
9#import "ui/app_list/cocoa/apps_grid_controller.h"
10#import "ui/app_list/cocoa/apps_grid_view_item.h"
11#import "ui/app_list/cocoa/apps_pagination_model_observer.h"
12#import "ui/app_list/cocoa/test/apps_grid_controller_test_helper.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#import "ui/base/test/cocoa_test_event_utils.h"
16
17@interface TestPaginationObserver : NSObject<AppsPaginationModelObserver> {
18 @private
19  int totalPagesChangedCount_;
20  int selectedPageChangedCount_;
21  int lastNewSelectedPage_;
22}
23
24@property(assign, nonatomic) int totalPagesChangedCount;
25@property(assign, nonatomic) int selectedPageChangedCount;
26@property(assign, nonatomic) int lastNewSelectedPage;
27
28@end
29
30@implementation TestPaginationObserver
31
32@synthesize totalPagesChangedCount = totalPagesChangedCount_;
33@synthesize selectedPageChangedCount = selectedPageChangedCount_;
34@synthesize lastNewSelectedPage = lastNewSelectedPage_;
35
36- (void)totalPagesChanged {
37  ++totalPagesChangedCount_;
38}
39
40- (void)selectedPageChanged:(int)newSelected {
41  ++selectedPageChangedCount_;
42  lastNewSelectedPage_ = newSelected;
43}
44
45@end
46
47namespace app_list {
48namespace test {
49
50namespace {
51
52class AppsGridControllerTest : public AppsGridControllerTestHelper {
53 public:
54  AppsGridControllerTest() {}
55
56  virtual void SetUp() OVERRIDE {
57    owned_apps_grid_controller_.reset([[AppsGridController alloc] init]);
58    [owned_apps_grid_controller_ setDelegate:delegate_.get()];
59    AppsGridControllerTestHelper::SetUpWithGridController(
60        owned_apps_grid_controller_.get());
61
62    [[test_window() contentView] addSubview:[apps_grid_controller_ view]];
63    [test_window() makePretendKeyWindowAndSetFirstResponder:
64        [apps_grid_controller_ collectionViewAtPageIndex:0]];
65  }
66
67  virtual void TearDown() OVERRIDE {
68    owned_apps_grid_controller_.reset();
69    AppsGridControllerTestHelper::TearDown();
70  }
71
72 private:
73  scoped_nsobject<AppsGridController> owned_apps_grid_controller_;
74
75  DISALLOW_COPY_AND_ASSIGN(AppsGridControllerTest);
76};
77
78}  // namespace
79
80TEST_VIEW(AppsGridControllerTest, [apps_grid_controller_ view]);
81
82// Test showing with an empty model.
83TEST_F(AppsGridControllerTest, EmptyModelAndShow) {
84  EXPECT_TRUE([[apps_grid_controller_ view] superview]);
85
86  // First page should always exist, even if empty.
87  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
88  EXPECT_EQ(0u, [[GetPageAt(0) content] count]);
89  EXPECT_TRUE([GetPageAt(0) superview]);  // The pages container.
90  EXPECT_TRUE([[GetPageAt(0) superview] superview]);
91}
92
93// Test with a single item.
94// This test is disabled in builders until the delay to wait for the collection
95// view to load subviews can be removed, or some other solution is found.
96TEST_F(AppsGridControllerTest, DISABLED_SingleEntryModel) {
97  // We need to "wake up" the NSCollectionView, otherwise it does not
98  // immediately update its subviews later in this function.
99  // When this test is run by itself, it's enough just to send a keypress (and
100  // this delay is not needed).
101  DelayForCollectionView();
102  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
103  EXPECT_EQ(0u, [[GetPageAt(0) content] count]);
104
105  model()->PopulateApps(1);
106  SinkEvents();
107  EXPECT_FALSE([GetPageAt(0) animations]);
108
109  EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
110  NSArray* subviews = [GetPageAt(0) subviews];
111  EXPECT_EQ(1u, [subviews count]);
112
113  // Note that using GetItemViewAt(0) here also works, and returns non-nil even
114  // without the delay, but a "click" on it does not register without the delay.
115  NSView* subview = [subviews objectAtIndex:0];
116
117  // Launch the item.
118  SimulateClick(subview);
119  SinkEvents();
120  EXPECT_EQ(1, delegate()->activate_count());
121  EXPECT_EQ(std::string("Item 0"), delegate()->last_activated()->title());
122}
123
124// Test activating an item on the second page (the 17th item).
125TEST_F(AppsGridControllerTest, DISABLED_TwoPageModel) {
126  DelayForCollectionView();
127  ReplaceTestModel(kItemsPerPage * 2);
128  [apps_grid_controller_ scrollToPage:1];
129
130  // The NSScrollView animator ignores the duration configured on the
131  // NSAnimationContext (set by CocoaTest::Init), so we need to delay here.
132  DelayForCollectionView();
133  NSArray* subviews = [GetPageAt(1) subviews];
134  NSView* subview = [subviews objectAtIndex:0];
135  // Launch the item.
136  SimulateClick(subview);
137  SinkEvents();
138  EXPECT_EQ(1, delegate()->activate_count());
139  EXPECT_EQ(std::string("Item 16"), delegate()->last_activated()->title());
140}
141
142// Test setModel.
143TEST_F(AppsGridControllerTest, ReplaceModel) {
144  const size_t kOrigItems = 1;
145  const size_t kNewItems = 2;
146
147  model()->PopulateApps(kOrigItems);
148  EXPECT_EQ(kOrigItems, [[GetPageAt(0) content] count]);
149
150  ReplaceTestModel(kNewItems);
151  EXPECT_EQ(kNewItems, [[GetPageAt(0) content] count]);
152}
153
154// Test pagination.
155TEST_F(AppsGridControllerTest, Pagination) {
156  model()->PopulateApps(1);
157  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
158  EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
159
160  ReplaceTestModel(kItemsPerPage);
161  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
162  EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
163
164  // Test adding an item onto the next page.
165  model()->PopulateApps(1);  // Now 17 items.
166  EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
167  EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
168  EXPECT_EQ(1u, [[GetPageAt(1) content] count]);
169
170  // Test N pages with the last page having one empty spot.
171  const size_t kPagesToTest = 3;
172  ReplaceTestModel(kPagesToTest * kItemsPerPage - 1);
173  EXPECT_EQ(kPagesToTest, [apps_grid_controller_ pageCount]);
174  for (size_t page_index = 0; page_index < kPagesToTest - 1; ++page_index) {
175    EXPECT_EQ(kItemsPerPage, [[GetPageAt(page_index) content] count]);
176  }
177  EXPECT_EQ(kItemsPerPage - 1, [[GetPageAt(kPagesToTest - 1) content] count]);
178
179  // Test removing pages.
180  ReplaceTestModel(1);
181  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
182  EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
183}
184
185// Tests basic left-right keyboard navigation on the first page, later tests
186// will test keyboard navigation across pages and other corner cases.
187TEST_F(AppsGridControllerTest, DISABLED_FirstPageKeyboardNavigation) {
188  model()->PopulateApps(3);
189  SinkEvents();
190  EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
191
192  SimulateKeyPress(NSRightArrowFunctionKey);
193  SinkEvents();
194  EXPECT_EQ(GetSelectedView(), GetItemViewAt(0));
195
196  SimulateKeyPress(NSRightArrowFunctionKey);
197  SinkEvents();
198  EXPECT_EQ(GetSelectedView(), GetItemViewAt(1));
199
200  SimulateKeyPress(NSLeftArrowFunctionKey);
201  SinkEvents();
202  EXPECT_EQ(GetSelectedView(), GetItemViewAt(0));
203
204  // Go to the last item, and launch it.
205  SimulateKeyPress(NSRightArrowFunctionKey);
206  SimulateKeyPress(NSRightArrowFunctionKey);
207  [apps_grid_controller_ activateSelection];
208  SinkEvents();
209  EXPECT_EQ(GetSelectedView(), GetItemViewAt(2));
210  EXPECT_EQ(1, delegate()->activate_count());
211  EXPECT_EQ(std::string("Item 2"), delegate()->last_activated()->title());
212}
213
214// Test runtime updates: adding items, changing titles and icons.
215TEST_F(AppsGridControllerTest, ModelUpdates) {
216  model()->PopulateApps(2);
217  EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
218
219  // Add an item (PopulateApps will create a duplicate "Item 0").
220  model()->PopulateApps(1);
221  EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
222  NSButton* button = GetItemViewAt(2);
223  EXPECT_NSEQ(@"Item 0", [button title]);
224
225  // Update the title via the ItemModelObserver.
226  app_list::AppListItemModel* item_model = model()->apps()->GetItemAt(2);
227  item_model->SetTitle("UpdatedItem");
228  EXPECT_NSEQ(@"UpdatedItem", [button title]);
229
230  // Update the icon, test by changing size.
231  NSSize icon_size = [[button image] size];
232  EXPECT_EQ(0, icon_size.width);
233  EXPECT_EQ(0, icon_size.height);
234
235  SkBitmap bitmap;
236  const int kTestImageSize = 10;
237  bitmap.setConfig(SkBitmap::kARGB_8888_Config, kTestImageSize, kTestImageSize);
238  item_model->SetIcon(gfx::ImageSkia::CreateFrom1xBitmap(bitmap), false);
239  icon_size = [[button image] size];
240  EXPECT_EQ(kTestImageSize, icon_size.width);
241  EXPECT_EQ(kTestImageSize, icon_size.height);
242}
243
244// Test mouseover selection.
245TEST_F(AppsGridControllerTest, MouseoverSelects) {
246  model()->PopulateApps(2);
247  EXPECT_EQ(nil, GetSelectedView());
248
249  // Test entering and exiting the first item.
250  SimulateMouseEnterItemAt(0);
251  EXPECT_EQ(GetItemViewAt(0), GetSelectedView());
252  SimulateMouseExitItemAt(0);
253  EXPECT_EQ(nil, GetSelectedView());
254
255  // AppKit doesn't guarantee the order, so test moving between items.
256  SimulateMouseEnterItemAt(0);
257  EXPECT_EQ(GetItemViewAt(0), GetSelectedView());
258  SimulateMouseEnterItemAt(1);
259  EXPECT_EQ(GetItemViewAt(1), GetSelectedView());
260  SimulateMouseExitItemAt(0);
261  EXPECT_EQ(GetItemViewAt(1), GetSelectedView());
262  SimulateMouseExitItemAt(1);
263  EXPECT_EQ(nil, GetSelectedView());
264}
265
266// Test AppsGridPaginationObserver totalPagesChanged().
267TEST_F(AppsGridControllerTest, PaginationObserverPagesChanged) {
268  scoped_nsobject<TestPaginationObserver> observer(
269      [[TestPaginationObserver alloc] init]);
270  [apps_grid_controller_ setPaginationObserver:observer];
271
272  // Test totalPagesChanged.
273  model()->PopulateApps(kItemsPerPage);
274  EXPECT_EQ(0, [observer totalPagesChangedCount]);
275  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
276  model()->PopulateApps(1);
277  EXPECT_EQ(1, [observer totalPagesChangedCount]);
278  EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
279  ReplaceTestModel(0);
280  EXPECT_EQ(2, [observer totalPagesChangedCount]);
281  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
282  ReplaceTestModel(kItemsPerPage * 3 + 1);
283  EXPECT_EQ(3, [observer totalPagesChangedCount]);
284  EXPECT_EQ(4u, [apps_grid_controller_ pageCount]);
285
286  EXPECT_EQ(0, [observer selectedPageChangedCount]);
287
288  [apps_grid_controller_ setPaginationObserver:nil];
289}
290
291// Test AppsGridPaginationObserver selectedPageChanged().
292TEST_F(AppsGridControllerTest, PaginationObserverSelectedPageChanged) {
293  [AppsGridController setScrollAnimationDuration:0.0];
294  scoped_nsobject<TestPaginationObserver> observer(
295      [[TestPaginationObserver alloc] init]);
296  [apps_grid_controller_ setPaginationObserver:observer];
297  EXPECT_EQ(0, [[NSAnimationContext currentContext] duration]);
298
299  ReplaceTestModel(kItemsPerPage * 3 + 1);
300  EXPECT_EQ(1, [observer totalPagesChangedCount]);
301  EXPECT_EQ(4u, [apps_grid_controller_ pageCount]);
302
303  EXPECT_EQ(0, [observer selectedPageChangedCount]);
304
305  [apps_grid_controller_ scrollToPage:1];
306  EXPECT_EQ(1, [observer selectedPageChangedCount]);
307  EXPECT_EQ(1, [observer lastNewSelectedPage]);
308
309  [apps_grid_controller_ scrollToPage:0];
310  EXPECT_EQ(2, [observer selectedPageChangedCount]);
311  EXPECT_EQ(0, [observer lastNewSelectedPage]);
312
313  [apps_grid_controller_ scrollToPage:3];
314  // Note: with no animations, there is only a single page change. However, with
315  // animations we expect multiple updates depending on the rate that the scroll
316  // view updates and sends out NSViewBoundsDidChangeNotification.
317  EXPECT_EQ(3, [observer selectedPageChangedCount]);
318  EXPECT_EQ(3, [observer lastNewSelectedPage]);
319
320  [apps_grid_controller_ setPaginationObserver:nil];
321}
322
323namespace {
324
325// Generate a mouse event at the centre of the view in |page| with the given
326// |index_in_page| that can be used to initiate, update and complete drag
327// operations.
328NSEvent* MouseEventInCell(NSCollectionView* page, size_t index_in_page) {
329  NSRect cell_rect = [page frameForItemAtIndex:index_in_page];
330  NSPoint point_in_view = NSMakePoint(NSMidX(cell_rect), NSMidY(cell_rect));
331  NSPoint point_in_window = [page convertPoint:point_in_view
332                                        toView:nil];
333  return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
334}
335
336}  // namespace
337
338// Test basic item moves with two items; swapping them around, dragging outside
339// of the view bounds, and dragging on the background.
340TEST_F(AppsGridControllerTest, DragAndDropSimple) {
341  model()->PopulateApps(2);
342  NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:0];
343  NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
344  NSEvent* mouse_at_cell_1 = MouseEventInCell(page, 1);
345  NSEvent* mouse_at_page_centre = MouseEventInCell(page, 6);
346  NSEvent* mouse_off_page = MouseEventInCell(page, kItemsPerPage * 2);
347
348  const std::string kOrdered = "Item 0,Item 1";
349  const std::string kSwapped = "Item 1,Item 0";
350  const std::string kOrderedView = "|Item 0,Item 1|";
351  const std::string kSwappedView = "|Item 1,Item 0|";
352
353  EXPECT_EQ(kOrdered, model()->GetModelContent());
354  EXPECT_EQ(kOrderedView, GetViewContent());
355  AppsCollectionViewDragManager* drag_manager =
356      [apps_grid_controller_ dragManager];
357
358  // Drag first item over the second item and release.
359  [drag_manager onMouseDownInPage:page
360                        withEvent:mouse_at_cell_0];
361  [drag_manager onMouseDragged:mouse_at_cell_1];
362  EXPECT_EQ(kOrdered, model()->GetModelContent());
363  EXPECT_EQ(kSwappedView, GetViewContent());  // View swaps first.
364  [drag_manager onMouseUp:mouse_at_cell_1];
365  EXPECT_EQ(kSwapped, model()->GetModelContent());
366  EXPECT_EQ(kSwappedView, GetViewContent());
367
368  // Drag item back.
369  [drag_manager onMouseDownInPage:page
370                        withEvent:mouse_at_cell_1];
371  [drag_manager onMouseDragged:mouse_at_cell_0];
372  EXPECT_EQ(kSwapped, model()->GetModelContent());
373  EXPECT_EQ(kOrderedView, GetViewContent());
374  [drag_manager onMouseUp:mouse_at_cell_0];
375  EXPECT_EQ(kOrdered, model()->GetModelContent());
376  EXPECT_EQ(kOrderedView, GetViewContent());
377
378  // Drag first item to centre of view (should put in last place).
379  [drag_manager onMouseDownInPage:page
380                        withEvent:mouse_at_cell_0];
381  [drag_manager onMouseDragged:mouse_at_page_centre];
382  EXPECT_EQ(kOrdered, model()->GetModelContent());
383  EXPECT_EQ(kSwappedView, GetViewContent());
384  [drag_manager onMouseUp:mouse_at_page_centre];
385  EXPECT_EQ(kSwapped, model()->GetModelContent());
386  EXPECT_EQ(kSwappedView, GetViewContent());
387
388  // Drag item to centre again (should leave it in the last place).
389  [drag_manager onMouseDownInPage:page
390                        withEvent:mouse_at_cell_1];
391  [drag_manager onMouseDragged:mouse_at_page_centre];
392  EXPECT_EQ(kSwapped, model()->GetModelContent());
393  EXPECT_EQ(kSwappedView, GetViewContent());
394  [drag_manager onMouseUp:mouse_at_page_centre];
395  EXPECT_EQ(kSwapped, model()->GetModelContent());
396  EXPECT_EQ(kSwappedView, GetViewContent());
397
398  // Drag starting in the centre of the view, should do nothing.
399  [drag_manager onMouseDownInPage:page
400                        withEvent:mouse_at_page_centre];
401  [drag_manager onMouseDragged:mouse_at_cell_0];
402  EXPECT_EQ(kSwapped, model()->GetModelContent());
403  EXPECT_EQ(kSwappedView, GetViewContent());
404  [drag_manager onMouseUp:mouse_at_cell_0];
405  EXPECT_EQ(kSwapped, model()->GetModelContent());
406  EXPECT_EQ(kSwappedView, GetViewContent());
407
408  // Click off page.
409  [drag_manager onMouseDownInPage:page
410                        withEvent:mouse_off_page];
411  [drag_manager onMouseDragged:mouse_at_cell_0];
412  EXPECT_EQ(kSwapped, model()->GetModelContent());
413  EXPECT_EQ(kSwappedView, GetViewContent());
414  [drag_manager onMouseUp:mouse_at_cell_0];
415  EXPECT_EQ(kSwapped, model()->GetModelContent());
416  EXPECT_EQ(kSwappedView, GetViewContent());
417
418  // Drag to first over second item, then off page.
419  [drag_manager onMouseDownInPage:page
420                        withEvent:mouse_at_cell_0];
421  [drag_manager onMouseDragged:mouse_at_cell_1];
422  EXPECT_EQ(kSwapped, model()->GetModelContent());
423  EXPECT_EQ(kOrderedView, GetViewContent());
424  [drag_manager onMouseDragged:mouse_off_page];
425  EXPECT_EQ(kSwapped, model()->GetModelContent());
426  EXPECT_EQ(kOrderedView, GetViewContent());
427  [drag_manager onMouseUp:mouse_off_page];
428  EXPECT_EQ(kOrdered, model()->GetModelContent());
429  EXPECT_EQ(kOrderedView, GetViewContent());
430
431  // Replace with an empty model, and ensure we do not break.
432  ReplaceTestModel(0);
433  EXPECT_EQ(std::string(), model()->GetModelContent());
434  EXPECT_EQ(std::string("||"), GetViewContent());
435  [drag_manager onMouseDownInPage:page
436                        withEvent:mouse_at_cell_0];
437  [drag_manager onMouseDragged:mouse_at_cell_1];
438  [drag_manager onMouseUp:mouse_at_cell_1];
439  EXPECT_EQ(std::string(), model()->GetModelContent());
440  EXPECT_EQ(std::string("||"), GetViewContent());
441}
442
443// Test item moves between pages.
444TEST_F(AppsGridControllerTest, DragAndDropMultiPage) {
445  [AppsGridController setScrollAnimationDuration:0.0];
446  const size_t kPagesToTest = 3;
447  // Put one item on the last page to hit more edge cases.
448  ReplaceTestModel(kItemsPerPage * (kPagesToTest - 1) + 1);
449  NSCollectionView* page[kPagesToTest];
450  for (size_t i = 0; i < kPagesToTest; ++i)
451    page[i] = [apps_grid_controller_ collectionViewAtPageIndex:i];
452
453  const std::string kSecondItemMovedToSecondPage =
454      "|Item 0,Item 2,Item 3,Item 4,Item 5,Item 6,Item 7,Item 8,"
455      "Item 9,Item 10,Item 11,Item 12,Item 13,Item 14,Item 15,Item 16|"
456      "|Item 17,Item 1,Item 18,Item 19,Item 20,Item 21,Item 22,Item 23,"
457      "Item 24,Item 25,Item 26,Item 27,Item 28,Item 29,Item 30,Item 31|"
458      "|Item 32|";
459
460  NSEvent* mouse_at_cell_0 = MouseEventInCell(page[0], 0);
461  NSEvent* mouse_at_cell_1 = MouseEventInCell(page[0], 1);
462  AppsCollectionViewDragManager* drag_manager =
463      [apps_grid_controller_ dragManager];
464  [drag_manager onMouseDownInPage:page[0]
465                        withEvent:mouse_at_cell_1];
466
467  // Initiate dragging before changing pages.
468  [drag_manager onMouseDragged:mouse_at_cell_0];
469
470  // Scroll to the second page.
471  [apps_grid_controller_ scrollToPage:1];
472  [drag_manager onMouseDragged:mouse_at_cell_1];
473
474  // Do one exhaustive check, and then spot-check corner cases.
475  EXPECT_EQ(kSecondItemMovedToSecondPage, GetViewContent());
476  EXPECT_EQ(0u, GetPageIndexForItem(0));
477  EXPECT_EQ(1u, GetPageIndexForItem(1));
478  EXPECT_EQ(0u, GetPageIndexForItem(2));
479  EXPECT_EQ(0u, GetPageIndexForItem(16));
480  EXPECT_EQ(1u, GetPageIndexForItem(17));
481  EXPECT_EQ(1u, GetPageIndexForItem(31));
482  EXPECT_EQ(2u, GetPageIndexForItem(32));
483
484  // Scroll to the third page and drag some more.
485  [apps_grid_controller_ scrollToPage:2];
486  [drag_manager onMouseDragged:mouse_at_cell_1];
487  EXPECT_EQ(2u, GetPageIndexForItem(1));
488  EXPECT_EQ(1u, GetPageIndexForItem(31));
489  EXPECT_EQ(1u, GetPageIndexForItem(32));
490
491  // Scroll backwards.
492  [apps_grid_controller_ scrollToPage:1];
493  [drag_manager onMouseDragged:mouse_at_cell_1];
494  EXPECT_EQ(kSecondItemMovedToSecondPage, GetViewContent());
495  EXPECT_EQ(1u, GetPageIndexForItem(1));
496  EXPECT_EQ(1u, GetPageIndexForItem(31));
497  EXPECT_EQ(2u, GetPageIndexForItem(32));
498
499  // Simulate installing an item while dragging (or have it appear during sync).
500  model()->PopulateAppWithId(33);
501  // Item should go back to its position before the drag.
502  EXPECT_EQ(0u, GetPageIndexForItem(1));
503  EXPECT_EQ(1u, GetPageIndexForItem(31));
504  EXPECT_EQ(2u, GetPageIndexForItem(32));
505  // New item should appear at end.
506  EXPECT_EQ(2u, GetPageIndexForItem(33));
507
508  // Scroll to end again, and keep dragging (should be ignored).
509  [apps_grid_controller_ scrollToPage:2];
510  [drag_manager onMouseDragged:mouse_at_cell_0];
511  EXPECT_EQ(0u, GetPageIndexForItem(1));
512  [drag_manager onMouseUp:mouse_at_cell_0];
513  EXPECT_EQ(0u, GetPageIndexForItem(1));
514}
515
516}  // namespace test
517}  // namespace app_list
518