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.
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"
27 using base::ASCIIToUTF16;
28 using bookmarks::BookmarkModel;
29 using bookmarks::BookmarkNode;
33 const int kLotsOfNodesCount = 150;
35 // Deletes the bookmark corresponding to |button|.
36 void DeleteBookmark(BookmarkButton* button, Profile* profile) {
37 const BookmarkNode* node = [button bookmarkNode];
39 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile);
46 // Add a redirect to make testing easier.
47 @interface BookmarkBarFolderController(MakeTestingEasier)
48 - (void)validateMenuSpacing;
51 @implementation BookmarkBarFolderController(MakeTestingEasier)
53 // Utility function to verify that the buttons in this folder are all
54 // evenly spaced in a progressive manner.
55 - (void)validateMenuSpacing {
56 BOOL firstButton = YES;
57 CGFloat lastVerticalOffset = 0.0;
58 for (BookmarkButton* button in [self buttons]) {
61 lastVerticalOffset = [button frame].origin.y;
63 CGFloat nextVerticalOffset = [button frame].origin.y;
64 EXPECT_CGFLOAT_EQ(lastVerticalOffset -
65 bookmarks::kBookmarkFolderButtonHeight,
67 lastVerticalOffset = nextVerticalOffset;
73 // Don't use a high window level when running unit tests -- it'll
74 // interfere with anything else you are working on.
76 @interface BookmarkBarFolderControllerNoLevel : BookmarkBarFolderController
79 @implementation BookmarkBarFolderControllerNoLevel
80 - (void)configureWindowLevel {
81 // Intentionally empty.
85 @interface BookmarkBarFolderControllerPong : BookmarkBarFolderController {
86 BOOL childFolderWillShow_;
87 BOOL childFolderWillClose_;
89 @property (nonatomic, readonly) BOOL childFolderWillShow;
90 @property (nonatomic, readonly) BOOL childFolderWillClose;
93 @implementation BookmarkBarFolderControllerPong
94 @synthesize childFolderWillShow = childFolderWillShow_;
95 @synthesize childFolderWillClose = childFolderWillClose_;
97 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
98 childFolderWillShow_ = YES;
101 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
102 childFolderWillClose_ = YES;
105 // We don't have a real BookmarkBarController as our parent root so
106 // we fake this one out.
107 - (void)closeAllBookmarkFolders {
108 [self closeBookmarkFolder:self];
113 // Redirect certain calls so they can be seen by tests.
115 @interface BookmarkBarControllerChildFolderRedirect : BookmarkBarController {
116 BookmarkBarFolderController* childFolderDelegate_;
118 @property (nonatomic, assign) BookmarkBarFolderController* childFolderDelegate;
121 @implementation BookmarkBarControllerChildFolderRedirect
123 @synthesize childFolderDelegate = childFolderDelegate_;
125 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
126 [childFolderDelegate_ childFolderWillShow:child];
129 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
130 [childFolderDelegate_ childFolderWillClose:child];
136 class BookmarkBarFolderControllerTest : public CocoaProfileTest {
138 base::scoped_nsobject<BookmarkBarControllerChildFolderRedirect> bar_;
139 const BookmarkNode* folderA_; // Owned by model.
140 const BookmarkNode* longTitleNode_; // Owned by model.
142 void SetUp() override {
143 CocoaProfileTest::SetUp();
144 ASSERT_TRUE(profile());
150 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
151 const BookmarkNode* parent = model->bookmark_bar_node();
152 const BookmarkNode* folderA = model->AddFolder(parent,
153 parent->child_count(),
154 ASCIIToUTF16("folder"));
156 model->AddFolder(parent, parent->child_count(),
157 ASCIIToUTF16("sibbling folder"));
158 const BookmarkNode* folderB = model->AddFolder(folderA,
159 folderA->child_count(),
160 ASCIIToUTF16("subfolder 1"));
161 model->AddFolder(folderA,
162 folderA->child_count(),
163 ASCIIToUTF16("subfolder 2"));
164 model->AddURL(folderA, folderA->child_count(), ASCIIToUTF16("title a"),
165 GURL("http://www.google.com/a"));
166 longTitleNode_ = model->AddURL(
167 folderA, folderA->child_count(),
168 ASCIIToUTF16("title super duper long long whoa momma title you betcha"),
169 GURL("http://www.google.com/b"));
170 model->AddURL(folderB, folderB->child_count(), ASCIIToUTF16("t"),
171 GURL("http://www.google.com/c"));
174 [[BookmarkBarControllerChildFolderRedirect alloc]
175 initWithBrowser:browser()
178 resizeDelegate:nil]);
180 // Make parent frame for bookmark bar then open it.
181 NSRect frame = [[test_window() contentView] frame];
182 frame = NSMakeRect(frame.origin.x,
183 frame.size.height - chrome::kNTPBookmarkBarHeight,
184 frame.size.width, chrome::kNTPBookmarkBarHeight);
185 NSView* fakeToolbarView = [[[NSView alloc] initWithFrame:frame]
187 [[test_window() contentView] addSubview:fakeToolbarView];
188 [fakeToolbarView addSubview:[bar_ view]];
189 [bar_ setBookmarkBarEnabled:YES];
192 // Remove the bookmark with the long title.
193 void RemoveLongTitleNode() {
194 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
195 model->Remove(longTitleNode_);
198 // Add LOTS of nodes to our model if needed (e.g. scrolling).
199 // Returns the number of nodes added.
200 int AddLotsOfNodes() {
201 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
202 for (int i = 0; i < kLotsOfNodesCount; i++) {
203 model->AddURL(folderA_, folderA_->child_count(),
204 ASCIIToUTF16("repeated title"),
205 GURL("http://www.google.com/repeated/url"));
207 return kLotsOfNodesCount;
210 // Return a simple BookmarkBarFolderController.
211 BookmarkBarFolderControllerPong* SimpleBookmarkBarFolderController() {
212 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
213 BookmarkBarFolderControllerPong* c =
214 [[BookmarkBarFolderControllerPong alloc]
215 initWithParentButton:parentButton
219 [c window]; // Force nib load.
224 TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) {
225 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
226 bbfc.reset(SimpleBookmarkBarFolderController());
228 // Make sure none of the buttons overlap, that all are inside
229 // the content frame, and their cells are of the proper class.
230 NSArray* buttons = [bbfc buttons];
231 EXPECT_TRUE([buttons count]);
232 for (unsigned int i = 0; i < ([buttons count]-1); i++) {
233 EXPECT_FALSE(NSContainsRect([[buttons objectAtIndex:i] frame],
234 [[buttons objectAtIndex:i+1] frame]));
236 Class cellClass = [BookmarkBarFolderButtonCell class];
237 for (BookmarkButton* button in buttons) {
238 NSRect r = [[bbfc folderView] convertRect:[button frame] fromView:button];
239 // TODO(jrg): remove this adjustment.
240 NSRect bigger = NSInsetRect([[bbfc folderView] frame], -2, 0);
241 EXPECT_TRUE(NSContainsRect(bigger, r));
242 EXPECT_TRUE([[button cell] isKindOfClass:cellClass]);
245 // Confirm folder buttons have no tooltip. The important thing
246 // really is that we insure folders and non-folders are treated
247 // differently; not sure of any other generic way to do this.
248 for (BookmarkButton* button in buttons) {
249 if ([button isFolder])
250 EXPECT_FALSE([button toolTip]);
252 EXPECT_TRUE([button toolTip]);
256 // Make sure closing of the window releases the controller.
257 // (e.g. valgrind shouldn't complain if we do this).
258 TEST_F(BookmarkBarFolderControllerTest, ReleaseOnClose) {
259 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
260 bbfc.reset(SimpleBookmarkBarFolderController());
261 EXPECT_TRUE(bbfc.get());
263 [bbfc retain]; // stop the scoped_nsobject from doing anything
264 [[bbfc window] close]; // trigger an autorelease of bbfc.get()
267 TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
268 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
269 EXPECT_TRUE(parentButton);
271 // If parent is a BookmarkBarController, grow down.
272 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
273 bbfc.reset([[BookmarkBarFolderController alloc]
274 initWithParentButton:parentButton
279 NSPoint pt = [bbfc windowTopLeftForWidth:0 height:100]; // screen coords
280 NSPoint buttonOriginInWindow =
281 [parentButton convertRect:[parentButton bounds]
283 NSPoint buttonOriginInScreen =
284 [[parentButton window] convertBaseToScreen:buttonOriginInWindow];
286 EXPECT_LE(std::abs(pt.x - buttonOriginInScreen.x),
287 bookmarks::kBookmarkMenuOverlap + 1);
288 EXPECT_LE(std::abs(pt.y - buttonOriginInScreen.y),
289 bookmarks::kBookmarkMenuOverlap + 1);
291 // Make sure we see the window shift left if it spills off the screen
292 pt = [bbfc windowTopLeftForWidth:0 height:100];
293 NSPoint shifted = [bbfc windowTopLeftForWidth:9999999 height:100];
294 EXPECT_LT(shifted.x, pt.x);
296 // If parent is a BookmarkBarFolderController, grow right.
297 base::scoped_nsobject<BookmarkBarFolderController> bbfc2;
298 bbfc2.reset([[BookmarkBarFolderController alloc]
299 initWithParentButton:[[bbfc buttons] objectAtIndex:0]
300 parentController:bbfc.get()
304 pt = [bbfc2 windowTopLeftForWidth:0 height:100];
305 // We're now overlapping the window a bit.
306 EXPECT_EQ(pt.x, NSMaxX([[bbfc.get() window] frame]) -
307 bookmarks::kBookmarkMenuOverlap);
310 // Confirm we grow right until end of screen, then start growing left
311 // until end of screen again, then right.
312 TEST_F(BookmarkBarFolderControllerTest, PositionRightLeftRight) {
313 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
314 const BookmarkNode* parent = model->bookmark_bar_node();
315 const BookmarkNode* folder = parent;
317 const int count = 100;
319 // Make some super duper deeply nested folders.
320 for (i = 0; i < count; i++) {
321 folder = model->AddFolder(folder, 0, ASCIIToUTF16("nested folder"));
324 // Setup initial state for opening all folders.
326 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
327 BookmarkBarFolderController* parentController = nil;
328 EXPECT_TRUE(parentButton);
331 base::scoped_nsobject<NSMutableArray> folder_controller_array;
332 folder_controller_array.reset([[NSMutableArray array] retain]);
333 for (i=0; i<count; i++) {
334 BookmarkBarFolderControllerNoLevel* bbfcl =
335 [[BookmarkBarFolderControllerNoLevel alloc]
336 initWithParentButton:parentButton
337 parentController:parentController
340 [folder_controller_array addObject:bbfcl];
343 parentController = bbfcl;
344 parentButton = [[bbfcl buttons] objectAtIndex:0];
347 // Make vector of all x positions.
348 std::vector<CGFloat> leftPositions;
349 for (i=0; i<count; i++) {
350 CGFloat x = [[[folder_controller_array objectAtIndex:i] window]
352 leftPositions.push_back(x);
355 // Make sure the first few grow right.
357 EXPECT_TRUE(leftPositions[i+1] > leftPositions[i]);
359 // Look for the first "grow left".
360 while (leftPositions[i] > leftPositions[i-1])
362 // Confirm the next few also grow left.
364 for (j=i; j<i+3; j++)
365 EXPECT_TRUE(leftPositions[j+1] < leftPositions[j]);
368 // Finally, confirm we see a "grow right" once more.
369 while (leftPositions[i] < leftPositions[i-1])
371 // (No need to EXPECT a final "grow right"; if we didn't find one
372 // we'd get a C++ array bounds exception).
375 TEST_F(BookmarkBarFolderControllerTest, DropDestination) {
376 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
377 bbfc.reset(SimpleBookmarkBarFolderController());
378 EXPECT_TRUE(bbfc.get());
380 // Confirm "off the top" and "off the bottom" match no buttons.
381 NSPoint p = NSMakePoint(NSMidX([[bbfc folderView] frame]), 10000);
382 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
383 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
384 p = NSMakePoint(NSMidX([[bbfc folderView] frame]), -1);
385 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
386 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
388 // Confirm "right in the center" (give or take a pixel) is a match,
389 // and confirm "just barely in the button" is not. Anything more
390 // specific seems likely to be tweaked. We don't loop over all
391 // buttons because the scroll view makes them not visible.
392 for (BookmarkButton* button in [bbfc buttons]) {
393 CGFloat x = NSMidX([button frame]);
394 CGFloat y = NSMidY([button frame]);
395 // Somewhere near the center: a match (but only if a folder!)
396 if ([button isFolder]) {
398 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
400 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
401 EXPECT_FALSE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
403 // If not a folder we don't drop into it.
404 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
405 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
406 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
411 TEST_F(BookmarkBarFolderControllerTest, OpenFolder) {
412 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
413 bbfc.reset(SimpleBookmarkBarFolderController());
414 EXPECT_TRUE(bbfc.get());
416 EXPECT_FALSE([bbfc folderController]);
417 BookmarkButton* button = [[bbfc buttons] objectAtIndex:0];
418 [bbfc openBookmarkFolderFromButton:button];
419 id controller = [bbfc folderController];
420 EXPECT_TRUE(controller);
421 EXPECT_EQ([controller parentButton], button);
423 // Click the same one --> it gets closed.
424 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
425 EXPECT_FALSE([bbfc folderController]);
427 // Open a new one --> change.
428 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:1]];
429 EXPECT_NE(controller, [bbfc folderController]);
430 EXPECT_NE([[bbfc folderController] parentButton], button);
432 // Close it --> all gone!
433 [bbfc closeBookmarkFolder:nil];
434 EXPECT_FALSE([bbfc folderController]);
437 TEST_F(BookmarkBarFolderControllerTest, DeleteOpenFolder) {
438 base::scoped_nsobject<BookmarkBarFolderController> parent_controller(
439 SimpleBookmarkBarFolderController());
442 EXPECT_FALSE([parent_controller folderController]);
443 BookmarkButton* button = [[parent_controller buttons] objectAtIndex:0];
444 [parent_controller openBookmarkFolderFromButton:button];
445 EXPECT_EQ([[parent_controller folderController] parentButton], button);
447 // Delete the folder's button - the folder should close.
448 [parent_controller removeButton:0 animate:NO];
449 EXPECT_FALSE([parent_controller folderController]);
452 TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) {
453 base::scoped_nsobject<BookmarkBarFolderControllerPong> bbfc;
454 bbfc.reset(SimpleBookmarkBarFolderController());
455 EXPECT_TRUE(bbfc.get());
456 [bar_ setChildFolderDelegate:bbfc.get()];
458 EXPECT_FALSE([bbfc childFolderWillShow]);
459 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
460 EXPECT_TRUE([bbfc childFolderWillShow]);
462 EXPECT_FALSE([bbfc childFolderWillClose]);
463 [bbfc closeBookmarkFolder:nil];
464 EXPECT_TRUE([bbfc childFolderWillClose]);
466 [bar_ setChildFolderDelegate:nil];
469 // Make sure bookmark folders have variable widths.
470 TEST_F(BookmarkBarFolderControllerTest, ChildFolderWidth) {
471 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
473 bbfc.reset(SimpleBookmarkBarFolderController());
474 EXPECT_TRUE(bbfc.get());
475 [bbfc showWindow:bbfc.get()];
476 CGFloat wideWidth = NSWidth([[bbfc window] frame]);
478 RemoveLongTitleNode();
479 bbfc.reset(SimpleBookmarkBarFolderController());
480 EXPECT_TRUE(bbfc.get());
481 CGFloat thinWidth = NSWidth([[bbfc window] frame]);
483 // Make sure window size changed as expected.
484 EXPECT_GT(wideWidth, thinWidth);
487 // Scrolling (in this case using keyboard up/down buttons) should
488 // not be a cause of item hovering change where the mouse is pointing to.
489 // Here we are simulating scrolling by calling -performOneScroll: which
490 // indirectly is called by keyboard up/down buttons.
491 TEST_F(BookmarkBarFolderControllerTest, ScrollingBehaviorAndMouseMovement){
492 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
494 bbfc.reset(SimpleBookmarkBarFolderController());
495 [bbfc showWindow:bbfc.get()];
496 // We should be able to scroll-up otherwise the rest of the test is pointless.
497 ASSERT_TRUE([bbfc canScrollUp]);
498 NSArray* buttons = [bbfc buttons];
499 BookmarkButton* currentButton = [bbfc buttonThatMouseIsIn];
500 // Mouse cursor is not pointing to any button.
501 EXPECT_FALSE(currentButton);
502 BookmarkButton* firstButton = [buttons objectAtIndex:0];
503 [bbfc mouseEnteredButton:firstButton event:nil];
504 // Mouse cursor should be over the first button.
505 EXPECT_EQ(firstButton, [bbfc buttonThatMouseIsIn]);
506 while ([bbfc canScrollUp]) {
507 [bbfc performOneScroll:200 updateMouseSelection:NO];
508 [bbfc mouseEnteredButton:[buttons objectAtIndex:2] event:nil];
509 // -buttonThatMouseIsIn: must return firstButton because we
510 // are still scrolling. i.e. should not be changed when
511 // -mouseEnteredButton: is called.
512 EXPECT_EQ(firstButton,[bbfc buttonThatMouseIsIn]);
513 // We are scrolling unless mouse movement happens.
514 EXPECT_TRUE([bbfc isScrolling]);
516 [bbfc mouseExitedButton:firstButton event:nil];
517 // If mouse exit from a button scrolling should be stopped.
518 EXPECT_FALSE([bbfc isScrolling]);
519 [bbfc mouseEnteredButton:nil event:nil];
522 // Simple scrolling tests.
523 // Currently flaky due to a changed definition of the correct menu boundaries.
524 TEST_F(BookmarkBarFolderControllerTest, DISABLED_SimpleScroll) {
525 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
526 NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
527 CGFloat screenHeight = NSHeight(screenFrame);
528 int nodecount = AddLotsOfNodes();
529 bbfc.reset(SimpleBookmarkBarFolderController());
530 EXPECT_TRUE(bbfc.get());
531 [bbfc showWindow:bbfc.get()];
532 NSWindow* window = [bbfc window];
534 // The window should be shorter than the screen but reach exactly to the
535 // bottom of the screen since it's scrollable.
536 EXPECT_LT(NSHeight([window frame]), screenHeight);
537 EXPECT_CGFLOAT_EQ(0.0, [window frame].origin.y);
539 // Initially, should show scroll-up but not scroll-down.
540 EXPECT_TRUE([bbfc canScrollUp]);
541 EXPECT_FALSE([bbfc canScrollDown]);
543 // Scroll up a bit. Make sure the window has gotten bigger each time.
544 // Also, for each scroll, make sure our hit test finds a new button
545 // (to confirm the content area changed).
546 NSView* savedHit = nil;
547 NSScrollView* scrollView = [bbfc scrollView];
549 // Find the next-to-last button showing at the bottom of the window and
550 // use its center for hit testing.
551 BookmarkButton* targetButton = nil;
552 NSPoint scrollPoint = [scrollView documentVisibleRect].origin;
553 for (BookmarkButton* button in [bbfc buttons]) {
554 NSRect buttonFrame = [button frame];
555 buttonFrame.origin.y -= scrollPoint.y;
556 if (buttonFrame.origin.y < 0.0)
558 targetButton = button;
560 EXPECT_TRUE(targetButton != nil);
561 NSPoint hitPoint = [targetButton frame].origin;
563 hitPoint.y += (bookmarks::kBookmarkFolderButtonHeight / 2.0) - scrollPoint.y;
564 hitPoint = [targetButton convertPoint:hitPoint toView:scrollView];
566 for (int i = 0; i < 3; i++) {
567 CGFloat height = NSHeight([window frame]);
568 [bbfc performOneScroll:60 updateMouseSelection:NO];
569 EXPECT_GT(NSHeight([window frame]), height);
570 NSView* hit = [scrollView hitTest:hitPoint];
571 // We should hit a bookmark button.
572 EXPECT_TRUE([[hit className] isEqualToString:@"BookmarkButton"]);
573 EXPECT_NE(hit, savedHit);
577 // Keep scrolling up; make sure we never get bigger than the screen.
578 // Also confirm we never scroll the window off the screen.
579 bool bothAtOnce = false;
580 while ([bbfc canScrollUp]) {
581 [bbfc performOneScroll:60 updateMouseSelection:NO];
582 EXPECT_TRUE(NSContainsRect([[NSScreen mainScreen] frame], [window frame]));
583 // Make sure, sometime during our scroll, we have the ability to
584 // scroll in either direction.
585 if ([bbfc canScrollUp] &&
586 [bbfc canScrollDown])
589 EXPECT_TRUE(bothAtOnce);
591 // Once we've scrolled to the end, our only option should be to scroll back.
592 EXPECT_FALSE([bbfc canScrollUp]);
593 EXPECT_TRUE([bbfc canScrollDown]);
595 NSRect wholeScreenRect = [[NSScreen mainScreen] frame];
597 // Now scroll down and make sure the window size does not change.
598 // Also confirm we never scroll the window off the screen the other
600 for (int i = 0; i < nodecount+50; ++i) {
601 [bbfc performOneScroll:-60 updateMouseSelection:NO];
602 // Once we can no longer scroll down the window height changes.
603 if (![bbfc canScrollDown])
605 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame]));
608 EXPECT_GT(NSHeight(wholeScreenRect), NSHeight([window frame]));
609 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame]));
612 // Folder menu sizing and placement while deleting bookmarks
613 // and scrolling tests.
614 TEST_F(BookmarkBarFolderControllerTest, MenuPlacementWhileScrollingDeleting) {
615 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
617 bbfc.reset(SimpleBookmarkBarFolderController());
618 [bbfc showWindow:bbfc.get()];
619 NSWindow* menuWindow = [bbfc window];
620 BookmarkBarFolderController* folder = [bar_ folderController];
621 NSArray* buttons = [folder buttons];
623 // Before scrolling any, delete a bookmark and make sure the window top has
624 // not moved. Pick a button which is near the top and visible.
625 CGFloat oldTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
626 BookmarkButton* button = [buttons objectAtIndex:3];
627 DeleteBookmark(button, profile());
628 CGFloat newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
629 EXPECT_CGFLOAT_EQ(oldTop, newTop);
631 // Scroll so that both the top and bottom scroll arrows show, make sure
632 // the top of the window has moved up, then delete a visible button and
633 // make sure the top has not moved.
635 const CGFloat scrollOneBookmark = bookmarks::kBookmarkFolderButtonHeight +
636 bookmarks::kBookmarkVerticalPadding;
637 NSUInteger buttonCounter = 0;
638 NSUInteger extraButtonLimit = 3;
639 while (![bbfc canScrollDown] || extraButtonLimit > 0) {
640 [bbfc performOneScroll:scrollOneBookmark updateMouseSelection:NO];
642 if ([bbfc canScrollDown])
645 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
646 EXPECT_NE(oldTop, newTop);
648 button = [buttons objectAtIndex:buttonCounter + 3];
649 DeleteBookmark(button, profile());
650 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
651 EXPECT_CGFLOAT_EQ(oldTop, newTop);
653 // Scroll so that the top scroll arrow is no longer showing, make sure
654 // the top of the window has not moved, then delete a visible button and
655 // make sure the top has not moved.
656 while ([bbfc canScrollDown]) {
657 [bbfc performOneScroll:-scrollOneBookmark updateMouseSelection:NO];
660 button = [buttons objectAtIndex:buttonCounter + 3];
661 DeleteBookmark(button, profile());
662 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
663 EXPECT_CGFLOAT_EQ(oldTop - bookmarks::kScrollWindowVerticalMargin, newTop);
666 // Make sure that we return the correct browser window.
667 TEST_F(BookmarkBarFolderControllerTest, BrowserWindow) {
668 base::scoped_nsobject<BookmarkBarFolderController> controller(
669 SimpleBookmarkBarFolderController());
670 EXPECT_EQ([bar_ browserWindow], [controller browserWindow]);
673 @interface FakedDragInfo : NSObject {
675 NSPoint dropLocation_;
676 NSDragOperation sourceMask_;
678 @property (nonatomic, assign) NSPoint dropLocation;
679 - (void)setDraggingSourceOperationMask:(NSDragOperation)mask;
682 @implementation FakedDragInfo
684 @synthesize dropLocation = dropLocation_;
687 if ((self = [super init])) {
688 dropLocation_ = NSZeroPoint;
689 sourceMask_ = NSDragOperationMove;
694 // NSDraggingInfo protocol functions.
696 - (id)draggingPasteboard {
700 - (id)draggingSource {
704 - (NSDragOperation)draggingSourceOperationMask {
708 - (NSPoint)draggingLocation {
709 return dropLocation_;
714 - (void)setDraggingSourceOperationMask:(NSDragOperation)mask {
721 class BookmarkBarFolderControllerMenuTest : public CocoaProfileTest {
723 base::scoped_nsobject<NSView> parent_view_;
724 base::scoped_nsobject<ViewResizerPong> resizeDelegate_;
725 base::scoped_nsobject<BookmarkBarController> bar_;
727 void SetUp() override {
728 CocoaProfileTest::SetUp();
729 ASSERT_TRUE(browser());
731 resizeDelegate_.reset([[ViewResizerPong alloc] init]);
732 NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
733 parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
734 [parent_view_ setHidden:YES];
735 bar_.reset([[BookmarkBarController alloc]
736 initWithBrowser:browser()
737 initialWidth:NSWidth(parent_frame)
739 resizeDelegate:resizeDelegate_.get()]);
740 InstallAndToggleBar(bar_.get());
743 void InstallAndToggleBar(BookmarkBarController* bar) {
744 // Force loading of the nib.
746 // Awkwardness to look like we've been installed.
747 [parent_view_ addSubview:[bar view]];
748 NSRect frame = [[[bar view] superview] frame];
749 frame.origin.y = 400;
750 [[[bar view] superview] setFrame:frame];
752 // Make sure it's on in a window so viewDidMoveToWindow is called
753 [[test_window() contentView] addSubview:parent_view_];
755 // Make sure it's open so certain things aren't no-ops.
756 [bar updateState:BookmarkBar::SHOW
757 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE];
761 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
762 WithNoAnimation at_all;
763 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
764 const BookmarkNode* root = model->bookmark_bar_node();
765 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
766 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
767 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
768 bookmarks::test::AddNodesFromModelString(model, root, model_string);
770 // Validate initial model.
771 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
772 EXPECT_EQ(model_string, actualModelString);
774 // Pop up a folder menu and drag in a button from the bar.
775 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
776 NSRect oldToFolderFrame = [toFolder frame];
777 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
778 withObject:toFolder];
779 BookmarkBarFolderController* folderController = [bar_ folderController];
780 EXPECT_TRUE(folderController);
781 NSWindow* toWindow = [folderController window];
782 EXPECT_TRUE(toWindow);
783 NSRect oldToWindowFrame = [toWindow frame];
784 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
785 // so it should end up below the target bookmark.
786 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
787 ASSERT_TRUE(draggedButton);
788 CGFloat horizontalShift =
789 NSWidth([draggedButton frame]) + bookmarks::kBookmarkHorizontalPadding;
790 BookmarkButton* targetButton =
791 [folderController buttonWithTitleEqualTo:@"2f1b"];
792 ASSERT_TRUE(targetButton);
793 [folderController dragButton:draggedButton
794 to:[targetButton center]
796 // The button should have landed just after "2f1b".
797 const std::string expected_string("2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
798 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
799 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
800 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
802 // Verify the window still appears by looking for its controller.
803 EXPECT_TRUE([bar_ folderController]);
805 // Gather the new frames.
806 NSRect newToFolderFrame = [toFolder frame];
807 NSRect newToWindowFrame = [toWindow frame];
808 // The toFolder should have shifted left horizontally but not vertically.
809 NSRect expectedToFolderFrame =
810 NSOffsetRect(oldToFolderFrame, -horizontalShift, 0);
811 EXPECT_NSRECT_EQ(expectedToFolderFrame, newToFolderFrame);
812 // The toWindow should have shifted left horizontally, down vertically,
813 // and grown vertically.
814 NSRect expectedToWindowFrame = oldToWindowFrame;
815 expectedToWindowFrame.origin.x -= horizontalShift;
816 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
817 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight;
818 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
820 // Check button spacing.
821 [folderController validateMenuSpacing];
823 // Move the button back to the bar at the beginning.
824 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
825 ASSERT_TRUE(draggedButton);
826 targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
827 ASSERT_TRUE(targetButton);
828 [bar_ dragButton:draggedButton
829 to:[targetButton left]
831 EXPECT_EQ(model_string, bookmarks::test::ModelStringFromNode(root));
832 // Don't check the folder window since it's not supposed to be showing.
835 TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
836 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
837 const BookmarkNode* root = model->bookmark_bar_node();
838 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
839 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
840 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
841 bookmarks::test::AddNodesFromModelString(model, root, model_string);
843 // Validate initial model.
844 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
845 EXPECT_EQ(model_string, actualModelString);
847 // Pop up a folder menu and copy in a button from the bar.
848 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
849 ASSERT_TRUE(toFolder);
850 NSRect oldToFolderFrame = [toFolder frame];
851 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
852 withObject:toFolder];
853 BookmarkBarFolderController* folderController = [bar_ folderController];
854 EXPECT_TRUE(folderController);
855 NSWindow* toWindow = [folderController window];
856 EXPECT_TRUE(toWindow);
857 NSRect oldToWindowFrame = [toWindow frame];
858 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
859 // so it should end up below the target bookmark.
860 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
861 ASSERT_TRUE(draggedButton);
862 BookmarkButton* targetButton =
863 [folderController buttonWithTitleEqualTo:@"2f1b"];
864 ASSERT_TRUE(targetButton);
865 [folderController dragButton:draggedButton
866 to:[targetButton center]
868 // The button should have landed just after "2f1b".
869 const std::string expected_1("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
870 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
871 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
872 EXPECT_EQ(expected_1, bookmarks::test::ModelStringFromNode(root));
874 // Gather the new frames.
875 NSRect newToFolderFrame = [toFolder frame];
876 NSRect newToWindowFrame = [toWindow frame];
877 // The toFolder should have shifted.
878 EXPECT_NSRECT_EQ(oldToFolderFrame, newToFolderFrame);
879 // The toWindow should have shifted down vertically and grown vertically.
880 NSRect expectedToWindowFrame = oldToWindowFrame;
881 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
882 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight;
883 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
885 // Copy the button back to the bar after "3b".
886 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
887 ASSERT_TRUE(draggedButton);
888 targetButton = [bar_ buttonWithTitleEqualTo:@"4f"];
889 ASSERT_TRUE(targetButton);
890 [bar_ dragButton:draggedButton
891 to:[targetButton left]
893 const std::string expected_2("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
894 "2f2f2b 2f2f3b ] 2f3b ] 3b 1b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
895 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
896 EXPECT_EQ(expected_2, bookmarks::test::ModelStringFromNode(root));
899 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
900 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
901 const BookmarkNode* root = model->bookmark_bar_node();
902 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
903 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
904 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
905 bookmarks::test::AddNodesFromModelString(model, root, model_string);
907 // Validate initial model.
908 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
909 EXPECT_EQ(model_string, actualModelString);
911 // Pop up a folder menu and a subfolder menu.
912 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
913 ASSERT_TRUE(toFolder);
914 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
915 withObject:toFolder];
916 BookmarkBarFolderController* folderController = [bar_ folderController];
917 EXPECT_TRUE(folderController);
918 NSWindow* toWindow = [folderController window];
919 EXPECT_TRUE(toWindow);
920 NSRect oldToWindowFrame = [toWindow frame];
921 BookmarkButton* toSubfolder =
922 [folderController buttonWithTitleEqualTo:@"4f2f"];
923 ASSERT_TRUE(toSubfolder);
924 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
925 withObject:toSubfolder];
926 BookmarkBarFolderController* subfolderController =
927 [folderController folderController];
928 EXPECT_TRUE(subfolderController);
929 NSWindow* toSubwindow = [subfolderController window];
930 EXPECT_TRUE(toSubwindow);
931 NSRect oldToSubwindowFrame = [toSubwindow frame];
932 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
933 // so it should end up below the target bookmark.
934 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"5b"];
935 ASSERT_TRUE(draggedButton);
936 BookmarkButton* targetButton =
937 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
938 ASSERT_TRUE(targetButton);
939 [subfolderController dragButton:draggedButton
940 to:[targetButton center]
942 // The button should have landed just after "2f".
943 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
944 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
945 "4f2f1b 4f2f2b 4f2f3b 5b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] ");
946 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
948 // Check button spacing.
949 [folderController validateMenuSpacing];
950 [subfolderController validateMenuSpacing];
952 // Check the window layouts. The folder window should not have changed,
953 // but the subfolder window should have shifted vertically and grown.
954 NSRect newToWindowFrame = [toWindow frame];
955 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
956 NSRect newToSubwindowFrame = [toSubwindow frame];
957 NSRect expectedToSubwindowFrame = oldToSubwindowFrame;
958 expectedToSubwindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
959 expectedToSubwindowFrame.size.height +=
960 bookmarks::kBookmarkFolderButtonHeight;
961 EXPECT_NSRECT_EQ(expectedToSubwindowFrame, newToSubwindowFrame);
964 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) {
965 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
966 const BookmarkNode* root = model->bookmark_bar_node();
967 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
968 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
969 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
970 bookmarks::test::AddNodesFromModelString(model, root, model_string);
972 // Validate initial model.
973 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
974 EXPECT_EQ(model_string, actualModelString);
976 // Pop up a folder menu.
977 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
978 ASSERT_TRUE(toFolder);
979 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
980 withObject:toFolder];
981 BookmarkBarFolderController* folderController = [bar_ folderController];
982 EXPECT_TRUE(folderController);
983 NSWindow* toWindow = [folderController window];
984 EXPECT_TRUE(toWindow);
985 NSRect oldToWindowFrame = [toWindow frame];
986 // Drag a folder button to the top within the same parent.
987 BookmarkButton* draggedButton =
988 [folderController buttonWithTitleEqualTo:@"4f2f"];
989 ASSERT_TRUE(draggedButton);
990 BookmarkButton* targetButton =
991 [folderController buttonWithTitleEqualTo:@"4f1f"];
992 ASSERT_TRUE(targetButton);
993 [folderController dragButton:draggedButton
994 to:[targetButton top]
996 // The button should have landed above "4f1f".
997 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
998 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f2f:[ 4f2f1b 4f2f2b 4f2f3b ] "
999 "4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
1000 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
1002 // The window should not have gone away.
1003 EXPECT_TRUE([bar_ folderController]);
1005 // The folder window should not have changed.
1006 NSRect newToWindowFrame = [toWindow frame];
1007 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
1009 // Check button spacing.
1010 [folderController validateMenuSpacing];
1013 TEST_F(BookmarkBarFolderControllerMenuTest, DragParentOntoChild) {
1014 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1015 const BookmarkNode* root = model->bookmark_bar_node();
1016 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1017 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
1018 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
1019 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1021 // Validate initial model.
1022 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1023 EXPECT_EQ(model_string, actualModelString);
1025 // Pop up a folder menu.
1026 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
1027 ASSERT_TRUE(toFolder);
1028 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1029 withObject:toFolder];
1030 BookmarkBarFolderController* folderController = [bar_ folderController];
1031 EXPECT_TRUE(folderController);
1032 NSWindow* toWindow = [folderController window];
1033 EXPECT_TRUE(toWindow);
1034 // Drag a folder button to one of its children.
1035 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"4f"];
1036 ASSERT_TRUE(draggedButton);
1037 BookmarkButton* targetButton =
1038 [folderController buttonWithTitleEqualTo:@"4f3f"];
1039 ASSERT_TRUE(targetButton);
1040 [folderController dragButton:draggedButton
1041 to:[targetButton top]
1043 // The model should not have changed.
1044 EXPECT_EQ(model_string, bookmarks::test::ModelStringFromNode(root));
1046 // Check button spacing.
1047 [folderController validateMenuSpacing];
1050 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) {
1051 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1052 const BookmarkNode* root = model->bookmark_bar_node();
1053 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1054 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
1055 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
1056 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1058 // Validate initial model.
1059 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1060 EXPECT_EQ(model_string, actualModelString);
1062 // Pop up a folder menu and a subfolder menu.
1063 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
1064 ASSERT_TRUE(toFolder);
1065 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1066 withObject:toFolder];
1067 BookmarkBarFolderController* folderController = [bar_ folderController];
1068 EXPECT_TRUE(folderController);
1069 BookmarkButton* toSubfolder =
1070 [folderController buttonWithTitleEqualTo:@"4f2f"];
1071 ASSERT_TRUE(toSubfolder);
1072 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1073 withObject:toSubfolder];
1074 BookmarkBarFolderController* subfolderController =
1075 [folderController folderController];
1076 EXPECT_TRUE(subfolderController);
1078 // Drag a subfolder bookmark to the parent folder.
1079 BookmarkButton* draggedButton =
1080 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
1081 ASSERT_TRUE(draggedButton);
1082 BookmarkButton* targetButton =
1083 [folderController buttonWithTitleEqualTo:@"4f2f"];
1084 ASSERT_TRUE(targetButton);
1085 [folderController dragButton:draggedButton
1086 to:[targetButton top]
1088 // The button should have landed above "4f2f".
1089 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1090 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f3b 4f2f:[ "
1091 "4f2f1b 4f2f2b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
1092 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
1094 // Check button spacing.
1095 [folderController validateMenuSpacing];
1096 // The window should not have gone away.
1097 EXPECT_TRUE([bar_ folderController]);
1098 // The subfolder should have gone away.
1099 EXPECT_FALSE([folderController folderController]);
1102 TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) {
1103 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1104 const BookmarkNode* root = model->bookmark_bar_node();
1105 const std::string model_string(
1106 "a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c ");
1107 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1109 // Validate initial model.
1110 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1111 EXPECT_EQ(model_string, actualModelString);
1113 // Pop up a folder menu.
1114 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"b"];
1115 ASSERT_TRUE(toFolder);
1116 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1117 withObject:toFolder];
1118 BookmarkBarFolderController* folderController = [bar_ folderController];
1119 EXPECT_TRUE(folderController);
1120 NSWindow* toWindow = [folderController window];
1121 EXPECT_TRUE(toWindow);
1122 CGFloat oldWidth = NSWidth([toWindow frame]);
1123 // Drag the bookmark with a long name to the folder.
1124 BookmarkButton* draggedButton =
1125 [bar_ buttonWithTitleEqualTo:@"reallyReallyLongBookmarkName"];
1126 ASSERT_TRUE(draggedButton);
1127 BookmarkButton* targetButton =
1128 [folderController buttonWithTitleEqualTo:@"b1"];
1129 ASSERT_TRUE(targetButton);
1130 [folderController dragButton:draggedButton
1131 to:[targetButton center]
1133 // Verify the model change.
1134 const std::string expected_string(
1135 "a b:[ b1 reallyReallyLongBookmarkName b2 b3 ] c ");
1136 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
1137 // Verify the window grew. Just test a reasonable width gain.
1138 CGFloat newWidth = NSWidth([toWindow frame]);
1139 EXPECT_LT(oldWidth + 30.0, newWidth);
1142 TEST_F(BookmarkBarFolderControllerMenuTest, MoveRemoveAddButtons) {
1143 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1144 const BookmarkNode* root = model->bookmark_bar_node();
1145 const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
1146 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1148 // Validate initial model.
1149 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1150 EXPECT_EQ(model_string, actualModelString);
1152 // Pop up a folder menu.
1153 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
1154 ASSERT_TRUE(toFolder);
1155 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1156 withObject:toFolder];
1157 BookmarkBarFolderController* folder = [bar_ folderController];
1158 EXPECT_TRUE(folder);
1160 // Remember how many buttons are showing.
1161 NSArray* buttons = [folder buttons];
1162 NSUInteger oldDisplayedButtons = [buttons count];
1164 // Move a button around a bit.
1165 [folder moveButtonFromIndex:0 toIndex:2];
1166 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:0] title]);
1167 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:1] title]);
1168 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:2] title]);
1169 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1170 [folder moveButtonFromIndex:2 toIndex:0];
1171 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
1172 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
1173 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
1174 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1176 // Add a couple of buttons.
1177 const BookmarkNode* node = root->GetChild(2); // Purloin an existing node.
1178 [folder addButtonForNode:node atIndex:0];
1179 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1180 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
1181 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
1182 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
1183 EXPECT_EQ(oldDisplayedButtons + 1, [buttons count]);
1184 node = root->GetChild(3);
1185 [folder addButtonForNode:node atIndex:-1];
1186 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1187 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
1188 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
1189 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
1190 EXPECT_NSEQ(@"4b", [[buttons objectAtIndex:4] title]);
1191 EXPECT_EQ(oldDisplayedButtons + 2, [buttons count]);
1193 // Remove a couple of buttons.
1194 [folder removeButton:4 animate:NO];
1195 [folder removeButton:1 animate:NO];
1196 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1197 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
1198 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
1199 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1201 // Check button spacing.
1202 [folder validateMenuSpacing];
1205 TEST_F(BookmarkBarFolderControllerMenuTest, RemoveLastButtonOtherBookmarks) {
1206 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1207 const BookmarkNode* otherBookmarks = model->other_node();
1209 BookmarkButton* otherButton = [bar_ otherBookmarksButton];
1210 ASSERT_TRUE(otherButton);
1212 // Open the folder to get the folderController_.
1213 [[otherButton target] openBookmarkFolderFromButton:otherButton];
1214 BookmarkBarFolderController* folder = [bar_ folderController];
1215 EXPECT_TRUE(folder);
1217 // Initially there is only (empty) placeholder button, hence buttonCount
1219 NSArray* buttons = [folder buttons];
1220 EXPECT_TRUE(buttons);
1221 EXPECT_EQ(1U, [buttons count]);
1223 // Add a new bookmark into 'Other bookmarks' folder.
1224 model->AddURL(otherBookmarks, otherBookmarks->child_count(),
1225 ASCIIToUTF16("TheOther"),
1226 GURL("http://www.other.com"));
1228 // buttonCount still should be 1, as we remove the (empty) placeholder button
1229 // when adding a new button to an empty folder.
1230 EXPECT_EQ(1U, [buttons count]);
1232 // Now we have only 1 button; remove it so that 'Other bookmarks' folder
1234 [folder removeButton:0 animate:NO];
1235 EXPECT_EQ(0U, [buttons count]);
1237 // 'Other bookmarks' folder gets closed once we remove the last button. Hence
1238 // folderController_ should be NULL.
1239 EXPECT_FALSE([bar_ folderController]);
1242 TEST_F(BookmarkBarFolderControllerMenuTest, ControllerForNode) {
1243 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1244 const BookmarkNode* root = model->bookmark_bar_node();
1245 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
1246 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1248 // Validate initial model.
1249 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1250 EXPECT_EQ(model_string, actualModelString);
1252 // Find the main bar controller.
1253 const void* expectedController = bar_;
1254 const void* actualController = [bar_ controllerForNode:root];
1255 EXPECT_EQ(expectedController, actualController);
1257 // Pop up the folder menu.
1258 BookmarkButton* targetFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
1259 ASSERT_TRUE(targetFolder);
1260 [[targetFolder target]
1261 performSelector:@selector(openBookmarkFolderFromButton:)
1262 withObject:targetFolder];
1263 BookmarkBarFolderController* folder = [bar_ folderController];
1264 EXPECT_TRUE(folder);
1266 // Find the folder controller using the folder controller.
1267 const BookmarkNode* targetNode = root->GetChild(1);
1268 expectedController = folder;
1269 actualController = [bar_ controllerForNode:targetNode];
1270 EXPECT_EQ(expectedController, actualController);
1272 // Find the folder controller from the bar.
1273 actualController = [folder controllerForNode:targetNode];
1274 EXPECT_EQ(expectedController, actualController);
1277 TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
1278 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1279 const BookmarkNode* root = model->bookmark_bar_node();
1280 const std::string model_string("1b 2b 3b ");
1281 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1283 // Validate initial model.
1284 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1285 EXPECT_EQ(model_string, actualModelString);
1287 const BookmarkNode* parent = model->bookmark_bar_node();
1288 const BookmarkNode* folder = model->AddFolder(parent,
1289 parent->child_count(),
1290 ASCIIToUTF16("BIG"));
1292 // Pop open the new folder window and verify it has one (empty) item.
1293 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
1294 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1296 BookmarkBarFolderController* folderController = [bar_ folderController];
1297 EXPECT_TRUE(folderController);
1298 NSWindow* folderWindow = [folderController window];
1299 EXPECT_TRUE(folderWindow);
1300 CGFloat expectedHeight = (CGFloat)bookmarks::kBookmarkFolderButtonHeight +
1301 (2*bookmarks::kBookmarkVerticalPadding);
1302 NSRect windowFrame = [folderWindow frame];
1303 CGFloat windowHeight = NSHeight(windowFrame);
1304 EXPECT_CGFLOAT_EQ(expectedHeight, windowHeight);
1305 EXPECT_FALSE([folderController canScrollUp]);
1306 EXPECT_FALSE([folderController canScrollDown]);
1308 // Now add a real bookmark and reopen.
1309 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("a"),
1310 GURL("http://a.com/"));
1311 folderController = [bar_ folderController];
1312 EXPECT_TRUE(folderController);
1313 NSView* folderView = [folderController folderView];
1314 EXPECT_TRUE(folderView);
1315 NSRect menuFrame = [folderView frame];
1316 NSView* visibleView = [folderController visibleView];
1317 NSRect visibleFrame = [visibleView frame];
1318 NSScrollView* scrollView = [folderController scrollView];
1319 NSRect scrollFrame = [scrollView frame];
1321 // Determine the margins between the scroll frame and the visible frame.
1322 CGFloat widthDelta = NSWidth(visibleFrame) - NSWidth(scrollFrame);
1324 CGFloat menuHeight = NSHeight(menuFrame);
1325 EXPECT_CGFLOAT_EQ(expectedHeight, menuHeight);
1326 CGFloat scrollerWidth = NSWidth(scrollFrame);
1327 button = [folderController buttonWithTitleEqualTo:@"a"];
1328 CGFloat buttonWidth = NSWidth([button frame]);
1329 EXPECT_CGFLOAT_EQ(scrollerWidth, buttonWidth);
1330 CGFloat visibleWidth = NSWidth(visibleFrame);
1331 EXPECT_CGFLOAT_EQ(visibleWidth - widthDelta, buttonWidth);
1332 EXPECT_LT(scrollerWidth, NSWidth([folderView frame]));
1334 // Add a wider bookmark and make sure the button widths match.
1335 int reallyWideButtonNumber = folder->child_count();
1336 model->AddURL(folder, reallyWideButtonNumber,
1337 ASCIIToUTF16("A really, really, really, really, really, "
1338 "really long name"),
1339 GURL("http://www.google.com/a"));
1340 BookmarkButton* bigButton =
1341 [folderController buttonWithTitleEqualTo:
1342 @"A really, really, really, really, really, really long name"];
1343 EXPECT_TRUE(bigButton);
1344 CGFloat buttonWidthB = NSWidth([bigButton frame]);
1345 EXPECT_LT(buttonWidth, buttonWidthB);
1346 // Add a bunch of bookmarks until the window becomes scrollable, then check
1347 // for a scroll up arrow.
1348 NSUInteger tripWire = 0; // Prevent a runaway.
1349 while (![folderController canScrollUp] && ++tripWire < 1000) {
1350 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("B"),
1351 GURL("http://b.com/"));
1353 EXPECT_TRUE([folderController canScrollUp]);
1355 // Remove one bookmark and make sure the scroll down arrow has been removed.
1356 // We'll remove the really long node so we can see if the buttons get resized.
1357 scrollerWidth = NSWidth([folderView frame]);
1358 buttonWidth = NSWidth([button frame]);
1359 model->Remove(folder->GetChild(reallyWideButtonNumber));
1360 EXPECT_FALSE([folderController canScrollUp]);
1361 EXPECT_FALSE([folderController canScrollDown]);
1363 // Check the size. It should have reduced.
1364 EXPECT_GT(scrollerWidth, NSWidth([folderView frame]));
1365 EXPECT_GT(buttonWidth, NSWidth([button frame]));
1367 // Check button spacing.
1368 [folderController validateMenuSpacing];
1371 // See http://crbug.com/46101
1372 TEST_F(BookmarkBarFolderControllerMenuTest, HoverThenDeleteBookmark) {
1373 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1374 const BookmarkNode* root = model->bookmark_bar_node();
1375 const BookmarkNode* folder = model->AddFolder(root,
1376 root->child_count(),
1377 ASCIIToUTF16("BIG"));
1378 for (int i = 0; i < kLotsOfNodesCount; i++)
1379 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("kid"),
1380 GURL("http://kid.com/smile"));
1382 // Pop open the new folder window and hover one of its kids.
1383 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
1384 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1386 BookmarkBarFolderController* bbfc = [bar_ folderController];
1387 NSArray* buttons = [bbfc buttons];
1389 // Hover over a button and verify that it is now known.
1390 button = [buttons objectAtIndex:3];
1391 BookmarkButton* buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1392 EXPECT_FALSE(buttonThatMouseIsIn);
1393 [bbfc mouseEnteredButton:button event:nil];
1394 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1395 EXPECT_EQ(button, buttonThatMouseIsIn);
1397 // Delete the bookmark and verify that it is now not known.
1398 model->Remove(folder->GetChild(3));
1399 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1400 EXPECT_FALSE(buttonThatMouseIsIn);
1403 // Just like a BookmarkBarFolderController but intercedes when providing
1404 // pasteboard drag data.
1405 @interface BookmarkBarFolderControllerDragData : BookmarkBarFolderController {
1406 const BookmarkNode* dragDataNode_; // Weak
1408 - (void)setDragDataNode:(const BookmarkNode*)node;
1411 @implementation BookmarkBarFolderControllerDragData
1413 - (id)initWithParentButton:(BookmarkButton*)button
1414 parentController:(BookmarkBarFolderController*)parentController
1415 barController:(BookmarkBarController*)barController
1416 profile:(Profile*)profile {
1417 if ((self = [super initWithParentButton:button
1418 parentController:parentController
1419 barController:barController
1420 profile:profile])) {
1421 dragDataNode_ = NULL;
1426 - (void)setDragDataNode:(const BookmarkNode*)node {
1427 dragDataNode_ = node;
1430 - (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
1431 std::vector<const BookmarkNode*> dragDataNodes;
1433 dragDataNodes.push_back(dragDataNode_);
1435 return dragDataNodes;
1440 TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
1441 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1442 const BookmarkNode* root = model->bookmark_bar_node();
1443 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1445 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1446 const BookmarkNode* other = model->other_node();
1447 const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
1448 "O4f:[ O4f1b O4f2f ] 05b ");
1449 bookmarks::test::AddNodesFromModelString(model, other, other_string);
1451 // Validate initial model.
1452 std::string actual = bookmarks::test::ModelStringFromNode(root);
1453 EXPECT_EQ(model_string, actual);
1454 actual = bookmarks::test::ModelStringFromNode(other);
1455 EXPECT_EQ(other_string, actual);
1457 // Pop open a folder.
1458 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1459 base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
1460 folderController.reset([[BookmarkBarFolderControllerDragData alloc]
1461 initWithParentButton:button
1462 parentController:nil
1464 profile:profile()]);
1465 BookmarkButton* targetButton =
1466 [folderController buttonWithTitleEqualTo:@"2f1b"];
1467 ASSERT_TRUE(targetButton);
1469 // Gen up some dragging data.
1470 const BookmarkNode* newNode = other->GetChild(2);
1471 [folderController setDragDataNode:newNode];
1472 base::scoped_nsobject<FakedDragInfo> dragInfo([[FakedDragInfo alloc] init]);
1473 [dragInfo setDropLocation:[targetButton top]];
1474 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
1476 // Verify the model.
1477 const std::string expected("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ 2f2f1b "
1478 "2f2f2b 2f2f3b ] 2f3b ] 3b 4b ");
1479 actual = bookmarks::test::ModelStringFromNode(root);
1480 EXPECT_EQ(expected, actual);
1482 // Now drag over a folder button.
1483 targetButton = [folderController buttonWithTitleEqualTo:@"2f2f"];
1484 ASSERT_TRUE(targetButton);
1485 newNode = other->GetChild(2); // Should be O4f.
1486 EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f"));
1487 [folderController setDragDataNode:newNode];
1488 [dragInfo setDropLocation:[targetButton center]];
1489 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
1491 // Verify the model.
1492 const std::string expectedA("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ "
1493 "2f2f1b 2f2f2b 2f2f3b O4f:[ O4f1b O4f2f ] ] "
1495 actual = bookmarks::test::ModelStringFromNode(root);
1496 EXPECT_EQ(expectedA, actual);
1498 // Check button spacing.
1499 [folderController validateMenuSpacing];
1502 TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkDataToTrash) {
1503 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1504 const BookmarkNode* root = model->bookmark_bar_node();
1505 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1507 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1509 // Validate initial model.
1510 std::string actual = bookmarks::test::ModelStringFromNode(root);
1511 EXPECT_EQ(model_string, actual);
1513 const BookmarkNode* folderNode = root->GetChild(1);
1514 int oldFolderChildCount = folderNode->child_count();
1516 // Pop open a folder.
1517 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1518 base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
1519 folderController.reset([[BookmarkBarFolderControllerDragData alloc]
1520 initWithParentButton:button
1521 parentController:nil
1523 profile:profile()]);
1525 // Drag a button to the trash.
1526 BookmarkButton* buttonToDelete =
1527 [folderController buttonWithTitleEqualTo:@"2f1b"];
1528 ASSERT_TRUE(buttonToDelete);
1529 EXPECT_TRUE([folderController canDragBookmarkButtonToTrash:buttonToDelete]);
1530 [folderController didDragBookmarkToTrash:buttonToDelete];
1532 // There should be one less button in the folder.
1533 int newFolderChildCount = folderNode->child_count();
1534 EXPECT_EQ(oldFolderChildCount - 1, newFolderChildCount);
1535 // Verify the model.
1536 const std::string expected("1b 2f:[ 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1538 actual = bookmarks::test::ModelStringFromNode(root);
1539 EXPECT_EQ(expected, actual);
1541 // Check button spacing.
1542 [folderController validateMenuSpacing];
1545 TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) {
1546 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1547 const BookmarkNode* root = model->bookmark_bar_node();
1548 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1550 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1552 // Validate initial model.
1553 std::string actual = bookmarks::test::ModelStringFromNode(root);
1554 EXPECT_EQ(model_string, actual);
1556 // Pop open a folder.
1557 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1558 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1560 BookmarkBarFolderController* folderController = [bar_ folderController];
1561 EXPECT_TRUE(folderController);
1562 NSArray* buttons = [folderController buttons];
1563 EXPECT_TRUE(buttons);
1565 // Remember how many buttons are showing.
1566 int oldDisplayedButtons = [buttons count];
1568 BookmarkButton* targetButton =
1569 [folderController buttonWithTitleEqualTo:@"2f1b"];
1570 ASSERT_TRUE(targetButton);
1572 NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/",
1573 @"http://www.b.com/", nil];
1574 NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil];
1575 [folderController addURLs:urls withTitles:titles at:[targetButton top]];
1577 // There should two more buttons in the folder.
1578 int newDisplayedButtons = [buttons count];
1579 EXPECT_EQ(oldDisplayedButtons + 2, newDisplayedButtons);
1580 // Verify the model.
1581 const std::string expected("1b 2f:[ SiteA SiteB 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1582 "2f2f3b ] 2f3b ] 3b 4b ");
1583 actual = bookmarks::test::ModelStringFromNode(root);
1584 EXPECT_EQ(expected, actual);
1586 // Check button spacing.
1587 [folderController validateMenuSpacing];
1590 TEST_F(BookmarkBarFolderControllerMenuTest, DropPositionIndicator) {
1591 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1592 const BookmarkNode* root = model->bookmark_bar_node();
1593 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1595 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1597 // Validate initial model.
1598 std::string actual = bookmarks::test::ModelStringFromNode(root);
1599 EXPECT_EQ(model_string, actual);
1601 // Pop open the folder.
1602 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1603 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1605 BookmarkBarFolderController* folder = [bar_ folderController];
1606 EXPECT_TRUE(folder);
1608 // Test a series of points starting at the top of the folder.
1609 const CGFloat yOffset = 0.5 * bookmarks::kBookmarkVerticalPadding;
1610 BookmarkButton* targetButton = [folder buttonWithTitleEqualTo:@"2f1b"];
1611 ASSERT_TRUE(targetButton);
1612 NSPoint targetPoint = [targetButton top];
1613 CGFloat pos = [folder indicatorPosForDragToPoint:targetPoint];
1614 EXPECT_CGFLOAT_EQ(targetPoint.y + yOffset, pos);
1615 pos = [folder indicatorPosForDragToPoint:[targetButton bottom]];
1616 targetButton = [folder buttonWithTitleEqualTo:@"2f2f"];
1617 EXPECT_CGFLOAT_EQ([targetButton top].y + yOffset, pos);
1618 pos = [folder indicatorPosForDragToPoint:NSMakePoint(10,0)];
1619 targetButton = [folder buttonWithTitleEqualTo:@"2f3b"];
1620 EXPECT_CGFLOAT_EQ([targetButton bottom].y - yOffset, pos);
1623 @interface BookmarkBarControllerNoDelete : BookmarkBarController
1624 - (IBAction)deleteBookmark:(id)sender;
1627 @implementation BookmarkBarControllerNoDelete
1628 - (IBAction)deleteBookmark:(id)sender {
1633 class BookmarkBarFolderControllerClosingTest : public
1634 BookmarkBarFolderControllerMenuTest {
1636 void SetUp() override {
1637 BookmarkBarFolderControllerMenuTest::SetUp();
1638 ASSERT_TRUE(browser());
1640 bar_.reset([[BookmarkBarControllerNoDelete alloc]
1641 initWithBrowser:browser()
1642 initialWidth:NSWidth([parent_view_ frame])
1644 resizeDelegate:resizeDelegate_.get()]);
1645 InstallAndToggleBar(bar_.get());
1649 TEST_F(BookmarkBarFolderControllerClosingTest, DeleteClosesFolder) {
1650 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1651 const BookmarkNode* root = model->bookmark_bar_node();
1652 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b ] "
1654 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1656 // Validate initial model.
1657 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1658 EXPECT_EQ(model_string, actualModelString);
1660 // Open the folder menu and submenu.
1661 BookmarkButton* target = [bar_ buttonWithTitleEqualTo:@"2f"];
1662 ASSERT_TRUE(target);
1663 [[target target] performSelector:@selector(openBookmarkFolderFromButton:)
1665 BookmarkBarFolderController* folder = [bar_ folderController];
1666 EXPECT_TRUE(folder);
1667 BookmarkButton* subTarget = [folder buttonWithTitleEqualTo:@"2f2f"];
1668 ASSERT_TRUE(subTarget);
1669 [[subTarget target] performSelector:@selector(openBookmarkFolderFromButton:)
1670 withObject:subTarget];
1671 BookmarkBarFolderController* subFolder = [folder folderController];
1672 EXPECT_TRUE(subFolder);
1674 // Delete the folder node and verify the window closed down by looking
1675 // for its controller again.
1676 DeleteBookmark([folder parentButton], profile());
1677 EXPECT_FALSE([folder folderController]);
1680 // TODO(jrg): draggingEntered: and draggingExited: trigger timers so
1681 // they are hard to test. Factor out "fire timers" into routines
1682 // which can be overridden to fire immediately to make behavior
1684 // There is a similar problem with mouseEnteredButton: and
1685 // mouseExitedButton:.