Views Omnibox: tolerate minor click-to-select-all dragging.
[chromium-blink-merge.git] / ui / app_list / cocoa / apps_grid_controller_unittest.mm
blob73f4f2d36c5c7af5f8c8dbffff79ec52966a8e93
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 "base/mac/foundation_util.h"
6 #include "base/mac/scoped_nsobject.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "skia/ext/skia_utils_mac.h"
9 #import "testing/gtest_mac.h"
10 #include "ui/app_list/app_list_constants.h"
11 #include "ui/app_list/app_list_item.h"
12 #import "ui/app_list/cocoa/apps_collection_view_drag_manager.h"
13 #import "ui/app_list/cocoa/apps_grid_controller.h"
14 #import "ui/app_list/cocoa/apps_grid_view_item.h"
15 #import "ui/app_list/cocoa/apps_pagination_model_observer.h"
16 #import "ui/app_list/cocoa/test/apps_grid_controller_test_helper.h"
17 #include "ui/app_list/test/app_list_test_model.h"
18 #include "ui/app_list/test/app_list_test_view_delegate.h"
19 #include "ui/base/models/simple_menu_model.h"
20 #import "ui/events/test/cocoa_test_event_utils.h"
22 @interface TestPaginationObserver : NSObject<AppsPaginationModelObserver> {
23  @private
24   NSInteger hoveredSegmentForTest_;
25   int totalPagesChangedCount_;
26   int selectedPageChangedCount_;
27   int lastNewSelectedPage_;
28   bool visibilityDidChange_;
31 @property(assign, nonatomic) NSInteger hoveredSegmentForTest;
32 @property(assign, nonatomic) int totalPagesChangedCount;
33 @property(assign, nonatomic) int selectedPageChangedCount;
34 @property(assign, nonatomic) int lastNewSelectedPage;
36 - (bool)readVisibilityDidChange;
38 @end
40 @implementation TestPaginationObserver
42 @synthesize hoveredSegmentForTest = hoveredSegmentForTest_;
43 @synthesize totalPagesChangedCount = totalPagesChangedCount_;
44 @synthesize selectedPageChangedCount = selectedPageChangedCount_;
45 @synthesize lastNewSelectedPage = lastNewSelectedPage_;
47 - (id)init {
48   if ((self = [super init]))
49     hoveredSegmentForTest_ = -1;
51   return self;
54 - (bool)readVisibilityDidChange {
55   bool truth = visibilityDidChange_;
56   visibilityDidChange_ = false;
57   return truth;
60 - (void)totalPagesChanged {
61   ++totalPagesChangedCount_;
64 - (void)selectedPageChanged:(int)newSelected {
65   ++selectedPageChangedCount_;
66   lastNewSelectedPage_ = newSelected;
69 - (void)pageVisibilityChanged {
70   visibilityDidChange_ = true;
73 - (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow {
74   return hoveredSegmentForTest_;
77 @end
79 namespace app_list {
80 namespace test {
82 namespace {
84 class AppsGridControllerTest : public AppsGridControllerTestHelper {
85  public:
86   AppsGridControllerTest() {}
88   AppListTestViewDelegate* delegate() {
89     return owned_delegate_.get();
90   }
92   NSColor* ButtonTitleColorAt(size_t index) {
93     NSDictionary* attributes =
94         [[[GetItemViewAt(index) cell] attributedTitle] attributesAtIndex:0
95                                                           effectiveRange:NULL];
96     return [attributes objectForKey:NSForegroundColorAttributeName];
97   }
99   virtual void SetUp() OVERRIDE {
100     owned_apps_grid_controller_.reset([[AppsGridController alloc] init]);
101     owned_delegate_.reset(new AppListTestViewDelegate);
102     [owned_apps_grid_controller_ setDelegate:owned_delegate_.get()];
103     AppsGridControllerTestHelper::SetUpWithGridController(
104         owned_apps_grid_controller_.get());
106     [[test_window() contentView] addSubview:[apps_grid_controller_ view]];
107     [test_window() makePretendKeyWindowAndSetFirstResponder:
108         [apps_grid_controller_ collectionViewAtPageIndex:0]];
109   }
111   virtual void TearDown() OVERRIDE {
112     [owned_apps_grid_controller_ setDelegate:NULL];
113     owned_apps_grid_controller_.reset();
114     AppsGridControllerTestHelper::TearDown();
115   }
117   void ReplaceTestModel(int item_count) {
118     // Clear the delegate before reseting and destroying the model.
119     [owned_apps_grid_controller_ setDelegate:NULL];
121     owned_delegate_->ReplaceTestModel(item_count);
122     [owned_apps_grid_controller_ setDelegate:owned_delegate_.get()];
123   }
125   AppListTestModel* model() { return owned_delegate_->GetTestModel(); }
127  private:
128   base::scoped_nsobject<AppsGridController> owned_apps_grid_controller_;
129   scoped_ptr<AppListTestViewDelegate> owned_delegate_;
131   DISALLOW_COPY_AND_ASSIGN(AppsGridControllerTest);
134 class AppListItemWithMenu : public AppListItem {
135  public:
136   explicit AppListItemWithMenu(const std::string& title)
137       : AppListItem(title),
138         menu_model_(NULL),
139         menu_ready_(true) {
140     SetTitleAndFullName(title, title);
141     menu_model_.AddItem(0, base::UTF8ToUTF16("Menu For: " + title));
142   }
144   void SetMenuReadyForTesting(bool ready) {
145     menu_ready_ = ready;
146   }
148   virtual ui::MenuModel* GetContextMenuModel() OVERRIDE {
149     if (!menu_ready_)
150       return NULL;
152     return &menu_model_;
153   }
155  private:
156   ui::SimpleMenuModel menu_model_;
157   bool menu_ready_;
159   DISALLOW_COPY_AND_ASSIGN(AppListItemWithMenu);
162 // Generate a mouse event at the centre of the view in |page| with the given
163 // |index_in_page| that can be used to initiate, update and complete drag
164 // operations.
165 NSEvent* MouseEventInCell(NSCollectionView* page, size_t index_in_page) {
166   NSRect cell_rect = [page frameForItemAtIndex:index_in_page];
167   NSPoint point_in_view = NSMakePoint(NSMidX(cell_rect), NSMidY(cell_rect));
168   NSPoint point_in_window = [page convertPoint:point_in_view
169                                         toView:nil];
170   return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
173 NSEvent* MouseEventForScroll(NSView* view, CGFloat relative_x) {
174   NSRect view_rect = [view frame];
175   NSPoint point_in_view = NSMakePoint(NSMidX(view_rect), NSMidY(view_rect));
176   point_in_view.x += point_in_view.x * relative_x;
177   NSPoint point_in_window = [view convertPoint:point_in_view
178                                         toView:nil];
179   return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
182 }  // namespace
184 TEST_VIEW(AppsGridControllerTest, [apps_grid_controller_ view]);
186 // Test showing with an empty model.
187 TEST_F(AppsGridControllerTest, EmptyModelAndShow) {
188   EXPECT_TRUE([[apps_grid_controller_ view] superview]);
190   // First page should always exist, even if empty.
191   EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
192   EXPECT_EQ(0u, [[GetPageAt(0) content] count]);
193   EXPECT_TRUE([GetPageAt(0) superview]);  // The pages container.
194   EXPECT_TRUE([[GetPageAt(0) superview] superview]);
197 // Test with a single item.
198 // This test is disabled in builders until the delay to wait for the collection
199 // view to load subviews can be removed, or some other solution is found.
200 TEST_F(AppsGridControllerTest, DISABLED_SingleEntryModel) {
201   // We need to "wake up" the NSCollectionView, otherwise it does not
202   // immediately update its subviews later in this function.
203   // When this test is run by itself, it's enough just to send a keypress (and
204   // this delay is not needed).
205   DelayForCollectionView();
206   EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
207   EXPECT_EQ(0u, [[GetPageAt(0) content] count]);
209   model()->PopulateApps(1);
210   SinkEvents();
211   EXPECT_FALSE([GetPageAt(0) animations]);
213   EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
214   NSArray* subviews = [GetPageAt(0) subviews];
215   EXPECT_EQ(1u, [subviews count]);
217   // Note that using GetItemViewAt(0) here also works, and returns non-nil even
218   // without the delay, but a "click" on it does not register without the delay.
219   NSView* subview = [subviews objectAtIndex:0];
221   // Launch the item.
222   SimulateClick(subview);
223   SinkEvents();
224   EXPECT_EQ(1, model()->activate_count());
225   ASSERT_TRUE(model()->last_activated());
226   EXPECT_EQ(std::string("Item 0"), model()->last_activated()->title());
229 // Test activating an item on the second page (the 17th item).
230 TEST_F(AppsGridControllerTest, DISABLED_TwoPageModel) {
231   DelayForCollectionView();
232   ReplaceTestModel(kItemsPerPage * 2);
233   [apps_grid_controller_ scrollToPage:1];
235   // The NSScrollView animator ignores the duration configured on the
236   // NSAnimationContext (set by CocoaTest::Init), so we need to delay here.
237   DelayForCollectionView();
238   NSArray* subviews = [GetPageAt(1) subviews];
239   NSView* subview = [subviews objectAtIndex:0];
240   // Launch the item.
241   SimulateClick(subview);
242   SinkEvents();
243   EXPECT_EQ(1, model()->activate_count());
244   ASSERT_TRUE(model()->last_activated());
245   EXPECT_EQ(std::string("Item 16"), model()->last_activated()->title());
248 // Test setModel.
249 TEST_F(AppsGridControllerTest, ReplaceModel) {
250   const size_t kOrigItems = 1;
251   const size_t kNewItems = 2;
253   model()->PopulateApps(kOrigItems);
254   EXPECT_EQ(kOrigItems, [[GetPageAt(0) content] count]);
256   ReplaceTestModel(kNewItems);
257   EXPECT_EQ(kNewItems, [[GetPageAt(0) content] count]);
260 // Test pagination.
261 TEST_F(AppsGridControllerTest, Pagination) {
262   model()->PopulateApps(1);
263   EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
264   EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
266   ReplaceTestModel(kItemsPerPage);
267   EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
268   EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
270   // Test adding an item onto the next page.
271   model()->PopulateApps(1);  // Now 17 items.
272   EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
273   EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
274   EXPECT_EQ(1u, [[GetPageAt(1) content] count]);
276   // Test N pages with the last page having one empty spot.
277   const size_t kPagesToTest = 3;
278   ReplaceTestModel(kPagesToTest * kItemsPerPage - 1);
279   EXPECT_EQ(kPagesToTest, [apps_grid_controller_ pageCount]);
280   for (size_t page_index = 0; page_index < kPagesToTest - 1; ++page_index) {
281     EXPECT_EQ(kItemsPerPage, [[GetPageAt(page_index) content] count]);
282   }
283   EXPECT_EQ(kItemsPerPage - 1, [[GetPageAt(kPagesToTest - 1) content] count]);
285   // Test removing pages.
286   ReplaceTestModel(1);
287   EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
288   EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
291 // Tests that selecting an item changes the text color correctly.
292 TEST_F(AppsGridControllerTest, SelectionChangesTextColor) {
293   model()->PopulateApps(2);
294   [apps_grid_controller_ selectItemAtIndex:0];
295   EXPECT_NSEQ(ButtonTitleColorAt(0),
296               gfx::SkColorToSRGBNSColor(app_list::kGridTitleHoverColor));
297   EXPECT_NSEQ(ButtonTitleColorAt(1),
298               gfx::SkColorToSRGBNSColor(app_list::kGridTitleColor));
300   [apps_grid_controller_ selectItemAtIndex:1];
301   EXPECT_NSEQ(ButtonTitleColorAt(0),
302               gfx::SkColorToSRGBNSColor(app_list::kGridTitleColor));
303   EXPECT_NSEQ(ButtonTitleColorAt(1),
304               gfx::SkColorToSRGBNSColor(app_list::kGridTitleHoverColor));
307 // Tests basic keyboard navigation on the first page.
308 TEST_F(AppsGridControllerTest, FirstPageKeyboardNavigation) {
309   model()->PopulateApps(kItemsPerPage - 2);
310   EXPECT_EQ(kItemsPerPage - 2, [[GetPageAt(0) content] count]);
312   SimulateKeyAction(@selector(moveRight:));
313   EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
315   SimulateKeyAction(@selector(moveRight:));
316   EXPECT_EQ(1u, [apps_grid_controller_ selectedItemIndex]);
318   SimulateKeyAction(@selector(moveDown:));
319   EXPECT_EQ(5u, [apps_grid_controller_ selectedItemIndex]);
321   SimulateKeyAction(@selector(moveLeft:));
322   EXPECT_EQ(4u, [apps_grid_controller_ selectedItemIndex]);
324   SimulateKeyAction(@selector(moveUp:));
325   EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
327   // Go to the third item, and launch it.
328   SimulateKeyAction(@selector(moveRight:));
329   SimulateKeyAction(@selector(moveRight:));
330   EXPECT_EQ(2u, [apps_grid_controller_ selectedItemIndex]);
331   SimulateKeyAction(@selector(insertNewline:));
332   EXPECT_EQ(1, model()->activate_count());
333   ASSERT_TRUE(model()->last_activated());
334   EXPECT_EQ(std::string("Item 2"), model()->last_activated()->title());
337 // Tests keyboard navigation across pages.
338 TEST_F(AppsGridControllerTest, CrossPageKeyboardNavigation) {
339   model()->PopulateApps(kItemsPerPage + 10);
340   EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
341   EXPECT_EQ(10u, [[GetPageAt(1) content] count]);
343   // Moving Left, Up, or PageUp from the top-left corner of the first page does
344   // nothing.
345   [apps_grid_controller_ selectItemAtIndex:0];
346   SimulateKeyAction(@selector(moveLeft:));
347   EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
348   SimulateKeyAction(@selector(moveUp:));
349   EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
350   SimulateKeyAction(@selector(scrollPageUp:));
351   EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
353   // Moving Right from the right side goes to the next page. Moving Left goes
354   // back to the first page.
355   [apps_grid_controller_ selectItemAtIndex:3];
356   SimulateKeyAction(@selector(moveRight:));
357   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
358   EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ selectedItemIndex]);
359   SimulateKeyAction(@selector(moveLeft:));
360   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
361   EXPECT_EQ(3u, [apps_grid_controller_ selectedItemIndex]);
363   // Moving Down from the bottom does nothing.
364   [apps_grid_controller_ selectItemAtIndex:13];
365   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
366   SimulateKeyAction(@selector(moveDown:));
367   EXPECT_EQ(13u, [apps_grid_controller_ selectedItemIndex]);
369   // Moving Right into a non-existent square on the next page will select the
370   // last item.
371   [apps_grid_controller_ selectItemAtIndex:15];
372   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
373   SimulateKeyAction(@selector(moveRight:));
374   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
375   EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
377   // PageDown and PageUp switches pages while maintaining the same selection
378   // position.
379   [apps_grid_controller_ selectItemAtIndex:6];
380   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
381   SimulateKeyAction(@selector(scrollPageDown:));
382   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
383   EXPECT_EQ(kItemsPerPage + 6, [apps_grid_controller_ selectedItemIndex]);
384   SimulateKeyAction(@selector(scrollPageUp:));
385   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
386   EXPECT_EQ(6u, [apps_grid_controller_ selectedItemIndex]);
388   // PageDown into a non-existent square on the next page will select the last
389   // item.
390   [apps_grid_controller_ selectItemAtIndex:11];
391   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
392   SimulateKeyAction(@selector(scrollPageDown:));
393   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
394   EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
396   // Moving Right, Down, or PageDown from the bottom-right corner of the last
397   // page (not the last item) does nothing.
398   [apps_grid_controller_ selectItemAtIndex:kItemsPerPage + 9];
399   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
400   SimulateKeyAction(@selector(moveRight:));
401   EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
402   SimulateKeyAction(@selector(moveDown:));
403   EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
404   SimulateKeyAction(@selector(scrollPageDown:));
405   EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
407   // After page switch, arrow keys select first item on current page.
408   [apps_grid_controller_ scrollToPage:0];
409   [apps_grid_controller_ scrollToPage:1];
410   EXPECT_EQ(NSNotFound, [apps_grid_controller_ selectedItemIndex]);
411   SimulateKeyAction(@selector(moveUp:));
412   EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ selectedItemIndex]);
415 // Highlighting an item should cause the page it's on to be visible.
416 TEST_F(AppsGridControllerTest, EnsureHighlightedVisible) {
417   model()->PopulateApps(3 * kItemsPerPage);
418   EXPECT_EQ(kItemsPerPage, [[GetPageAt(2) content] count]);
420   // First and last items of first page.
421   [apps_grid_controller_ selectItemAtIndex:0];
422   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
423   [apps_grid_controller_ selectItemAtIndex:kItemsPerPage - 1];
424   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
426   // First item of second page.
427   [apps_grid_controller_ selectItemAtIndex:kItemsPerPage + 1];
428   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
430   // Last item in model.
431   [apps_grid_controller_ selectItemAtIndex:3 * kItemsPerPage - 1];
432   EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
435 // Test runtime updates: adding items, removing items, and moving items (e.g. in
436 // response to app install, uninstall, and chrome sync changes. Also test
437 // changing titles and icons.
438 TEST_F(AppsGridControllerTest, ModelUpdate) {
439   model()->PopulateApps(2);
440   EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
441   EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
443   // Add an item (PopulateApps will create a new "Item 2").
444   model()->PopulateApps(1);
445   EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
446   NSButton* button = GetItemViewAt(2);
447   EXPECT_NSEQ(@"Item 2", [button title]);
448   EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
450   // Update the title via the ItemModelObserver.
451   app_list::AppListItem* item_model = model()->item_list()->item_at(2);
452   item_model->SetTitleAndFullName("UpdatedItem", "UpdatedItem");
453   EXPECT_NSEQ(@"UpdatedItem", [button title]);
454   EXPECT_EQ(std::string("|Item 0,Item 1,UpdatedItem|"), GetViewContent());
456   // Test icon updates through the model observer by ensuring the icon changes.
457   NSSize icon_size = [[button image] size];
458   EXPECT_EQ(0, icon_size.width);
459   EXPECT_EQ(0, icon_size.height);
461   SkBitmap bitmap;
462   const int kTestImageSize = 10;
463   const int kTargetImageSize = 48;
464   bitmap.setConfig(SkBitmap::kARGB_8888_Config, kTestImageSize, kTestImageSize);
465   item_model->SetIcon(gfx::ImageSkia::CreateFrom1xBitmap(bitmap), false);
466   icon_size = [[button image] size];
467   // Icon should always be resized to 48x48.
468   EXPECT_EQ(kTargetImageSize, icon_size.width);
469   EXPECT_EQ(kTargetImageSize, icon_size.height);
472 TEST_F(AppsGridControllerTest, ModelAdd) {
473   model()->PopulateApps(2);
474   EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
475   EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
477   app_list::AppListItemList* item_list = model()->item_list();
479   model()->CreateAndAddItem("Item 2");
480   ASSERT_EQ(3u, item_list->item_count());
481   EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
482   EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
484   // Test adding an item whose position is in the middle.
485   app_list::AppListItem* item0 = item_list->item_at(0);
486   app_list::AppListItem* item1 = item_list->item_at(1);
487   app_list::AppListItem* item3 =
488       model()->CreateItem("Item Three", "Item Three");
489   model()->AddItem(item3);
490   item_list->SetItemPosition(
491       item3, item0->position().CreateBetween(item1->position()));
492   EXPECT_EQ(4u, [apps_grid_controller_ itemCount]);
493   EXPECT_EQ(std::string("|Item 0,Item Three,Item 1,Item 2|"), GetViewContent());
496 TEST_F(AppsGridControllerTest, ModelMove) {
497   model()->PopulateApps(3);
498   EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
499   EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
501   // Test swapping items (e.g. rearranging via sync).
502   model()->item_list()->MoveItem(1, 2);
503   EXPECT_EQ(std::string("|Item 0,Item 2,Item 1|"), GetViewContent());
506 TEST_F(AppsGridControllerTest, ModelRemove) {
507   model()->PopulateApps(3);
508   EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
509   EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
511   // Test removing an item at the end.
512   model()->DeleteItem("Item 2");
513   EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
514   EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
516   // Test removing in the middle.
517   model()->CreateAndAddItem("Item 2", "");
518   EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
519   EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
520   model()->DeleteItem("Item 1");
521   EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
522   EXPECT_EQ(std::string("|Item 0,Item 2|"), GetViewContent());
525 TEST_F(AppsGridControllerTest, ModelRemoveSeveral) {
526   model()->PopulateApps(3);
527   EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
528   EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
530   // Test removing multiple items via the model.
531   model()->DeleteItem("Item 0");
532   model()->DeleteItem("Item 1");
533   model()->DeleteItem("Item 2");
534   EXPECT_EQ(0u, [apps_grid_controller_ itemCount]);
535   EXPECT_EQ(std::string("||"), GetViewContent());
538 TEST_F(AppsGridControllerTest, ModelRemovePage) {
539   app_list::AppListItemList* item_list = model()->item_list();
541   model()->PopulateApps(kItemsPerPage + 1);
542   ASSERT_EQ(kItemsPerPage + 1, item_list->item_count());
543   EXPECT_EQ(kItemsPerPage + 1, [apps_grid_controller_ itemCount]);
544   EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
546   // Test removing the last item when there is one item on the second page.
547   app_list::AppListItem* last_item = item_list->item_at(kItemsPerPage);
548   model()->DeleteItem(last_item->id());
549   EXPECT_EQ(kItemsPerPage, item_list->item_count());
550   EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ itemCount]);
551   EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
554 // Test install progress bars, and install flow with item highlighting.
555 TEST_F(AppsGridControllerTest, ItemInstallProgress) {
556   ReplaceTestModel(kItemsPerPage + 1);
557   EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
558   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
559   app_list::AppListItem* item_model =
560       model()->item_list()->item_at(kItemsPerPage);
562   // Highlighting an item should activate the page it is on.
563   item_model->SetHighlighted(true);
564   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
566   // Clearing a highlight stays on the current page.
567   [apps_grid_controller_ scrollToPage:0];
568   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
569   item_model->SetHighlighted(false);
570   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
572   // Starting install should add a progress bar, and temporarily clear the
573   // button title.
574   NSButton* button = GetItemViewAt(kItemsPerPage);
575   NSView* containerView = [button superview];
576   EXPECT_EQ(1u, [[containerView subviews] count]);
577   EXPECT_NSEQ(@"Item 16", [button title]);
578   item_model->SetHighlighted(true);
579   item_model->SetIsInstalling(true);
580   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
582   EXPECT_EQ(2u, [[containerView subviews] count]);
583   EXPECT_NSEQ(@"", [button title]);
584   NSProgressIndicator* progressIndicator =
585       [[containerView subviews] objectAtIndex:1];
586   EXPECT_FALSE([progressIndicator isIndeterminate]);
587   EXPECT_EQ(0.0, [progressIndicator doubleValue]);
589   // Updating the progress in the model should update the progress bar.
590   item_model->SetPercentDownloaded(50);
591   EXPECT_EQ(50.0, [progressIndicator doubleValue]);
593   // Two things can be installing simultaneously. When one starts or completes
594   // the model builder will ask for the item to be highlighted.
595   app_list::AppListItem* alternate_item_model =
596       model()->item_list()->item_at(0);
597   item_model->SetHighlighted(false);
598   alternate_item_model->SetHighlighted(true);
599   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
601   // Update the first item (page doesn't change on updates).
602   item_model->SetPercentDownloaded(100);
603   EXPECT_EQ(100.0, [progressIndicator doubleValue]);
604   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
606   // A percent of -1 indicates the download is complete and the unpack/install
607   // process has started.
608   item_model->SetPercentDownloaded(-1);
609   EXPECT_TRUE([progressIndicator isIndeterminate]);
611   // Completing install removes the progress bar, and restores the title.
612   // ExtensionAppModelBuilder will reload the ExtensionAppItem, which also
613   // highlights. Do the same here.
614   alternate_item_model->SetHighlighted(false);
615   item_model->SetHighlighted(true);
616   item_model->SetIsInstalling(false);
617   EXPECT_EQ(1u, [[containerView subviews] count]);
618   EXPECT_NSEQ(@"Item 16", [button title]);
619   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
621   // Things should cleanup OK with |alternate_item_model| left installing.
624 // Test mouseover selection.
625 TEST_F(AppsGridControllerTest, MouseoverSelects) {
626   model()->PopulateApps(2);
627   EXPECT_EQ(nil, GetSelectedView());
629   // Test entering and exiting the first item.
630   SimulateMouseEnterItemAt(0);
631   EXPECT_EQ(GetItemViewAt(0), GetSelectedView());
632   SimulateMouseExitItemAt(0);
633   EXPECT_EQ(nil, GetSelectedView());
635   // AppKit doesn't guarantee the order, so test moving between items.
636   SimulateMouseEnterItemAt(0);
637   EXPECT_EQ(GetItemViewAt(0), GetSelectedView());
638   SimulateMouseEnterItemAt(1);
639   EXPECT_EQ(GetItemViewAt(1), GetSelectedView());
640   SimulateMouseExitItemAt(0);
641   EXPECT_EQ(GetItemViewAt(1), GetSelectedView());
642   SimulateMouseExitItemAt(1);
643   EXPECT_EQ(nil, GetSelectedView());
646 // Test AppsGridPaginationObserver totalPagesChanged().
647 TEST_F(AppsGridControllerTest, PaginationObserverPagesChanged) {
648   base::scoped_nsobject<TestPaginationObserver> observer(
649       [[TestPaginationObserver alloc] init]);
650   [apps_grid_controller_ setPaginationObserver:observer];
652   // Test totalPagesChanged.
653   model()->PopulateApps(kItemsPerPage);
654   EXPECT_EQ(0, [observer totalPagesChangedCount]);
655   EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
656   model()->PopulateApps(1);
657   EXPECT_EQ(1, [observer totalPagesChangedCount]);
658   EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
659   ReplaceTestModel(0);
660   EXPECT_EQ(2, [observer totalPagesChangedCount]);
661   EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
662   ReplaceTestModel(kItemsPerPage * 3 + 1);
663   EXPECT_EQ(3, [observer totalPagesChangedCount]);
664   EXPECT_EQ(4u, [apps_grid_controller_ pageCount]);
666   EXPECT_FALSE([observer readVisibilityDidChange]);
667   EXPECT_EQ(0, [observer selectedPageChangedCount]);
669   [apps_grid_controller_ setPaginationObserver:nil];
672 // Test AppsGridPaginationObserver selectedPageChanged().
673 TEST_F(AppsGridControllerTest, PaginationObserverSelectedPageChanged) {
674   base::scoped_nsobject<TestPaginationObserver> observer(
675       [[TestPaginationObserver alloc] init]);
676   [apps_grid_controller_ setPaginationObserver:observer];
677   EXPECT_EQ(0, [[NSAnimationContext currentContext] duration]);
679   ReplaceTestModel(kItemsPerPage * 3 + 1);
680   EXPECT_EQ(1, [observer totalPagesChangedCount]);
681   EXPECT_EQ(4u, [apps_grid_controller_ pageCount]);
683   EXPECT_FALSE([observer readVisibilityDidChange]);
684   EXPECT_EQ(0, [observer selectedPageChangedCount]);
686   [apps_grid_controller_ scrollToPage:1];
687   EXPECT_EQ(1, [observer selectedPageChangedCount]);
688   EXPECT_EQ(1, [observer lastNewSelectedPage]);
689   EXPECT_TRUE([observer readVisibilityDidChange]);
690   EXPECT_FALSE([observer readVisibilityDidChange]);  // Testing test behaviour.
691   EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:0]);
692   EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:1]);
693   EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:2]);
694   EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:3]);
696   [apps_grid_controller_ scrollToPage:0];
697   EXPECT_EQ(2, [observer selectedPageChangedCount]);
698   EXPECT_EQ(0, [observer lastNewSelectedPage]);
699   EXPECT_TRUE([observer readVisibilityDidChange]);
700   EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:0]);
701   EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:1]);
703   [apps_grid_controller_ scrollToPage:3];
704   // Note: with no animations, there is only a single page change. However, with
705   // animations we expect multiple updates depending on the rate that the scroll
706   // view updates and sends out NSViewBoundsDidChangeNotification.
707   EXPECT_EQ(3, [observer selectedPageChangedCount]);
708   EXPECT_EQ(3, [observer lastNewSelectedPage]);
709   EXPECT_TRUE([observer readVisibilityDidChange]);
710   EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:0]);
711   EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:3]);
713   [apps_grid_controller_ setPaginationObserver:nil];
716 // Test basic item moves with two items; swapping them around, dragging outside
717 // of the view bounds, and dragging on the background.
718 TEST_F(AppsGridControllerTest, DragAndDropSimple) {
719   model()->PopulateApps(2);
720   NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:0];
721   NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
722   NSEvent* mouse_at_cell_1 = MouseEventInCell(page, 1);
723   NSEvent* mouse_at_page_centre = MouseEventInCell(page, 6);
724   NSEvent* mouse_off_page = MouseEventInCell(page, kItemsPerPage * 2);
726   const std::string kOrdered = "Item 0,Item 1";
727   const std::string kSwapped = "Item 1,Item 0";
728   const std::string kOrderedView = "|Item 0,Item 1|";
729   const std::string kSwappedView = "|Item 1,Item 0|";
731   EXPECT_EQ(kOrdered, model()->GetModelContent());
732   EXPECT_EQ(kOrderedView, GetViewContent());
733   AppsCollectionViewDragManager* drag_manager =
734       [apps_grid_controller_ dragManager];
736   // Drag first item over the second item and release.
737   [drag_manager onMouseDownInPage:page
738                         withEvent:mouse_at_cell_0];
739   [drag_manager onMouseDragged:mouse_at_cell_1];
740   EXPECT_EQ(kOrdered, model()->GetModelContent());
741   EXPECT_EQ(kSwappedView, GetViewContent());  // View swaps first.
742   [drag_manager onMouseUp:mouse_at_cell_1];
743   EXPECT_EQ(kSwapped, model()->GetModelContent());
744   EXPECT_EQ(kSwappedView, GetViewContent());
746   // Drag item back.
747   [drag_manager onMouseDownInPage:page
748                         withEvent:mouse_at_cell_1];
749   [drag_manager onMouseDragged:mouse_at_cell_0];
750   EXPECT_EQ(kSwapped, model()->GetModelContent());
751   EXPECT_EQ(kOrderedView, GetViewContent());
752   [drag_manager onMouseUp:mouse_at_cell_0];
753   EXPECT_EQ(kOrdered, model()->GetModelContent());
754   EXPECT_EQ(kOrderedView, GetViewContent());
756   // Drag first item to centre of view (should put in last place).
757   [drag_manager onMouseDownInPage:page
758                         withEvent:mouse_at_cell_0];
759   [drag_manager onMouseDragged:mouse_at_page_centre];
760   EXPECT_EQ(kOrdered, model()->GetModelContent());
761   EXPECT_EQ(kSwappedView, GetViewContent());
762   [drag_manager onMouseUp:mouse_at_page_centre];
763   EXPECT_EQ(kSwapped, model()->GetModelContent());
764   EXPECT_EQ(kSwappedView, GetViewContent());
766   // Drag item to centre again (should leave it in the last place).
767   [drag_manager onMouseDownInPage:page
768                         withEvent:mouse_at_cell_1];
769   [drag_manager onMouseDragged:mouse_at_page_centre];
770   EXPECT_EQ(kSwapped, model()->GetModelContent());
771   EXPECT_EQ(kSwappedView, GetViewContent());
772   [drag_manager onMouseUp:mouse_at_page_centre];
773   EXPECT_EQ(kSwapped, model()->GetModelContent());
774   EXPECT_EQ(kSwappedView, GetViewContent());
776   // Drag starting in the centre of the view, should do nothing.
777   [drag_manager onMouseDownInPage:page
778                         withEvent:mouse_at_page_centre];
779   [drag_manager onMouseDragged:mouse_at_cell_0];
780   EXPECT_EQ(kSwapped, model()->GetModelContent());
781   EXPECT_EQ(kSwappedView, GetViewContent());
782   [drag_manager onMouseUp:mouse_at_cell_0];
783   EXPECT_EQ(kSwapped, model()->GetModelContent());
784   EXPECT_EQ(kSwappedView, GetViewContent());
786   // Click off page.
787   [drag_manager onMouseDownInPage:page
788                         withEvent:mouse_off_page];
789   [drag_manager onMouseDragged:mouse_at_cell_0];
790   EXPECT_EQ(kSwapped, model()->GetModelContent());
791   EXPECT_EQ(kSwappedView, GetViewContent());
792   [drag_manager onMouseUp:mouse_at_cell_0];
793   EXPECT_EQ(kSwapped, model()->GetModelContent());
794   EXPECT_EQ(kSwappedView, GetViewContent());
796   // Drag to first over second item, then off page.
797   [drag_manager onMouseDownInPage:page
798                         withEvent:mouse_at_cell_0];
799   [drag_manager onMouseDragged:mouse_at_cell_1];
800   EXPECT_EQ(kSwapped, model()->GetModelContent());
801   EXPECT_EQ(kOrderedView, GetViewContent());
802   [drag_manager onMouseDragged:mouse_off_page];
803   EXPECT_EQ(kSwapped, model()->GetModelContent());
804   EXPECT_EQ(kOrderedView, GetViewContent());
805   [drag_manager onMouseUp:mouse_off_page];
806   EXPECT_EQ(kOrdered, model()->GetModelContent());
807   EXPECT_EQ(kOrderedView, GetViewContent());
809   // Replace with an empty model, and ensure we do not break.
810   ReplaceTestModel(0);
811   EXPECT_EQ(std::string(), model()->GetModelContent());
812   EXPECT_EQ(std::string("||"), GetViewContent());
813   [drag_manager onMouseDownInPage:page
814                         withEvent:mouse_at_cell_0];
815   [drag_manager onMouseDragged:mouse_at_cell_1];
816   [drag_manager onMouseUp:mouse_at_cell_1];
817   EXPECT_EQ(std::string(), model()->GetModelContent());
818   EXPECT_EQ(std::string("||"), GetViewContent());
821 // Test item moves between pages.
822 TEST_F(AppsGridControllerTest, DragAndDropMultiPage) {
823   const size_t kPagesToTest = 3;
824   // Put one item on the last page to hit more edge cases.
825   ReplaceTestModel(kItemsPerPage * (kPagesToTest - 1) + 1);
826   NSCollectionView* page[kPagesToTest];
827   for (size_t i = 0; i < kPagesToTest; ++i)
828     page[i] = [apps_grid_controller_ collectionViewAtPageIndex:i];
830   const std::string kSecondItemMovedToSecondPage =
831       "|Item 0,Item 2,Item 3,Item 4,Item 5,Item 6,Item 7,Item 8,"
832       "Item 9,Item 10,Item 11,Item 12,Item 13,Item 14,Item 15,Item 16|"
833       "|Item 17,Item 1,Item 18,Item 19,Item 20,Item 21,Item 22,Item 23,"
834       "Item 24,Item 25,Item 26,Item 27,Item 28,Item 29,Item 30,Item 31|"
835       "|Item 32|";
837   NSEvent* mouse_at_cell_0 = MouseEventInCell(page[0], 0);
838   NSEvent* mouse_at_cell_1 = MouseEventInCell(page[0], 1);
839   AppsCollectionViewDragManager* drag_manager =
840       [apps_grid_controller_ dragManager];
841   [drag_manager onMouseDownInPage:page[0]
842                         withEvent:mouse_at_cell_1];
844   // Initiate dragging before changing pages.
845   [drag_manager onMouseDragged:mouse_at_cell_0];
847   // Scroll to the second page.
848   [apps_grid_controller_ scrollToPage:1];
849   [drag_manager onMouseDragged:mouse_at_cell_1];
851   // Do one exhaustive check, and then spot-check corner cases.
852   EXPECT_EQ(kSecondItemMovedToSecondPage, GetViewContent());
853   EXPECT_EQ(0u, GetPageIndexForItem(0));
854   EXPECT_EQ(1u, GetPageIndexForItem(1));
855   EXPECT_EQ(0u, GetPageIndexForItem(2));
856   EXPECT_EQ(0u, GetPageIndexForItem(16));
857   EXPECT_EQ(1u, GetPageIndexForItem(17));
858   EXPECT_EQ(1u, GetPageIndexForItem(31));
859   EXPECT_EQ(2u, GetPageIndexForItem(32));
861   // Scroll to the third page and drag some more.
862   [apps_grid_controller_ scrollToPage:2];
863   [drag_manager onMouseDragged:mouse_at_cell_1];
864   EXPECT_EQ(2u, GetPageIndexForItem(1));
865   EXPECT_EQ(1u, GetPageIndexForItem(31));
866   EXPECT_EQ(1u, GetPageIndexForItem(32));
868   // Scroll backwards.
869   [apps_grid_controller_ scrollToPage:1];
870   [drag_manager onMouseDragged:mouse_at_cell_1];
871   EXPECT_EQ(kSecondItemMovedToSecondPage, GetViewContent());
872   EXPECT_EQ(1u, GetPageIndexForItem(1));
873   EXPECT_EQ(1u, GetPageIndexForItem(31));
874   EXPECT_EQ(2u, GetPageIndexForItem(32));
876   // Simulate installing an item while dragging (or have it appear during sync).
877   model()->PopulateAppWithId(33);
878   // Item should go back to its position before the drag.
879   EXPECT_EQ(0u, GetPageIndexForItem(1));
880   EXPECT_EQ(1u, GetPageIndexForItem(31));
881   EXPECT_EQ(2u, GetPageIndexForItem(32));
882   // New item should appear at end.
883   EXPECT_EQ(2u, GetPageIndexForItem(33));
885   // Scroll to end again, and keep dragging (should be ignored).
886   [apps_grid_controller_ scrollToPage:2];
887   [drag_manager onMouseDragged:mouse_at_cell_0];
888   EXPECT_EQ(0u, GetPageIndexForItem(1));
889   [drag_manager onMouseUp:mouse_at_cell_0];
890   EXPECT_EQ(0u, GetPageIndexForItem(1));
893 // Test scrolling when dragging past edge or over the pager.
894 TEST_F(AppsGridControllerTest, ScrollingWhileDragging) {
895   base::scoped_nsobject<TestPaginationObserver> observer(
896       [[TestPaginationObserver alloc] init]);
897   [apps_grid_controller_ setPaginationObserver:observer];
899   ReplaceTestModel(kItemsPerPage * 3);
900   // Start on the middle page.
901   [apps_grid_controller_ scrollToPage:1];
902   NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:1];
903   NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
905   NSEvent* at_center = MouseEventForScroll([apps_grid_controller_ view], 0.0);
906   NSEvent* at_left = MouseEventForScroll([apps_grid_controller_ view], -1.1);
907   NSEvent* at_right = MouseEventForScroll([apps_grid_controller_ view], 1.1);
909   AppsCollectionViewDragManager* drag_manager =
910       [apps_grid_controller_ dragManager];
911   [drag_manager onMouseDownInPage:page
912                         withEvent:mouse_at_cell_0];
913   [drag_manager onMouseDragged:at_center];
915   // Nothing should be scheduled: target page is visible page.
916   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
917   EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
919   // Drag to the left, should go to first page and no further.
920   [drag_manager onMouseDragged:at_left];
921   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
922   EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
923   [apps_grid_controller_ scrollToPage:0];  // Commit without timer for testing.
924   [drag_manager onMouseDragged:at_left];
925   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
926   EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
928   // Drag to the right, should go to last page and no futher.
929   [drag_manager onMouseDragged:at_right];
930   EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
931   EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
932   [apps_grid_controller_ scrollToPage:1];
933   [drag_manager onMouseDragged:at_right];
934   EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
935   EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
936   [apps_grid_controller_ scrollToPage:2];
937   [drag_manager onMouseDragged:at_right];
938   EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
939   EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
941   // Simulate a hover over the first pager segment.
942   [observer setHoveredSegmentForTest:0];
943   [drag_manager onMouseDragged:at_center];
944   EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
945   EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
947   // Drag it back, should cancel schedule.
948   [observer setHoveredSegmentForTest:-1];
949   [drag_manager onMouseDragged:at_center];
950   EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
951   EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
953   // Hover again, now over middle segment, and ensure a release also cancels.
954   [observer setHoveredSegmentForTest:1];
955   [drag_manager onMouseDragged:at_center];
956   EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
957   EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
958   [drag_manager onMouseUp:at_center];
959   EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
960   EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
962   [apps_grid_controller_ setPaginationObserver:nil];
965 TEST_F(AppsGridControllerTest, ContextMenus) {
966   AppListItemWithMenu* item_two_model = new AppListItemWithMenu("Item Two");
967   model()->AddItem(new AppListItemWithMenu("Item One"));
968   model()->AddItem(item_two_model);
969   EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
971   NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:0];
972   NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
973   NSEvent* mouse_at_cell_1 = MouseEventInCell(page, 1);
975   NSMenu* menu = [page menuForEvent:mouse_at_cell_0];
976   EXPECT_EQ(1, [menu numberOfItems]);
977   EXPECT_NSEQ(@"Menu For: Item One", [[menu itemAtIndex:0] title]);
979   // Test a context menu request while the item is still installing.
980   item_two_model->SetMenuReadyForTesting(false);
981   menu = [page menuForEvent:mouse_at_cell_1];
982   EXPECT_EQ(nil, menu);
984   item_two_model->SetMenuReadyForTesting(true);
985   menu = [page menuForEvent:mouse_at_cell_1];
986   EXPECT_EQ(1, [menu numberOfItems]);
987   EXPECT_NSEQ(@"Menu For: Item Two", [[menu itemAtIndex:0] title]);
989   // Test that a button being held down with the left button does not also show
990   // a context menu.
991   [GetItemViewAt(0) highlight:YES];
992   EXPECT_FALSE([page menuForEvent:mouse_at_cell_0]);
993   [GetItemViewAt(0) highlight:NO];
994   EXPECT_TRUE([page menuForEvent:mouse_at_cell_0]);
997 }  // namespace test
998 }  // namespace app_list