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