bookmark_bar_controller_unittest.mm revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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#import <Cocoa/Cocoa.h> 6 7#include "base/basictypes.h" 8#include "base/command_line.h" 9#include "base/mac/scoped_nsobject.h" 10#include "base/strings/string16.h" 11#include "base/strings/string_util.h" 12#include "base/strings/sys_string_conversions.h" 13#include "base/strings/utf_string_conversions.h" 14#include "chrome/browser/bookmarks/bookmark_model.h" 15#include "chrome/browser/bookmarks/bookmark_model_factory.h" 16#include "chrome/browser/bookmarks/bookmark_model_test_utils.h" 17#include "chrome/browser/bookmarks/bookmark_utils.h" 18#include "chrome/browser/extensions/test_extension_system.h" 19#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h" 20#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" 21#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h" 22#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h" 23#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h" 24#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" 25#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h" 26#include "chrome/browser/ui/cocoa/cocoa_profile_test.h" 27#import "chrome/browser/ui/cocoa/view_resizer_pong.h" 28#include "chrome/common/chrome_switches.h" 29#include "chrome/common/pref_names.h" 30#include "testing/gtest/include/gtest/gtest.h" 31#import "testing/gtest_mac.h" 32#include "testing/platform_test.h" 33#import "third_party/ocmock/OCMock/OCMock.h" 34#include "third_party/ocmock/gtest_support.h" 35#include "ui/base/cocoa/animation_utils.h" 36#include "ui/base/test/cocoa_test_event_utils.h" 37#include "ui/base/theme_provider.h" 38#include "ui/gfx/image/image_skia.h" 39 40// Unit tests don't need time-consuming asynchronous animations. 41@interface BookmarkBarControllerTestable : BookmarkBarController { 42} 43 44@end 45 46@implementation BookmarkBarControllerTestable 47 48- (id)initWithBrowser:(Browser*)browser 49 initialWidth:(CGFloat)initialWidth 50 delegate:(id<BookmarkBarControllerDelegate>)delegate 51 resizeDelegate:(id<ViewResizer>)resizeDelegate { 52 if ((self = [super initWithBrowser:browser 53 initialWidth:initialWidth 54 delegate:delegate 55 resizeDelegate:resizeDelegate])) { 56 [self setStateAnimationsEnabled:NO]; 57 [self setInnerContentAnimationsEnabled:NO]; 58 } 59 return self; 60} 61 62@end 63 64// Just like a BookmarkBarController but openURL: is stubbed out. 65@interface BookmarkBarControllerNoOpen : BookmarkBarControllerTestable { 66 @public 67 std::vector<GURL> urls_; 68 std::vector<WindowOpenDisposition> dispositions_; 69} 70@end 71 72@implementation BookmarkBarControllerNoOpen 73- (void)openURL:(GURL)url disposition:(WindowOpenDisposition)disposition { 74 urls_.push_back(url); 75 dispositions_.push_back(disposition); 76} 77- (void)clear { 78 urls_.clear(); 79 dispositions_.clear(); 80} 81@end 82 83 84// NSCell that is pre-provided with a desired size that becomes the 85// return value for -(NSSize)cellSize:. 86@interface CellWithDesiredSize : NSCell { 87 @private 88 NSSize cellSize_; 89} 90@property (nonatomic, readonly) NSSize cellSize; 91@end 92 93@implementation CellWithDesiredSize 94 95@synthesize cellSize = cellSize_; 96 97- (id)initTextCell:(NSString*)string desiredSize:(NSSize)size { 98 if ((self = [super initTextCell:string])) { 99 cellSize_ = size; 100 } 101 return self; 102} 103 104@end 105 106// Remember the number of times we've gotten a frameDidChange notification. 107@interface BookmarkBarControllerTogglePong : BookmarkBarControllerNoOpen { 108 @private 109 int toggles_; 110} 111@property (nonatomic, readonly) int toggles; 112@end 113 114@implementation BookmarkBarControllerTogglePong 115 116@synthesize toggles = toggles_; 117 118- (void)frameDidChange { 119 toggles_++; 120} 121 122@end 123 124// Remembers if a notification callback was called. 125@interface BookmarkBarControllerNotificationPong : BookmarkBarControllerNoOpen { 126 BOOL windowWillCloseReceived_; 127 BOOL windowDidResignKeyReceived_; 128} 129@property (nonatomic, readonly) BOOL windowWillCloseReceived; 130@property (nonatomic, readonly) BOOL windowDidResignKeyReceived; 131@end 132 133@implementation BookmarkBarControllerNotificationPong 134@synthesize windowWillCloseReceived = windowWillCloseReceived_; 135@synthesize windowDidResignKeyReceived = windowDidResignKeyReceived_; 136 137// Override NSNotificationCenter callback. 138- (void)parentWindowWillClose:(NSNotification*)notification { 139 windowWillCloseReceived_ = YES; 140} 141 142// NSNotificationCenter callback. 143- (void)parentWindowDidResignKey:(NSNotification*)notification { 144 windowDidResignKeyReceived_ = YES; 145} 146@end 147 148// Remembers if and what kind of openAll was performed. 149@interface BookmarkBarControllerOpenAllPong : BookmarkBarControllerNoOpen { 150 WindowOpenDisposition dispositionDetected_; 151} 152@property (nonatomic) WindowOpenDisposition dispositionDetected; 153@end 154 155@implementation BookmarkBarControllerOpenAllPong 156@synthesize dispositionDetected = dispositionDetected_; 157 158// Intercede for the openAll:disposition: method. 159- (void)openAll:(const BookmarkNode*)node 160 disposition:(WindowOpenDisposition)disposition { 161 [self setDispositionDetected:disposition]; 162} 163 164@end 165 166// Just like a BookmarkBarController but intercedes when providing 167// pasteboard drag data. 168@interface BookmarkBarControllerDragData : BookmarkBarControllerTestable { 169 const BookmarkNode* dragDataNode_; // Weak 170} 171- (void)setDragDataNode:(const BookmarkNode*)node; 172@end 173 174@implementation BookmarkBarControllerDragData 175 176- (id)initWithBrowser:(Browser*)browser 177 initialWidth:(CGFloat)initialWidth 178 delegate:(id<BookmarkBarControllerDelegate>)delegate 179 resizeDelegate:(id<ViewResizer>)resizeDelegate { 180 if ((self = [super initWithBrowser:browser 181 initialWidth:initialWidth 182 delegate:delegate 183 resizeDelegate:resizeDelegate])) { 184 dragDataNode_ = NULL; 185 } 186 return self; 187} 188 189- (void)setDragDataNode:(const BookmarkNode*)node { 190 dragDataNode_ = node; 191} 192 193- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData { 194 std::vector<const BookmarkNode*> dragDataNodes; 195 if(dragDataNode_) { 196 dragDataNodes.push_back(dragDataNode_); 197 } 198 return dragDataNodes; 199} 200 201@end 202 203 204class FakeTheme : public ui::ThemeProvider { 205 public: 206 FakeTheme(NSColor* color) : color_(color) {} 207 base::scoped_nsobject<NSColor> color_; 208 209 virtual gfx::ImageSkia* GetImageSkiaNamed(int id) const OVERRIDE { 210 return NULL; 211 } 212 virtual SkColor GetColor(int id) const OVERRIDE { return SkColor(); } 213 virtual bool GetDisplayProperty(int id, int* result) const OVERRIDE { 214 return false; 215 } 216 virtual bool ShouldUseNativeFrame() const OVERRIDE { return false; } 217 virtual bool HasCustomImage(int id) const OVERRIDE { return false; } 218 virtual base::RefCountedMemory* GetRawData( 219 int id, 220 ui::ScaleFactor scale_factor) const OVERRIDE { 221 return NULL; 222 } 223 virtual NSImage* GetNSImageNamed(int id, bool allow_default) const OVERRIDE { 224 return nil; 225 } 226 virtual NSColor* GetNSImageColorNamed( 227 int id, 228 bool allow_default) const OVERRIDE { 229 return nil; 230 } 231 virtual NSColor* GetNSColor(int id, bool allow_default) const OVERRIDE { 232 return color_.get(); 233 } 234 virtual NSColor* GetNSColorTint(int id, bool allow_default) const OVERRIDE { 235 return nil; 236 } 237 virtual NSGradient* GetNSGradient(int id) const OVERRIDE { 238 return nil; 239 } 240}; 241 242 243@interface FakeDragInfo : NSObject { 244 @public 245 NSPoint dropLocation_; 246 NSDragOperation sourceMask_; 247} 248@property (nonatomic, assign) NSPoint dropLocation; 249- (void)setDraggingSourceOperationMask:(NSDragOperation)mask; 250@end 251 252@implementation FakeDragInfo 253 254@synthesize dropLocation = dropLocation_; 255 256- (id)init { 257 if ((self = [super init])) { 258 dropLocation_ = NSZeroPoint; 259 sourceMask_ = NSDragOperationMove; 260 } 261 return self; 262} 263 264// NSDraggingInfo protocol functions. 265 266- (id)draggingPasteboard { 267 return self; 268} 269 270- (id)draggingSource { 271 return self; 272} 273 274- (NSDragOperation)draggingSourceOperationMask { 275 return sourceMask_; 276} 277 278- (NSPoint)draggingLocation { 279 return dropLocation_; 280} 281 282// Other functions. 283 284- (void)setDraggingSourceOperationMask:(NSDragOperation)mask { 285 sourceMask_ = mask; 286} 287 288@end 289 290 291namespace { 292 293class BookmarkBarControllerTestBase : public CocoaProfileTest { 294 public: 295 base::scoped_nsobject<NSView> parent_view_; 296 base::scoped_nsobject<ViewResizerPong> resizeDelegate_; 297 298 virtual void SetUp() { 299 CocoaProfileTest::SetUp(); 300 ASSERT_TRUE(profile()); 301 302 base::FilePath extension_dir; 303 static_cast<extensions::TestExtensionSystem*>( 304 extensions::ExtensionSystem::Get(profile()))-> 305 CreateExtensionService( 306 CommandLine::ForCurrentProcess(), 307 extension_dir, false); 308 resizeDelegate_.reset([[ViewResizerPong alloc] init]); 309 NSRect parent_frame = NSMakeRect(0, 0, 800, 50); 310 parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]); 311 [parent_view_ setHidden:YES]; 312 } 313 314 void InstallAndToggleBar(BookmarkBarController* bar) { 315 // Force loading of the nib. 316 [bar view]; 317 // Awkwardness to look like we've been installed. 318 for (NSView* subView in [parent_view_ subviews]) 319 [subView removeFromSuperview]; 320 [parent_view_ addSubview:[bar view]]; 321 NSRect frame = [[[bar view] superview] frame]; 322 frame.origin.y = 100; 323 [[[bar view] superview] setFrame:frame]; 324 325 // Make sure it's on in a window so viewDidMoveToWindow is called 326 NSView* contentView = [test_window() contentView]; 327 if (![parent_view_ isDescendantOf:contentView]) 328 [contentView addSubview:parent_view_]; 329 330 // Make sure it's open so certain things aren't no-ops. 331 [bar updateState:BookmarkBar::SHOW 332 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 333 } 334}; 335 336class BookmarkBarControllerTest : public BookmarkBarControllerTestBase { 337 public: 338 base::scoped_nsobject<NSButtonCell> cell_; 339 base::scoped_nsobject<BookmarkBarControllerNoOpen> bar_; 340 341 virtual void SetUp() { 342 BookmarkBarControllerTestBase::SetUp(); 343 ASSERT_TRUE(browser()); 344 AddCommandLineSwitches(); 345 346 bar_.reset( 347 [[BookmarkBarControllerNoOpen alloc] 348 initWithBrowser:browser() 349 initialWidth:NSWidth([parent_view_ frame]) 350 delegate:nil 351 resizeDelegate:resizeDelegate_.get()]); 352 353 InstallAndToggleBar(bar_.get()); 354 } 355 356 virtual void AddCommandLineSwitches() {} 357 358 BookmarkBarControllerNoOpen* noOpenBar() { 359 return (BookmarkBarControllerNoOpen*)bar_.get(); 360 } 361}; 362 363TEST_F(BookmarkBarControllerTest, ShowWhenShowBookmarkBarTrue) { 364 [bar_ updateState:BookmarkBar::SHOW 365 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 366 EXPECT_TRUE([bar_ isInState:BookmarkBar::SHOW]); 367 EXPECT_FALSE([bar_ isInState:BookmarkBar::DETACHED]); 368 EXPECT_TRUE([bar_ isVisible]); 369 EXPECT_FALSE([bar_ isAnimationRunning]); 370 EXPECT_FALSE([[bar_ view] isHidden]); 371 EXPECT_GT([resizeDelegate_ height], 0); 372 EXPECT_GT([[bar_ view] frame].size.height, 0); 373} 374 375TEST_F(BookmarkBarControllerTest, HideWhenShowBookmarkBarFalse) { 376 [bar_ updateState:BookmarkBar::HIDDEN 377 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 378 EXPECT_FALSE([bar_ isInState:BookmarkBar::SHOW]); 379 EXPECT_FALSE([bar_ isInState:BookmarkBar::DETACHED]); 380 EXPECT_FALSE([bar_ isVisible]); 381 EXPECT_FALSE([bar_ isAnimationRunning]); 382 EXPECT_TRUE([[bar_ view] isHidden]); 383 EXPECT_EQ(0, [resizeDelegate_ height]); 384 EXPECT_EQ(0, [[bar_ view] frame].size.height); 385} 386 387TEST_F(BookmarkBarControllerTest, HideWhenShowBookmarkBarTrueButDisabled) { 388 [bar_ setBookmarkBarEnabled:NO]; 389 [bar_ updateState:BookmarkBar::SHOW 390 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 391 EXPECT_TRUE([bar_ isInState:BookmarkBar::SHOW]); 392 EXPECT_FALSE([bar_ isInState:BookmarkBar::DETACHED]); 393 EXPECT_FALSE([bar_ isVisible]); 394 EXPECT_FALSE([bar_ isAnimationRunning]); 395 EXPECT_TRUE([[bar_ view] isHidden]); 396 EXPECT_EQ(0, [resizeDelegate_ height]); 397 EXPECT_EQ(0, [[bar_ view] frame].size.height); 398} 399 400TEST_F(BookmarkBarControllerTest, ShowOnNewTabPage) { 401 [bar_ updateState:BookmarkBar::DETACHED 402 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 403 EXPECT_FALSE([bar_ isInState:BookmarkBar::SHOW]); 404 EXPECT_TRUE([bar_ isInState:BookmarkBar::DETACHED]); 405 EXPECT_TRUE([bar_ isVisible]); 406 EXPECT_FALSE([bar_ isAnimationRunning]); 407 EXPECT_FALSE([[bar_ view] isHidden]); 408 EXPECT_GT([resizeDelegate_ height], 0); 409 EXPECT_GT([[bar_ view] frame].size.height, 0); 410 411 // Make sure no buttons fall off the bar, either now or when resized 412 // bigger or smaller. 413 CGFloat sizes[] = { 300.0, -100.0, 200.0, -420.0 }; 414 CGFloat previousX = 0.0; 415 for (unsigned x = 0; x < arraysize(sizes); x++) { 416 // Confirm the buttons moved from the last check (which may be 417 // init but that's fine). 418 CGFloat newX = [[bar_ offTheSideButton] frame].origin.x; 419 EXPECT_NE(previousX, newX); 420 previousX = newX; 421 422 // Confirm the buttons have a reasonable bounds. Recall that |-frame| 423 // returns rectangles in the superview's coordinates. 424 NSRect buttonViewFrame = 425 [[bar_ buttonView] convertRect:[[bar_ buttonView] frame] 426 fromView:[[bar_ buttonView] superview]]; 427 EXPECT_EQ([bar_ buttonView], [[bar_ offTheSideButton] superview]); 428 EXPECT_TRUE(NSContainsRect(buttonViewFrame, 429 [[bar_ offTheSideButton] frame])); 430 EXPECT_EQ([bar_ buttonView], [[bar_ otherBookmarksButton] superview]); 431 EXPECT_TRUE(NSContainsRect(buttonViewFrame, 432 [[bar_ otherBookmarksButton] frame])); 433 434 // Now move them implicitly. 435 // We confirm FrameChangeNotification works in the next unit test; 436 // we simply assume it works here to resize or reposition the 437 // buttons above. 438 NSRect frame = [[bar_ view] frame]; 439 frame.size.width += sizes[x]; 440 [[bar_ view] setFrame:frame]; 441 } 442} 443 444// Test whether |-updateState:...| sets currentState as expected. Make 445// sure things don't crash. 446TEST_F(BookmarkBarControllerTest, StateChanges) { 447 // First, go in one-at-a-time cycle. 448 [bar_ updateState:BookmarkBar::HIDDEN 449 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 450 EXPECT_EQ(BookmarkBar::HIDDEN, [bar_ currentState]); 451 EXPECT_FALSE([bar_ isVisible]); 452 EXPECT_FALSE([bar_ isAnimationRunning]); 453 454 [bar_ updateState:BookmarkBar::SHOW 455 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 456 EXPECT_EQ(BookmarkBar::SHOW, [bar_ currentState]); 457 EXPECT_TRUE([bar_ isVisible]); 458 EXPECT_FALSE([bar_ isAnimationRunning]); 459 460 [bar_ updateState:BookmarkBar::DETACHED 461 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 462 EXPECT_EQ(BookmarkBar::DETACHED, [bar_ currentState]); 463 EXPECT_TRUE([bar_ isVisible]); 464 EXPECT_FALSE([bar_ isAnimationRunning]); 465 466 // Now try some "jumps". 467 for (int i = 0; i < 2; i++) { 468 [bar_ updateState:BookmarkBar::HIDDEN 469 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 470 EXPECT_EQ(BookmarkBar::HIDDEN, [bar_ currentState]); 471 EXPECT_FALSE([bar_ isVisible]); 472 EXPECT_FALSE([bar_ isAnimationRunning]); 473 474 [bar_ updateState:BookmarkBar::SHOW 475 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 476 EXPECT_EQ(BookmarkBar::SHOW, [bar_ currentState]); 477 EXPECT_TRUE([bar_ isVisible]); 478 EXPECT_FALSE([bar_ isAnimationRunning]); 479 } 480 481 // Now try some "jumps". 482 for (int i = 0; i < 2; i++) { 483 [bar_ updateState:BookmarkBar::SHOW 484 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 485 EXPECT_EQ(BookmarkBar::SHOW, [bar_ currentState]); 486 EXPECT_TRUE([bar_ isVisible]); 487 EXPECT_FALSE([bar_ isAnimationRunning]); 488 489 [bar_ updateState:BookmarkBar::DETACHED 490 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 491 EXPECT_EQ(BookmarkBar::DETACHED, [bar_ currentState]); 492 EXPECT_TRUE([bar_ isVisible]); 493 EXPECT_FALSE([bar_ isAnimationRunning]); 494 } 495} 496 497// Make sure we're watching for frame change notifications. 498TEST_F(BookmarkBarControllerTest, FrameChangeNotification) { 499 base::scoped_nsobject<BookmarkBarControllerTogglePong> bar; 500 bar.reset( 501 [[BookmarkBarControllerTogglePong alloc] 502 initWithBrowser:browser() 503 initialWidth:100 // arbitrary 504 delegate:nil 505 resizeDelegate:resizeDelegate_.get()]); 506 InstallAndToggleBar(bar.get()); 507 508 // Send a frame did change notification for the pong's view. 509 [[NSNotificationCenter defaultCenter] 510 postNotificationName:NSViewFrameDidChangeNotification 511 object:[bar view]]; 512 513 EXPECT_GT([bar toggles], 0); 514} 515 516// Confirm our "no items" container goes away when we add the 1st 517// bookmark, and comes back when we delete the bookmark. 518TEST_F(BookmarkBarControllerTest, NoItemContainerGoesAway) { 519 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 520 const BookmarkNode* bar = model->bookmark_bar_node(); 521 522 [bar_ loaded:model]; 523 BookmarkBarView* view = [bar_ buttonView]; 524 DCHECK(view); 525 NSView* noItemContainer = [view noItemContainer]; 526 DCHECK(noItemContainer); 527 528 EXPECT_FALSE([noItemContainer isHidden]); 529 const BookmarkNode* node = model->AddURL(bar, bar->child_count(), 530 ASCIIToUTF16("title"), 531 GURL("http://www.google.com")); 532 EXPECT_TRUE([noItemContainer isHidden]); 533 model->Remove(bar, bar->GetIndexOf(node)); 534 EXPECT_FALSE([noItemContainer isHidden]); 535 536 // Now try it using a bookmark from the Other Bookmarks. 537 const BookmarkNode* otherBookmarks = model->other_node(); 538 node = model->AddURL(otherBookmarks, otherBookmarks->child_count(), 539 ASCIIToUTF16("TheOther"), 540 GURL("http://www.other.com")); 541 EXPECT_FALSE([noItemContainer isHidden]); 542 // Move it from Other Bookmarks to the bar. 543 model->Move(node, bar, 0); 544 EXPECT_TRUE([noItemContainer isHidden]); 545 // Move it back to Other Bookmarks from the bar. 546 model->Move(node, otherBookmarks, 0); 547 EXPECT_FALSE([noItemContainer isHidden]); 548} 549 550// Confirm off the side button only enabled when reasonable. 551TEST_F(BookmarkBarControllerTest, OffTheSideButtonHidden) { 552 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 553 554 [bar_ loaded:model]; 555 EXPECT_TRUE([bar_ offTheSideButtonIsHidden]); 556 557 for (int i = 0; i < 2; i++) { 558 bookmark_utils::AddIfNotBookmarked( 559 model, GURL("http://www.foo.com"), ASCIIToUTF16("small")); 560 EXPECT_TRUE([bar_ offTheSideButtonIsHidden]); 561 } 562 563 const BookmarkNode* parent = model->bookmark_bar_node(); 564 for (int i = 0; i < 20; i++) { 565 model->AddURL(parent, parent->child_count(), 566 ASCIIToUTF16("super duper wide title"), 567 GURL("http://superfriends.hall-of-justice.edu")); 568 } 569 EXPECT_FALSE([bar_ offTheSideButtonIsHidden]); 570 571 // Open the "off the side" and start deleting nodes. Make sure 572 // deletion of the last node in "off the side" causes the folder to 573 // close. 574 EXPECT_FALSE([bar_ offTheSideButtonIsHidden]); 575 NSButton* offTheSideButton = [bar_ offTheSideButton]; 576 // Open "off the side" menu. 577 [bar_ openOffTheSideFolderFromButton:offTheSideButton]; 578 BookmarkBarFolderController* bbfc = [bar_ folderController]; 579 EXPECT_TRUE(bbfc); 580 [bbfc setIgnoreAnimations:YES]; 581 while (!parent->empty()) { 582 // We've completed the job so we're done. 583 if ([bar_ offTheSideButtonIsHidden]) 584 break; 585 // Delete the last button. 586 model->Remove(parent, parent->child_count() - 1); 587 // If last one make sure the menu is closed and the button is hidden. 588 // Else make sure menu stays open. 589 if ([bar_ offTheSideButtonIsHidden]) { 590 EXPECT_FALSE([bar_ folderController]); 591 } else { 592 EXPECT_TRUE([bar_ folderController]); 593 } 594 } 595} 596 597// http://crbug.com/46175 is a crash when deleting bookmarks from the 598// off-the-side menu while it is open. This test tries to bang hard 599// in this area to reproduce the crash. 600TEST_F(BookmarkBarControllerTest, DeleteFromOffTheSideWhileItIsOpen) { 601 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 602 [bar_ loaded:model]; 603 604 // Add a lot of bookmarks (per the bug). 605 const BookmarkNode* parent = model->bookmark_bar_node(); 606 for (int i = 0; i < 100; i++) { 607 std::ostringstream title; 608 title << "super duper wide title " << i; 609 model->AddURL(parent, parent->child_count(), ASCIIToUTF16(title.str()), 610 GURL("http://superfriends.hall-of-justice.edu")); 611 } 612 EXPECT_FALSE([bar_ offTheSideButtonIsHidden]); 613 614 // Open "off the side" menu. 615 NSButton* offTheSideButton = [bar_ offTheSideButton]; 616 [bar_ openOffTheSideFolderFromButton:offTheSideButton]; 617 BookmarkBarFolderController* bbfc = [bar_ folderController]; 618 EXPECT_TRUE(bbfc); 619 [bbfc setIgnoreAnimations:YES]; 620 621 // Start deleting items; try and delete randomish ones in case it 622 // makes a difference. 623 int indices[] = { 2, 4, 5, 1, 7, 9, 2, 0, 10, 9 }; 624 while (!parent->empty()) { 625 for (unsigned int i = 0; i < arraysize(indices); i++) { 626 if (indices[i] < parent->child_count()) { 627 // First we mouse-enter the button to make things harder. 628 NSArray* buttons = [bbfc buttons]; 629 for (BookmarkButton* button in buttons) { 630 if ([button bookmarkNode] == parent->GetChild(indices[i])) { 631 [bbfc mouseEnteredButton:button event:nil]; 632 break; 633 } 634 } 635 // Then we remove the node. This triggers the button to get 636 // deleted. 637 model->Remove(parent, indices[i]); 638 // Force visual update which is otherwise delayed. 639 [[bbfc window] displayIfNeeded]; 640 } 641 } 642 } 643} 644 645// Test whether |-dragShouldLockBarVisibility| returns NO iff the bar is 646// detached. 647TEST_F(BookmarkBarControllerTest, TestDragShouldLockBarVisibility) { 648 [bar_ updateState:BookmarkBar::HIDDEN 649 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 650 EXPECT_TRUE([bar_ dragShouldLockBarVisibility]); 651 652 [bar_ updateState:BookmarkBar::SHOW 653 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 654 EXPECT_TRUE([bar_ dragShouldLockBarVisibility]); 655 656 [bar_ updateState:BookmarkBar::DETACHED 657 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE]; 658 EXPECT_FALSE([bar_ dragShouldLockBarVisibility]); 659} 660 661TEST_F(BookmarkBarControllerTest, TagMap) { 662 int64 ids[] = { 1, 3, 4, 40, 400, 4000, 800000000, 2, 123456789 }; 663 std::vector<int32> tags; 664 665 // Generate some tags 666 for (unsigned int i = 0; i < arraysize(ids); i++) { 667 tags.push_back([bar_ menuTagFromNodeId:ids[i]]); 668 } 669 670 // Confirm reverse mapping. 671 for (unsigned int i = 0; i < arraysize(ids); i++) { 672 EXPECT_EQ(ids[i], [bar_ nodeIdFromMenuTag:tags[i]]); 673 } 674 675 // Confirm uniqueness. 676 std::sort(tags.begin(), tags.end()); 677 for (unsigned int i=0; i<(tags.size()-1); i++) { 678 EXPECT_NE(tags[i], tags[i+1]); 679 } 680} 681 682TEST_F(BookmarkBarControllerTest, MenuForFolderNode) { 683 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 684 685 // First make sure something (e.g. "(empty)" string) is always present. 686 NSMenu* menu = [bar_ menuForFolderNode:model->bookmark_bar_node()]; 687 EXPECT_GT([menu numberOfItems], 0); 688 689 // Test two bookmarks. 690 GURL gurl("http://www.foo.com"); 691 bookmark_utils::AddIfNotBookmarked(model, gurl, ASCIIToUTF16("small")); 692 bookmark_utils::AddIfNotBookmarked( 693 model, GURL("http://www.cnn.com"), ASCIIToUTF16("bigger title")); 694 menu = [bar_ menuForFolderNode:model->bookmark_bar_node()]; 695 EXPECT_EQ([menu numberOfItems], 2); 696 NSMenuItem *item = [menu itemWithTitle:@"bigger title"]; 697 EXPECT_TRUE(item); 698 item = [menu itemWithTitle:@"small"]; 699 EXPECT_TRUE(item); 700 if (item) { 701 int64 tag = [bar_ nodeIdFromMenuTag:[item tag]]; 702 const BookmarkNode* node = model->GetNodeByID(tag); 703 EXPECT_TRUE(node); 704 EXPECT_EQ(gurl, node->url()); 705 } 706 707 // Test with an actual folder as well 708 const BookmarkNode* parent = model->bookmark_bar_node(); 709 const BookmarkNode* folder = model->AddFolder(parent, 710 parent->child_count(), 711 ASCIIToUTF16("folder")); 712 model->AddURL(folder, folder->child_count(), 713 ASCIIToUTF16("f1"), GURL("http://framma-lamma.com")); 714 model->AddURL(folder, folder->child_count(), 715 ASCIIToUTF16("f2"), GURL("http://framma-lamma-ding-dong.com")); 716 menu = [bar_ menuForFolderNode:model->bookmark_bar_node()]; 717 EXPECT_EQ([menu numberOfItems], 3); 718 719 item = [menu itemWithTitle:@"folder"]; 720 EXPECT_TRUE(item); 721 EXPECT_TRUE([item hasSubmenu]); 722 NSMenu *submenu = [item submenu]; 723 EXPECT_TRUE(submenu); 724 EXPECT_EQ(2, [submenu numberOfItems]); 725 EXPECT_TRUE([submenu itemWithTitle:@"f1"]); 726 EXPECT_TRUE([submenu itemWithTitle:@"f2"]); 727} 728 729// Confirm openBookmark: forwards the request to the controller's delegate 730TEST_F(BookmarkBarControllerTest, OpenBookmark) { 731 GURL gurl("http://walla.walla.ding.dong.com"); 732 scoped_ptr<BookmarkNode> node(new BookmarkNode(gurl)); 733 734 base::scoped_nsobject<BookmarkButtonCell> cell( 735 [[BookmarkButtonCell alloc] init]); 736 [cell setBookmarkNode:node.get()]; 737 base::scoped_nsobject<BookmarkButton> button([[BookmarkButton alloc] init]); 738 [button setCell:cell.get()]; 739 [cell setRepresentedObject:[NSValue valueWithPointer:node.get()]]; 740 741 [bar_ openBookmark:button]; 742 EXPECT_EQ(noOpenBar()->urls_[0], node->url()); 743 EXPECT_EQ(noOpenBar()->dispositions_[0], CURRENT_TAB); 744} 745 746TEST_F(BookmarkBarControllerTest, TestAddRemoveAndClear) { 747 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 748 NSView* buttonView = [bar_ buttonView]; 749 EXPECT_EQ(0U, [[bar_ buttons] count]); 750 unsigned int initial_subview_count = [[buttonView subviews] count]; 751 752 // Make sure a redundant call doesn't choke 753 [bar_ clearBookmarkBar]; 754 EXPECT_EQ(0U, [[bar_ buttons] count]); 755 EXPECT_EQ(initial_subview_count, [[buttonView subviews] count]); 756 757 GURL gurl1("http://superfriends.hall-of-justice.edu"); 758 // Short titles increase the chances of this test succeeding if the view is 759 // narrow. 760 // TODO(viettrungluu): make the test independent of window/view size, font 761 // metrics, button size and spacing, and everything else. 762 string16 title1(ASCIIToUTF16("x")); 763 bookmark_utils::AddIfNotBookmarked(model, gurl1, title1); 764 EXPECT_EQ(1U, [[bar_ buttons] count]); 765 EXPECT_EQ(1+initial_subview_count, [[buttonView subviews] count]); 766 767 GURL gurl2("http://legion-of-doom.gov"); 768 string16 title2(ASCIIToUTF16("y")); 769 bookmark_utils::AddIfNotBookmarked(model, gurl2, title2); 770 EXPECT_EQ(2U, [[bar_ buttons] count]); 771 EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]); 772 773 for (int i = 0; i < 3; i++) { 774 bookmark_utils::RemoveAllBookmarks(model, gurl2); 775 EXPECT_EQ(1U, [[bar_ buttons] count]); 776 EXPECT_EQ(1+initial_subview_count, [[buttonView subviews] count]); 777 778 // and bring it back 779 bookmark_utils::AddIfNotBookmarked(model, gurl2, title2); 780 EXPECT_EQ(2U, [[bar_ buttons] count]); 781 EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]); 782 } 783 784 [bar_ clearBookmarkBar]; 785 EXPECT_EQ(0U, [[bar_ buttons] count]); 786 EXPECT_EQ(initial_subview_count, [[buttonView subviews] count]); 787 788 // Explicit test of loaded: since this is a convenient spot 789 [bar_ loaded:model]; 790 EXPECT_EQ(2U, [[bar_ buttons] count]); 791 EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]); 792} 793 794// Make sure we don't create too many buttons; we only really need 795// ones that will be visible. 796TEST_F(BookmarkBarControllerTest, TestButtonLimits) { 797 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 798 EXPECT_EQ(0U, [[bar_ buttons] count]); 799 // Add one; make sure we see it. 800 const BookmarkNode* parent = model->bookmark_bar_node(); 801 model->AddURL(parent, parent->child_count(), 802 ASCIIToUTF16("title"), GURL("http://www.google.com")); 803 EXPECT_EQ(1U, [[bar_ buttons] count]); 804 805 // Add 30 which we expect to be 'too many'. Make sure we don't see 806 // 30 buttons. 807 model->Remove(parent, 0); 808 EXPECT_EQ(0U, [[bar_ buttons] count]); 809 for (int i=0; i<30; i++) { 810 model->AddURL(parent, parent->child_count(), 811 ASCIIToUTF16("title"), GURL("http://www.google.com")); 812 } 813 int count = [[bar_ buttons] count]; 814 EXPECT_LT(count, 30L); 815 816 // Add 10 more (to the front of the list so the on-screen buttons 817 // would change) and make sure the count stays the same. 818 for (int i=0; i<10; i++) { 819 model->AddURL(parent, 0, /* index is 0, so front, not end */ 820 ASCIIToUTF16("title"), GURL("http://www.google.com")); 821 } 822 823 // Finally, grow the view and make sure the button count goes up. 824 NSRect frame = [[bar_ view] frame]; 825 frame.size.width += 600; 826 [[bar_ view] setFrame:frame]; 827 int finalcount = [[bar_ buttons] count]; 828 EXPECT_GT(finalcount, count); 829} 830 831// Make sure that each button we add marches to the right and does not 832// overlap with the previous one. 833TEST_F(BookmarkBarControllerTest, TestButtonMarch) { 834 base::scoped_nsobject<NSMutableArray> cells([[NSMutableArray alloc] init]); 835 836 CGFloat widths[] = { 10, 10, 100, 10, 500, 500, 80000, 60000, 1, 345 }; 837 for (unsigned int i = 0; i < arraysize(widths); i++) { 838 NSCell* cell = [[CellWithDesiredSize alloc] 839 initTextCell:@"foo" 840 desiredSize:NSMakeSize(widths[i], 30)]; 841 [cells addObject:cell]; 842 [cell release]; 843 } 844 845 int x_offset = 0; 846 CGFloat x_end = x_offset; // end of the previous button 847 for (unsigned int i = 0; i < arraysize(widths); i++) { 848 NSRect r = [bar_ frameForBookmarkButtonFromCell:[cells objectAtIndex:i] 849 xOffset:&x_offset]; 850 EXPECT_GE(r.origin.x, x_end); 851 x_end = NSMaxX(r); 852 } 853} 854 855TEST_F(BookmarkBarControllerTest, CheckForGrowth) { 856 WithNoAnimation at_all; // Turn off Cocoa auto animation in this scope. 857 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 858 GURL gurl1("http://www.google.com"); 859 string16 title1(ASCIIToUTF16("x")); 860 bookmark_utils::AddIfNotBookmarked(model, gurl1, title1); 861 862 GURL gurl2("http://www.google.com/blah"); 863 string16 title2(ASCIIToUTF16("y")); 864 bookmark_utils::AddIfNotBookmarked(model, gurl2, title2); 865 866 EXPECT_EQ(2U, [[bar_ buttons] count]); 867 CGFloat width_1 = [[[bar_ buttons] objectAtIndex:0] frame].size.width; 868 CGFloat x_2 = [[[bar_ buttons] objectAtIndex:1] frame].origin.x; 869 870 NSButton* first = [[bar_ buttons] objectAtIndex:0]; 871 [[first cell] setTitle:@"This is a really big title; watch out mom!"]; 872 [bar_ checkForBookmarkButtonGrowth:first]; 873 874 // Make sure the 1st button is now wider, the 2nd one is moved over, 875 // and they don't overlap. 876 NSRect frame_1 = [[[bar_ buttons] objectAtIndex:0] frame]; 877 NSRect frame_2 = [[[bar_ buttons] objectAtIndex:1] frame]; 878 EXPECT_GT(frame_1.size.width, width_1); 879 EXPECT_GT(frame_2.origin.x, x_2); 880 EXPECT_GE(frame_2.origin.x, frame_1.origin.x + frame_1.size.width); 881} 882 883TEST_F(BookmarkBarControllerTest, DeleteBookmark) { 884 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 885 886 const char* urls[] = { "https://secret.url.com", 887 "http://super.duper.web.site.for.doodz.gov", 888 "http://www.foo-bar-baz.com/" }; 889 const BookmarkNode* parent = model->bookmark_bar_node(); 890 for (unsigned int i = 0; i < arraysize(urls); i++) { 891 model->AddURL(parent, parent->child_count(), 892 ASCIIToUTF16("title"), GURL(urls[i])); 893 } 894 EXPECT_EQ(3, parent->child_count()); 895 const BookmarkNode* middle_node = parent->GetChild(1); 896 model->Remove(middle_node->parent(), 897 middle_node->parent()->GetIndexOf(middle_node)); 898 899 EXPECT_EQ(2, parent->child_count()); 900 EXPECT_EQ(parent->GetChild(0)->url(), GURL(urls[0])); 901 // node 2 moved into spot 1 902 EXPECT_EQ(parent->GetChild(1)->url(), GURL(urls[2])); 903} 904 905// TODO(jrg): write a test to confirm that nodeFaviconLoaded calls 906// checkForBookmarkButtonGrowth:. 907 908TEST_F(BookmarkBarControllerTest, Cell) { 909 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 910 [bar_ loaded:model]; 911 912 const BookmarkNode* parent = model->bookmark_bar_node(); 913 model->AddURL(parent, parent->child_count(), 914 ASCIIToUTF16("supertitle"), 915 GURL("http://superfriends.hall-of-justice.edu")); 916 const BookmarkNode* node = parent->GetChild(0); 917 918 NSCell* cell = [bar_ cellForBookmarkNode:node]; 919 EXPECT_TRUE(cell); 920 EXPECT_NSEQ(@"supertitle", [cell title]); 921 EXPECT_EQ(node, [[cell representedObject] pointerValue]); 922 EXPECT_TRUE([cell menu]); 923 924 // Empty cells have no menu. 925 cell = [bar_ cellForBookmarkNode:nil]; 926 EXPECT_FALSE([cell menu]); 927 // Even empty cells have a title (of "(empty)") 928 EXPECT_TRUE([cell title]); 929 930 // cell is autoreleased; no need to release here 931} 932 933// Test drawing, mostly to ensure nothing leaks or crashes. 934TEST_F(BookmarkBarControllerTest, Display) { 935 [[bar_ view] display]; 936} 937 938// Test that middle clicking on a bookmark button results in an open action. 939TEST_F(BookmarkBarControllerTest, MiddleClick) { 940 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 941 GURL gurl1("http://www.google.com/"); 942 string16 title1(ASCIIToUTF16("x")); 943 bookmark_utils::AddIfNotBookmarked(model, gurl1, title1); 944 945 EXPECT_EQ(1U, [[bar_ buttons] count]); 946 NSButton* first = [[bar_ buttons] objectAtIndex:0]; 947 EXPECT_TRUE(first); 948 949 [first otherMouseUp: 950 cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, 0)]; 951 EXPECT_EQ(noOpenBar()->urls_.size(), 1U); 952} 953 954TEST_F(BookmarkBarControllerTest, DisplaysHelpMessageOnEmpty) { 955 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 956 [bar_ loaded:model]; 957 EXPECT_FALSE([[[bar_ buttonView] noItemContainer] isHidden]); 958} 959 960TEST_F(BookmarkBarControllerTest, HidesHelpMessageWithBookmark) { 961 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 962 963 const BookmarkNode* parent = model->bookmark_bar_node(); 964 model->AddURL(parent, parent->child_count(), 965 ASCIIToUTF16("title"), GURL("http://one.com")); 966 967 [bar_ loaded:model]; 968 EXPECT_TRUE([[[bar_ buttonView] noItemContainer] isHidden]); 969} 970 971TEST_F(BookmarkBarControllerTest, BookmarkButtonSizing) { 972 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 973 974 const BookmarkNode* parent = model->bookmark_bar_node(); 975 model->AddURL(parent, parent->child_count(), 976 ASCIIToUTF16("title"), GURL("http://one.com")); 977 978 [bar_ loaded:model]; 979 980 // Make sure the internal bookmark button also is the correct height. 981 NSArray* buttons = [bar_ buttons]; 982 EXPECT_GT([buttons count], 0u); 983 for (NSButton* button in buttons) { 984 EXPECT_FLOAT_EQ( 985 (bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset) - 2 * 986 bookmarks::kBookmarkVerticalPadding, 987 [button frame].size.height); 988 } 989} 990 991TEST_F(BookmarkBarControllerTest, DropBookmarks) { 992 const char* urls[] = { 993 "http://qwantz.com", 994 "http://xkcd.com", 995 "javascript:alert('lolwut')", 996 "file://localhost/tmp/local-file.txt" // As if dragged from the desktop. 997 }; 998 const char* titles[] = { 999 "Philosophoraptor", 1000 "Can't draw", 1001 "Inspiration", 1002 "Frum stuf" 1003 }; 1004 EXPECT_EQ(arraysize(urls), arraysize(titles)); 1005 1006 NSMutableArray* nsurls = [NSMutableArray array]; 1007 NSMutableArray* nstitles = [NSMutableArray array]; 1008 for (size_t i = 0; i < arraysize(urls); ++i) { 1009 [nsurls addObject:base::SysUTF8ToNSString(urls[i])]; 1010 [nstitles addObject:base::SysUTF8ToNSString(titles[i])]; 1011 } 1012 1013 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1014 const BookmarkNode* parent = model->bookmark_bar_node(); 1015 [bar_ addURLs:nsurls withTitles:nstitles at:NSZeroPoint]; 1016 EXPECT_EQ(4, parent->child_count()); 1017 for (int i = 0; i < parent->child_count(); ++i) { 1018 GURL gurl = parent->GetChild(i)->url(); 1019 if (gurl.scheme() == "http" || 1020 gurl.scheme() == "javascript") { 1021 EXPECT_EQ(parent->GetChild(i)->url(), GURL(urls[i])); 1022 } else { 1023 // Be flexible if the scheme needed to be added. 1024 std::string gurl_string = gurl.spec(); 1025 std::string my_string = parent->GetChild(i)->url().spec(); 1026 EXPECT_NE(gurl_string.find(my_string), std::string::npos); 1027 } 1028 EXPECT_EQ(parent->GetChild(i)->GetTitle(), ASCIIToUTF16(titles[i])); 1029 } 1030} 1031 1032TEST_F(BookmarkBarControllerTest, TestDragButton) { 1033 WithNoAnimation at_all; 1034 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1035 1036 GURL gurls[] = { GURL("http://www.google.com/a"), 1037 GURL("http://www.google.com/b"), 1038 GURL("http://www.google.com/c") }; 1039 string16 titles[] = { ASCIIToUTF16("a"), 1040 ASCIIToUTF16("b"), 1041 ASCIIToUTF16("c") }; 1042 for (unsigned i = 0; i < arraysize(titles); i++) 1043 bookmark_utils::AddIfNotBookmarked(model, gurls[i], titles[i]); 1044 1045 EXPECT_EQ([[bar_ buttons] count], arraysize(titles)); 1046 EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]); 1047 1048 [bar_ dragButton:[[bar_ buttons] objectAtIndex:2] 1049 to:NSZeroPoint 1050 copy:NO]; 1051 EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:0] title]); 1052 // Make sure a 'copy' did not happen. 1053 EXPECT_EQ([[bar_ buttons] count], arraysize(titles)); 1054 1055 [bar_ dragButton:[[bar_ buttons] objectAtIndex:1] 1056 to:NSMakePoint(1000, 0) 1057 copy:NO]; 1058 EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:0] title]); 1059 EXPECT_NSEQ(@"b", [[[bar_ buttons] objectAtIndex:1] title]); 1060 EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:2] title]); 1061 EXPECT_EQ([[bar_ buttons] count], arraysize(titles)); 1062 1063 // A drop of the 1st between the next 2. 1064 CGFloat x = NSMinX([[[bar_ buttons] objectAtIndex:2] frame]); 1065 x += [[bar_ view] frame].origin.x; 1066 [bar_ dragButton:[[bar_ buttons] objectAtIndex:0] 1067 to:NSMakePoint(x, 0) 1068 copy:NO]; 1069 EXPECT_NSEQ(@"b", [[[bar_ buttons] objectAtIndex:0] title]); 1070 EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:1] title]); 1071 EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:2] title]); 1072 EXPECT_EQ([[bar_ buttons] count], arraysize(titles)); 1073 1074 // A drop on a non-folder button. (Shouldn't try and go in it.) 1075 x = NSMidX([[[bar_ buttons] objectAtIndex:0] frame]); 1076 x += [[bar_ view] frame].origin.x; 1077 [bar_ dragButton:[[bar_ buttons] objectAtIndex:2] 1078 to:NSMakePoint(x, 0) 1079 copy:NO]; 1080 EXPECT_EQ(arraysize(titles), [[bar_ buttons] count]); 1081 1082 // A drop on a folder button. 1083 const BookmarkNode* folder = model->AddFolder( 1084 model->bookmark_bar_node(), 0, ASCIIToUTF16("awesome folder")); 1085 DCHECK(folder); 1086 model->AddURL(folder, 0, ASCIIToUTF16("already"), 1087 GURL("http://www.google.com")); 1088 EXPECT_EQ(arraysize(titles) + 1, [[bar_ buttons] count]); 1089 EXPECT_EQ(1, folder->child_count()); 1090 x = NSMidX([[[bar_ buttons] objectAtIndex:0] frame]); 1091 x += [[bar_ view] frame].origin.x; 1092 string16 title = [[[bar_ buttons] objectAtIndex:2] bookmarkNode]->GetTitle(); 1093 [bar_ dragButton:[[bar_ buttons] objectAtIndex:2] 1094 to:NSMakePoint(x, 0) 1095 copy:NO]; 1096 // Gone from the bar 1097 EXPECT_EQ(arraysize(titles), [[bar_ buttons] count]); 1098 // In the folder 1099 EXPECT_EQ(2, folder->child_count()); 1100 // At the end 1101 EXPECT_EQ(title, folder->GetChild(1)->GetTitle()); 1102} 1103 1104TEST_F(BookmarkBarControllerTest, TestCopyButton) { 1105 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1106 1107 GURL gurls[] = { GURL("http://www.google.com/a"), 1108 GURL("http://www.google.com/b"), 1109 GURL("http://www.google.com/c") }; 1110 string16 titles[] = { ASCIIToUTF16("a"), 1111 ASCIIToUTF16("b"), 1112 ASCIIToUTF16("c") }; 1113 for (unsigned i = 0; i < arraysize(titles); i++) 1114 bookmark_utils::AddIfNotBookmarked(model, gurls[i], titles[i]); 1115 1116 EXPECT_EQ([[bar_ buttons] count], arraysize(titles)); 1117 EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]); 1118 1119 // Drag 'a' between 'b' and 'c'. 1120 CGFloat x = NSMinX([[[bar_ buttons] objectAtIndex:2] frame]); 1121 x += [[bar_ view] frame].origin.x; 1122 [bar_ dragButton:[[bar_ buttons] objectAtIndex:0] 1123 to:NSMakePoint(x, 0) 1124 copy:YES]; 1125 EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]); 1126 EXPECT_NSEQ(@"b", [[[bar_ buttons] objectAtIndex:1] title]); 1127 EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:2] title]); 1128 EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:3] title]); 1129 EXPECT_EQ([[bar_ buttons] count], 4U); 1130} 1131 1132// Fake a theme with colored text. Apply it and make sure bookmark 1133// buttons have the same colored text. Repeat more than once. 1134TEST_F(BookmarkBarControllerTest, TestThemedButton) { 1135 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1136 bookmark_utils::AddIfNotBookmarked( 1137 model, GURL("http://www.foo.com"), ASCIIToUTF16("small")); 1138 BookmarkButton* button = [[bar_ buttons] objectAtIndex:0]; 1139 EXPECT_TRUE(button); 1140 1141 NSArray* colors = [NSArray arrayWithObjects:[NSColor redColor], 1142 [NSColor blueColor], 1143 nil]; 1144 for (NSColor* color in colors) { 1145 FakeTheme theme(color); 1146 [bar_ updateTheme:&theme]; 1147 NSAttributedString* astr = [button attributedTitle]; 1148 EXPECT_TRUE(astr); 1149 EXPECT_NSEQ(@"small", [astr string]); 1150 // Pick a char in the middle to test (index 3) 1151 NSDictionary* attributes = [astr attributesAtIndex:3 effectiveRange:NULL]; 1152 NSColor* newColor = 1153 [attributes objectForKey:NSForegroundColorAttributeName]; 1154 EXPECT_NSEQ(newColor, color); 1155 } 1156} 1157 1158// Test that delegates and targets of buttons are cleared on dealloc. 1159TEST_F(BookmarkBarControllerTest, TestClearOnDealloc) { 1160 // Make some bookmark buttons. 1161 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1162 GURL gurls[] = { GURL("http://www.foo.com/"), 1163 GURL("http://www.bar.com/"), 1164 GURL("http://www.baz.com/") }; 1165 string16 titles[] = { ASCIIToUTF16("a"), 1166 ASCIIToUTF16("b"), 1167 ASCIIToUTF16("c") }; 1168 for (size_t i = 0; i < arraysize(titles); i++) 1169 bookmark_utils::AddIfNotBookmarked(model, gurls[i], titles[i]); 1170 1171 // Get and retain the buttons so we can examine them after dealloc. 1172 base::scoped_nsobject<NSArray> buttons([[bar_ buttons] retain]); 1173 EXPECT_EQ([buttons count], arraysize(titles)); 1174 1175 // Make sure that everything is set. 1176 for (BookmarkButton* button in buttons.get()) { 1177 ASSERT_TRUE([button isKindOfClass:[BookmarkButton class]]); 1178 EXPECT_TRUE([button delegate]); 1179 EXPECT_TRUE([button target]); 1180 EXPECT_TRUE([button action]); 1181 } 1182 1183 // This will dealloc.... 1184 bar_.reset(); 1185 1186 // Make sure that everything is cleared. 1187 for (BookmarkButton* button in buttons.get()) { 1188 EXPECT_FALSE([button delegate]); 1189 EXPECT_FALSE([button target]); 1190 EXPECT_FALSE([button action]); 1191 } 1192} 1193 1194TEST_F(BookmarkBarControllerTest, TestFolders) { 1195 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1196 1197 // Create some folder buttons. 1198 const BookmarkNode* parent = model->bookmark_bar_node(); 1199 const BookmarkNode* folder = model->AddFolder(parent, 1200 parent->child_count(), 1201 ASCIIToUTF16("folder")); 1202 model->AddURL(folder, folder->child_count(), 1203 ASCIIToUTF16("f1"), GURL("http://framma-lamma.com")); 1204 folder = model->AddFolder(parent, parent->child_count(), 1205 ASCIIToUTF16("empty")); 1206 1207 EXPECT_EQ([[bar_ buttons] count], 2U); 1208 1209 // First confirm mouseEntered does nothing if "menus" aren't active. 1210 NSEvent* event = 1211 cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, 0); 1212 [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:0] event:event]; 1213 EXPECT_FALSE([bar_ folderController]); 1214 1215 // Make one active. Entering it is now a no-op. 1216 [bar_ openBookmarkFolderFromButton:[[bar_ buttons] objectAtIndex:0]]; 1217 BookmarkBarFolderController* bbfc = [bar_ folderController]; 1218 EXPECT_TRUE(bbfc); 1219 [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:0] event:event]; 1220 EXPECT_EQ(bbfc, [bar_ folderController]); 1221 1222 // Enter a different one; a new folderController is active. 1223 [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:1] event:event]; 1224 EXPECT_NE(bbfc, [bar_ folderController]); 1225 1226 // Confirm exited is a no-op. 1227 [bar_ mouseExitedButton:[[bar_ buttons] objectAtIndex:1] event:event]; 1228 EXPECT_NE(bbfc, [bar_ folderController]); 1229 1230 // Clean up. 1231 [bar_ closeBookmarkFolder:nil]; 1232} 1233 1234// Verify that the folder menu presentation properly tracks mouse movements 1235// over the bar. Until there is a click no folder menus should show. After a 1236// click on a folder folder menus should show until another click on a folder 1237// button, and a click outside the bar and its folder menus. 1238TEST_F(BookmarkBarControllerTest, TestFolderButtons) { 1239 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1240 const BookmarkNode* root = model->bookmark_bar_node(); 1241 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b 4f:[ 4f1b 4f2b ] "); 1242 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1243 1244 // Validate initial model and that we do not have a folder controller. 1245 std::string actualModelString = 1246 BookmarkModelTestUtils::ModelStringFromNode(root); 1247 EXPECT_EQ(model_string, actualModelString); 1248 EXPECT_FALSE([bar_ folderController]); 1249 1250 // Add a real bookmark so we can click on it. 1251 const BookmarkNode* folder = root->GetChild(3); 1252 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("CLICK ME"), 1253 GURL("http://www.google.com/")); 1254 1255 // Click on a folder button. 1256 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"4f"]; 1257 EXPECT_TRUE(button); 1258 [bar_ openBookmarkFolderFromButton:button]; 1259 BookmarkBarFolderController* bbfc = [bar_ folderController]; 1260 EXPECT_TRUE(bbfc); 1261 1262 // Make sure a 2nd click on the same button closes things. 1263 [bar_ openBookmarkFolderFromButton:button]; 1264 EXPECT_FALSE([bar_ folderController]); 1265 1266 // Next open is a different button. 1267 button = [bar_ buttonWithTitleEqualTo:@"2f"]; 1268 EXPECT_TRUE(button); 1269 [bar_ openBookmarkFolderFromButton:button]; 1270 EXPECT_TRUE([bar_ folderController]); 1271 1272 // Mouse over a non-folder button and confirm controller has gone away. 1273 button = [bar_ buttonWithTitleEqualTo:@"1b"]; 1274 EXPECT_TRUE(button); 1275 NSEvent* event = cocoa_test_event_utils::MouseEventAtPoint([button center], 1276 NSMouseMoved, 0); 1277 [bar_ mouseEnteredButton:button event:event]; 1278 EXPECT_FALSE([bar_ folderController]); 1279 1280 // Mouse over the original folder and confirm a new controller. 1281 button = [bar_ buttonWithTitleEqualTo:@"2f"]; 1282 EXPECT_TRUE(button); 1283 [bar_ mouseEnteredButton:button event:event]; 1284 BookmarkBarFolderController* oldBBFC = [bar_ folderController]; 1285 EXPECT_TRUE(oldBBFC); 1286 1287 // 'Jump' over to a different folder and confirm a new controller. 1288 button = [bar_ buttonWithTitleEqualTo:@"4f"]; 1289 EXPECT_TRUE(button); 1290 [bar_ mouseEnteredButton:button event:event]; 1291 BookmarkBarFolderController* newBBFC = [bar_ folderController]; 1292 EXPECT_TRUE(newBBFC); 1293 EXPECT_NE(oldBBFC, newBBFC); 1294} 1295 1296// Make sure the "off the side" folder looks like a bookmark folder 1297// but only contains "off the side" items. 1298TEST_F(BookmarkBarControllerTest, OffTheSideFolder) { 1299 1300 // It starts hidden. 1301 EXPECT_TRUE([bar_ offTheSideButtonIsHidden]); 1302 1303 // Create some buttons. 1304 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1305 const BookmarkNode* parent = model->bookmark_bar_node(); 1306 for (int x = 0; x < 30; x++) { 1307 model->AddURL(parent, parent->child_count(), 1308 ASCIIToUTF16("medium-size-title"), 1309 GURL("http://framma-lamma.com")); 1310 } 1311 // Add a couple more so we can delete one and make sure its button goes away. 1312 model->AddURL(parent, parent->child_count(), 1313 ASCIIToUTF16("DELETE_ME"), GURL("http://ashton-tate.com")); 1314 model->AddURL(parent, parent->child_count(), 1315 ASCIIToUTF16("medium-size-title"), 1316 GURL("http://framma-lamma.com")); 1317 1318 // Should no longer be hidden. 1319 EXPECT_FALSE([bar_ offTheSideButtonIsHidden]); 1320 1321 // Open it; make sure we have a folder controller. 1322 EXPECT_FALSE([bar_ folderController]); 1323 [bar_ openOffTheSideFolderFromButton:[bar_ offTheSideButton]]; 1324 BookmarkBarFolderController* bbfc = [bar_ folderController]; 1325 EXPECT_TRUE(bbfc); 1326 1327 // Confirm the contents are only buttons which fell off the side by 1328 // making sure that none of the nodes in the off-the-side folder are 1329 // found in bar buttons. Be careful since not all the bar buttons 1330 // may be currently displayed. 1331 NSArray* folderButtons = [bbfc buttons]; 1332 NSArray* barButtons = [bar_ buttons]; 1333 for (BookmarkButton* folderButton in folderButtons) { 1334 for (BookmarkButton* barButton in barButtons) { 1335 if ([barButton superview]) { 1336 EXPECT_NE([folderButton bookmarkNode], [barButton bookmarkNode]); 1337 } 1338 } 1339 } 1340 1341 // Delete a bookmark in the off-the-side and verify it's gone. 1342 BookmarkButton* button = [bbfc buttonWithTitleEqualTo:@"DELETE_ME"]; 1343 EXPECT_TRUE(button); 1344 model->Remove(parent, parent->child_count() - 2); 1345 button = [bbfc buttonWithTitleEqualTo:@"DELETE_ME"]; 1346 EXPECT_FALSE(button); 1347} 1348 1349TEST_F(BookmarkBarControllerTest, EventToExitCheck) { 1350 NSEvent* event = cocoa_test_event_utils::MouseEventWithType(NSMouseMoved, 0); 1351 EXPECT_FALSE([bar_ isEventAnExitEvent:event]); 1352 1353 BookmarkBarFolderWindow* folderWindow = [[[BookmarkBarFolderWindow alloc] 1354 init] autorelease]; 1355 [[[bar_ view] window] addChildWindow:folderWindow 1356 ordered:NSWindowAbove]; 1357 event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(NSMakePoint(1,1), 1358 folderWindow); 1359 EXPECT_FALSE([bar_ isEventAnExitEvent:event]); 1360 1361 event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( 1362 NSMakePoint(100,100), test_window()); 1363 EXPECT_TRUE([bar_ isEventAnExitEvent:event]); 1364 1365 // Many components are arbitrary (e.g. location, keycode). 1366 event = [NSEvent keyEventWithType:NSKeyDown 1367 location:NSMakePoint(1,1) 1368 modifierFlags:0 1369 timestamp:0 1370 windowNumber:0 1371 context:nil 1372 characters:@"x" 1373 charactersIgnoringModifiers:@"x" 1374 isARepeat:NO 1375 keyCode:87]; 1376 EXPECT_FALSE([bar_ isEventAnExitEvent:event]); 1377 1378 [[[bar_ view] window] removeChildWindow:folderWindow]; 1379} 1380 1381TEST_F(BookmarkBarControllerTest, DropDestination) { 1382 // Make some buttons. 1383 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1384 const BookmarkNode* parent = model->bookmark_bar_node(); 1385 model->AddFolder(parent, parent->child_count(), ASCIIToUTF16("folder 1")); 1386 model->AddFolder(parent, parent->child_count(), ASCIIToUTF16("folder 2")); 1387 EXPECT_EQ([[bar_ buttons] count], 2U); 1388 1389 // Confirm "off to left" and "off to right" match nothing. 1390 NSPoint p = NSMakePoint(-1, 2); 1391 EXPECT_FALSE([bar_ buttonForDroppingOnAtPoint:p]); 1392 EXPECT_TRUE([bar_ shouldShowIndicatorShownForPoint:p]); 1393 p = NSMakePoint(50000, 10); 1394 EXPECT_FALSE([bar_ buttonForDroppingOnAtPoint:p]); 1395 EXPECT_TRUE([bar_ shouldShowIndicatorShownForPoint:p]); 1396 1397 // Confirm "right in the center" (give or take a pixel) is a match, 1398 // and confirm "just barely in the button" is not. Anything more 1399 // specific seems likely to be tweaked. 1400 CGFloat viewFrameXOffset = [[bar_ view] frame].origin.x; 1401 for (BookmarkButton* button in [bar_ buttons]) { 1402 CGFloat x = NSMidX([button frame]) + viewFrameXOffset; 1403 // Somewhere near the center: a match 1404 EXPECT_EQ(button, 1405 [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x-1, 10)]); 1406 EXPECT_EQ(button, 1407 [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x+1, 10)]); 1408 EXPECT_FALSE([bar_ shouldShowIndicatorShownForPoint:NSMakePoint(x, 10)]);; 1409 1410 // On the very edges: NOT a match 1411 x = NSMinX([button frame]) + viewFrameXOffset; 1412 EXPECT_NE(button, 1413 [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x, 9)]); 1414 x = NSMaxX([button frame]) + viewFrameXOffset; 1415 EXPECT_NE(button, 1416 [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x, 11)]); 1417 } 1418} 1419 1420TEST_F(BookmarkBarControllerTest, CloseFolderOnAnimate) { 1421 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1422 [bar_ setStateAnimationsEnabled:YES]; 1423 const BookmarkNode* parent = model->bookmark_bar_node(); 1424 const BookmarkNode* folder = model->AddFolder(parent, 1425 parent->child_count(), 1426 ASCIIToUTF16("folder")); 1427 model->AddFolder(parent, parent->child_count(), 1428 ASCIIToUTF16("sibbling folder")); 1429 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("title a"), 1430 GURL("http://www.google.com/a")); 1431 model->AddURL(folder, folder->child_count(), 1432 ASCIIToUTF16("title super duper long long whoa momma title you betcha"), 1433 GURL("http://www.google.com/b")); 1434 BookmarkButton* button = [[bar_ buttons] objectAtIndex:0]; 1435 EXPECT_FALSE([bar_ folderController]); 1436 [bar_ openBookmarkFolderFromButton:button]; 1437 BookmarkBarFolderController* bbfc = [bar_ folderController]; 1438 // The following tells us that the folder menu is showing. We want to make 1439 // sure the folder menu goes away if the bookmark bar is hidden. 1440 EXPECT_TRUE(bbfc); 1441 EXPECT_TRUE([bar_ isVisible]); 1442 1443 // Hide the bookmark bar. 1444 [bar_ updateState:BookmarkBar::DETACHED 1445 changeType:BookmarkBar::ANIMATE_STATE_CHANGE]; 1446 EXPECT_TRUE([bar_ isAnimationRunning]); 1447 1448 // Now that we've closed the bookmark bar (with animation) the folder menu 1449 // should have been closed thus releasing the folderController. 1450 EXPECT_FALSE([bar_ folderController]); 1451} 1452 1453TEST_F(BookmarkBarControllerTest, MoveRemoveAddButtons) { 1454 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1455 const BookmarkNode* root = model->bookmark_bar_node(); 1456 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b "); 1457 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1458 1459 // Validate initial model. 1460 std::string actualModelString = 1461 BookmarkModelTestUtils::ModelStringFromNode(root); 1462 EXPECT_EQ(model_string, actualModelString); 1463 1464 // Remember how many buttons are showing. 1465 int oldDisplayedButtons = [bar_ displayedButtonCount]; 1466 NSArray* buttons = [bar_ buttons]; 1467 1468 // Move a button around a bit. 1469 [bar_ moveButtonFromIndex:0 toIndex:2]; 1470 EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:0] title]); 1471 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:1] title]); 1472 EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:2] title]); 1473 EXPECT_EQ(oldDisplayedButtons, [bar_ displayedButtonCount]); 1474 [bar_ moveButtonFromIndex:2 toIndex:0]; 1475 EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:0] title]); 1476 EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:1] title]); 1477 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:2] title]); 1478 EXPECT_EQ(oldDisplayedButtons, [bar_ displayedButtonCount]); 1479 1480 // Add a couple of buttons. 1481 const BookmarkNode* parent = root->GetChild(1); // Purloin an existing node. 1482 const BookmarkNode* node = parent->GetChild(0); 1483 [bar_ addButtonForNode:node atIndex:0]; 1484 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]); 1485 EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:1] title]); 1486 EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:2] title]); 1487 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:3] title]); 1488 EXPECT_EQ(oldDisplayedButtons + 1, [bar_ displayedButtonCount]); 1489 node = parent->GetChild(1); 1490 [bar_ addButtonForNode:node atIndex:-1]; 1491 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]); 1492 EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:1] title]); 1493 EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:2] title]); 1494 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:3] title]); 1495 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:4] title]); 1496 EXPECT_EQ(oldDisplayedButtons + 2, [bar_ displayedButtonCount]); 1497 1498 // Remove a couple of buttons. 1499 [bar_ removeButton:4 animate:NO]; 1500 [bar_ removeButton:1 animate:NO]; 1501 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]); 1502 EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:1] title]); 1503 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:2] title]); 1504 EXPECT_EQ(oldDisplayedButtons, [bar_ displayedButtonCount]); 1505} 1506 1507TEST_F(BookmarkBarControllerTest, ShrinkOrHideView) { 1508 NSRect viewFrame = NSMakeRect(0.0, 0.0, 500.0, 50.0); 1509 NSView* view = [[[NSView alloc] initWithFrame:viewFrame] autorelease]; 1510 EXPECT_FALSE([view isHidden]); 1511 [bar_ shrinkOrHideView:view forMaxX:500.0]; 1512 EXPECT_EQ(500.0, NSWidth([view frame])); 1513 EXPECT_FALSE([view isHidden]); 1514 [bar_ shrinkOrHideView:view forMaxX:450.0]; 1515 EXPECT_EQ(450.0, NSWidth([view frame])); 1516 EXPECT_FALSE([view isHidden]); 1517 [bar_ shrinkOrHideView:view forMaxX:40.0]; 1518 EXPECT_EQ(40.0, NSWidth([view frame])); 1519 EXPECT_FALSE([view isHidden]); 1520 [bar_ shrinkOrHideView:view forMaxX:31.0]; 1521 EXPECT_EQ(31.0, NSWidth([view frame])); 1522 EXPECT_FALSE([view isHidden]); 1523 [bar_ shrinkOrHideView:view forMaxX:29.0]; 1524 EXPECT_TRUE([view isHidden]); 1525} 1526 1527TEST_F(BookmarkBarControllerTest, LastBookmarkResizeBehavior) { 1528 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1529 const BookmarkNode* root = model->bookmark_bar_node(); 1530 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b "); 1531 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1532 [bar_ frameDidChange]; 1533 1534 CGFloat viewWidths[] = { 123.0, 124.0, 151.0, 152.0, 153.0, 154.0, 155.0, 1535 200.0, 155.0, 154.0, 153.0, 152.0, 151.0, 124.0, 1536 123.0 }; 1537 BOOL offTheSideButtonIsHiddenResults[] = { NO, NO, NO, NO, YES, YES, YES, YES, 1538 YES, YES, YES, NO, NO, NO, NO}; 1539 int displayedButtonCountResults[] = { 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1540 2, 1 }; 1541 1542 for (unsigned int i = 0; i < sizeof(viewWidths) / sizeof(viewWidths[0]); 1543 ++i) { 1544 NSRect frame = [[bar_ view] frame]; 1545 frame.size.width = viewWidths[i] + bookmarks::kBookmarkRightMargin; 1546 [[bar_ view] setFrame:frame]; 1547 EXPECT_EQ(offTheSideButtonIsHiddenResults[i], 1548 [bar_ offTheSideButtonIsHidden]); 1549 EXPECT_EQ(displayedButtonCountResults[i], [bar_ displayedButtonCount]); 1550 } 1551} 1552 1553class BookmarkBarControllerWithInstantExtendedTest : 1554 public BookmarkBarControllerTest { 1555 public: 1556 virtual void AddCommandLineSwitches() OVERRIDE { 1557 CommandLine::ForCurrentProcess()->AppendSwitch( 1558 switches::kEnableInstantExtendedAPI); 1559 } 1560}; 1561 1562TEST_F(BookmarkBarControllerWithInstantExtendedTest, 1563 BookmarksWithAppsPageShortcut) { 1564 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1565 const BookmarkNode* root = model->bookmark_bar_node(); 1566 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b "); 1567 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1568 [bar_ frameDidChange]; 1569 1570 // Apps page shortcut button should be visible. 1571 ASSERT_FALSE([bar_ appsPageShortcutButtonIsHidden]); 1572 1573 // Bookmarks should be to the right of the Apps page shortcut button. 1574 CGFloat apps_button_right = NSMaxX([[bar_ appsPageShortcutButton] frame]); 1575 CGFloat right = apps_button_right; 1576 NSArray* buttons = [bar_ buttons]; 1577 for (size_t i = 0; i < [buttons count]; ++i) { 1578 EXPECT_LE(right, NSMinX([[buttons objectAtIndex:i] frame])); 1579 right = NSMaxX([[buttons objectAtIndex:i] frame]); 1580 } 1581 1582 // Removing the Apps button should move every bookmark to the left. 1583 profile()->GetPrefs()->SetBoolean(prefs::kShowAppsShortcutInBookmarkBar, 1584 false); 1585 ASSERT_TRUE([bar_ appsPageShortcutButtonIsHidden]); 1586 EXPECT_GT(apps_button_right, NSMinX([[buttons objectAtIndex:0] frame])); 1587 for (size_t i = 1; i < [buttons count]; ++i) { 1588 EXPECT_LE(NSMaxX([[buttons objectAtIndex:i - 1] frame]), 1589 NSMinX([[buttons objectAtIndex:i] frame])); 1590 } 1591} 1592 1593TEST_F(BookmarkBarControllerWithInstantExtendedTest, 1594 BookmarksWithoutAppsPageShortcut) { 1595 // The no item containers should be to the right of the Apps button. 1596 ASSERT_FALSE([bar_ appsPageShortcutButtonIsHidden]); 1597 CGFloat apps_button_right = NSMaxX([[bar_ appsPageShortcutButton] frame]); 1598 EXPECT_LE(apps_button_right, 1599 NSMinX([[[bar_ buttonView] noItemTextfield] frame])); 1600 EXPECT_LE(NSMaxX([[[bar_ buttonView] noItemTextfield] frame]), 1601 NSMinX([[[bar_ buttonView] importBookmarksButton] frame])); 1602 1603 // Removing the Apps button should move the no item containers to the left. 1604 profile()->GetPrefs()->SetBoolean(prefs::kShowAppsShortcutInBookmarkBar, 1605 false); 1606 ASSERT_TRUE([bar_ appsPageShortcutButtonIsHidden]); 1607 EXPECT_GT(apps_button_right, 1608 NSMinX([[[bar_ buttonView] noItemTextfield] frame])); 1609 EXPECT_LE(NSMaxX([[[bar_ buttonView] noItemTextfield] frame]), 1610 NSMinX([[[bar_ buttonView] importBookmarksButton] frame])); 1611} 1612 1613class BookmarkBarControllerOpenAllTest : public BookmarkBarControllerTest { 1614public: 1615 virtual void SetUp() { 1616 BookmarkBarControllerTest::SetUp(); 1617 ASSERT_TRUE(profile()); 1618 1619 resizeDelegate_.reset([[ViewResizerPong alloc] init]); 1620 NSRect parent_frame = NSMakeRect(0, 0, 800, 50); 1621 bar_.reset( 1622 [[BookmarkBarControllerOpenAllPong alloc] 1623 initWithBrowser:browser() 1624 initialWidth:NSWidth(parent_frame) 1625 delegate:nil 1626 resizeDelegate:resizeDelegate_.get()]); 1627 [bar_ view]; 1628 // Awkwardness to look like we've been installed. 1629 [parent_view_ addSubview:[bar_ view]]; 1630 NSRect frame = [[[bar_ view] superview] frame]; 1631 frame.origin.y = 100; 1632 [[[bar_ view] superview] setFrame:frame]; 1633 1634 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1635 parent_ = model->bookmark_bar_node(); 1636 // { one, { two-one, two-two }, three } 1637 model->AddURL(parent_, parent_->child_count(), ASCIIToUTF16("title"), 1638 GURL("http://one.com")); 1639 folder_ = model->AddFolder(parent_, parent_->child_count(), 1640 ASCIIToUTF16("folder")); 1641 model->AddURL(folder_, folder_->child_count(), 1642 ASCIIToUTF16("title"), GURL("http://two-one.com")); 1643 model->AddURL(folder_, folder_->child_count(), 1644 ASCIIToUTF16("title"), GURL("http://two-two.com")); 1645 model->AddURL(parent_, parent_->child_count(), 1646 ASCIIToUTF16("title"), GURL("https://three.com")); 1647 } 1648 const BookmarkNode* parent_; // Weak 1649 const BookmarkNode* folder_; // Weak 1650}; 1651 1652// Command-click on a folder should open all the bookmarks in it. 1653TEST_F(BookmarkBarControllerOpenAllTest, CommandClickOnFolder) { 1654 NSButton* first = [[bar_ buttons] objectAtIndex:0]; 1655 EXPECT_TRUE(first); 1656 1657 // Create the right kind of event; mock NSApp so [NSApp 1658 // currentEvent] finds it. 1659 NSEvent* commandClick = 1660 cocoa_test_event_utils::MouseEventAtPoint(NSZeroPoint, 1661 NSLeftMouseDown, 1662 NSCommandKeyMask); 1663 id fakeApp = [OCMockObject partialMockForObject:NSApp]; 1664 [[[fakeApp stub] andReturn:commandClick] currentEvent]; 1665 id oldApp = NSApp; 1666 NSApp = fakeApp; 1667 size_t originalDispositionCount = noOpenBar()->dispositions_.size(); 1668 1669 // Click! 1670 [first performClick:first]; 1671 1672 size_t dispositionCount = noOpenBar()->dispositions_.size(); 1673 EXPECT_EQ(originalDispositionCount+1, dispositionCount); 1674 EXPECT_EQ(noOpenBar()->dispositions_[dispositionCount-1], NEW_BACKGROUND_TAB); 1675 1676 // Replace NSApp 1677 NSApp = oldApp; 1678} 1679 1680class BookmarkBarControllerNotificationTest : public CocoaProfileTest { 1681 public: 1682 virtual void SetUp() { 1683 CocoaProfileTest::SetUp(); 1684 ASSERT_TRUE(browser()); 1685 1686 resizeDelegate_.reset([[ViewResizerPong alloc] init]); 1687 NSRect parent_frame = NSMakeRect(0, 0, 800, 50); 1688 parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]); 1689 [parent_view_ setHidden:YES]; 1690 bar_.reset( 1691 [[BookmarkBarControllerNotificationPong alloc] 1692 initWithBrowser:browser() 1693 initialWidth:NSWidth(parent_frame) 1694 delegate:nil 1695 resizeDelegate:resizeDelegate_.get()]); 1696 1697 // Force loading of the nib. 1698 [bar_ view]; 1699 // Awkwardness to look like we've been installed. 1700 [parent_view_ addSubview:[bar_ view]]; 1701 NSRect frame = [[[bar_ view] superview] frame]; 1702 frame.origin.y = 100; 1703 [[[bar_ view] superview] setFrame:frame]; 1704 1705 // Do not add the bar to a window, yet. 1706 } 1707 1708 base::scoped_nsobject<NSView> parent_view_; 1709 base::scoped_nsobject<ViewResizerPong> resizeDelegate_; 1710 base::scoped_nsobject<BookmarkBarControllerNotificationPong> bar_; 1711}; 1712 1713TEST_F(BookmarkBarControllerNotificationTest, DeregistersForNotifications) { 1714 NSWindow* window = [[CocoaTestHelperWindow alloc] init]; 1715 [window setReleasedWhenClosed:YES]; 1716 1717 // First add the bookmark bar to the temp window, then to another window. 1718 [[window contentView] addSubview:parent_view_]; 1719 [[test_window() contentView] addSubview:parent_view_]; 1720 1721 // Post a fake windowDidResignKey notification for the temp window and make 1722 // sure the bookmark bar controller wasn't listening. 1723 [[NSNotificationCenter defaultCenter] 1724 postNotificationName:NSWindowDidResignKeyNotification 1725 object:window]; 1726 EXPECT_FALSE([bar_ windowDidResignKeyReceived]); 1727 1728 // Close the temp window and make sure no notification was received. 1729 [window close]; 1730 EXPECT_FALSE([bar_ windowWillCloseReceived]); 1731} 1732 1733 1734// TODO(jrg): draggingEntered: and draggingExited: trigger timers so 1735// they are hard to test. Factor out "fire timers" into routines 1736// which can be overridden to fire immediately to make behavior 1737// confirmable. 1738 1739// TODO(jrg): add unit test to make sure "Other Bookmarks" responds 1740// properly to a hover open. 1741 1742// TODO(viettrungluu): figure out how to test animations. 1743 1744class BookmarkBarControllerDragDropTest : public BookmarkBarControllerTestBase { 1745 public: 1746 base::scoped_nsobject<BookmarkBarControllerDragData> bar_; 1747 1748 virtual void SetUp() { 1749 BookmarkBarControllerTestBase::SetUp(); 1750 ASSERT_TRUE(browser()); 1751 1752 bar_.reset( 1753 [[BookmarkBarControllerDragData alloc] 1754 initWithBrowser:browser() 1755 initialWidth:NSWidth([parent_view_ frame]) 1756 delegate:nil 1757 resizeDelegate:resizeDelegate_.get()]); 1758 InstallAndToggleBar(bar_.get()); 1759 } 1760}; 1761 1762TEST_F(BookmarkBarControllerDragDropTest, DragMoveBarBookmarkToOffTheSide) { 1763 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1764 const BookmarkNode* root = model->bookmark_bar_node(); 1765 const std::string model_string("1bWithLongName 2fWithLongName:[ " 1766 "2f1bWithLongName 2f2fWithLongName:[ 2f2f1bWithLongName " 1767 "2f2f2bWithLongName 2f2f3bWithLongName 2f4b ] 2f3bWithLongName ] " 1768 "3bWithLongName 4bWithLongName 5bWithLongName 6bWithLongName " 1769 "7bWithLongName 8bWithLongName 9bWithLongName 10bWithLongName " 1770 "11bWithLongName 12bWithLongName 13b "); 1771 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1772 1773 // Validate initial model. 1774 std::string actualModelString = 1775 BookmarkModelTestUtils::ModelStringFromNode(root); 1776 EXPECT_EQ(model_string, actualModelString); 1777 1778 // Insure that the off-the-side is not showing. 1779 ASSERT_FALSE([bar_ offTheSideButtonIsHidden]); 1780 1781 // Remember how many buttons are showing and are available. 1782 int oldDisplayedButtons = [bar_ displayedButtonCount]; 1783 int oldChildCount = root->child_count(); 1784 1785 // Pop up the off-the-side menu. 1786 BookmarkButton* otsButton = (BookmarkButton*)[bar_ offTheSideButton]; 1787 ASSERT_TRUE(otsButton); 1788 [[otsButton target] performSelector:@selector(openOffTheSideFolderFromButton:) 1789 withObject:otsButton]; 1790 BookmarkBarFolderController* otsController = [bar_ folderController]; 1791 EXPECT_TRUE(otsController); 1792 NSWindow* toWindow = [otsController window]; 1793 EXPECT_TRUE(toWindow); 1794 BookmarkButton* draggedButton = 1795 [bar_ buttonWithTitleEqualTo:@"3bWithLongName"]; 1796 ASSERT_TRUE(draggedButton); 1797 int oldOTSCount = (int)[[otsController buttons] count]; 1798 EXPECT_EQ(oldOTSCount, oldChildCount - oldDisplayedButtons); 1799 BookmarkButton* targetButton = [[otsController buttons] objectAtIndex:0]; 1800 ASSERT_TRUE(targetButton); 1801 [otsController dragButton:draggedButton 1802 to:[targetButton center] 1803 copy:YES]; 1804 // There should still be the same number of buttons in the bar 1805 // and off-the-side should have one more. 1806 int newDisplayedButtons = [bar_ displayedButtonCount]; 1807 int newChildCount = root->child_count(); 1808 int newOTSCount = (int)[[otsController buttons] count]; 1809 EXPECT_EQ(oldDisplayedButtons, newDisplayedButtons); 1810 EXPECT_EQ(oldChildCount + 1, newChildCount); 1811 EXPECT_EQ(oldOTSCount + 1, newOTSCount); 1812 EXPECT_EQ(newOTSCount, newChildCount - newDisplayedButtons); 1813} 1814 1815TEST_F(BookmarkBarControllerDragDropTest, DragOffTheSideToOther) { 1816 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1817 const BookmarkNode* root = model->bookmark_bar_node(); 1818 const std::string model_string("1bWithLongName 2bWithLongName " 1819 "3bWithLongName 4bWithLongName 5bWithLongName 6bWithLongName " 1820 "7bWithLongName 8bWithLongName 9bWithLongName 10bWithLongName " 1821 "11bWithLongName 12bWithLongName 13bWithLongName 14bWithLongName " 1822 "15bWithLongName 16bWithLongName 17bWithLongName 18bWithLongName " 1823 "19bWithLongName 20bWithLongName "); 1824 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1825 1826 const BookmarkNode* other = model->other_node(); 1827 const std::string other_string("1other 2other 3other "); 1828 BookmarkModelTestUtils::AddNodesFromModelString(model, other, other_string); 1829 1830 // Validate initial model. 1831 std::string actualModelString = 1832 BookmarkModelTestUtils::ModelStringFromNode(root); 1833 EXPECT_EQ(model_string, actualModelString); 1834 std::string actualOtherString = 1835 BookmarkModelTestUtils::ModelStringFromNode(other); 1836 EXPECT_EQ(other_string, actualOtherString); 1837 1838 // Insure that the off-the-side is showing. 1839 ASSERT_FALSE([bar_ offTheSideButtonIsHidden]); 1840 1841 // Remember how many buttons are showing and are available. 1842 int oldDisplayedButtons = [bar_ displayedButtonCount]; 1843 int oldRootCount = root->child_count(); 1844 int oldOtherCount = other->child_count(); 1845 1846 // Pop up the off-the-side menu. 1847 BookmarkButton* otsButton = (BookmarkButton*)[bar_ offTheSideButton]; 1848 ASSERT_TRUE(otsButton); 1849 [[otsButton target] performSelector:@selector(openOffTheSideFolderFromButton:) 1850 withObject:otsButton]; 1851 BookmarkBarFolderController* otsController = [bar_ folderController]; 1852 EXPECT_TRUE(otsController); 1853 int oldOTSCount = (int)[[otsController buttons] count]; 1854 EXPECT_EQ(oldOTSCount, oldRootCount - oldDisplayedButtons); 1855 1856 // Pick an off-the-side button and drag it to the other bookmarks. 1857 BookmarkButton* draggedButton = 1858 [otsController buttonWithTitleEqualTo:@"20bWithLongName"]; 1859 ASSERT_TRUE(draggedButton); 1860 BookmarkButton* targetButton = [bar_ otherBookmarksButton]; 1861 ASSERT_TRUE(targetButton); 1862 [bar_ dragButton:draggedButton to:[targetButton center] copy:NO]; 1863 1864 // There should one less button in the bar, one less in off-the-side, 1865 // and one more in other bookmarks. 1866 int newRootCount = root->child_count(); 1867 int newOTSCount = (int)[[otsController buttons] count]; 1868 int newOtherCount = other->child_count(); 1869 EXPECT_EQ(oldRootCount - 1, newRootCount); 1870 EXPECT_EQ(oldOTSCount - 1, newOTSCount); 1871 EXPECT_EQ(oldOtherCount + 1, newOtherCount); 1872} 1873 1874TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkData) { 1875 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1876 const BookmarkNode* root = model->bookmark_bar_node(); 1877 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1878 "2f3b ] 3b 4b "); 1879 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1880 const BookmarkNode* other = model->other_node(); 1881 const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] " 1882 "O4f:[ O4f1b O4f2f ] 05b "); 1883 BookmarkModelTestUtils::AddNodesFromModelString(model, other, other_string); 1884 1885 // Validate initial model. 1886 std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root); 1887 EXPECT_EQ(model_string, actual); 1888 actual = BookmarkModelTestUtils::ModelStringFromNode(other); 1889 EXPECT_EQ(other_string, actual); 1890 1891 // Remember the little ones. 1892 int oldChildCount = root->child_count(); 1893 1894 BookmarkButton* targetButton = [bar_ buttonWithTitleEqualTo:@"3b"]; 1895 ASSERT_TRUE(targetButton); 1896 1897 // Gen up some dragging data. 1898 const BookmarkNode* newNode = other->GetChild(2); 1899 [bar_ setDragDataNode:newNode]; 1900 base::scoped_nsobject<FakeDragInfo> dragInfo([[FakeDragInfo alloc] init]); 1901 [dragInfo setDropLocation:[targetButton center]]; 1902 [bar_ dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()]; 1903 1904 // There should one more button in the bar. 1905 int newChildCount = root->child_count(); 1906 EXPECT_EQ(oldChildCount + 1, newChildCount); 1907 // Verify the model. 1908 const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1909 "2f3b ] O3f:[ O3f1b O3f2f ] 3b 4b "); 1910 actual = BookmarkModelTestUtils::ModelStringFromNode(root); 1911 EXPECT_EQ(expected, actual); 1912 oldChildCount = newChildCount; 1913 1914 // Now do it over a folder button. 1915 targetButton = [bar_ buttonWithTitleEqualTo:@"2f"]; 1916 ASSERT_TRUE(targetButton); 1917 NSPoint targetPoint = [targetButton center]; 1918 newNode = other->GetChild(2); // Should be O4f. 1919 EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f")); 1920 [bar_ setDragDataNode:newNode]; 1921 [dragInfo setDropLocation:targetPoint]; 1922 [bar_ dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()]; 1923 1924 newChildCount = root->child_count(); 1925 EXPECT_EQ(oldChildCount, newChildCount); 1926 // Verify the model. 1927 const std::string expected1("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1928 "2f3b O4f:[ O4f1b O4f2f ] ] O3f:[ O3f1b O3f2f ] " 1929 "3b 4b "); 1930 actual = BookmarkModelTestUtils::ModelStringFromNode(root); 1931 EXPECT_EQ(expected1, actual); 1932} 1933 1934TEST_F(BookmarkBarControllerDragDropTest, AddURLs) { 1935 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1936 const BookmarkNode* root = model->bookmark_bar_node(); 1937 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1938 "2f3b ] 3b 4b "); 1939 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1940 1941 // Validate initial model. 1942 std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root); 1943 EXPECT_EQ(model_string, actual); 1944 1945 // Remember the children. 1946 int oldChildCount = root->child_count(); 1947 1948 BookmarkButton* targetButton = [bar_ buttonWithTitleEqualTo:@"3b"]; 1949 ASSERT_TRUE(targetButton); 1950 1951 NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/", 1952 @"http://www.b.com/", nil]; 1953 NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil]; 1954 [bar_ addURLs:urls withTitles:titles at:[targetButton center]]; 1955 1956 // There should two more nodes in the bar. 1957 int newChildCount = root->child_count(); 1958 EXPECT_EQ(oldChildCount + 2, newChildCount); 1959 // Verify the model. 1960 const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 1961 "2f3b ] SiteA SiteB 3b 4b "); 1962 actual = BookmarkModelTestUtils::ModelStringFromNode(root); 1963 EXPECT_EQ(expected, actual); 1964} 1965 1966TEST_F(BookmarkBarControllerDragDropTest, ControllerForNode) { 1967 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1968 const BookmarkNode* root = model->bookmark_bar_node(); 1969 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b "); 1970 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1971 1972 // Validate initial model. 1973 std::string actualModelString = 1974 BookmarkModelTestUtils::ModelStringFromNode(root); 1975 EXPECT_EQ(model_string, actualModelString); 1976 1977 // Find the main bar controller. 1978 const void* expectedController = bar_; 1979 const void* actualController = [bar_ controllerForNode:root]; 1980 EXPECT_EQ(expectedController, actualController); 1981} 1982 1983TEST_F(BookmarkBarControllerDragDropTest, DropPositionIndicator) { 1984 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 1985 const BookmarkNode* root = model->bookmark_bar_node(); 1986 const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b "); 1987 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 1988 1989 // Validate initial model. 1990 std::string actualModel = BookmarkModelTestUtils::ModelStringFromNode(root); 1991 EXPECT_EQ(model_string, actualModel); 1992 1993 // Test a series of points starting at the right edge of the bar. 1994 BookmarkButton* targetButton = [bar_ buttonWithTitleEqualTo:@"1b"]; 1995 ASSERT_TRUE(targetButton); 1996 NSPoint targetPoint = [targetButton left]; 1997 CGFloat leftMarginIndicatorPosition = bookmarks::kBookmarkLeftMargin - 0.5 * 1998 bookmarks::kBookmarkHorizontalPadding; 1999 const CGFloat baseOffset = targetPoint.x; 2000 CGFloat expected = leftMarginIndicatorPosition; 2001 CGFloat actual = [bar_ indicatorPosForDragToPoint:targetPoint]; 2002 EXPECT_CGFLOAT_EQ(expected, actual); 2003 targetButton = [bar_ buttonWithTitleEqualTo:@"2f"]; 2004 actual = [bar_ indicatorPosForDragToPoint:[targetButton right]]; 2005 targetButton = [bar_ buttonWithTitleEqualTo:@"3b"]; 2006 expected = [targetButton left].x - baseOffset + leftMarginIndicatorPosition; 2007 EXPECT_CGFLOAT_EQ(expected, actual); 2008 targetButton = [bar_ buttonWithTitleEqualTo:@"4b"]; 2009 targetPoint = [targetButton right]; 2010 targetPoint.x += 100; // Somewhere off to the right. 2011 CGFloat xDelta = 0.5 * bookmarks::kBookmarkHorizontalPadding; 2012 expected = NSMaxX([targetButton frame]) + xDelta; 2013 actual = [bar_ indicatorPosForDragToPoint:targetPoint]; 2014 EXPECT_CGFLOAT_EQ(expected, actual); 2015} 2016 2017TEST_F(BookmarkBarControllerDragDropTest, PulseButton) { 2018 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 2019 const BookmarkNode* root = model->bookmark_bar_node(); 2020 GURL gurl("http://www.google.com"); 2021 const BookmarkNode* node = model->AddURL(root, root->child_count(), 2022 ASCIIToUTF16("title"), gurl); 2023 2024 BookmarkButton* button = [[bar_ buttons] objectAtIndex:0]; 2025 EXPECT_FALSE([button isContinuousPulsing]); 2026 2027 NSValue *value = [NSValue valueWithPointer:node]; 2028 NSDictionary *dict = [NSDictionary 2029 dictionaryWithObjectsAndKeys:value, 2030 bookmark_button::kBookmarkKey, 2031 [NSNumber numberWithBool:YES], 2032 bookmark_button::kBookmarkPulseFlagKey, 2033 nil]; 2034 [[NSNotificationCenter defaultCenter] 2035 postNotificationName:bookmark_button::kPulseBookmarkButtonNotification 2036 object:nil 2037 userInfo:dict]; 2038 EXPECT_TRUE([button isContinuousPulsing]); 2039 2040 dict = [NSDictionary dictionaryWithObjectsAndKeys:value, 2041 bookmark_button::kBookmarkKey, 2042 [NSNumber numberWithBool:NO], 2043 bookmark_button::kBookmarkPulseFlagKey, 2044 nil]; 2045 [[NSNotificationCenter defaultCenter] 2046 postNotificationName:bookmark_button::kPulseBookmarkButtonNotification 2047 object:nil 2048 userInfo:dict]; 2049 EXPECT_FALSE([button isContinuousPulsing]); 2050} 2051 2052TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkDataToTrash) { 2053 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile()); 2054 const BookmarkNode* root = model->bookmark_bar_node(); 2055 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 2056 "2f3b ] 3b 4b "); 2057 BookmarkModelTestUtils::AddNodesFromModelString(model, root, model_string); 2058 2059 // Validate initial model. 2060 std::string actual = BookmarkModelTestUtils::ModelStringFromNode(root); 2061 EXPECT_EQ(model_string, actual); 2062 2063 int oldChildCount = root->child_count(); 2064 2065 // Drag a button to the trash. 2066 BookmarkButton* buttonToDelete = [bar_ buttonWithTitleEqualTo:@"3b"]; 2067 ASSERT_TRUE(buttonToDelete); 2068 EXPECT_TRUE([bar_ canDragBookmarkButtonToTrash:buttonToDelete]); 2069 [bar_ didDragBookmarkToTrash:buttonToDelete]; 2070 2071 // There should be one less button in the bar. 2072 int newChildCount = root->child_count(); 2073 EXPECT_EQ(oldChildCount - 1, newChildCount); 2074 // Verify the model. 2075 const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] " 2076 "2f3b ] 4b "); 2077 actual = BookmarkModelTestUtils::ModelStringFromNode(root); 2078 EXPECT_EQ(expected, actual); 2079 2080 // Verify that the other bookmark folder can't be deleted. 2081 BookmarkButton *otherButton = [bar_ otherBookmarksButton]; 2082 EXPECT_FALSE([bar_ canDragBookmarkButtonToTrash:otherButton]); 2083} 2084 2085} // namespace 2086