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