1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/basictypes.h" 6#include "base/mac/scoped_nsobject.h" 7#include "base/strings/utf_string_conversions.h" 8#include "chrome/browser/bookmarks/bookmark_model_factory.h" 9#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h" 10#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" 11#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h" 12#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" 13#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h" 14#include "chrome/browser/ui/cocoa/cocoa_profile_test.h" 15#import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 16#import "chrome/browser/ui/cocoa/view_resizer_pong.h" 17#include "chrome/test/base/testing_profile.h" 18#include "components/bookmarks/browser/bookmark_model.h" 19#include "components/bookmarks/test/bookmark_test_helpers.h" 20#include "testing/gtest/include/gtest/gtest.h" 21#import "testing/gtest_mac.h" 22#include "testing/platform_test.h" 23#include "ui/base/cocoa/animation_utils.h" 24 25#include <cmath> 26 27using base::ASCIIToUTF16; 28 29namespace { 30 31const int kLotsOfNodesCount = 150; 32 33// Deletes the bookmark corresponding to |button|. 34void DeleteBookmark(BookmarkButton* button, Profile* profile) { 35 const BookmarkNode* node = [button bookmarkNode]; 36 if (node) { 37 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile); 38 model->Remove(node->parent(), node->parent()->GetIndexOf(node)); 39 } 40} 41 42} // namespace 43 44// Add a redirect to make testing easier. 45@interface BookmarkBarFolderController(MakeTestingEasier) 46- (void)validateMenuSpacing; 47@end 48 49@implementation BookmarkBarFolderController(MakeTestingEasier) 50 51// Utility function to verify that the buttons in this folder are all 52// evenly spaced in a progressive manner. 53- (void)validateMenuSpacing { 54 BOOL firstButton = YES; 55 CGFloat lastVerticalOffset = 0.0; 56 for (BookmarkButton* button in [self buttons]) { 57 if (firstButton) { 58 firstButton = NO; 59 lastVerticalOffset = [button frame].origin.y; 60 } else { 61 CGFloat nextVerticalOffset = [button frame].origin.y; 62 EXPECT_CGFLOAT_EQ(lastVerticalOffset - 63 bookmarks::kBookmarkFolderButtonHeight, 64 nextVerticalOffset); 65 lastVerticalOffset = nextVerticalOffset; 66 } 67 } 68} 69@end 70 71// Don't use a high window level when running unit tests -- it'll 72// interfere with anything else you are working on. 73// For testing. 74@interface BookmarkBarFolderControllerNoLevel : BookmarkBarFolderController 75@end 76 77@implementation BookmarkBarFolderControllerNoLevel 78- (void)configureWindowLevel { 79 // Intentionally empty. 80} 81@end 82 83@interface BookmarkBarFolderControllerPong : BookmarkBarFolderController { 84 BOOL childFolderWillShow_; 85 BOOL childFolderWillClose_; 86} 87@property (nonatomic, readonly) BOOL childFolderWillShow; 88@property (nonatomic, readonly) BOOL childFolderWillClose; 89@end 90 91@implementation BookmarkBarFolderControllerPong 92@synthesize childFolderWillShow = childFolderWillShow_; 93@synthesize childFolderWillClose = childFolderWillClose_; 94 95- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child { 96 childFolderWillShow_ = YES; 97} 98 99- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child { 100 childFolderWillClose_ = YES; 101} 102 103// We don't have a real BookmarkBarController as our parent root so 104// we fake this one out. 105- (void)closeAllBookmarkFolders { 106 [self closeBookmarkFolder:self]; 107} 108 109@end 110 111// Redirect certain calls so they can be seen by tests. 112 113@interface BookmarkBarControllerChildFolderRedirect : BookmarkBarController { 114 BookmarkBarFolderController* childFolderDelegate_; 115} 116@property (nonatomic, assign) BookmarkBarFolderController* childFolderDelegate; 117@end 118 119@implementation BookmarkBarControllerChildFolderRedirect 120 121@synthesize childFolderDelegate = childFolderDelegate_; 122 123- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child { 124 [childFolderDelegate_ childFolderWillShow:child]; 125} 126 127- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child { 128 [childFolderDelegate_ childFolderWillClose:child]; 129} 130 131@end 132 133 134class BookmarkBarFolderControllerTest : public CocoaProfileTest { 135 public: 136 base::scoped_nsobject<BookmarkBarControllerChildFolderRedirect> bar_; 137 const BookmarkNode* folderA_; // Owned by model. 138 const BookmarkNode* longTitleNode_; // Owned by model. 139 140 virtual void SetUp() { 141 CocoaProfileTest::SetUp(); 142 ASSERT_TRUE(profile()); 143 144 CreateModel(); 145 } 146 147 void CreateModel() { 148 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 149 const BookmarkNode* parent = model->bookmark_bar_node(); 150 const BookmarkNode* folderA = model->AddFolder(parent, 151 parent->child_count(), 152 ASCIIToUTF16("folder")); 153 folderA_ = folderA; 154 model->AddFolder(parent, parent->child_count(), 155 ASCIIToUTF16("sibbling folder")); 156 const BookmarkNode* folderB = model->AddFolder(folderA, 157 folderA->child_count(), 158 ASCIIToUTF16("subfolder 1")); 159 model->AddFolder(folderA, 160 folderA->child_count(), 161 ASCIIToUTF16("subfolder 2")); 162 model->AddURL(folderA, folderA->child_count(), ASCIIToUTF16("title a"), 163 GURL("http://www.google.com/a")); 164 longTitleNode_ = model->AddURL( 165 folderA, folderA->child_count(), 166 ASCIIToUTF16("title super duper long long whoa momma title you betcha"), 167 GURL("http://www.google.com/b")); 168 model->AddURL(folderB, folderB->child_count(), ASCIIToUTF16("t"), 169 GURL("http://www.google.com/c")); 170 171 bar_.reset( 172 [[BookmarkBarControllerChildFolderRedirect alloc] 173 initWithBrowser:browser() 174 initialWidth:300 175 delegate:nil 176 resizeDelegate:nil]); 177 [bar_ loaded:model]; 178 // Make parent frame for bookmark bar then open it. 179 NSRect frame = [[test_window() contentView] frame]; 180 frame = NSMakeRect(frame.origin.x, 181 frame.size.height - chrome::kNTPBookmarkBarHeight, 182 frame.size.width, chrome::kNTPBookmarkBarHeight); 183 NSView* fakeToolbarView = [[[NSView alloc] initWithFrame:frame] 184 autorelease]; 185 [[test_window() contentView] addSubview:fakeToolbarView]; 186 [fakeToolbarView addSubview:[bar_ view]]; 187 [bar_ setBookmarkBarEnabled:YES]; 188 } 189 190 // Remove the bookmark with the long title. 191 void RemoveLongTitleNode() { 192 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 193 model->Remove(longTitleNode_->parent(), 194 longTitleNode_->parent()->GetIndexOf(longTitleNode_)); 195 } 196 197 // Add LOTS of nodes to our model if needed (e.g. scrolling). 198 // Returns the number of nodes added. 199 int AddLotsOfNodes() { 200 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 201 for (int i = 0; i < kLotsOfNodesCount; i++) { 202 model->AddURL(folderA_, folderA_->child_count(), 203 ASCIIToUTF16("repeated title"), 204 GURL("http://www.google.com/repeated/url")); 205 } 206 return kLotsOfNodesCount; 207 } 208 209 // Return a simple BookmarkBarFolderController. 210 BookmarkBarFolderControllerPong* SimpleBookmarkBarFolderController() { 211 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0]; 212 BookmarkBarFolderControllerPong* c = 213 [[BookmarkBarFolderControllerPong alloc] 214 initWithParentButton:parentButton 215 parentController:nil 216 barController:bar_ 217 profile:profile()]; 218 [c window]; // Force nib load. 219 return c; 220 } 221}; 222 223TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) { 224 base::scoped_nsobject<BookmarkBarFolderController> bbfc; 225 bbfc.reset(SimpleBookmarkBarFolderController()); 226 227 // Make sure none of the buttons overlap, that all are inside 228 // the content frame, and their cells are of the proper class. 229 NSArray* buttons = [bbfc buttons]; 230 EXPECT_TRUE([buttons count]); 231 for (unsigned int i = 0; i < ([buttons count]-1); i++) { 232 EXPECT_FALSE(NSContainsRect([[buttons objectAtIndex:i] frame], 233 [[buttons objectAtIndex:i+1] frame])); 234 } 235 Class cellClass = [BookmarkBarFolderButtonCell class]; 236 for (BookmarkButton* button in buttons) { 237 NSRect r = [[bbfc folderView] convertRect:[button frame] fromView:button]; 238 // TODO(jrg): remove this adjustment. 239 NSRect bigger = NSInsetRect([[bbfc folderView] frame], -2, 0); 240 EXPECT_TRUE(NSContainsRect(bigger, r)); 241 EXPECT_TRUE([[button cell] isKindOfClass:cellClass]); 242 } 243 244 // Confirm folder buttons have no tooltip. The important thing 245 // really is that we insure folders and non-folders are treated 246 // differently; not sure of any other generic way to do this. 247 for (BookmarkButton* button in buttons) { 248 if ([button isFolder]) 249 EXPECT_FALSE([button toolTip]); 250 else 251 EXPECT_TRUE([button toolTip]); 252 } 253} 254 255// Make sure closing of the window releases the controller. 256// (e.g. valgrind shouldn't complain if we do this). 257TEST_F(BookmarkBarFolderControllerTest, ReleaseOnClose) { 258 base::scoped_nsobject<BookmarkBarFolderController> bbfc; 259 bbfc.reset(SimpleBookmarkBarFolderController()); 260 EXPECT_TRUE(bbfc.get()); 261 262 [bbfc retain]; // stop the scoped_nsobject from doing anything 263 [[bbfc window] close]; // trigger an autorelease of bbfc.get() 264} 265 266TEST_F(BookmarkBarFolderControllerTest, BasicPosition) { 267 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0]; 268 EXPECT_TRUE(parentButton); 269 270 // If parent is a BookmarkBarController, grow down. 271 base::scoped_nsobject<BookmarkBarFolderController> bbfc; 272 bbfc.reset([[BookmarkBarFolderController alloc] 273 initWithParentButton:parentButton 274 parentController:nil 275 barController:bar_ 276 profile:profile()]); 277 [bbfc window]; 278 NSPoint pt = [bbfc windowTopLeftForWidth:0 height:100]; // screen coords 279 NSPoint buttonOriginInWindow = 280 [parentButton convertRect:[parentButton bounds] 281 toView:nil].origin; 282 NSPoint buttonOriginInScreen = 283 [[parentButton window] convertBaseToScreen:buttonOriginInWindow]; 284 // Within margin 285 EXPECT_LE(std::abs(pt.x - buttonOriginInScreen.x), 286 bookmarks::kBookmarkMenuOverlap + 1); 287 EXPECT_LE(std::abs(pt.y - buttonOriginInScreen.y), 288 bookmarks::kBookmarkMenuOverlap + 1); 289 290 // Make sure we see the window shift left if it spills off the screen 291 pt = [bbfc windowTopLeftForWidth:0 height:100]; 292 NSPoint shifted = [bbfc windowTopLeftForWidth:9999999 height:100]; 293 EXPECT_LT(shifted.x, pt.x); 294 295 // If parent is a BookmarkBarFolderController, grow right. 296 base::scoped_nsobject<BookmarkBarFolderController> bbfc2; 297 bbfc2.reset([[BookmarkBarFolderController alloc] 298 initWithParentButton:[[bbfc buttons] objectAtIndex:0] 299 parentController:bbfc.get() 300 barController:bar_ 301 profile:profile()]); 302 [bbfc2 window]; 303 pt = [bbfc2 windowTopLeftForWidth:0 height:100]; 304 // We're now overlapping the window a bit. 305 EXPECT_EQ(pt.x, NSMaxX([[bbfc.get() window] frame]) - 306 bookmarks::kBookmarkMenuOverlap); 307} 308 309// Confirm we grow right until end of screen, then start growing left 310// until end of screen again, then right. 311TEST_F(BookmarkBarFolderControllerTest, PositionRightLeftRight) { 312 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 313 const BookmarkNode* parent = model->bookmark_bar_node(); 314 const BookmarkNode* folder = parent; 315 316 const int count = 100; 317 int i; 318 // Make some super duper deeply nested folders. 319 for (i = 0; i < count; i++) { 320 folder = model->AddFolder(folder, 0, ASCIIToUTF16("nested folder")); 321 } 322 323 // Setup initial state for opening all folders. 324 folder = parent; 325 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0]; 326 BookmarkBarFolderController* parentController = nil; 327 EXPECT_TRUE(parentButton); 328 329 // Open them all. 330 base::scoped_nsobject<NSMutableArray> folder_controller_array; 331 folder_controller_array.reset([[NSMutableArray array] retain]); 332 for (i=0; i<count; i++) { 333 BookmarkBarFolderControllerNoLevel* bbfcl = 334 [[BookmarkBarFolderControllerNoLevel alloc] 335 initWithParentButton:parentButton 336 parentController:parentController 337 barController:bar_ 338 profile:profile()]; 339 [folder_controller_array addObject:bbfcl]; 340 [bbfcl autorelease]; 341 [bbfcl window]; 342 parentController = bbfcl; 343 parentButton = [[bbfcl buttons] objectAtIndex:0]; 344 } 345 346 // Make vector of all x positions. 347 std::vector<CGFloat> leftPositions; 348 for (i=0; i<count; i++) { 349 CGFloat x = [[[folder_controller_array objectAtIndex:i] window] 350 frame].origin.x; 351 leftPositions.push_back(x); 352 } 353 354 // Make sure the first few grow right. 355 for (i=0; i<3; i++) 356 EXPECT_TRUE(leftPositions[i+1] > leftPositions[i]); 357 358 // Look for the first "grow left". 359 while (leftPositions[i] > leftPositions[i-1]) 360 i++; 361 // Confirm the next few also grow left. 362 int j; 363 for (j=i; j<i+3; j++) 364 EXPECT_TRUE(leftPositions[j+1] < leftPositions[j]); 365 i = j; 366 367 // Finally, confirm we see a "grow right" once more. 368 while (leftPositions[i] < leftPositions[i-1]) 369 i++; 370 // (No need to EXPECT a final "grow right"; if we didn't find one 371 // we'd get a C++ array bounds exception). 372} 373 374TEST_F(BookmarkBarFolderControllerTest, DropDestination) { 375 base::scoped_nsobject<BookmarkBarFolderController> bbfc; 376 bbfc.reset(SimpleBookmarkBarFolderController()); 377 EXPECT_TRUE(bbfc.get()); 378 379 // Confirm "off the top" and "off the bottom" match no buttons. 380 NSPoint p = NSMakePoint(NSMidX([[bbfc folderView] frame]), 10000); 381 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]); 382 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]); 383 p = NSMakePoint(NSMidX([[bbfc folderView] frame]), -1); 384 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]); 385 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]); 386 387 // Confirm "right in the center" (give or take a pixel) is a match, 388 // and confirm "just barely in the button" is not. Anything more 389 // specific seems likely to be tweaked. We don't loop over all 390 // buttons because the scroll view makes them not visible. 391 for (BookmarkButton* button in [bbfc buttons]) { 392 CGFloat x = NSMidX([button frame]); 393 CGFloat y = NSMidY([button frame]); 394 // Somewhere near the center: a match (but only if a folder!) 395 if ([button isFolder]) { 396 EXPECT_EQ(button, 397 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]); 398 EXPECT_EQ(button, 399 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]); 400 EXPECT_FALSE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);; 401 } else { 402 // If not a folder we don't drop into it. 403 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]); 404 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]); 405 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);; 406 } 407 } 408} 409 410TEST_F(BookmarkBarFolderControllerTest, OpenFolder) { 411 base::scoped_nsobject<BookmarkBarFolderController> bbfc; 412 bbfc.reset(SimpleBookmarkBarFolderController()); 413 EXPECT_TRUE(bbfc.get()); 414 415 EXPECT_FALSE([bbfc folderController]); 416 BookmarkButton* button = [[bbfc buttons] objectAtIndex:0]; 417 [bbfc openBookmarkFolderFromButton:button]; 418 id controller = [bbfc folderController]; 419 EXPECT_TRUE(controller); 420 EXPECT_EQ([controller parentButton], button); 421 422 // Click the same one --> it gets closed. 423 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]]; 424 EXPECT_FALSE([bbfc folderController]); 425 426 // Open a new one --> change. 427 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:1]]; 428 EXPECT_NE(controller, [bbfc folderController]); 429 EXPECT_NE([[bbfc folderController] parentButton], button); 430 431 // Close it --> all gone! 432 [bbfc closeBookmarkFolder:nil]; 433 EXPECT_FALSE([bbfc folderController]); 434} 435 436TEST_F(BookmarkBarFolderControllerTest, DeleteOpenFolder) { 437 base::scoped_nsobject<BookmarkBarFolderController> parent_controller( 438 SimpleBookmarkBarFolderController()); 439 440 // Open a folder. 441 EXPECT_FALSE([parent_controller folderController]); 442 BookmarkButton* button = [[parent_controller buttons] objectAtIndex:0]; 443 [parent_controller openBookmarkFolderFromButton:button]; 444 EXPECT_EQ([[parent_controller folderController] parentButton], button); 445 446 // Delete the folder's button - the folder should close. 447 [parent_controller removeButton:0 animate:NO]; 448 EXPECT_FALSE([parent_controller folderController]); 449} 450 451TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) { 452 base::scoped_nsobject<BookmarkBarFolderControllerPong> bbfc; 453 bbfc.reset(SimpleBookmarkBarFolderController()); 454 EXPECT_TRUE(bbfc.get()); 455 [bar_ setChildFolderDelegate:bbfc.get()]; 456 457 EXPECT_FALSE([bbfc childFolderWillShow]); 458 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]]; 459 EXPECT_TRUE([bbfc childFolderWillShow]); 460 461 EXPECT_FALSE([bbfc childFolderWillClose]); 462 [bbfc closeBookmarkFolder:nil]; 463 EXPECT_TRUE([bbfc childFolderWillClose]); 464 465 [bar_ setChildFolderDelegate:nil]; 466} 467 468// Make sure bookmark folders have variable widths. 469TEST_F(BookmarkBarFolderControllerTest, ChildFolderWidth) { 470 base::scoped_nsobject<BookmarkBarFolderController> bbfc; 471 472 bbfc.reset(SimpleBookmarkBarFolderController()); 473 EXPECT_TRUE(bbfc.get()); 474 [bbfc showWindow:bbfc.get()]; 475 CGFloat wideWidth = NSWidth([[bbfc window] frame]); 476 477 RemoveLongTitleNode(); 478 bbfc.reset(SimpleBookmarkBarFolderController()); 479 EXPECT_TRUE(bbfc.get()); 480 CGFloat thinWidth = NSWidth([[bbfc window] frame]); 481 482 // Make sure window size changed as expected. 483 EXPECT_GT(wideWidth, thinWidth); 484} 485 486// Simple scrolling tests. 487// Currently flaky due to a changed definition of the correct menu boundaries. 488TEST_F(BookmarkBarFolderControllerTest, DISABLED_SimpleScroll) { 489 base::scoped_nsobject<BookmarkBarFolderController> bbfc; 490 NSRect screenFrame = [[NSScreen mainScreen] visibleFrame]; 491 CGFloat screenHeight = NSHeight(screenFrame); 492 int nodecount = AddLotsOfNodes(); 493 bbfc.reset(SimpleBookmarkBarFolderController()); 494 EXPECT_TRUE(bbfc.get()); 495 [bbfc showWindow:bbfc.get()]; 496 NSWindow* window = [bbfc window]; 497 498 // The window should be shorter than the screen but reach exactly to the 499 // bottom of the screen since it's scrollable. 500 EXPECT_LT(NSHeight([window frame]), screenHeight); 501 EXPECT_CGFLOAT_EQ(0.0, [window frame].origin.y); 502 503 // Initially, should show scroll-up but not scroll-down. 504 EXPECT_TRUE([bbfc canScrollUp]); 505 EXPECT_FALSE([bbfc canScrollDown]); 506 507 // Scroll up a bit. Make sure the window has gotten bigger each time. 508 // Also, for each scroll, make sure our hit test finds a new button 509 // (to confirm the content area changed). 510 NSView* savedHit = nil; 511 NSScrollView* scrollView = [bbfc scrollView]; 512 513 // Find the next-to-last button showing at the bottom of the window and 514 // use its center for hit testing. 515 BookmarkButton* targetButton = nil; 516 NSPoint scrollPoint = [scrollView documentVisibleRect].origin; 517 for (BookmarkButton* button in [bbfc buttons]) { 518 NSRect buttonFrame = [button frame]; 519 buttonFrame.origin.y -= scrollPoint.y; 520 if (buttonFrame.origin.y < 0.0) 521 break; 522 targetButton = button; 523 } 524 EXPECT_TRUE(targetButton != nil); 525 NSPoint hitPoint = [targetButton frame].origin; 526 hitPoint.x += 50.0; 527 hitPoint.y += (bookmarks::kBookmarkFolderButtonHeight / 2.0) - scrollPoint.y; 528 hitPoint = [targetButton convertPoint:hitPoint toView:scrollView]; 529 530 for (int i = 0; i < 3; i++) { 531 CGFloat height = NSHeight([window frame]); 532 [bbfc performOneScroll:60]; 533 EXPECT_GT(NSHeight([window frame]), height); 534 NSView* hit = [scrollView hitTest:hitPoint]; 535 // We should hit a bookmark button. 536 EXPECT_TRUE([[hit className] isEqualToString:@"BookmarkButton"]); 537 EXPECT_NE(hit, savedHit); 538 savedHit = hit; 539 } 540 541 // Keep scrolling up; make sure we never get bigger than the screen. 542 // Also confirm we never scroll the window off the screen. 543 bool bothAtOnce = false; 544 while ([bbfc canScrollUp]) { 545 [bbfc performOneScroll:60]; 546 EXPECT_TRUE(NSContainsRect([[NSScreen mainScreen] frame], [window frame])); 547 // Make sure, sometime during our scroll, we have the ability to 548 // scroll in either direction. 549 if ([bbfc canScrollUp] && 550 [bbfc canScrollDown]) 551 bothAtOnce = true; 552 } 553 EXPECT_TRUE(bothAtOnce); 554 555 // Once we've scrolled to the end, our only option should be to scroll back. 556 EXPECT_FALSE([bbfc canScrollUp]); 557 EXPECT_TRUE([bbfc canScrollDown]); 558 559 NSRect wholeScreenRect = [[NSScreen mainScreen] frame]; 560 561 // Now scroll down and make sure the window size does not change. 562 // Also confirm we never scroll the window off the screen the other 563 // way. 564 for (int i = 0; i < nodecount+50; ++i) { 565 [bbfc performOneScroll:-60]; 566 // Once we can no longer scroll down the window height changes. 567 if (![bbfc canScrollDown]) 568 break; 569 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame])); 570 } 571 572 EXPECT_GT(NSHeight(wholeScreenRect), NSHeight([window frame])); 573 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame])); 574} 575 576// Folder menu sizing and placement while deleting bookmarks 577// and scrolling tests. 578TEST_F(BookmarkBarFolderControllerTest, MenuPlacementWhileScrollingDeleting) { 579 base::scoped_nsobject<BookmarkBarFolderController> bbfc; 580 AddLotsOfNodes(); 581 bbfc.reset(SimpleBookmarkBarFolderController()); 582 [bbfc showWindow:bbfc.get()]; 583 NSWindow* menuWindow = [bbfc window]; 584 BookmarkBarFolderController* folder = [bar_ folderController]; 585 NSArray* buttons = [folder buttons]; 586 587 // Before scrolling any, delete a bookmark and make sure the window top has 588 // not moved. Pick a button which is near the top and visible. 589 CGFloat oldTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]); 590 BookmarkButton* button = [buttons objectAtIndex:3]; 591 DeleteBookmark(button, profile()); 592 CGFloat newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]); 593 EXPECT_CGFLOAT_EQ(oldTop, newTop); 594 595 // Scroll so that both the top and bottom scroll arrows show, make sure 596 // the top of the window has moved up, then delete a visible button and 597 // make sure the top has not moved. 598 oldTop = newTop; 599 const CGFloat scrollOneBookmark = bookmarks::kBookmarkFolderButtonHeight + 600 bookmarks::kBookmarkVerticalPadding; 601 NSUInteger buttonCounter = 0; 602 NSUInteger extraButtonLimit = 3; 603 while (![bbfc canScrollDown] || extraButtonLimit > 0) { 604 [bbfc performOneScroll:scrollOneBookmark]; 605 ++buttonCounter; 606 if ([bbfc canScrollDown]) 607 --extraButtonLimit; 608 } 609 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]); 610 EXPECT_NE(oldTop, newTop); 611 oldTop = newTop; 612 button = [buttons objectAtIndex:buttonCounter + 3]; 613 DeleteBookmark(button, profile()); 614 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]); 615 EXPECT_CGFLOAT_EQ(oldTop, newTop); 616 617 // Scroll so that the top scroll arrow is no longer showing, make sure 618 // the top of the window has not moved, then delete a visible button and 619 // make sure the top has not moved. 620 while ([bbfc canScrollDown]) { 621 [bbfc performOneScroll:-scrollOneBookmark]; 622 --buttonCounter; 623 } 624 button = [buttons objectAtIndex:buttonCounter + 3]; 625 DeleteBookmark(button, profile()); 626 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]); 627 EXPECT_CGFLOAT_EQ(oldTop - bookmarks::kScrollWindowVerticalMargin, newTop); 628} 629 630// Make sure that we return the correct browser window. 631TEST_F(BookmarkBarFolderControllerTest, BrowserWindow) { 632 base::scoped_nsobject<BookmarkBarFolderController> controller( 633 SimpleBookmarkBarFolderController()); 634 EXPECT_EQ([bar_ browserWindow], [controller browserWindow]); 635} 636 637@interface FakedDragInfo : NSObject { 638@public 639 NSPoint dropLocation_; 640 NSDragOperation sourceMask_; 641} 642@property (nonatomic, assign) NSPoint dropLocation; 643- (void)setDraggingSourceOperationMask:(NSDragOperation)mask; 644@end 645 646@implementation FakedDragInfo 647 648@synthesize dropLocation = dropLocation_; 649 650- (id)init { 651 if ((self = [super init])) { 652 dropLocation_ = NSZeroPoint; 653 sourceMask_ = NSDragOperationMove; 654 } 655 return self; 656} 657 658// NSDraggingInfo protocol functions. 659 660- (id)draggingPasteboard { 661 return self; 662} 663 664- (id)draggingSource { 665 return self; 666} 667 668- (NSDragOperation)draggingSourceOperationMask { 669 return sourceMask_; 670} 671 672- (NSPoint)draggingLocation { 673 return dropLocation_; 674} 675 676// Other functions. 677 678- (void)setDraggingSourceOperationMask:(NSDragOperation)mask { 679 sourceMask_ = mask; 680} 681 682@end 683 684 685class BookmarkBarFolderControllerMenuTest : public CocoaProfileTest { 686 public: 687 base::scoped_nsobject<NSView> parent_view_; 688 base::scoped_nsobject<ViewResizerPong> resizeDelegate_; 689 base::scoped_nsobject<BookmarkBarController> bar_; 690 691 virtual void SetUp() { 692 CocoaProfileTest::SetUp(); 693 ASSERT_TRUE(browser()); 694 695 resizeDelegate_.reset([[ViewResizerPong alloc] init]); 696 NSRect parent_frame = NSMakeRect(0, 0, 800, 50); 697 parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]); 698 [parent_view_ setHidden:YES]; 699 bar_.reset([[BookmarkBarController alloc] 700 initWithBrowser:browser() 701 initialWidth:NSWidth(parent_frame) 702 delegate:nil 703 resizeDelegate:resizeDelegate_.get()]); 704 InstallAndToggleBar(bar_.get()); 705 } 706 707 void InstallAndToggleBar(BookmarkBarController* bar) { 708 // Force loading of the nib. 709 [bar view]; 710 // Awkwardness to look like we've been installed. 711 [parent_view_ addSubview:[bar view]]; 712 NSRect frame = [[[bar view] superview] frame]; 713 frame.origin.y = 400; 714 [[[bar view] superview] setFrame:frame]; 715 716 // Make sure it's on in a window so viewDidMoveToWindow is called 717 [[test_window() contentView] addSubview:parent_view_]; 718 719 // Make sure it's open so certain things aren't no-ops. 720 [bar updateState:BookmarkBar::SHOW 721 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 722 } 723}; 724 725TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) { 726 WithNoAnimation at_all; 727 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 728 const BookmarkNode* root = model->bookmark_bar_node(); 729 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b " 730 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b " 731 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 732 test::AddNodesFromModelString(model, root, model_string); 733 734 // Validate initial model. 735 std::string actualModelString = test::ModelStringFromNode(root); 736 EXPECT_EQ(model_string, actualModelString); 737 738 // Pop up a folder menu and drag in a button from the bar. 739 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"]; 740 NSRect oldToFolderFrame = [toFolder frame]; 741 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:) 742 withObject:toFolder]; 743 BookmarkBarFolderController* folderController = [bar_ folderController]; 744 EXPECT_TRUE(folderController); 745 NSWindow* toWindow = [folderController window]; 746 EXPECT_TRUE(toWindow); 747 NSRect oldToWindowFrame = [toWindow frame]; 748 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder 749 // so it should end up below the target bookmark. 750 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"]; 751 ASSERT_TRUE(draggedButton); 752 CGFloat horizontalShift = 753 NSWidth([draggedButton frame]) + bookmarks::kBookmarkHorizontalPadding; 754 BookmarkButton* targetButton = 755 [folderController buttonWithTitleEqualTo:@"2f1b"]; 756 ASSERT_TRUE(targetButton); 757 [folderController dragButton:draggedButton 758 to:[targetButton center] 759 copy:NO]; 760 // The button should have landed just after "2f1b". 761 const std::string expected_string("2f:[ 2f1b 1b 2f2f:[ 2f2f1b " 762 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ " 763 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 764 EXPECT_EQ(expected_string, test::ModelStringFromNode(root)); 765 766 // Verify the window still appears by looking for its controller. 767 EXPECT_TRUE([bar_ folderController]); 768 769 // Gather the new frames. 770 NSRect newToFolderFrame = [toFolder frame]; 771 NSRect newToWindowFrame = [toWindow frame]; 772 // The toFolder should have shifted left horizontally but not vertically. 773 NSRect expectedToFolderFrame = 774 NSOffsetRect(oldToFolderFrame, -horizontalShift, 0); 775 EXPECT_NSRECT_EQ(expectedToFolderFrame, newToFolderFrame); 776 // The toWindow should have shifted left horizontally, down vertically, 777 // and grown vertically. 778 NSRect expectedToWindowFrame = oldToWindowFrame; 779 expectedToWindowFrame.origin.x -= horizontalShift; 780 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight; 781 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight; 782 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame); 783 784 // Check button spacing. 785 [folderController validateMenuSpacing]; 786 787 // Move the button back to the bar at the beginning. 788 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"]; 789 ASSERT_TRUE(draggedButton); 790 targetButton = [bar_ buttonWithTitleEqualTo:@"2f"]; 791 ASSERT_TRUE(targetButton); 792 [bar_ dragButton:draggedButton 793 to:[targetButton left] 794 copy:NO]; 795 EXPECT_EQ(model_string, test::ModelStringFromNode(root)); 796 // Don't check the folder window since it's not supposed to be showing. 797} 798 799TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) { 800 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 801 const BookmarkNode* root = model->bookmark_bar_node(); 802 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b " 803 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b " 804 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 805 test::AddNodesFromModelString(model, root, model_string); 806 807 // Validate initial model. 808 std::string actualModelString = test::ModelStringFromNode(root); 809 EXPECT_EQ(model_string, actualModelString); 810 811 // Pop up a folder menu and copy in a button from the bar. 812 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"]; 813 ASSERT_TRUE(toFolder); 814 NSRect oldToFolderFrame = [toFolder frame]; 815 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:) 816 withObject:toFolder]; 817 BookmarkBarFolderController* folderController = [bar_ folderController]; 818 EXPECT_TRUE(folderController); 819 NSWindow* toWindow = [folderController window]; 820 EXPECT_TRUE(toWindow); 821 NSRect oldToWindowFrame = [toWindow frame]; 822 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder 823 // so it should end up below the target bookmark. 824 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"]; 825 ASSERT_TRUE(draggedButton); 826 BookmarkButton* targetButton = 827 [folderController buttonWithTitleEqualTo:@"2f1b"]; 828 ASSERT_TRUE(targetButton); 829 [folderController dragButton:draggedButton 830 to:[targetButton center] 831 copy:YES]; 832 // The button should have landed just after "2f1b". 833 const std::string expected_1("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b " 834 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ " 835 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 836 EXPECT_EQ(expected_1, test::ModelStringFromNode(root)); 837 838 // Gather the new frames. 839 NSRect newToFolderFrame = [toFolder frame]; 840 NSRect newToWindowFrame = [toWindow frame]; 841 // The toFolder should have shifted. 842 EXPECT_NSRECT_EQ(oldToFolderFrame, newToFolderFrame); 843 // The toWindow should have shifted down vertically and grown vertically. 844 NSRect expectedToWindowFrame = oldToWindowFrame; 845 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight; 846 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight; 847 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame); 848 849 // Copy the button back to the bar after "3b". 850 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"]; 851 ASSERT_TRUE(draggedButton); 852 targetButton = [bar_ buttonWithTitleEqualTo:@"4f"]; 853 ASSERT_TRUE(targetButton); 854 [bar_ dragButton:draggedButton 855 to:[targetButton left] 856 copy:YES]; 857 const std::string expected_2("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b " 858 "2f2f2b 2f2f3b ] 2f3b ] 3b 1b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ " 859 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 860 EXPECT_EQ(expected_2, test::ModelStringFromNode(root)); 861} 862 863TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) { 864 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 865 const BookmarkNode* root = model->bookmark_bar_node(); 866 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b " 867 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b " 868 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 869 test::AddNodesFromModelString(model, root, model_string); 870 871 // Validate initial model. 872 std::string actualModelString = test::ModelStringFromNode(root); 873 EXPECT_EQ(model_string, actualModelString); 874 875 // Pop up a folder menu and a subfolder menu. 876 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"]; 877 ASSERT_TRUE(toFolder); 878 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:) 879 withObject:toFolder]; 880 BookmarkBarFolderController* folderController = [bar_ folderController]; 881 EXPECT_TRUE(folderController); 882 NSWindow* toWindow = [folderController window]; 883 EXPECT_TRUE(toWindow); 884 NSRect oldToWindowFrame = [toWindow frame]; 885 BookmarkButton* toSubfolder = 886 [folderController buttonWithTitleEqualTo:@"4f2f"]; 887 ASSERT_TRUE(toSubfolder); 888 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:) 889 withObject:toSubfolder]; 890 BookmarkBarFolderController* subfolderController = 891 [folderController folderController]; 892 EXPECT_TRUE(subfolderController); 893 NSWindow* toSubwindow = [subfolderController window]; 894 EXPECT_TRUE(toSubwindow); 895 NSRect oldToSubwindowFrame = [toSubwindow frame]; 896 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder 897 // so it should end up below the target bookmark. 898 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"5b"]; 899 ASSERT_TRUE(draggedButton); 900 BookmarkButton* targetButton = 901 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"]; 902 ASSERT_TRUE(targetButton); 903 [subfolderController dragButton:draggedButton 904 to:[targetButton center] 905 copy:NO]; 906 // The button should have landed just after "2f". 907 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b " 908 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ " 909 "4f2f1b 4f2f2b 4f2f3b 5b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] "); 910 EXPECT_EQ(expected_string, test::ModelStringFromNode(root)); 911 912 // Check button spacing. 913 [folderController validateMenuSpacing]; 914 [subfolderController validateMenuSpacing]; 915 916 // Check the window layouts. The folder window should not have changed, 917 // but the subfolder window should have shifted vertically and grown. 918 NSRect newToWindowFrame = [toWindow frame]; 919 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame); 920 NSRect newToSubwindowFrame = [toSubwindow frame]; 921 NSRect expectedToSubwindowFrame = oldToSubwindowFrame; 922 expectedToSubwindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight; 923 expectedToSubwindowFrame.size.height += 924 bookmarks::kBookmarkFolderButtonHeight; 925 EXPECT_NSRECT_EQ(expectedToSubwindowFrame, newToSubwindowFrame); 926} 927 928TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) { 929 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 930 const BookmarkNode* root = model->bookmark_bar_node(); 931 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b " 932 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b " 933 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 934 test::AddNodesFromModelString(model, root, model_string); 935 936 // Validate initial model. 937 std::string actualModelString = test::ModelStringFromNode(root); 938 EXPECT_EQ(model_string, actualModelString); 939 940 // Pop up a folder menu. 941 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"]; 942 ASSERT_TRUE(toFolder); 943 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:) 944 withObject:toFolder]; 945 BookmarkBarFolderController* folderController = [bar_ folderController]; 946 EXPECT_TRUE(folderController); 947 NSWindow* toWindow = [folderController window]; 948 EXPECT_TRUE(toWindow); 949 NSRect oldToWindowFrame = [toWindow frame]; 950 // Drag a folder button to the top within the same parent. 951 BookmarkButton* draggedButton = 952 [folderController buttonWithTitleEqualTo:@"4f2f"]; 953 ASSERT_TRUE(draggedButton); 954 BookmarkButton* targetButton = 955 [folderController buttonWithTitleEqualTo:@"4f1f"]; 956 ASSERT_TRUE(targetButton); 957 [folderController dragButton:draggedButton 958 to:[targetButton top] 959 copy:NO]; 960 // The button should have landed above "4f1f". 961 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b " 962 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f2f:[ 4f2f1b 4f2f2b 4f2f3b ] " 963 "4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 964 EXPECT_EQ(expected_string, test::ModelStringFromNode(root)); 965 966 // The window should not have gone away. 967 EXPECT_TRUE([bar_ folderController]); 968 969 // The folder window should not have changed. 970 NSRect newToWindowFrame = [toWindow frame]; 971 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame); 972 973 // Check button spacing. 974 [folderController validateMenuSpacing]; 975} 976 977TEST_F(BookmarkBarFolderControllerMenuTest, DragParentOntoChild) { 978 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 979 const BookmarkNode* root = model->bookmark_bar_node(); 980 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b " 981 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b " 982 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 983 test::AddNodesFromModelString(model, root, model_string); 984 985 // Validate initial model. 986 std::string actualModelString = test::ModelStringFromNode(root); 987 EXPECT_EQ(model_string, actualModelString); 988 989 // Pop up a folder menu. 990 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"]; 991 ASSERT_TRUE(toFolder); 992 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:) 993 withObject:toFolder]; 994 BookmarkBarFolderController* folderController = [bar_ folderController]; 995 EXPECT_TRUE(folderController); 996 NSWindow* toWindow = [folderController window]; 997 EXPECT_TRUE(toWindow); 998 // Drag a folder button to one of its children. 999 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"4f"]; 1000 ASSERT_TRUE(draggedButton); 1001 BookmarkButton* targetButton = 1002 [folderController buttonWithTitleEqualTo:@"4f3f"]; 1003 ASSERT_TRUE(targetButton); 1004 [folderController dragButton:draggedButton 1005 to:[targetButton top] 1006 copy:NO]; 1007 // The model should not have changed. 1008 EXPECT_EQ(model_string, test::ModelStringFromNode(root)); 1009 1010 // Check button spacing. 1011 [folderController validateMenuSpacing]; 1012} 1013 1014TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) { 1015 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1016 const BookmarkNode* root = model->bookmark_bar_node(); 1017 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b " 1018 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b " 1019 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 1020 test::AddNodesFromModelString(model, root, model_string); 1021 1022 // Validate initial model. 1023 std::string actualModelString = test::ModelStringFromNode(root); 1024 EXPECT_EQ(model_string, actualModelString); 1025 1026 // Pop up a folder menu and a subfolder menu. 1027 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"]; 1028 ASSERT_TRUE(toFolder); 1029 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:) 1030 withObject:toFolder]; 1031 BookmarkBarFolderController* folderController = [bar_ folderController]; 1032 EXPECT_TRUE(folderController); 1033 BookmarkButton* toSubfolder = 1034 [folderController buttonWithTitleEqualTo:@"4f2f"]; 1035 ASSERT_TRUE(toSubfolder); 1036 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:) 1037 withObject:toSubfolder]; 1038 BookmarkBarFolderController* subfolderController = 1039 [folderController folderController]; 1040 EXPECT_TRUE(subfolderController); 1041 1042 // Drag a subfolder bookmark to the parent folder. 1043 BookmarkButton* draggedButton = 1044 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"]; 1045 ASSERT_TRUE(draggedButton); 1046 BookmarkButton* targetButton = 1047 [folderController buttonWithTitleEqualTo:@"4f2f"]; 1048 ASSERT_TRUE(targetButton); 1049 [folderController dragButton:draggedButton 1050 to:[targetButton top] 1051 copy:NO]; 1052 // The button should have landed above "4f2f". 1053 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b " 1054 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f3b 4f2f:[ " 1055 "4f2f1b 4f2f2b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b "); 1056 EXPECT_EQ(expected_string, test::ModelStringFromNode(root)); 1057 1058 // Check button spacing. 1059 [folderController validateMenuSpacing]; 1060 // The window should not have gone away. 1061 EXPECT_TRUE([bar_ folderController]); 1062 // The subfolder should have gone away. 1063 EXPECT_FALSE([folderController folderController]); 1064} 1065 1066TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) { 1067 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1068 const BookmarkNode* root = model->bookmark_bar_node(); 1069 const std::string model_string( 1070 "a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c "); 1071 test::AddNodesFromModelString(model, root, model_string); 1072 1073 // Validate initial model. 1074 std::string actualModelString = test::ModelStringFromNode(root); 1075 EXPECT_EQ(model_string, actualModelString); 1076 1077 // Pop up a folder menu. 1078 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"b"]; 1079 ASSERT_TRUE(toFolder); 1080 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:) 1081 withObject:toFolder]; 1082 BookmarkBarFolderController* folderController = [bar_ folderController]; 1083 EXPECT_TRUE(folderController); 1084 NSWindow* toWindow = [folderController window]; 1085 EXPECT_TRUE(toWindow); 1086 CGFloat oldWidth = NSWidth([toWindow frame]); 1087 // Drag the bookmark with a long name to the folder. 1088 BookmarkButton* draggedButton = 1089 [bar_ buttonWithTitleEqualTo:@"reallyReallyLongBookmarkName"]; 1090 ASSERT_TRUE(draggedButton); 1091 BookmarkButton* targetButton = 1092 [folderController buttonWithTitleEqualTo:@"b1"]; 1093 ASSERT_TRUE(targetButton); 1094 [folderController dragButton:draggedButton 1095 to:[targetButton center] 1096 copy:NO]; 1097 // Verify the model change. 1098 const std::string expected_string( 1099 "a b:[ b1 reallyReallyLongBookmarkName b2 b3 ] c "); 1100 EXPECT_EQ(expected_string, test::ModelStringFromNode(root)); 1101 // Verify the window grew. Just test a reasonable width gain. 1102 CGFloat newWidth = NSWidth([toWindow frame]); 1103 EXPECT_LT(oldWidth + 30.0, newWidth); 1104} 1105 1106TEST_F(BookmarkBarFolderControllerMenuTest, MoveRemoveAddButtons) { 1107 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1108 const BookmarkNode* root = model->bookmark_bar_node(); 1109 const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b "); 1110 test::AddNodesFromModelString(model, root, model_string); 1111 1112 // Validate initial model. 1113 std::string actualModelString = test::ModelStringFromNode(root); 1114 EXPECT_EQ(model_string, actualModelString); 1115 1116 // Pop up a folder menu. 1117 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"]; 1118 ASSERT_TRUE(toFolder); 1119 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:) 1120 withObject:toFolder]; 1121 BookmarkBarFolderController* folder = [bar_ folderController]; 1122 EXPECT_TRUE(folder); 1123 1124 // Remember how many buttons are showing. 1125 NSArray* buttons = [folder buttons]; 1126 NSUInteger oldDisplayedButtons = [buttons count]; 1127 1128 // Move a button around a bit. 1129 [folder moveButtonFromIndex:0 toIndex:2]; 1130 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:0] title]); 1131 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:1] title]); 1132 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:2] title]); 1133 EXPECT_EQ(oldDisplayedButtons, [buttons count]); 1134 [folder moveButtonFromIndex:2 toIndex:0]; 1135 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]); 1136 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]); 1137 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]); 1138 EXPECT_EQ(oldDisplayedButtons, [buttons count]); 1139 1140 // Add a couple of buttons. 1141 const BookmarkNode* node = root->GetChild(2); // Purloin an existing node. 1142 [folder addButtonForNode:node atIndex:0]; 1143 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]); 1144 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]); 1145 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]); 1146 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]); 1147 EXPECT_EQ(oldDisplayedButtons + 1, [buttons count]); 1148 node = root->GetChild(3); 1149 [folder addButtonForNode:node atIndex:-1]; 1150 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]); 1151 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]); 1152 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]); 1153 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]); 1154 EXPECT_NSEQ(@"4b", [[buttons objectAtIndex:4] title]); 1155 EXPECT_EQ(oldDisplayedButtons + 2, [buttons count]); 1156 1157 // Remove a couple of buttons. 1158 [folder removeButton:4 animate:NO]; 1159 [folder removeButton:1 animate:NO]; 1160 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]); 1161 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]); 1162 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]); 1163 EXPECT_EQ(oldDisplayedButtons, [buttons count]); 1164 1165 // Check button spacing. 1166 [folder validateMenuSpacing]; 1167} 1168 1169TEST_F(BookmarkBarFolderControllerMenuTest, RemoveLastButtonOtherBookmarks) { 1170 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1171 const BookmarkNode* otherBookmarks = model->other_node(); 1172 1173 BookmarkButton* otherButton = [bar_ otherBookmarksButton]; 1174 ASSERT_TRUE(otherButton); 1175 1176 // Open the folder to get the folderController_. 1177 [[otherButton target] openBookmarkFolderFromButton:otherButton]; 1178 BookmarkBarFolderController* folder = [bar_ folderController]; 1179 EXPECT_TRUE(folder); 1180 1181 // Initially there is only (empty) placeholder button, hence buttonCount 1182 // should be 1. 1183 NSArray* buttons = [folder buttons]; 1184 EXPECT_TRUE(buttons); 1185 EXPECT_EQ(1U, [buttons count]); 1186 1187 // Add a new bookmark into 'Other bookmarks' folder. 1188 model->AddURL(otherBookmarks, otherBookmarks->child_count(), 1189 ASCIIToUTF16("TheOther"), 1190 GURL("http://www.other.com")); 1191 1192 // buttonCount still should be 1, as we remove the (empty) placeholder button 1193 // when adding a new button to an empty folder. 1194 EXPECT_EQ(1U, [buttons count]); 1195 1196 // Now we have only 1 button; remove it so that 'Other bookmarks' folder 1197 // is hidden. 1198 [folder removeButton:0 animate:NO]; 1199 EXPECT_EQ(0U, [buttons count]); 1200 1201 // 'Other bookmarks' folder gets closed once we remove the last button. Hence 1202 // folderController_ should be NULL. 1203 EXPECT_FALSE([bar_ folderController]); 1204} 1205 1206TEST_F(BookmarkBarFolderControllerMenuTest, ControllerForNode) { 1207 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1208 const BookmarkNode* root = model->bookmark_bar_node(); 1209 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b "); 1210 test::AddNodesFromModelString(model, root, model_string); 1211 1212 // Validate initial model. 1213 std::string actualModelString = test::ModelStringFromNode(root); 1214 EXPECT_EQ(model_string, actualModelString); 1215 1216 // Find the main bar controller. 1217 const void* expectedController = bar_; 1218 const void* actualController = [bar_ controllerForNode:root]; 1219 EXPECT_EQ(expectedController, actualController); 1220 1221 // Pop up the folder menu. 1222 BookmarkButton* targetFolder = [bar_ buttonWithTitleEqualTo:@"2f"]; 1223 ASSERT_TRUE(targetFolder); 1224 [[targetFolder target] 1225 performSelector:@selector(openBookmarkFolderFromButton:) 1226 withObject:targetFolder]; 1227 BookmarkBarFolderController* folder = [bar_ folderController]; 1228 EXPECT_TRUE(folder); 1229 1230 // Find the folder controller using the folder controller. 1231 const BookmarkNode* targetNode = root->GetChild(1); 1232 expectedController = folder; 1233 actualController = [bar_ controllerForNode:targetNode]; 1234 EXPECT_EQ(expectedController, actualController); 1235 1236 // Find the folder controller from the bar. 1237 actualController = [folder controllerForNode:targetNode]; 1238 EXPECT_EQ(expectedController, actualController); 1239} 1240 1241TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) { 1242 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1243 const BookmarkNode* root = model->bookmark_bar_node(); 1244 const std::string model_string("1b 2b 3b "); 1245 test::AddNodesFromModelString(model, root, model_string); 1246 1247 // Validate initial model. 1248 std::string actualModelString = test::ModelStringFromNode(root); 1249 EXPECT_EQ(model_string, actualModelString); 1250 1251 const BookmarkNode* parent = model->bookmark_bar_node(); 1252 const BookmarkNode* folder = model->AddFolder(parent, 1253 parent->child_count(), 1254 ASCIIToUTF16("BIG")); 1255 1256 // Pop open the new folder window and verify it has one (empty) item. 1257 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"]; 1258 [[button target] performSelector:@selector(openBookmarkFolderFromButton:) 1259 withObject:button]; 1260 BookmarkBarFolderController* folderController = [bar_ folderController]; 1261 EXPECT_TRUE(folderController); 1262 NSWindow* folderWindow = [folderController window]; 1263 EXPECT_TRUE(folderWindow); 1264 CGFloat expectedHeight = (CGFloat)bookmarks::kBookmarkFolderButtonHeight + 1265 (2*bookmarks::kBookmarkVerticalPadding); 1266 NSRect windowFrame = [folderWindow frame]; 1267 CGFloat windowHeight = NSHeight(windowFrame); 1268 EXPECT_CGFLOAT_EQ(expectedHeight, windowHeight); 1269 EXPECT_FALSE([folderController canScrollUp]); 1270 EXPECT_FALSE([folderController canScrollDown]); 1271 1272 // Now add a real bookmark and reopen. 1273 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("a"), 1274 GURL("http://a.com/")); 1275 folderController = [bar_ folderController]; 1276 EXPECT_TRUE(folderController); 1277 NSView* folderView = [folderController folderView]; 1278 EXPECT_TRUE(folderView); 1279 NSRect menuFrame = [folderView frame]; 1280 NSView* visibleView = [folderController visibleView]; 1281 NSRect visibleFrame = [visibleView frame]; 1282 NSScrollView* scrollView = [folderController scrollView]; 1283 NSRect scrollFrame = [scrollView frame]; 1284 1285 // Determine the margins between the scroll frame and the visible frame. 1286 CGFloat widthDelta = NSWidth(visibleFrame) - NSWidth(scrollFrame); 1287 1288 CGFloat menuHeight = NSHeight(menuFrame); 1289 EXPECT_CGFLOAT_EQ(expectedHeight, menuHeight); 1290 CGFloat scrollerWidth = NSWidth(scrollFrame); 1291 button = [folderController buttonWithTitleEqualTo:@"a"]; 1292 CGFloat buttonWidth = NSWidth([button frame]); 1293 EXPECT_CGFLOAT_EQ(scrollerWidth, buttonWidth); 1294 CGFloat visibleWidth = NSWidth(visibleFrame); 1295 EXPECT_CGFLOAT_EQ(visibleWidth - widthDelta, buttonWidth); 1296 EXPECT_LT(scrollerWidth, NSWidth([folderView frame])); 1297 1298 // Add a wider bookmark and make sure the button widths match. 1299 int reallyWideButtonNumber = folder->child_count(); 1300 model->AddURL(folder, reallyWideButtonNumber, 1301 ASCIIToUTF16("A really, really, really, really, really, " 1302 "really long name"), 1303 GURL("http://www.google.com/a")); 1304 BookmarkButton* bigButton = 1305 [folderController buttonWithTitleEqualTo: 1306 @"A really, really, really, really, really, really long name"]; 1307 EXPECT_TRUE(bigButton); 1308 CGFloat buttonWidthB = NSWidth([bigButton frame]); 1309 EXPECT_LT(buttonWidth, buttonWidthB); 1310 // Add a bunch of bookmarks until the window becomes scrollable, then check 1311 // for a scroll up arrow. 1312 NSUInteger tripWire = 0; // Prevent a runaway. 1313 while (![folderController canScrollUp] && ++tripWire < 1000) { 1314 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("B"), 1315 GURL("http://b.com/")); 1316 } 1317 EXPECT_TRUE([folderController canScrollUp]); 1318 1319 // Remove one bookmark and make sure the scroll down arrow has been removed. 1320 // We'll remove the really long node so we can see if the buttons get resized. 1321 scrollerWidth = NSWidth([folderView frame]); 1322 buttonWidth = NSWidth([button frame]); 1323 model->Remove(folder, reallyWideButtonNumber); 1324 EXPECT_FALSE([folderController canScrollUp]); 1325 EXPECT_FALSE([folderController canScrollDown]); 1326 1327 // Check the size. It should have reduced. 1328 EXPECT_GT(scrollerWidth, NSWidth([folderView frame])); 1329 EXPECT_GT(buttonWidth, NSWidth([button frame])); 1330 1331 // Check button spacing. 1332 [folderController validateMenuSpacing]; 1333} 1334 1335// See http://crbug.com/46101 1336TEST_F(BookmarkBarFolderControllerMenuTest, HoverThenDeleteBookmark) { 1337 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1338 const BookmarkNode* root = model->bookmark_bar_node(); 1339 const BookmarkNode* folder = model->AddFolder(root, 1340 root->child_count(), 1341 ASCIIToUTF16("BIG")); 1342 for (int i = 0; i < kLotsOfNodesCount; i++) 1343 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("kid"), 1344 GURL("http://kid.com/smile")); 1345 1346 // Pop open the new folder window and hover one of its kids. 1347 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"]; 1348 [[button target] performSelector:@selector(openBookmarkFolderFromButton:) 1349 withObject:button]; 1350 BookmarkBarFolderController* bbfc = [bar_ folderController]; 1351 NSArray* buttons = [bbfc buttons]; 1352 1353 // Hover over a button and verify that it is now known. 1354 button = [buttons objectAtIndex:3]; 1355 BookmarkButton* buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn]; 1356 EXPECT_FALSE(buttonThatMouseIsIn); 1357 [bbfc mouseEnteredButton:button event:nil]; 1358 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn]; 1359 EXPECT_EQ(button, buttonThatMouseIsIn); 1360 1361 // Delete the bookmark and verify that it is now not known. 1362 model->Remove(folder, 3); 1363 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn]; 1364 EXPECT_FALSE(buttonThatMouseIsIn); 1365} 1366 1367// Just like a BookmarkBarFolderController but intercedes when providing 1368// pasteboard drag data. 1369@interface BookmarkBarFolderControllerDragData : BookmarkBarFolderController { 1370 const BookmarkNode* dragDataNode_; // Weak 1371} 1372- (void)setDragDataNode:(const BookmarkNode*)node; 1373@end 1374 1375@implementation BookmarkBarFolderControllerDragData 1376 1377- (id)initWithParentButton:(BookmarkButton*)button 1378 parentController:(BookmarkBarFolderController*)parentController 1379 barController:(BookmarkBarController*)barController 1380 profile:(Profile*)profile { 1381 if ((self = [super initWithParentButton:button 1382 parentController:parentController 1383 barController:barController 1384 profile:profile])) { 1385 dragDataNode_ = NULL; 1386 } 1387 return self; 1388} 1389 1390- (void)setDragDataNode:(const BookmarkNode*)node { 1391 dragDataNode_ = node; 1392} 1393 1394- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData { 1395 std::vector<const BookmarkNode*> dragDataNodes; 1396 if(dragDataNode_) { 1397 dragDataNodes.push_back(dragDataNode_); 1398 } 1399 return dragDataNodes; 1400} 1401 1402@end 1403 1404TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) { 1405 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1406 const BookmarkNode* root = model->bookmark_bar_node(); 1407 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1408 "2f3b ] 3b 4b "); 1409 test::AddNodesFromModelString(model, root, model_string); 1410 const BookmarkNode* other = model->other_node(); 1411 const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] " 1412 "O4f:[ O4f1b O4f2f ] 05b "); 1413 test::AddNodesFromModelString(model, other, other_string); 1414 1415 // Validate initial model. 1416 std::string actual = test::ModelStringFromNode(root); 1417 EXPECT_EQ(model_string, actual); 1418 actual = test::ModelStringFromNode(other); 1419 EXPECT_EQ(other_string, actual); 1420 1421 // Pop open a folder. 1422 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"]; 1423 base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController; 1424 folderController.reset([[BookmarkBarFolderControllerDragData alloc] 1425 initWithParentButton:button 1426 parentController:nil 1427 barController:bar_ 1428 profile:profile()]); 1429 BookmarkButton* targetButton = 1430 [folderController buttonWithTitleEqualTo:@"2f1b"]; 1431 ASSERT_TRUE(targetButton); 1432 1433 // Gen up some dragging data. 1434 const BookmarkNode* newNode = other->GetChild(2); 1435 [folderController setDragDataNode:newNode]; 1436 base::scoped_nsobject<FakedDragInfo> dragInfo([[FakedDragInfo alloc] init]); 1437 [dragInfo setDropLocation:[targetButton top]]; 1438 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()]; 1439 1440 // Verify the model. 1441 const std::string expected("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ 2f2f1b " 1442 "2f2f2b 2f2f3b ] 2f3b ] 3b 4b "); 1443 actual = test::ModelStringFromNode(root); 1444 EXPECT_EQ(expected, actual); 1445 1446 // Now drag over a folder button. 1447 targetButton = [folderController buttonWithTitleEqualTo:@"2f2f"]; 1448 ASSERT_TRUE(targetButton); 1449 newNode = other->GetChild(2); // Should be O4f. 1450 EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f")); 1451 [folderController setDragDataNode:newNode]; 1452 [dragInfo setDropLocation:[targetButton center]]; 1453 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()]; 1454 1455 // Verify the model. 1456 const std::string expectedA("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ " 1457 "2f2f1b 2f2f2b 2f2f3b O4f:[ O4f1b O4f2f ] ] " 1458 "2f3b ] 3b 4b "); 1459 actual = test::ModelStringFromNode(root); 1460 EXPECT_EQ(expectedA, actual); 1461 1462 // Check button spacing. 1463 [folderController validateMenuSpacing]; 1464} 1465 1466TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkDataToTrash) { 1467 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1468 const BookmarkNode* root = model->bookmark_bar_node(); 1469 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1470 "2f3b ] 3b 4b "); 1471 test::AddNodesFromModelString(model, root, model_string); 1472 1473 // Validate initial model. 1474 std::string actual = test::ModelStringFromNode(root); 1475 EXPECT_EQ(model_string, actual); 1476 1477 const BookmarkNode* folderNode = root->GetChild(1); 1478 int oldFolderChildCount = folderNode->child_count(); 1479 1480 // Pop open a folder. 1481 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"]; 1482 base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController; 1483 folderController.reset([[BookmarkBarFolderControllerDragData alloc] 1484 initWithParentButton:button 1485 parentController:nil 1486 barController:bar_ 1487 profile:profile()]); 1488 1489 // Drag a button to the trash. 1490 BookmarkButton* buttonToDelete = 1491 [folderController buttonWithTitleEqualTo:@"2f1b"]; 1492 ASSERT_TRUE(buttonToDelete); 1493 EXPECT_TRUE([folderController canDragBookmarkButtonToTrash:buttonToDelete]); 1494 [folderController didDragBookmarkToTrash:buttonToDelete]; 1495 1496 // There should be one less button in the folder. 1497 int newFolderChildCount = folderNode->child_count(); 1498 EXPECT_EQ(oldFolderChildCount - 1, newFolderChildCount); 1499 // Verify the model. 1500 const std::string expected("1b 2f:[ 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1501 "2f3b ] 3b 4b "); 1502 actual = test::ModelStringFromNode(root); 1503 EXPECT_EQ(expected, actual); 1504 1505 // Check button spacing. 1506 [folderController validateMenuSpacing]; 1507} 1508 1509TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) { 1510 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1511 const BookmarkNode* root = model->bookmark_bar_node(); 1512 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1513 "2f3b ] 3b 4b "); 1514 test::AddNodesFromModelString(model, root, model_string); 1515 1516 // Validate initial model. 1517 std::string actual = test::ModelStringFromNode(root); 1518 EXPECT_EQ(model_string, actual); 1519 1520 // Pop open a folder. 1521 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"]; 1522 [[button target] performSelector:@selector(openBookmarkFolderFromButton:) 1523 withObject:button]; 1524 BookmarkBarFolderController* folderController = [bar_ folderController]; 1525 EXPECT_TRUE(folderController); 1526 NSArray* buttons = [folderController buttons]; 1527 EXPECT_TRUE(buttons); 1528 1529 // Remember how many buttons are showing. 1530 int oldDisplayedButtons = [buttons count]; 1531 1532 BookmarkButton* targetButton = 1533 [folderController buttonWithTitleEqualTo:@"2f1b"]; 1534 ASSERT_TRUE(targetButton); 1535 1536 NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/", 1537 @"http://www.b.com/", nil]; 1538 NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil]; 1539 [folderController addURLs:urls withTitles:titles at:[targetButton top]]; 1540 1541 // There should two more buttons in the folder. 1542 int newDisplayedButtons = [buttons count]; 1543 EXPECT_EQ(oldDisplayedButtons + 2, newDisplayedButtons); 1544 // Verify the model. 1545 const std::string expected("1b 2f:[ SiteA SiteB 2f1b 2f2f:[ 2f2f1b 2f2f2b " 1546 "2f2f3b ] 2f3b ] 3b 4b "); 1547 actual = test::ModelStringFromNode(root); 1548 EXPECT_EQ(expected, actual); 1549 1550 // Check button spacing. 1551 [folderController validateMenuSpacing]; 1552} 1553 1554TEST_F(BookmarkBarFolderControllerMenuTest, DropPositionIndicator) { 1555 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1556 const BookmarkNode* root = model->bookmark_bar_node(); 1557 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1558 "2f3b ] 3b 4b "); 1559 test::AddNodesFromModelString(model, root, model_string); 1560 1561 // Validate initial model. 1562 std::string actual = test::ModelStringFromNode(root); 1563 EXPECT_EQ(model_string, actual); 1564 1565 // Pop open the folder. 1566 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"]; 1567 [[button target] performSelector:@selector(openBookmarkFolderFromButton:) 1568 withObject:button]; 1569 BookmarkBarFolderController* folder = [bar_ folderController]; 1570 EXPECT_TRUE(folder); 1571 1572 // Test a series of points starting at the top of the folder. 1573 const CGFloat yOffset = 0.5 * bookmarks::kBookmarkVerticalPadding; 1574 BookmarkButton* targetButton = [folder buttonWithTitleEqualTo:@"2f1b"]; 1575 ASSERT_TRUE(targetButton); 1576 NSPoint targetPoint = [targetButton top]; 1577 CGFloat pos = [folder indicatorPosForDragToPoint:targetPoint]; 1578 EXPECT_CGFLOAT_EQ(targetPoint.y + yOffset, pos); 1579 pos = [folder indicatorPosForDragToPoint:[targetButton bottom]]; 1580 targetButton = [folder buttonWithTitleEqualTo:@"2f2f"]; 1581 EXPECT_CGFLOAT_EQ([targetButton top].y + yOffset, pos); 1582 pos = [folder indicatorPosForDragToPoint:NSMakePoint(10,0)]; 1583 targetButton = [folder buttonWithTitleEqualTo:@"2f3b"]; 1584 EXPECT_CGFLOAT_EQ([targetButton bottom].y - yOffset, pos); 1585} 1586 1587@interface BookmarkBarControllerNoDelete : BookmarkBarController 1588- (IBAction)deleteBookmark:(id)sender; 1589@end 1590 1591@implementation BookmarkBarControllerNoDelete 1592- (IBAction)deleteBookmark:(id)sender { 1593 // NOP 1594} 1595@end 1596 1597class BookmarkBarFolderControllerClosingTest : public 1598 BookmarkBarFolderControllerMenuTest { 1599 public: 1600 virtual void SetUp() { 1601 BookmarkBarFolderControllerMenuTest::SetUp(); 1602 ASSERT_TRUE(browser()); 1603 1604 bar_.reset([[BookmarkBarControllerNoDelete alloc] 1605 initWithBrowser:browser() 1606 initialWidth:NSWidth([parent_view_ frame]) 1607 delegate:nil 1608 resizeDelegate:resizeDelegate_.get()]); 1609 InstallAndToggleBar(bar_.get()); 1610 } 1611}; 1612 1613TEST_F(BookmarkBarFolderControllerClosingTest, DeleteClosesFolder) { 1614 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1615 const BookmarkNode* root = model->bookmark_bar_node(); 1616 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b ] " 1617 "2f3b ] 3b "); 1618 test::AddNodesFromModelString(model, root, model_string); 1619 1620 // Validate initial model. 1621 std::string actualModelString = test::ModelStringFromNode(root); 1622 EXPECT_EQ(model_string, actualModelString); 1623 1624 // Open the folder menu and submenu. 1625 BookmarkButton* target = [bar_ buttonWithTitleEqualTo:@"2f"]; 1626 ASSERT_TRUE(target); 1627 [[target target] performSelector:@selector(openBookmarkFolderFromButton:) 1628 withObject:target]; 1629 BookmarkBarFolderController* folder = [bar_ folderController]; 1630 EXPECT_TRUE(folder); 1631 BookmarkButton* subTarget = [folder buttonWithTitleEqualTo:@"2f2f"]; 1632 ASSERT_TRUE(subTarget); 1633 [[subTarget target] performSelector:@selector(openBookmarkFolderFromButton:) 1634 withObject:subTarget]; 1635 BookmarkBarFolderController* subFolder = [folder folderController]; 1636 EXPECT_TRUE(subFolder); 1637 1638 // Delete the folder node and verify the window closed down by looking 1639 // for its controller again. 1640 DeleteBookmark([folder parentButton], profile()); 1641 EXPECT_FALSE([folder folderController]); 1642} 1643 1644// TODO(jrg): draggingEntered: and draggingExited: trigger timers so 1645// they are hard to test. Factor out "fire timers" into routines 1646// which can be overridden to fire immediately to make behavior 1647// confirmable. 1648// There is a similar problem with mouseEnteredButton: and 1649// mouseExitedButton:. 1650