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);
40 model->Remove(node->parent(), node->parent()->GetIndexOf(node));
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_->parent(),
196 longTitleNode_->parent()->GetIndexOf(longTitleNode_));
199 // Add LOTS of nodes to our model if needed (e.g. scrolling).
200 // Returns the number of nodes added.
201 int AddLotsOfNodes() {
202 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
203 for (int i = 0; i < kLotsOfNodesCount; i++) {
204 model->AddURL(folderA_, folderA_->child_count(),
205 ASCIIToUTF16("repeated title"),
206 GURL("http://www.google.com/repeated/url"));
208 return kLotsOfNodesCount;
211 // Return a simple BookmarkBarFolderController.
212 BookmarkBarFolderControllerPong* SimpleBookmarkBarFolderController() {
213 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
214 BookmarkBarFolderControllerPong* c =
215 [[BookmarkBarFolderControllerPong alloc]
216 initWithParentButton:parentButton
220 [c window]; // Force nib load.
225 TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) {
226 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
227 bbfc.reset(SimpleBookmarkBarFolderController());
229 // Make sure none of the buttons overlap, that all are inside
230 // the content frame, and their cells are of the proper class.
231 NSArray* buttons = [bbfc buttons];
232 EXPECT_TRUE([buttons count]);
233 for (unsigned int i = 0; i < ([buttons count]-1); i++) {
234 EXPECT_FALSE(NSContainsRect([[buttons objectAtIndex:i] frame],
235 [[buttons objectAtIndex:i+1] frame]));
237 Class cellClass = [BookmarkBarFolderButtonCell class];
238 for (BookmarkButton* button in buttons) {
239 NSRect r = [[bbfc folderView] convertRect:[button frame] fromView:button];
240 // TODO(jrg): remove this adjustment.
241 NSRect bigger = NSInsetRect([[bbfc folderView] frame], -2, 0);
242 EXPECT_TRUE(NSContainsRect(bigger, r));
243 EXPECT_TRUE([[button cell] isKindOfClass:cellClass]);
246 // Confirm folder buttons have no tooltip. The important thing
247 // really is that we insure folders and non-folders are treated
248 // differently; not sure of any other generic way to do this.
249 for (BookmarkButton* button in buttons) {
250 if ([button isFolder])
251 EXPECT_FALSE([button toolTip]);
253 EXPECT_TRUE([button toolTip]);
257 // Make sure closing of the window releases the controller.
258 // (e.g. valgrind shouldn't complain if we do this).
259 TEST_F(BookmarkBarFolderControllerTest, ReleaseOnClose) {
260 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
261 bbfc.reset(SimpleBookmarkBarFolderController());
262 EXPECT_TRUE(bbfc.get());
264 [bbfc retain]; // stop the scoped_nsobject from doing anything
265 [[bbfc window] close]; // trigger an autorelease of bbfc.get()
268 TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
269 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
270 EXPECT_TRUE(parentButton);
272 // If parent is a BookmarkBarController, grow down.
273 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
274 bbfc.reset([[BookmarkBarFolderController alloc]
275 initWithParentButton:parentButton
280 NSPoint pt = [bbfc windowTopLeftForWidth:0 height:100]; // screen coords
281 NSPoint buttonOriginInWindow =
282 [parentButton convertRect:[parentButton bounds]
284 NSPoint buttonOriginInScreen =
285 [[parentButton window] convertBaseToScreen:buttonOriginInWindow];
287 EXPECT_LE(std::abs(pt.x - buttonOriginInScreen.x),
288 bookmarks::kBookmarkMenuOverlap + 1);
289 EXPECT_LE(std::abs(pt.y - buttonOriginInScreen.y),
290 bookmarks::kBookmarkMenuOverlap + 1);
292 // Make sure we see the window shift left if it spills off the screen
293 pt = [bbfc windowTopLeftForWidth:0 height:100];
294 NSPoint shifted = [bbfc windowTopLeftForWidth:9999999 height:100];
295 EXPECT_LT(shifted.x, pt.x);
297 // If parent is a BookmarkBarFolderController, grow right.
298 base::scoped_nsobject<BookmarkBarFolderController> bbfc2;
299 bbfc2.reset([[BookmarkBarFolderController alloc]
300 initWithParentButton:[[bbfc buttons] objectAtIndex:0]
301 parentController:bbfc.get()
305 pt = [bbfc2 windowTopLeftForWidth:0 height:100];
306 // We're now overlapping the window a bit.
307 EXPECT_EQ(pt.x, NSMaxX([[bbfc.get() window] frame]) -
308 bookmarks::kBookmarkMenuOverlap);
311 // Confirm we grow right until end of screen, then start growing left
312 // until end of screen again, then right.
313 TEST_F(BookmarkBarFolderControllerTest, PositionRightLeftRight) {
314 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
315 const BookmarkNode* parent = model->bookmark_bar_node();
316 const BookmarkNode* folder = parent;
318 const int count = 100;
320 // Make some super duper deeply nested folders.
321 for (i = 0; i < count; i++) {
322 folder = model->AddFolder(folder, 0, ASCIIToUTF16("nested folder"));
325 // Setup initial state for opening all folders.
327 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
328 BookmarkBarFolderController* parentController = nil;
329 EXPECT_TRUE(parentButton);
332 base::scoped_nsobject<NSMutableArray> folder_controller_array;
333 folder_controller_array.reset([[NSMutableArray array] retain]);
334 for (i=0; i<count; i++) {
335 BookmarkBarFolderControllerNoLevel* bbfcl =
336 [[BookmarkBarFolderControllerNoLevel alloc]
337 initWithParentButton:parentButton
338 parentController:parentController
341 [folder_controller_array addObject:bbfcl];
344 parentController = bbfcl;
345 parentButton = [[bbfcl buttons] objectAtIndex:0];
348 // Make vector of all x positions.
349 std::vector<CGFloat> leftPositions;
350 for (i=0; i<count; i++) {
351 CGFloat x = [[[folder_controller_array objectAtIndex:i] window]
353 leftPositions.push_back(x);
356 // Make sure the first few grow right.
358 EXPECT_TRUE(leftPositions[i+1] > leftPositions[i]);
360 // Look for the first "grow left".
361 while (leftPositions[i] > leftPositions[i-1])
363 // Confirm the next few also grow left.
365 for (j=i; j<i+3; j++)
366 EXPECT_TRUE(leftPositions[j+1] < leftPositions[j]);
369 // Finally, confirm we see a "grow right" once more.
370 while (leftPositions[i] < leftPositions[i-1])
372 // (No need to EXPECT a final "grow right"; if we didn't find one
373 // we'd get a C++ array bounds exception).
376 TEST_F(BookmarkBarFolderControllerTest, DropDestination) {
377 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
378 bbfc.reset(SimpleBookmarkBarFolderController());
379 EXPECT_TRUE(bbfc.get());
381 // Confirm "off the top" and "off the bottom" match no buttons.
382 NSPoint p = NSMakePoint(NSMidX([[bbfc folderView] frame]), 10000);
383 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
384 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
385 p = NSMakePoint(NSMidX([[bbfc folderView] frame]), -1);
386 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
387 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
389 // Confirm "right in the center" (give or take a pixel) is a match,
390 // and confirm "just barely in the button" is not. Anything more
391 // specific seems likely to be tweaked. We don't loop over all
392 // buttons because the scroll view makes them not visible.
393 for (BookmarkButton* button in [bbfc buttons]) {
394 CGFloat x = NSMidX([button frame]);
395 CGFloat y = NSMidY([button frame]);
396 // Somewhere near the center: a match (but only if a folder!)
397 if ([button isFolder]) {
399 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
401 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
402 EXPECT_FALSE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
404 // If not a folder we don't drop into it.
405 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
406 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
407 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
412 TEST_F(BookmarkBarFolderControllerTest, OpenFolder) {
413 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
414 bbfc.reset(SimpleBookmarkBarFolderController());
415 EXPECT_TRUE(bbfc.get());
417 EXPECT_FALSE([bbfc folderController]);
418 BookmarkButton* button = [[bbfc buttons] objectAtIndex:0];
419 [bbfc openBookmarkFolderFromButton:button];
420 id controller = [bbfc folderController];
421 EXPECT_TRUE(controller);
422 EXPECT_EQ([controller parentButton], button);
424 // Click the same one --> it gets closed.
425 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
426 EXPECT_FALSE([bbfc folderController]);
428 // Open a new one --> change.
429 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:1]];
430 EXPECT_NE(controller, [bbfc folderController]);
431 EXPECT_NE([[bbfc folderController] parentButton], button);
433 // Close it --> all gone!
434 [bbfc closeBookmarkFolder:nil];
435 EXPECT_FALSE([bbfc folderController]);
438 TEST_F(BookmarkBarFolderControllerTest, DeleteOpenFolder) {
439 base::scoped_nsobject<BookmarkBarFolderController> parent_controller(
440 SimpleBookmarkBarFolderController());
443 EXPECT_FALSE([parent_controller folderController]);
444 BookmarkButton* button = [[parent_controller buttons] objectAtIndex:0];
445 [parent_controller openBookmarkFolderFromButton:button];
446 EXPECT_EQ([[parent_controller folderController] parentButton], button);
448 // Delete the folder's button - the folder should close.
449 [parent_controller removeButton:0 animate:NO];
450 EXPECT_FALSE([parent_controller folderController]);
453 TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) {
454 base::scoped_nsobject<BookmarkBarFolderControllerPong> bbfc;
455 bbfc.reset(SimpleBookmarkBarFolderController());
456 EXPECT_TRUE(bbfc.get());
457 [bar_ setChildFolderDelegate:bbfc.get()];
459 EXPECT_FALSE([bbfc childFolderWillShow]);
460 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
461 EXPECT_TRUE([bbfc childFolderWillShow]);
463 EXPECT_FALSE([bbfc childFolderWillClose]);
464 [bbfc closeBookmarkFolder:nil];
465 EXPECT_TRUE([bbfc childFolderWillClose]);
467 [bar_ setChildFolderDelegate:nil];
470 // Make sure bookmark folders have variable widths.
471 TEST_F(BookmarkBarFolderControllerTest, ChildFolderWidth) {
472 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
474 bbfc.reset(SimpleBookmarkBarFolderController());
475 EXPECT_TRUE(bbfc.get());
476 [bbfc showWindow:bbfc.get()];
477 CGFloat wideWidth = NSWidth([[bbfc window] frame]);
479 RemoveLongTitleNode();
480 bbfc.reset(SimpleBookmarkBarFolderController());
481 EXPECT_TRUE(bbfc.get());
482 CGFloat thinWidth = NSWidth([[bbfc window] frame]);
484 // Make sure window size changed as expected.
485 EXPECT_GT(wideWidth, thinWidth);
488 // Simple scrolling tests.
489 // Currently flaky due to a changed definition of the correct menu boundaries.
490 TEST_F(BookmarkBarFolderControllerTest, DISABLED_SimpleScroll) {
491 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
492 NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
493 CGFloat screenHeight = NSHeight(screenFrame);
494 int nodecount = AddLotsOfNodes();
495 bbfc.reset(SimpleBookmarkBarFolderController());
496 EXPECT_TRUE(bbfc.get());
497 [bbfc showWindow:bbfc.get()];
498 NSWindow* window = [bbfc window];
500 // The window should be shorter than the screen but reach exactly to the
501 // bottom of the screen since it's scrollable.
502 EXPECT_LT(NSHeight([window frame]), screenHeight);
503 EXPECT_CGFLOAT_EQ(0.0, [window frame].origin.y);
505 // Initially, should show scroll-up but not scroll-down.
506 EXPECT_TRUE([bbfc canScrollUp]);
507 EXPECT_FALSE([bbfc canScrollDown]);
509 // Scroll up a bit. Make sure the window has gotten bigger each time.
510 // Also, for each scroll, make sure our hit test finds a new button
511 // (to confirm the content area changed).
512 NSView* savedHit = nil;
513 NSScrollView* scrollView = [bbfc scrollView];
515 // Find the next-to-last button showing at the bottom of the window and
516 // use its center for hit testing.
517 BookmarkButton* targetButton = nil;
518 NSPoint scrollPoint = [scrollView documentVisibleRect].origin;
519 for (BookmarkButton* button in [bbfc buttons]) {
520 NSRect buttonFrame = [button frame];
521 buttonFrame.origin.y -= scrollPoint.y;
522 if (buttonFrame.origin.y < 0.0)
524 targetButton = button;
526 EXPECT_TRUE(targetButton != nil);
527 NSPoint hitPoint = [targetButton frame].origin;
529 hitPoint.y += (bookmarks::kBookmarkFolderButtonHeight / 2.0) - scrollPoint.y;
530 hitPoint = [targetButton convertPoint:hitPoint toView:scrollView];
532 for (int i = 0; i < 3; i++) {
533 CGFloat height = NSHeight([window frame]);
534 [bbfc performOneScroll:60];
535 EXPECT_GT(NSHeight([window frame]), height);
536 NSView* hit = [scrollView hitTest:hitPoint];
537 // We should hit a bookmark button.
538 EXPECT_TRUE([[hit className] isEqualToString:@"BookmarkButton"]);
539 EXPECT_NE(hit, savedHit);
543 // Keep scrolling up; make sure we never get bigger than the screen.
544 // Also confirm we never scroll the window off the screen.
545 bool bothAtOnce = false;
546 while ([bbfc canScrollUp]) {
547 [bbfc performOneScroll:60];
548 EXPECT_TRUE(NSContainsRect([[NSScreen mainScreen] frame], [window frame]));
549 // Make sure, sometime during our scroll, we have the ability to
550 // scroll in either direction.
551 if ([bbfc canScrollUp] &&
552 [bbfc canScrollDown])
555 EXPECT_TRUE(bothAtOnce);
557 // Once we've scrolled to the end, our only option should be to scroll back.
558 EXPECT_FALSE([bbfc canScrollUp]);
559 EXPECT_TRUE([bbfc canScrollDown]);
561 NSRect wholeScreenRect = [[NSScreen mainScreen] frame];
563 // Now scroll down and make sure the window size does not change.
564 // Also confirm we never scroll the window off the screen the other
566 for (int i = 0; i < nodecount+50; ++i) {
567 [bbfc performOneScroll:-60];
568 // Once we can no longer scroll down the window height changes.
569 if (![bbfc canScrollDown])
571 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame]));
574 EXPECT_GT(NSHeight(wholeScreenRect), NSHeight([window frame]));
575 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame]));
578 // Folder menu sizing and placement while deleting bookmarks
579 // and scrolling tests.
580 TEST_F(BookmarkBarFolderControllerTest, MenuPlacementWhileScrollingDeleting) {
581 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
583 bbfc.reset(SimpleBookmarkBarFolderController());
584 [bbfc showWindow:bbfc.get()];
585 NSWindow* menuWindow = [bbfc window];
586 BookmarkBarFolderController* folder = [bar_ folderController];
587 NSArray* buttons = [folder buttons];
589 // Before scrolling any, delete a bookmark and make sure the window top has
590 // not moved. Pick a button which is near the top and visible.
591 CGFloat oldTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
592 BookmarkButton* button = [buttons objectAtIndex:3];
593 DeleteBookmark(button, profile());
594 CGFloat newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
595 EXPECT_CGFLOAT_EQ(oldTop, newTop);
597 // Scroll so that both the top and bottom scroll arrows show, make sure
598 // the top of the window has moved up, then delete a visible button and
599 // make sure the top has not moved.
601 const CGFloat scrollOneBookmark = bookmarks::kBookmarkFolderButtonHeight +
602 bookmarks::kBookmarkVerticalPadding;
603 NSUInteger buttonCounter = 0;
604 NSUInteger extraButtonLimit = 3;
605 while (![bbfc canScrollDown] || extraButtonLimit > 0) {
606 [bbfc performOneScroll:scrollOneBookmark];
608 if ([bbfc canScrollDown])
611 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
612 EXPECT_NE(oldTop, newTop);
614 button = [buttons objectAtIndex:buttonCounter + 3];
615 DeleteBookmark(button, profile());
616 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
617 EXPECT_CGFLOAT_EQ(oldTop, newTop);
619 // Scroll so that the top scroll arrow is no longer showing, make sure
620 // the top of the window has not moved, then delete a visible button and
621 // make sure the top has not moved.
622 while ([bbfc canScrollDown]) {
623 [bbfc performOneScroll:-scrollOneBookmark];
626 button = [buttons objectAtIndex:buttonCounter + 3];
627 DeleteBookmark(button, profile());
628 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
629 EXPECT_CGFLOAT_EQ(oldTop - bookmarks::kScrollWindowVerticalMargin, newTop);
632 // Make sure that we return the correct browser window.
633 TEST_F(BookmarkBarFolderControllerTest, BrowserWindow) {
634 base::scoped_nsobject<BookmarkBarFolderController> controller(
635 SimpleBookmarkBarFolderController());
636 EXPECT_EQ([bar_ browserWindow], [controller browserWindow]);
639 @interface FakedDragInfo : NSObject {
641 NSPoint dropLocation_;
642 NSDragOperation sourceMask_;
644 @property (nonatomic, assign) NSPoint dropLocation;
645 - (void)setDraggingSourceOperationMask:(NSDragOperation)mask;
648 @implementation FakedDragInfo
650 @synthesize dropLocation = dropLocation_;
653 if ((self = [super init])) {
654 dropLocation_ = NSZeroPoint;
655 sourceMask_ = NSDragOperationMove;
660 // NSDraggingInfo protocol functions.
662 - (id)draggingPasteboard {
666 - (id)draggingSource {
670 - (NSDragOperation)draggingSourceOperationMask {
674 - (NSPoint)draggingLocation {
675 return dropLocation_;
680 - (void)setDraggingSourceOperationMask:(NSDragOperation)mask {
687 class BookmarkBarFolderControllerMenuTest : public CocoaProfileTest {
689 base::scoped_nsobject<NSView> parent_view_;
690 base::scoped_nsobject<ViewResizerPong> resizeDelegate_;
691 base::scoped_nsobject<BookmarkBarController> bar_;
693 void SetUp() override {
694 CocoaProfileTest::SetUp();
695 ASSERT_TRUE(browser());
697 resizeDelegate_.reset([[ViewResizerPong alloc] init]);
698 NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
699 parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
700 [parent_view_ setHidden:YES];
701 bar_.reset([[BookmarkBarController alloc]
702 initWithBrowser:browser()
703 initialWidth:NSWidth(parent_frame)
705 resizeDelegate:resizeDelegate_.get()]);
706 InstallAndToggleBar(bar_.get());
709 void InstallAndToggleBar(BookmarkBarController* bar) {
710 // Force loading of the nib.
712 // Awkwardness to look like we've been installed.
713 [parent_view_ addSubview:[bar view]];
714 NSRect frame = [[[bar view] superview] frame];
715 frame.origin.y = 400;
716 [[[bar view] superview] setFrame:frame];
718 // Make sure it's on in a window so viewDidMoveToWindow is called
719 [[test_window() contentView] addSubview:parent_view_];
721 // Make sure it's open so certain things aren't no-ops.
722 [bar updateState:BookmarkBar::SHOW
723 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE];
727 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
728 WithNoAnimation at_all;
729 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
730 const BookmarkNode* root = model->bookmark_bar_node();
731 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
732 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
733 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
734 bookmarks::test::AddNodesFromModelString(model, root, model_string);
736 // Validate initial model.
737 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
738 EXPECT_EQ(model_string, actualModelString);
740 // Pop up a folder menu and drag in a button from the bar.
741 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
742 NSRect oldToFolderFrame = [toFolder frame];
743 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
744 withObject:toFolder];
745 BookmarkBarFolderController* folderController = [bar_ folderController];
746 EXPECT_TRUE(folderController);
747 NSWindow* toWindow = [folderController window];
748 EXPECT_TRUE(toWindow);
749 NSRect oldToWindowFrame = [toWindow frame];
750 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
751 // so it should end up below the target bookmark.
752 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
753 ASSERT_TRUE(draggedButton);
754 CGFloat horizontalShift =
755 NSWidth([draggedButton frame]) + bookmarks::kBookmarkHorizontalPadding;
756 BookmarkButton* targetButton =
757 [folderController buttonWithTitleEqualTo:@"2f1b"];
758 ASSERT_TRUE(targetButton);
759 [folderController dragButton:draggedButton
760 to:[targetButton center]
762 // The button should have landed just after "2f1b".
763 const std::string expected_string("2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
764 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
765 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
766 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
768 // Verify the window still appears by looking for its controller.
769 EXPECT_TRUE([bar_ folderController]);
771 // Gather the new frames.
772 NSRect newToFolderFrame = [toFolder frame];
773 NSRect newToWindowFrame = [toWindow frame];
774 // The toFolder should have shifted left horizontally but not vertically.
775 NSRect expectedToFolderFrame =
776 NSOffsetRect(oldToFolderFrame, -horizontalShift, 0);
777 EXPECT_NSRECT_EQ(expectedToFolderFrame, newToFolderFrame);
778 // The toWindow should have shifted left horizontally, down vertically,
779 // and grown vertically.
780 NSRect expectedToWindowFrame = oldToWindowFrame;
781 expectedToWindowFrame.origin.x -= horizontalShift;
782 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
783 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight;
784 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
786 // Check button spacing.
787 [folderController validateMenuSpacing];
789 // Move the button back to the bar at the beginning.
790 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
791 ASSERT_TRUE(draggedButton);
792 targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
793 ASSERT_TRUE(targetButton);
794 [bar_ dragButton:draggedButton
795 to:[targetButton left]
797 EXPECT_EQ(model_string, bookmarks::test::ModelStringFromNode(root));
798 // Don't check the folder window since it's not supposed to be showing.
801 TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
802 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
803 const BookmarkNode* root = model->bookmark_bar_node();
804 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
805 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
806 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
807 bookmarks::test::AddNodesFromModelString(model, root, model_string);
809 // Validate initial model.
810 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
811 EXPECT_EQ(model_string, actualModelString);
813 // Pop up a folder menu and copy in a button from the bar.
814 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
815 ASSERT_TRUE(toFolder);
816 NSRect oldToFolderFrame = [toFolder frame];
817 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
818 withObject:toFolder];
819 BookmarkBarFolderController* folderController = [bar_ folderController];
820 EXPECT_TRUE(folderController);
821 NSWindow* toWindow = [folderController window];
822 EXPECT_TRUE(toWindow);
823 NSRect oldToWindowFrame = [toWindow frame];
824 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
825 // so it should end up below the target bookmark.
826 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
827 ASSERT_TRUE(draggedButton);
828 BookmarkButton* targetButton =
829 [folderController buttonWithTitleEqualTo:@"2f1b"];
830 ASSERT_TRUE(targetButton);
831 [folderController dragButton:draggedButton
832 to:[targetButton center]
834 // The button should have landed just after "2f1b".
835 const std::string expected_1("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
836 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
837 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
838 EXPECT_EQ(expected_1, bookmarks::test::ModelStringFromNode(root));
840 // Gather the new frames.
841 NSRect newToFolderFrame = [toFolder frame];
842 NSRect newToWindowFrame = [toWindow frame];
843 // The toFolder should have shifted.
844 EXPECT_NSRECT_EQ(oldToFolderFrame, newToFolderFrame);
845 // The toWindow should have shifted down vertically and grown vertically.
846 NSRect expectedToWindowFrame = oldToWindowFrame;
847 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
848 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight;
849 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
851 // Copy the button back to the bar after "3b".
852 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
853 ASSERT_TRUE(draggedButton);
854 targetButton = [bar_ buttonWithTitleEqualTo:@"4f"];
855 ASSERT_TRUE(targetButton);
856 [bar_ dragButton:draggedButton
857 to:[targetButton left]
859 const std::string expected_2("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
860 "2f2f2b 2f2f3b ] 2f3b ] 3b 1b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
861 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
862 EXPECT_EQ(expected_2, bookmarks::test::ModelStringFromNode(root));
865 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
866 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
867 const BookmarkNode* root = model->bookmark_bar_node();
868 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
869 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
870 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
871 bookmarks::test::AddNodesFromModelString(model, root, model_string);
873 // Validate initial model.
874 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
875 EXPECT_EQ(model_string, actualModelString);
877 // Pop up a folder menu and a subfolder menu.
878 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
879 ASSERT_TRUE(toFolder);
880 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
881 withObject:toFolder];
882 BookmarkBarFolderController* folderController = [bar_ folderController];
883 EXPECT_TRUE(folderController);
884 NSWindow* toWindow = [folderController window];
885 EXPECT_TRUE(toWindow);
886 NSRect oldToWindowFrame = [toWindow frame];
887 BookmarkButton* toSubfolder =
888 [folderController buttonWithTitleEqualTo:@"4f2f"];
889 ASSERT_TRUE(toSubfolder);
890 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
891 withObject:toSubfolder];
892 BookmarkBarFolderController* subfolderController =
893 [folderController folderController];
894 EXPECT_TRUE(subfolderController);
895 NSWindow* toSubwindow = [subfolderController window];
896 EXPECT_TRUE(toSubwindow);
897 NSRect oldToSubwindowFrame = [toSubwindow frame];
898 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
899 // so it should end up below the target bookmark.
900 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"5b"];
901 ASSERT_TRUE(draggedButton);
902 BookmarkButton* targetButton =
903 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
904 ASSERT_TRUE(targetButton);
905 [subfolderController dragButton:draggedButton
906 to:[targetButton center]
908 // The button should have landed just after "2f".
909 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
910 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
911 "4f2f1b 4f2f2b 4f2f3b 5b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] ");
912 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
914 // Check button spacing.
915 [folderController validateMenuSpacing];
916 [subfolderController validateMenuSpacing];
918 // Check the window layouts. The folder window should not have changed,
919 // but the subfolder window should have shifted vertically and grown.
920 NSRect newToWindowFrame = [toWindow frame];
921 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
922 NSRect newToSubwindowFrame = [toSubwindow frame];
923 NSRect expectedToSubwindowFrame = oldToSubwindowFrame;
924 expectedToSubwindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
925 expectedToSubwindowFrame.size.height +=
926 bookmarks::kBookmarkFolderButtonHeight;
927 EXPECT_NSRECT_EQ(expectedToSubwindowFrame, newToSubwindowFrame);
930 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) {
931 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
932 const BookmarkNode* root = model->bookmark_bar_node();
933 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
934 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
935 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
936 bookmarks::test::AddNodesFromModelString(model, root, model_string);
938 // Validate initial model.
939 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
940 EXPECT_EQ(model_string, actualModelString);
942 // Pop up a folder menu.
943 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
944 ASSERT_TRUE(toFolder);
945 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
946 withObject:toFolder];
947 BookmarkBarFolderController* folderController = [bar_ folderController];
948 EXPECT_TRUE(folderController);
949 NSWindow* toWindow = [folderController window];
950 EXPECT_TRUE(toWindow);
951 NSRect oldToWindowFrame = [toWindow frame];
952 // Drag a folder button to the top within the same parent.
953 BookmarkButton* draggedButton =
954 [folderController buttonWithTitleEqualTo:@"4f2f"];
955 ASSERT_TRUE(draggedButton);
956 BookmarkButton* targetButton =
957 [folderController buttonWithTitleEqualTo:@"4f1f"];
958 ASSERT_TRUE(targetButton);
959 [folderController dragButton:draggedButton
960 to:[targetButton top]
962 // The button should have landed above "4f1f".
963 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
964 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f2f:[ 4f2f1b 4f2f2b 4f2f3b ] "
965 "4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
966 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
968 // The window should not have gone away.
969 EXPECT_TRUE([bar_ folderController]);
971 // The folder window should not have changed.
972 NSRect newToWindowFrame = [toWindow frame];
973 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
975 // Check button spacing.
976 [folderController validateMenuSpacing];
979 TEST_F(BookmarkBarFolderControllerMenuTest, DragParentOntoChild) {
980 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
981 const BookmarkNode* root = model->bookmark_bar_node();
982 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
983 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
984 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
985 bookmarks::test::AddNodesFromModelString(model, root, model_string);
987 // Validate initial model.
988 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
989 EXPECT_EQ(model_string, actualModelString);
991 // Pop up a folder menu.
992 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
993 ASSERT_TRUE(toFolder);
994 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
995 withObject:toFolder];
996 BookmarkBarFolderController* folderController = [bar_ folderController];
997 EXPECT_TRUE(folderController);
998 NSWindow* toWindow = [folderController window];
999 EXPECT_TRUE(toWindow);
1000 // Drag a folder button to one of its children.
1001 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"4f"];
1002 ASSERT_TRUE(draggedButton);
1003 BookmarkButton* targetButton =
1004 [folderController buttonWithTitleEqualTo:@"4f3f"];
1005 ASSERT_TRUE(targetButton);
1006 [folderController dragButton:draggedButton
1007 to:[targetButton top]
1009 // The model should not have changed.
1010 EXPECT_EQ(model_string, bookmarks::test::ModelStringFromNode(root));
1012 // Check button spacing.
1013 [folderController validateMenuSpacing];
1016 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) {
1017 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1018 const BookmarkNode* root = model->bookmark_bar_node();
1019 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1020 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
1021 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
1022 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1024 // Validate initial model.
1025 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1026 EXPECT_EQ(model_string, actualModelString);
1028 // Pop up a folder menu and a subfolder menu.
1029 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
1030 ASSERT_TRUE(toFolder);
1031 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1032 withObject:toFolder];
1033 BookmarkBarFolderController* folderController = [bar_ folderController];
1034 EXPECT_TRUE(folderController);
1035 BookmarkButton* toSubfolder =
1036 [folderController buttonWithTitleEqualTo:@"4f2f"];
1037 ASSERT_TRUE(toSubfolder);
1038 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1039 withObject:toSubfolder];
1040 BookmarkBarFolderController* subfolderController =
1041 [folderController folderController];
1042 EXPECT_TRUE(subfolderController);
1044 // Drag a subfolder bookmark to the parent folder.
1045 BookmarkButton* draggedButton =
1046 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
1047 ASSERT_TRUE(draggedButton);
1048 BookmarkButton* targetButton =
1049 [folderController buttonWithTitleEqualTo:@"4f2f"];
1050 ASSERT_TRUE(targetButton);
1051 [folderController dragButton:draggedButton
1052 to:[targetButton top]
1054 // The button should have landed above "4f2f".
1055 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1056 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f3b 4f2f:[ "
1057 "4f2f1b 4f2f2b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
1058 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
1060 // Check button spacing.
1061 [folderController validateMenuSpacing];
1062 // The window should not have gone away.
1063 EXPECT_TRUE([bar_ folderController]);
1064 // The subfolder should have gone away.
1065 EXPECT_FALSE([folderController folderController]);
1068 TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) {
1069 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1070 const BookmarkNode* root = model->bookmark_bar_node();
1071 const std::string model_string(
1072 "a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c ");
1073 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1075 // Validate initial model.
1076 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1077 EXPECT_EQ(model_string, actualModelString);
1079 // Pop up a folder menu.
1080 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"b"];
1081 ASSERT_TRUE(toFolder);
1082 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1083 withObject:toFolder];
1084 BookmarkBarFolderController* folderController = [bar_ folderController];
1085 EXPECT_TRUE(folderController);
1086 NSWindow* toWindow = [folderController window];
1087 EXPECT_TRUE(toWindow);
1088 CGFloat oldWidth = NSWidth([toWindow frame]);
1089 // Drag the bookmark with a long name to the folder.
1090 BookmarkButton* draggedButton =
1091 [bar_ buttonWithTitleEqualTo:@"reallyReallyLongBookmarkName"];
1092 ASSERT_TRUE(draggedButton);
1093 BookmarkButton* targetButton =
1094 [folderController buttonWithTitleEqualTo:@"b1"];
1095 ASSERT_TRUE(targetButton);
1096 [folderController dragButton:draggedButton
1097 to:[targetButton center]
1099 // Verify the model change.
1100 const std::string expected_string(
1101 "a b:[ b1 reallyReallyLongBookmarkName b2 b3 ] c ");
1102 EXPECT_EQ(expected_string, bookmarks::test::ModelStringFromNode(root));
1103 // Verify the window grew. Just test a reasonable width gain.
1104 CGFloat newWidth = NSWidth([toWindow frame]);
1105 EXPECT_LT(oldWidth + 30.0, newWidth);
1108 TEST_F(BookmarkBarFolderControllerMenuTest, MoveRemoveAddButtons) {
1109 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1110 const BookmarkNode* root = model->bookmark_bar_node();
1111 const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
1112 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1114 // Validate initial model.
1115 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1116 EXPECT_EQ(model_string, actualModelString);
1118 // Pop up a folder menu.
1119 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
1120 ASSERT_TRUE(toFolder);
1121 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1122 withObject:toFolder];
1123 BookmarkBarFolderController* folder = [bar_ folderController];
1124 EXPECT_TRUE(folder);
1126 // Remember how many buttons are showing.
1127 NSArray* buttons = [folder buttons];
1128 NSUInteger oldDisplayedButtons = [buttons count];
1130 // Move a button around a bit.
1131 [folder moveButtonFromIndex:0 toIndex:2];
1132 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:0] title]);
1133 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:1] title]);
1134 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:2] title]);
1135 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1136 [folder moveButtonFromIndex:2 toIndex:0];
1137 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
1138 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
1139 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
1140 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1142 // Add a couple of buttons.
1143 const BookmarkNode* node = root->GetChild(2); // Purloin an existing node.
1144 [folder addButtonForNode:node atIndex:0];
1145 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1146 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
1147 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
1148 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
1149 EXPECT_EQ(oldDisplayedButtons + 1, [buttons count]);
1150 node = root->GetChild(3);
1151 [folder addButtonForNode:node atIndex:-1];
1152 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1153 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
1154 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
1155 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
1156 EXPECT_NSEQ(@"4b", [[buttons objectAtIndex:4] title]);
1157 EXPECT_EQ(oldDisplayedButtons + 2, [buttons count]);
1159 // Remove a couple of buttons.
1160 [folder removeButton:4 animate:NO];
1161 [folder removeButton:1 animate:NO];
1162 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1163 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
1164 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
1165 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1167 // Check button spacing.
1168 [folder validateMenuSpacing];
1171 TEST_F(BookmarkBarFolderControllerMenuTest, RemoveLastButtonOtherBookmarks) {
1172 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1173 const BookmarkNode* otherBookmarks = model->other_node();
1175 BookmarkButton* otherButton = [bar_ otherBookmarksButton];
1176 ASSERT_TRUE(otherButton);
1178 // Open the folder to get the folderController_.
1179 [[otherButton target] openBookmarkFolderFromButton:otherButton];
1180 BookmarkBarFolderController* folder = [bar_ folderController];
1181 EXPECT_TRUE(folder);
1183 // Initially there is only (empty) placeholder button, hence buttonCount
1185 NSArray* buttons = [folder buttons];
1186 EXPECT_TRUE(buttons);
1187 EXPECT_EQ(1U, [buttons count]);
1189 // Add a new bookmark into 'Other bookmarks' folder.
1190 model->AddURL(otherBookmarks, otherBookmarks->child_count(),
1191 ASCIIToUTF16("TheOther"),
1192 GURL("http://www.other.com"));
1194 // buttonCount still should be 1, as we remove the (empty) placeholder button
1195 // when adding a new button to an empty folder.
1196 EXPECT_EQ(1U, [buttons count]);
1198 // Now we have only 1 button; remove it so that 'Other bookmarks' folder
1200 [folder removeButton:0 animate:NO];
1201 EXPECT_EQ(0U, [buttons count]);
1203 // 'Other bookmarks' folder gets closed once we remove the last button. Hence
1204 // folderController_ should be NULL.
1205 EXPECT_FALSE([bar_ folderController]);
1208 TEST_F(BookmarkBarFolderControllerMenuTest, ControllerForNode) {
1209 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1210 const BookmarkNode* root = model->bookmark_bar_node();
1211 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
1212 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1214 // Validate initial model.
1215 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1216 EXPECT_EQ(model_string, actualModelString);
1218 // Find the main bar controller.
1219 const void* expectedController = bar_;
1220 const void* actualController = [bar_ controllerForNode:root];
1221 EXPECT_EQ(expectedController, actualController);
1223 // Pop up the folder menu.
1224 BookmarkButton* targetFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
1225 ASSERT_TRUE(targetFolder);
1226 [[targetFolder target]
1227 performSelector:@selector(openBookmarkFolderFromButton:)
1228 withObject:targetFolder];
1229 BookmarkBarFolderController* folder = [bar_ folderController];
1230 EXPECT_TRUE(folder);
1232 // Find the folder controller using the folder controller.
1233 const BookmarkNode* targetNode = root->GetChild(1);
1234 expectedController = folder;
1235 actualController = [bar_ controllerForNode:targetNode];
1236 EXPECT_EQ(expectedController, actualController);
1238 // Find the folder controller from the bar.
1239 actualController = [folder controllerForNode:targetNode];
1240 EXPECT_EQ(expectedController, actualController);
1243 TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
1244 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1245 const BookmarkNode* root = model->bookmark_bar_node();
1246 const std::string model_string("1b 2b 3b ");
1247 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1249 // Validate initial model.
1250 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1251 EXPECT_EQ(model_string, actualModelString);
1253 const BookmarkNode* parent = model->bookmark_bar_node();
1254 const BookmarkNode* folder = model->AddFolder(parent,
1255 parent->child_count(),
1256 ASCIIToUTF16("BIG"));
1258 // Pop open the new folder window and verify it has one (empty) item.
1259 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
1260 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1262 BookmarkBarFolderController* folderController = [bar_ folderController];
1263 EXPECT_TRUE(folderController);
1264 NSWindow* folderWindow = [folderController window];
1265 EXPECT_TRUE(folderWindow);
1266 CGFloat expectedHeight = (CGFloat)bookmarks::kBookmarkFolderButtonHeight +
1267 (2*bookmarks::kBookmarkVerticalPadding);
1268 NSRect windowFrame = [folderWindow frame];
1269 CGFloat windowHeight = NSHeight(windowFrame);
1270 EXPECT_CGFLOAT_EQ(expectedHeight, windowHeight);
1271 EXPECT_FALSE([folderController canScrollUp]);
1272 EXPECT_FALSE([folderController canScrollDown]);
1274 // Now add a real bookmark and reopen.
1275 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("a"),
1276 GURL("http://a.com/"));
1277 folderController = [bar_ folderController];
1278 EXPECT_TRUE(folderController);
1279 NSView* folderView = [folderController folderView];
1280 EXPECT_TRUE(folderView);
1281 NSRect menuFrame = [folderView frame];
1282 NSView* visibleView = [folderController visibleView];
1283 NSRect visibleFrame = [visibleView frame];
1284 NSScrollView* scrollView = [folderController scrollView];
1285 NSRect scrollFrame = [scrollView frame];
1287 // Determine the margins between the scroll frame and the visible frame.
1288 CGFloat widthDelta = NSWidth(visibleFrame) - NSWidth(scrollFrame);
1290 CGFloat menuHeight = NSHeight(menuFrame);
1291 EXPECT_CGFLOAT_EQ(expectedHeight, menuHeight);
1292 CGFloat scrollerWidth = NSWidth(scrollFrame);
1293 button = [folderController buttonWithTitleEqualTo:@"a"];
1294 CGFloat buttonWidth = NSWidth([button frame]);
1295 EXPECT_CGFLOAT_EQ(scrollerWidth, buttonWidth);
1296 CGFloat visibleWidth = NSWidth(visibleFrame);
1297 EXPECT_CGFLOAT_EQ(visibleWidth - widthDelta, buttonWidth);
1298 EXPECT_LT(scrollerWidth, NSWidth([folderView frame]));
1300 // Add a wider bookmark and make sure the button widths match.
1301 int reallyWideButtonNumber = folder->child_count();
1302 model->AddURL(folder, reallyWideButtonNumber,
1303 ASCIIToUTF16("A really, really, really, really, really, "
1304 "really long name"),
1305 GURL("http://www.google.com/a"));
1306 BookmarkButton* bigButton =
1307 [folderController buttonWithTitleEqualTo:
1308 @"A really, really, really, really, really, really long name"];
1309 EXPECT_TRUE(bigButton);
1310 CGFloat buttonWidthB = NSWidth([bigButton frame]);
1311 EXPECT_LT(buttonWidth, buttonWidthB);
1312 // Add a bunch of bookmarks until the window becomes scrollable, then check
1313 // for a scroll up arrow.
1314 NSUInteger tripWire = 0; // Prevent a runaway.
1315 while (![folderController canScrollUp] && ++tripWire < 1000) {
1316 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("B"),
1317 GURL("http://b.com/"));
1319 EXPECT_TRUE([folderController canScrollUp]);
1321 // Remove one bookmark and make sure the scroll down arrow has been removed.
1322 // We'll remove the really long node so we can see if the buttons get resized.
1323 scrollerWidth = NSWidth([folderView frame]);
1324 buttonWidth = NSWidth([button frame]);
1325 model->Remove(folder, reallyWideButtonNumber);
1326 EXPECT_FALSE([folderController canScrollUp]);
1327 EXPECT_FALSE([folderController canScrollDown]);
1329 // Check the size. It should have reduced.
1330 EXPECT_GT(scrollerWidth, NSWidth([folderView frame]));
1331 EXPECT_GT(buttonWidth, NSWidth([button frame]));
1333 // Check button spacing.
1334 [folderController validateMenuSpacing];
1337 // See http://crbug.com/46101
1338 TEST_F(BookmarkBarFolderControllerMenuTest, HoverThenDeleteBookmark) {
1339 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1340 const BookmarkNode* root = model->bookmark_bar_node();
1341 const BookmarkNode* folder = model->AddFolder(root,
1342 root->child_count(),
1343 ASCIIToUTF16("BIG"));
1344 for (int i = 0; i < kLotsOfNodesCount; i++)
1345 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("kid"),
1346 GURL("http://kid.com/smile"));
1348 // Pop open the new folder window and hover one of its kids.
1349 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
1350 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1352 BookmarkBarFolderController* bbfc = [bar_ folderController];
1353 NSArray* buttons = [bbfc buttons];
1355 // Hover over a button and verify that it is now known.
1356 button = [buttons objectAtIndex:3];
1357 BookmarkButton* buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1358 EXPECT_FALSE(buttonThatMouseIsIn);
1359 [bbfc mouseEnteredButton:button event:nil];
1360 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1361 EXPECT_EQ(button, buttonThatMouseIsIn);
1363 // Delete the bookmark and verify that it is now not known.
1364 model->Remove(folder, 3);
1365 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1366 EXPECT_FALSE(buttonThatMouseIsIn);
1369 // Just like a BookmarkBarFolderController but intercedes when providing
1370 // pasteboard drag data.
1371 @interface BookmarkBarFolderControllerDragData : BookmarkBarFolderController {
1372 const BookmarkNode* dragDataNode_; // Weak
1374 - (void)setDragDataNode:(const BookmarkNode*)node;
1377 @implementation BookmarkBarFolderControllerDragData
1379 - (id)initWithParentButton:(BookmarkButton*)button
1380 parentController:(BookmarkBarFolderController*)parentController
1381 barController:(BookmarkBarController*)barController
1382 profile:(Profile*)profile {
1383 if ((self = [super initWithParentButton:button
1384 parentController:parentController
1385 barController:barController
1386 profile:profile])) {
1387 dragDataNode_ = NULL;
1392 - (void)setDragDataNode:(const BookmarkNode*)node {
1393 dragDataNode_ = node;
1396 - (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
1397 std::vector<const BookmarkNode*> dragDataNodes;
1399 dragDataNodes.push_back(dragDataNode_);
1401 return dragDataNodes;
1406 TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
1407 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1408 const BookmarkNode* root = model->bookmark_bar_node();
1409 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1411 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1412 const BookmarkNode* other = model->other_node();
1413 const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
1414 "O4f:[ O4f1b O4f2f ] 05b ");
1415 bookmarks::test::AddNodesFromModelString(model, other, other_string);
1417 // Validate initial model.
1418 std::string actual = bookmarks::test::ModelStringFromNode(root);
1419 EXPECT_EQ(model_string, actual);
1420 actual = bookmarks::test::ModelStringFromNode(other);
1421 EXPECT_EQ(other_string, actual);
1423 // Pop open a folder.
1424 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1425 base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
1426 folderController.reset([[BookmarkBarFolderControllerDragData alloc]
1427 initWithParentButton:button
1428 parentController:nil
1430 profile:profile()]);
1431 BookmarkButton* targetButton =
1432 [folderController buttonWithTitleEqualTo:@"2f1b"];
1433 ASSERT_TRUE(targetButton);
1435 // Gen up some dragging data.
1436 const BookmarkNode* newNode = other->GetChild(2);
1437 [folderController setDragDataNode:newNode];
1438 base::scoped_nsobject<FakedDragInfo> dragInfo([[FakedDragInfo alloc] init]);
1439 [dragInfo setDropLocation:[targetButton top]];
1440 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
1442 // Verify the model.
1443 const std::string expected("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ 2f2f1b "
1444 "2f2f2b 2f2f3b ] 2f3b ] 3b 4b ");
1445 actual = bookmarks::test::ModelStringFromNode(root);
1446 EXPECT_EQ(expected, actual);
1448 // Now drag over a folder button.
1449 targetButton = [folderController buttonWithTitleEqualTo:@"2f2f"];
1450 ASSERT_TRUE(targetButton);
1451 newNode = other->GetChild(2); // Should be O4f.
1452 EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f"));
1453 [folderController setDragDataNode:newNode];
1454 [dragInfo setDropLocation:[targetButton center]];
1455 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
1457 // Verify the model.
1458 const std::string expectedA("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ "
1459 "2f2f1b 2f2f2b 2f2f3b O4f:[ O4f1b O4f2f ] ] "
1461 actual = bookmarks::test::ModelStringFromNode(root);
1462 EXPECT_EQ(expectedA, actual);
1464 // Check button spacing.
1465 [folderController validateMenuSpacing];
1468 TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkDataToTrash) {
1469 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1470 const BookmarkNode* root = model->bookmark_bar_node();
1471 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1473 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1475 // Validate initial model.
1476 std::string actual = bookmarks::test::ModelStringFromNode(root);
1477 EXPECT_EQ(model_string, actual);
1479 const BookmarkNode* folderNode = root->GetChild(1);
1480 int oldFolderChildCount = folderNode->child_count();
1482 // Pop open a folder.
1483 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1484 base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
1485 folderController.reset([[BookmarkBarFolderControllerDragData alloc]
1486 initWithParentButton:button
1487 parentController:nil
1489 profile:profile()]);
1491 // Drag a button to the trash.
1492 BookmarkButton* buttonToDelete =
1493 [folderController buttonWithTitleEqualTo:@"2f1b"];
1494 ASSERT_TRUE(buttonToDelete);
1495 EXPECT_TRUE([folderController canDragBookmarkButtonToTrash:buttonToDelete]);
1496 [folderController didDragBookmarkToTrash:buttonToDelete];
1498 // There should be one less button in the folder.
1499 int newFolderChildCount = folderNode->child_count();
1500 EXPECT_EQ(oldFolderChildCount - 1, newFolderChildCount);
1501 // Verify the model.
1502 const std::string expected("1b 2f:[ 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1504 actual = bookmarks::test::ModelStringFromNode(root);
1505 EXPECT_EQ(expected, actual);
1507 // Check button spacing.
1508 [folderController validateMenuSpacing];
1511 TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) {
1512 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1513 const BookmarkNode* root = model->bookmark_bar_node();
1514 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1516 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1518 // Validate initial model.
1519 std::string actual = bookmarks::test::ModelStringFromNode(root);
1520 EXPECT_EQ(model_string, actual);
1522 // Pop open a folder.
1523 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1524 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1526 BookmarkBarFolderController* folderController = [bar_ folderController];
1527 EXPECT_TRUE(folderController);
1528 NSArray* buttons = [folderController buttons];
1529 EXPECT_TRUE(buttons);
1531 // Remember how many buttons are showing.
1532 int oldDisplayedButtons = [buttons count];
1534 BookmarkButton* targetButton =
1535 [folderController buttonWithTitleEqualTo:@"2f1b"];
1536 ASSERT_TRUE(targetButton);
1538 NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/",
1539 @"http://www.b.com/", nil];
1540 NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil];
1541 [folderController addURLs:urls withTitles:titles at:[targetButton top]];
1543 // There should two more buttons in the folder.
1544 int newDisplayedButtons = [buttons count];
1545 EXPECT_EQ(oldDisplayedButtons + 2, newDisplayedButtons);
1546 // Verify the model.
1547 const std::string expected("1b 2f:[ SiteA SiteB 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1548 "2f2f3b ] 2f3b ] 3b 4b ");
1549 actual = bookmarks::test::ModelStringFromNode(root);
1550 EXPECT_EQ(expected, actual);
1552 // Check button spacing.
1553 [folderController validateMenuSpacing];
1556 TEST_F(BookmarkBarFolderControllerMenuTest, DropPositionIndicator) {
1557 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1558 const BookmarkNode* root = model->bookmark_bar_node();
1559 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1561 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1563 // Validate initial model.
1564 std::string actual = bookmarks::test::ModelStringFromNode(root);
1565 EXPECT_EQ(model_string, actual);
1567 // Pop open the folder.
1568 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1569 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1571 BookmarkBarFolderController* folder = [bar_ folderController];
1572 EXPECT_TRUE(folder);
1574 // Test a series of points starting at the top of the folder.
1575 const CGFloat yOffset = 0.5 * bookmarks::kBookmarkVerticalPadding;
1576 BookmarkButton* targetButton = [folder buttonWithTitleEqualTo:@"2f1b"];
1577 ASSERT_TRUE(targetButton);
1578 NSPoint targetPoint = [targetButton top];
1579 CGFloat pos = [folder indicatorPosForDragToPoint:targetPoint];
1580 EXPECT_CGFLOAT_EQ(targetPoint.y + yOffset, pos);
1581 pos = [folder indicatorPosForDragToPoint:[targetButton bottom]];
1582 targetButton = [folder buttonWithTitleEqualTo:@"2f2f"];
1583 EXPECT_CGFLOAT_EQ([targetButton top].y + yOffset, pos);
1584 pos = [folder indicatorPosForDragToPoint:NSMakePoint(10,0)];
1585 targetButton = [folder buttonWithTitleEqualTo:@"2f3b"];
1586 EXPECT_CGFLOAT_EQ([targetButton bottom].y - yOffset, pos);
1589 @interface BookmarkBarControllerNoDelete : BookmarkBarController
1590 - (IBAction)deleteBookmark:(id)sender;
1593 @implementation BookmarkBarControllerNoDelete
1594 - (IBAction)deleteBookmark:(id)sender {
1599 class BookmarkBarFolderControllerClosingTest : public
1600 BookmarkBarFolderControllerMenuTest {
1602 void SetUp() override {
1603 BookmarkBarFolderControllerMenuTest::SetUp();
1604 ASSERT_TRUE(browser());
1606 bar_.reset([[BookmarkBarControllerNoDelete alloc]
1607 initWithBrowser:browser()
1608 initialWidth:NSWidth([parent_view_ frame])
1610 resizeDelegate:resizeDelegate_.get()]);
1611 InstallAndToggleBar(bar_.get());
1615 TEST_F(BookmarkBarFolderControllerClosingTest, DeleteClosesFolder) {
1616 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1617 const BookmarkNode* root = model->bookmark_bar_node();
1618 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b ] "
1620 bookmarks::test::AddNodesFromModelString(model, root, model_string);
1622 // Validate initial model.
1623 std::string actualModelString = bookmarks::test::ModelStringFromNode(root);
1624 EXPECT_EQ(model_string, actualModelString);
1626 // Open the folder menu and submenu.
1627 BookmarkButton* target = [bar_ buttonWithTitleEqualTo:@"2f"];
1628 ASSERT_TRUE(target);
1629 [[target target] performSelector:@selector(openBookmarkFolderFromButton:)
1631 BookmarkBarFolderController* folder = [bar_ folderController];
1632 EXPECT_TRUE(folder);
1633 BookmarkButton* subTarget = [folder buttonWithTitleEqualTo:@"2f2f"];
1634 ASSERT_TRUE(subTarget);
1635 [[subTarget target] performSelector:@selector(openBookmarkFolderFromButton:)
1636 withObject:subTarget];
1637 BookmarkBarFolderController* subFolder = [folder folderController];
1638 EXPECT_TRUE(subFolder);
1640 // Delete the folder node and verify the window closed down by looking
1641 // for its controller again.
1642 DeleteBookmark([folder parentButton], profile());
1643 EXPECT_FALSE([folder folderController]);
1646 // TODO(jrg): draggingEntered: and draggingExited: trigger timers so
1647 // they are hard to test. Factor out "fire timers" into routines
1648 // which can be overridden to fire immediately to make behavior
1650 // There is a similar problem with mouseEnteredButton: and
1651 // mouseExitedButton:.