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;
31 const int kLotsOfNodesCount = 150;
33 // Deletes the bookmark corresponding to |button|.
34 void DeleteBookmark(BookmarkButton* button, Profile* profile) {
35 const BookmarkNode* node = [button bookmarkNode];
37 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile);
38 model->Remove(node->parent(), node->parent()->GetIndexOf(node));
44 // Add a redirect to make testing easier.
45 @interface BookmarkBarFolderController(MakeTestingEasier)
46 - (void)validateMenuSpacing;
49 @implementation BookmarkBarFolderController(MakeTestingEasier)
51 // Utility function to verify that the buttons in this folder are all
52 // evenly spaced in a progressive manner.
53 - (void)validateMenuSpacing {
54 BOOL firstButton = YES;
55 CGFloat lastVerticalOffset = 0.0;
56 for (BookmarkButton* button in [self buttons]) {
59 lastVerticalOffset = [button frame].origin.y;
61 CGFloat nextVerticalOffset = [button frame].origin.y;
62 EXPECT_CGFLOAT_EQ(lastVerticalOffset -
63 bookmarks::kBookmarkFolderButtonHeight,
65 lastVerticalOffset = nextVerticalOffset;
71 // Don't use a high window level when running unit tests -- it'll
72 // interfere with anything else you are working on.
74 @interface BookmarkBarFolderControllerNoLevel : BookmarkBarFolderController
77 @implementation BookmarkBarFolderControllerNoLevel
78 - (void)configureWindowLevel {
79 // Intentionally empty.
83 @interface BookmarkBarFolderControllerPong : BookmarkBarFolderController {
84 BOOL childFolderWillShow_;
85 BOOL childFolderWillClose_;
87 @property (nonatomic, readonly) BOOL childFolderWillShow;
88 @property (nonatomic, readonly) BOOL childFolderWillClose;
91 @implementation BookmarkBarFolderControllerPong
92 @synthesize childFolderWillShow = childFolderWillShow_;
93 @synthesize childFolderWillClose = childFolderWillClose_;
95 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
96 childFolderWillShow_ = YES;
99 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
100 childFolderWillClose_ = YES;
103 // We don't have a real BookmarkBarController as our parent root so
104 // we fake this one out.
105 - (void)closeAllBookmarkFolders {
106 [self closeBookmarkFolder:self];
111 // Redirect certain calls so they can be seen by tests.
113 @interface BookmarkBarControllerChildFolderRedirect : BookmarkBarController {
114 BookmarkBarFolderController* childFolderDelegate_;
116 @property (nonatomic, assign) BookmarkBarFolderController* childFolderDelegate;
119 @implementation BookmarkBarControllerChildFolderRedirect
121 @synthesize childFolderDelegate = childFolderDelegate_;
123 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
124 [childFolderDelegate_ childFolderWillShow:child];
127 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
128 [childFolderDelegate_ childFolderWillClose:child];
134 class BookmarkBarFolderControllerTest : public CocoaProfileTest {
136 base::scoped_nsobject<BookmarkBarControllerChildFolderRedirect> bar_;
137 const BookmarkNode* folderA_; // Owned by model.
138 const BookmarkNode* longTitleNode_; // Owned by model.
140 virtual void SetUp() {
141 CocoaProfileTest::SetUp();
142 ASSERT_TRUE(profile());
148 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
149 const BookmarkNode* parent = model->bookmark_bar_node();
150 const BookmarkNode* folderA = model->AddFolder(parent,
151 parent->child_count(),
152 ASCIIToUTF16("folder"));
154 model->AddFolder(parent, parent->child_count(),
155 ASCIIToUTF16("sibbling folder"));
156 const BookmarkNode* folderB = model->AddFolder(folderA,
157 folderA->child_count(),
158 ASCIIToUTF16("subfolder 1"));
159 model->AddFolder(folderA,
160 folderA->child_count(),
161 ASCIIToUTF16("subfolder 2"));
162 model->AddURL(folderA, folderA->child_count(), ASCIIToUTF16("title a"),
163 GURL("http://www.google.com/a"));
164 longTitleNode_ = model->AddURL(
165 folderA, folderA->child_count(),
166 ASCIIToUTF16("title super duper long long whoa momma title you betcha"),
167 GURL("http://www.google.com/b"));
168 model->AddURL(folderB, folderB->child_count(), ASCIIToUTF16("t"),
169 GURL("http://www.google.com/c"));
172 [[BookmarkBarControllerChildFolderRedirect alloc]
173 initWithBrowser:browser()
176 resizeDelegate:nil]);
178 // Make parent frame for bookmark bar then open it.
179 NSRect frame = [[test_window() contentView] frame];
180 frame = NSMakeRect(frame.origin.x,
181 frame.size.height - chrome::kNTPBookmarkBarHeight,
182 frame.size.width, chrome::kNTPBookmarkBarHeight);
183 NSView* fakeToolbarView = [[[NSView alloc] initWithFrame:frame]
185 [[test_window() contentView] addSubview:fakeToolbarView];
186 [fakeToolbarView addSubview:[bar_ view]];
187 [bar_ setBookmarkBarEnabled:YES];
190 // Remove the bookmark with the long title.
191 void RemoveLongTitleNode() {
192 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
193 model->Remove(longTitleNode_->parent(),
194 longTitleNode_->parent()->GetIndexOf(longTitleNode_));
197 // Add LOTS of nodes to our model if needed (e.g. scrolling).
198 // Returns the number of nodes added.
199 int AddLotsOfNodes() {
200 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
201 for (int i = 0; i < kLotsOfNodesCount; i++) {
202 model->AddURL(folderA_, folderA_->child_count(),
203 ASCIIToUTF16("repeated title"),
204 GURL("http://www.google.com/repeated/url"));
206 return kLotsOfNodesCount;
209 // Return a simple BookmarkBarFolderController.
210 BookmarkBarFolderControllerPong* SimpleBookmarkBarFolderController() {
211 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
212 BookmarkBarFolderControllerPong* c =
213 [[BookmarkBarFolderControllerPong alloc]
214 initWithParentButton:parentButton
218 [c window]; // Force nib load.
223 TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) {
224 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
225 bbfc.reset(SimpleBookmarkBarFolderController());
227 // Make sure none of the buttons overlap, that all are inside
228 // the content frame, and their cells are of the proper class.
229 NSArray* buttons = [bbfc buttons];
230 EXPECT_TRUE([buttons count]);
231 for (unsigned int i = 0; i < ([buttons count]-1); i++) {
232 EXPECT_FALSE(NSContainsRect([[buttons objectAtIndex:i] frame],
233 [[buttons objectAtIndex:i+1] frame]));
235 Class cellClass = [BookmarkBarFolderButtonCell class];
236 for (BookmarkButton* button in buttons) {
237 NSRect r = [[bbfc folderView] convertRect:[button frame] fromView:button];
238 // TODO(jrg): remove this adjustment.
239 NSRect bigger = NSInsetRect([[bbfc folderView] frame], -2, 0);
240 EXPECT_TRUE(NSContainsRect(bigger, r));
241 EXPECT_TRUE([[button cell] isKindOfClass:cellClass]);
244 // Confirm folder buttons have no tooltip. The important thing
245 // really is that we insure folders and non-folders are treated
246 // differently; not sure of any other generic way to do this.
247 for (BookmarkButton* button in buttons) {
248 if ([button isFolder])
249 EXPECT_FALSE([button toolTip]);
251 EXPECT_TRUE([button toolTip]);
255 // Make sure closing of the window releases the controller.
256 // (e.g. valgrind shouldn't complain if we do this).
257 TEST_F(BookmarkBarFolderControllerTest, ReleaseOnClose) {
258 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
259 bbfc.reset(SimpleBookmarkBarFolderController());
260 EXPECT_TRUE(bbfc.get());
262 [bbfc retain]; // stop the scoped_nsobject from doing anything
263 [[bbfc window] close]; // trigger an autorelease of bbfc.get()
266 TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
267 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
268 EXPECT_TRUE(parentButton);
270 // If parent is a BookmarkBarController, grow down.
271 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
272 bbfc.reset([[BookmarkBarFolderController alloc]
273 initWithParentButton:parentButton
278 NSPoint pt = [bbfc windowTopLeftForWidth:0 height:100]; // screen coords
279 NSPoint buttonOriginInWindow =
280 [parentButton convertRect:[parentButton bounds]
282 NSPoint buttonOriginInScreen =
283 [[parentButton window] convertBaseToScreen:buttonOriginInWindow];
285 EXPECT_LE(std::abs(pt.x - buttonOriginInScreen.x),
286 bookmarks::kBookmarkMenuOverlap + 1);
287 EXPECT_LE(std::abs(pt.y - buttonOriginInScreen.y),
288 bookmarks::kBookmarkMenuOverlap + 1);
290 // Make sure we see the window shift left if it spills off the screen
291 pt = [bbfc windowTopLeftForWidth:0 height:100];
292 NSPoint shifted = [bbfc windowTopLeftForWidth:9999999 height:100];
293 EXPECT_LT(shifted.x, pt.x);
295 // If parent is a BookmarkBarFolderController, grow right.
296 base::scoped_nsobject<BookmarkBarFolderController> bbfc2;
297 bbfc2.reset([[BookmarkBarFolderController alloc]
298 initWithParentButton:[[bbfc buttons] objectAtIndex:0]
299 parentController:bbfc.get()
303 pt = [bbfc2 windowTopLeftForWidth:0 height:100];
304 // We're now overlapping the window a bit.
305 EXPECT_EQ(pt.x, NSMaxX([[bbfc.get() window] frame]) -
306 bookmarks::kBookmarkMenuOverlap);
309 // Confirm we grow right until end of screen, then start growing left
310 // until end of screen again, then right.
311 TEST_F(BookmarkBarFolderControllerTest, PositionRightLeftRight) {
312 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
313 const BookmarkNode* parent = model->bookmark_bar_node();
314 const BookmarkNode* folder = parent;
316 const int count = 100;
318 // Make some super duper deeply nested folders.
319 for (i = 0; i < count; i++) {
320 folder = model->AddFolder(folder, 0, ASCIIToUTF16("nested folder"));
323 // Setup initial state for opening all folders.
325 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
326 BookmarkBarFolderController* parentController = nil;
327 EXPECT_TRUE(parentButton);
330 base::scoped_nsobject<NSMutableArray> folder_controller_array;
331 folder_controller_array.reset([[NSMutableArray array] retain]);
332 for (i=0; i<count; i++) {
333 BookmarkBarFolderControllerNoLevel* bbfcl =
334 [[BookmarkBarFolderControllerNoLevel alloc]
335 initWithParentButton:parentButton
336 parentController:parentController
339 [folder_controller_array addObject:bbfcl];
342 parentController = bbfcl;
343 parentButton = [[bbfcl buttons] objectAtIndex:0];
346 // Make vector of all x positions.
347 std::vector<CGFloat> leftPositions;
348 for (i=0; i<count; i++) {
349 CGFloat x = [[[folder_controller_array objectAtIndex:i] window]
351 leftPositions.push_back(x);
354 // Make sure the first few grow right.
356 EXPECT_TRUE(leftPositions[i+1] > leftPositions[i]);
358 // Look for the first "grow left".
359 while (leftPositions[i] > leftPositions[i-1])
361 // Confirm the next few also grow left.
363 for (j=i; j<i+3; j++)
364 EXPECT_TRUE(leftPositions[j+1] < leftPositions[j]);
367 // Finally, confirm we see a "grow right" once more.
368 while (leftPositions[i] < leftPositions[i-1])
370 // (No need to EXPECT a final "grow right"; if we didn't find one
371 // we'd get a C++ array bounds exception).
374 TEST_F(BookmarkBarFolderControllerTest, DropDestination) {
375 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
376 bbfc.reset(SimpleBookmarkBarFolderController());
377 EXPECT_TRUE(bbfc.get());
379 // Confirm "off the top" and "off the bottom" match no buttons.
380 NSPoint p = NSMakePoint(NSMidX([[bbfc folderView] frame]), 10000);
381 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
382 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
383 p = NSMakePoint(NSMidX([[bbfc folderView] frame]), -1);
384 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
385 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
387 // Confirm "right in the center" (give or take a pixel) is a match,
388 // and confirm "just barely in the button" is not. Anything more
389 // specific seems likely to be tweaked. We don't loop over all
390 // buttons because the scroll view makes them not visible.
391 for (BookmarkButton* button in [bbfc buttons]) {
392 CGFloat x = NSMidX([button frame]);
393 CGFloat y = NSMidY([button frame]);
394 // Somewhere near the center: a match (but only if a folder!)
395 if ([button isFolder]) {
397 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
399 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
400 EXPECT_FALSE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
402 // If not a folder we don't drop into it.
403 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
404 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
405 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
410 TEST_F(BookmarkBarFolderControllerTest, OpenFolder) {
411 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
412 bbfc.reset(SimpleBookmarkBarFolderController());
413 EXPECT_TRUE(bbfc.get());
415 EXPECT_FALSE([bbfc folderController]);
416 BookmarkButton* button = [[bbfc buttons] objectAtIndex:0];
417 [bbfc openBookmarkFolderFromButton:button];
418 id controller = [bbfc folderController];
419 EXPECT_TRUE(controller);
420 EXPECT_EQ([controller parentButton], button);
422 // Click the same one --> it gets closed.
423 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
424 EXPECT_FALSE([bbfc folderController]);
426 // Open a new one --> change.
427 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:1]];
428 EXPECT_NE(controller, [bbfc folderController]);
429 EXPECT_NE([[bbfc folderController] parentButton], button);
431 // Close it --> all gone!
432 [bbfc closeBookmarkFolder:nil];
433 EXPECT_FALSE([bbfc folderController]);
436 TEST_F(BookmarkBarFolderControllerTest, DeleteOpenFolder) {
437 base::scoped_nsobject<BookmarkBarFolderController> parent_controller(
438 SimpleBookmarkBarFolderController());
441 EXPECT_FALSE([parent_controller folderController]);
442 BookmarkButton* button = [[parent_controller buttons] objectAtIndex:0];
443 [parent_controller openBookmarkFolderFromButton:button];
444 EXPECT_EQ([[parent_controller folderController] parentButton], button);
446 // Delete the folder's button - the folder should close.
447 [parent_controller removeButton:0 animate:NO];
448 EXPECT_FALSE([parent_controller folderController]);
451 TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) {
452 base::scoped_nsobject<BookmarkBarFolderControllerPong> bbfc;
453 bbfc.reset(SimpleBookmarkBarFolderController());
454 EXPECT_TRUE(bbfc.get());
455 [bar_ setChildFolderDelegate:bbfc.get()];
457 EXPECT_FALSE([bbfc childFolderWillShow]);
458 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
459 EXPECT_TRUE([bbfc childFolderWillShow]);
461 EXPECT_FALSE([bbfc childFolderWillClose]);
462 [bbfc closeBookmarkFolder:nil];
463 EXPECT_TRUE([bbfc childFolderWillClose]);
465 [bar_ setChildFolderDelegate:nil];
468 // Make sure bookmark folders have variable widths.
469 TEST_F(BookmarkBarFolderControllerTest, ChildFolderWidth) {
470 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
472 bbfc.reset(SimpleBookmarkBarFolderController());
473 EXPECT_TRUE(bbfc.get());
474 [bbfc showWindow:bbfc.get()];
475 CGFloat wideWidth = NSWidth([[bbfc window] frame]);
477 RemoveLongTitleNode();
478 bbfc.reset(SimpleBookmarkBarFolderController());
479 EXPECT_TRUE(bbfc.get());
480 CGFloat thinWidth = NSWidth([[bbfc window] frame]);
482 // Make sure window size changed as expected.
483 EXPECT_GT(wideWidth, thinWidth);
486 // Simple scrolling tests.
487 // Currently flaky due to a changed definition of the correct menu boundaries.
488 TEST_F(BookmarkBarFolderControllerTest, DISABLED_SimpleScroll) {
489 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
490 NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
491 CGFloat screenHeight = NSHeight(screenFrame);
492 int nodecount = AddLotsOfNodes();
493 bbfc.reset(SimpleBookmarkBarFolderController());
494 EXPECT_TRUE(bbfc.get());
495 [bbfc showWindow:bbfc.get()];
496 NSWindow* window = [bbfc window];
498 // The window should be shorter than the screen but reach exactly to the
499 // bottom of the screen since it's scrollable.
500 EXPECT_LT(NSHeight([window frame]), screenHeight);
501 EXPECT_CGFLOAT_EQ(0.0, [window frame].origin.y);
503 // Initially, should show scroll-up but not scroll-down.
504 EXPECT_TRUE([bbfc canScrollUp]);
505 EXPECT_FALSE([bbfc canScrollDown]);
507 // Scroll up a bit. Make sure the window has gotten bigger each time.
508 // Also, for each scroll, make sure our hit test finds a new button
509 // (to confirm the content area changed).
510 NSView* savedHit = nil;
511 NSScrollView* scrollView = [bbfc scrollView];
513 // Find the next-to-last button showing at the bottom of the window and
514 // use its center for hit testing.
515 BookmarkButton* targetButton = nil;
516 NSPoint scrollPoint = [scrollView documentVisibleRect].origin;
517 for (BookmarkButton* button in [bbfc buttons]) {
518 NSRect buttonFrame = [button frame];
519 buttonFrame.origin.y -= scrollPoint.y;
520 if (buttonFrame.origin.y < 0.0)
522 targetButton = button;
524 EXPECT_TRUE(targetButton != nil);
525 NSPoint hitPoint = [targetButton frame].origin;
527 hitPoint.y += (bookmarks::kBookmarkFolderButtonHeight / 2.0) - scrollPoint.y;
528 hitPoint = [targetButton convertPoint:hitPoint toView:scrollView];
530 for (int i = 0; i < 3; i++) {
531 CGFloat height = NSHeight([window frame]);
532 [bbfc performOneScroll:60];
533 EXPECT_GT(NSHeight([window frame]), height);
534 NSView* hit = [scrollView hitTest:hitPoint];
535 // We should hit a bookmark button.
536 EXPECT_TRUE([[hit className] isEqualToString:@"BookmarkButton"]);
537 EXPECT_NE(hit, savedHit);
541 // Keep scrolling up; make sure we never get bigger than the screen.
542 // Also confirm we never scroll the window off the screen.
543 bool bothAtOnce = false;
544 while ([bbfc canScrollUp]) {
545 [bbfc performOneScroll:60];
546 EXPECT_TRUE(NSContainsRect([[NSScreen mainScreen] frame], [window frame]));
547 // Make sure, sometime during our scroll, we have the ability to
548 // scroll in either direction.
549 if ([bbfc canScrollUp] &&
550 [bbfc canScrollDown])
553 EXPECT_TRUE(bothAtOnce);
555 // Once we've scrolled to the end, our only option should be to scroll back.
556 EXPECT_FALSE([bbfc canScrollUp]);
557 EXPECT_TRUE([bbfc canScrollDown]);
559 NSRect wholeScreenRect = [[NSScreen mainScreen] frame];
561 // Now scroll down and make sure the window size does not change.
562 // Also confirm we never scroll the window off the screen the other
564 for (int i = 0; i < nodecount+50; ++i) {
565 [bbfc performOneScroll:-60];
566 // Once we can no longer scroll down the window height changes.
567 if (![bbfc canScrollDown])
569 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame]));
572 EXPECT_GT(NSHeight(wholeScreenRect), NSHeight([window frame]));
573 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame]));
576 // Folder menu sizing and placement while deleting bookmarks
577 // and scrolling tests.
578 TEST_F(BookmarkBarFolderControllerTest, MenuPlacementWhileScrollingDeleting) {
579 base::scoped_nsobject<BookmarkBarFolderController> bbfc;
581 bbfc.reset(SimpleBookmarkBarFolderController());
582 [bbfc showWindow:bbfc.get()];
583 NSWindow* menuWindow = [bbfc window];
584 BookmarkBarFolderController* folder = [bar_ folderController];
585 NSArray* buttons = [folder buttons];
587 // Before scrolling any, delete a bookmark and make sure the window top has
588 // not moved. Pick a button which is near the top and visible.
589 CGFloat oldTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
590 BookmarkButton* button = [buttons objectAtIndex:3];
591 DeleteBookmark(button, profile());
592 CGFloat newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
593 EXPECT_CGFLOAT_EQ(oldTop, newTop);
595 // Scroll so that both the top and bottom scroll arrows show, make sure
596 // the top of the window has moved up, then delete a visible button and
597 // make sure the top has not moved.
599 const CGFloat scrollOneBookmark = bookmarks::kBookmarkFolderButtonHeight +
600 bookmarks::kBookmarkVerticalPadding;
601 NSUInteger buttonCounter = 0;
602 NSUInteger extraButtonLimit = 3;
603 while (![bbfc canScrollDown] || extraButtonLimit > 0) {
604 [bbfc performOneScroll:scrollOneBookmark];
606 if ([bbfc canScrollDown])
609 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
610 EXPECT_NE(oldTop, newTop);
612 button = [buttons objectAtIndex:buttonCounter + 3];
613 DeleteBookmark(button, profile());
614 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
615 EXPECT_CGFLOAT_EQ(oldTop, newTop);
617 // Scroll so that the top scroll arrow is no longer showing, make sure
618 // the top of the window has not moved, then delete a visible button and
619 // make sure the top has not moved.
620 while ([bbfc canScrollDown]) {
621 [bbfc performOneScroll:-scrollOneBookmark];
624 button = [buttons objectAtIndex:buttonCounter + 3];
625 DeleteBookmark(button, profile());
626 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
627 EXPECT_CGFLOAT_EQ(oldTop - bookmarks::kScrollWindowVerticalMargin, newTop);
630 // Make sure that we return the correct browser window.
631 TEST_F(BookmarkBarFolderControllerTest, BrowserWindow) {
632 base::scoped_nsobject<BookmarkBarFolderController> controller(
633 SimpleBookmarkBarFolderController());
634 EXPECT_EQ([bar_ browserWindow], [controller browserWindow]);
637 @interface FakedDragInfo : NSObject {
639 NSPoint dropLocation_;
640 NSDragOperation sourceMask_;
642 @property (nonatomic, assign) NSPoint dropLocation;
643 - (void)setDraggingSourceOperationMask:(NSDragOperation)mask;
646 @implementation FakedDragInfo
648 @synthesize dropLocation = dropLocation_;
651 if ((self = [super init])) {
652 dropLocation_ = NSZeroPoint;
653 sourceMask_ = NSDragOperationMove;
658 // NSDraggingInfo protocol functions.
660 - (id)draggingPasteboard {
664 - (id)draggingSource {
668 - (NSDragOperation)draggingSourceOperationMask {
672 - (NSPoint)draggingLocation {
673 return dropLocation_;
678 - (void)setDraggingSourceOperationMask:(NSDragOperation)mask {
685 class BookmarkBarFolderControllerMenuTest : public CocoaProfileTest {
687 base::scoped_nsobject<NSView> parent_view_;
688 base::scoped_nsobject<ViewResizerPong> resizeDelegate_;
689 base::scoped_nsobject<BookmarkBarController> bar_;
691 virtual void SetUp() {
692 CocoaProfileTest::SetUp();
693 ASSERT_TRUE(browser());
695 resizeDelegate_.reset([[ViewResizerPong alloc] init]);
696 NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
697 parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
698 [parent_view_ setHidden:YES];
699 bar_.reset([[BookmarkBarController alloc]
700 initWithBrowser:browser()
701 initialWidth:NSWidth(parent_frame)
703 resizeDelegate:resizeDelegate_.get()]);
704 InstallAndToggleBar(bar_.get());
707 void InstallAndToggleBar(BookmarkBarController* bar) {
708 // Force loading of the nib.
710 // Awkwardness to look like we've been installed.
711 [parent_view_ addSubview:[bar view]];
712 NSRect frame = [[[bar view] superview] frame];
713 frame.origin.y = 400;
714 [[[bar view] superview] setFrame:frame];
716 // Make sure it's on in a window so viewDidMoveToWindow is called
717 [[test_window() contentView] addSubview:parent_view_];
719 // Make sure it's open so certain things aren't no-ops.
720 [bar updateState:BookmarkBar::SHOW
721 changeType:BookmarkBar::DONT_ANIMATE_STATE_CHANGE];
725 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
726 WithNoAnimation at_all;
727 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
728 const BookmarkNode* root = model->bookmark_bar_node();
729 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
730 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
731 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
732 test::AddNodesFromModelString(model, root, model_string);
734 // Validate initial model.
735 std::string actualModelString = test::ModelStringFromNode(root);
736 EXPECT_EQ(model_string, actualModelString);
738 // Pop up a folder menu and drag in a button from the bar.
739 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
740 NSRect oldToFolderFrame = [toFolder frame];
741 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
742 withObject:toFolder];
743 BookmarkBarFolderController* folderController = [bar_ folderController];
744 EXPECT_TRUE(folderController);
745 NSWindow* toWindow = [folderController window];
746 EXPECT_TRUE(toWindow);
747 NSRect oldToWindowFrame = [toWindow frame];
748 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
749 // so it should end up below the target bookmark.
750 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
751 ASSERT_TRUE(draggedButton);
752 CGFloat horizontalShift =
753 NSWidth([draggedButton frame]) + bookmarks::kBookmarkHorizontalPadding;
754 BookmarkButton* targetButton =
755 [folderController buttonWithTitleEqualTo:@"2f1b"];
756 ASSERT_TRUE(targetButton);
757 [folderController dragButton:draggedButton
758 to:[targetButton center]
760 // The button should have landed just after "2f1b".
761 const std::string expected_string("2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
762 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
763 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
764 EXPECT_EQ(expected_string, test::ModelStringFromNode(root));
766 // Verify the window still appears by looking for its controller.
767 EXPECT_TRUE([bar_ folderController]);
769 // Gather the new frames.
770 NSRect newToFolderFrame = [toFolder frame];
771 NSRect newToWindowFrame = [toWindow frame];
772 // The toFolder should have shifted left horizontally but not vertically.
773 NSRect expectedToFolderFrame =
774 NSOffsetRect(oldToFolderFrame, -horizontalShift, 0);
775 EXPECT_NSRECT_EQ(expectedToFolderFrame, newToFolderFrame);
776 // The toWindow should have shifted left horizontally, down vertically,
777 // and grown vertically.
778 NSRect expectedToWindowFrame = oldToWindowFrame;
779 expectedToWindowFrame.origin.x -= horizontalShift;
780 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
781 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight;
782 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
784 // Check button spacing.
785 [folderController validateMenuSpacing];
787 // Move the button back to the bar at the beginning.
788 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
789 ASSERT_TRUE(draggedButton);
790 targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
791 ASSERT_TRUE(targetButton);
792 [bar_ dragButton:draggedButton
793 to:[targetButton left]
795 EXPECT_EQ(model_string, test::ModelStringFromNode(root));
796 // Don't check the folder window since it's not supposed to be showing.
799 TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
800 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
801 const BookmarkNode* root = model->bookmark_bar_node();
802 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
803 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
804 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
805 test::AddNodesFromModelString(model, root, model_string);
807 // Validate initial model.
808 std::string actualModelString = test::ModelStringFromNode(root);
809 EXPECT_EQ(model_string, actualModelString);
811 // Pop up a folder menu and copy in a button from the bar.
812 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
813 ASSERT_TRUE(toFolder);
814 NSRect oldToFolderFrame = [toFolder frame];
815 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
816 withObject:toFolder];
817 BookmarkBarFolderController* folderController = [bar_ folderController];
818 EXPECT_TRUE(folderController);
819 NSWindow* toWindow = [folderController window];
820 EXPECT_TRUE(toWindow);
821 NSRect oldToWindowFrame = [toWindow frame];
822 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
823 // so it should end up below the target bookmark.
824 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
825 ASSERT_TRUE(draggedButton);
826 BookmarkButton* targetButton =
827 [folderController buttonWithTitleEqualTo:@"2f1b"];
828 ASSERT_TRUE(targetButton);
829 [folderController dragButton:draggedButton
830 to:[targetButton center]
832 // The button should have landed just after "2f1b".
833 const std::string expected_1("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
834 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
835 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
836 EXPECT_EQ(expected_1, test::ModelStringFromNode(root));
838 // Gather the new frames.
839 NSRect newToFolderFrame = [toFolder frame];
840 NSRect newToWindowFrame = [toWindow frame];
841 // The toFolder should have shifted.
842 EXPECT_NSRECT_EQ(oldToFolderFrame, newToFolderFrame);
843 // The toWindow should have shifted down vertically and grown vertically.
844 NSRect expectedToWindowFrame = oldToWindowFrame;
845 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
846 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight;
847 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
849 // Copy the button back to the bar after "3b".
850 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
851 ASSERT_TRUE(draggedButton);
852 targetButton = [bar_ buttonWithTitleEqualTo:@"4f"];
853 ASSERT_TRUE(targetButton);
854 [bar_ dragButton:draggedButton
855 to:[targetButton left]
857 const std::string expected_2("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
858 "2f2f2b 2f2f3b ] 2f3b ] 3b 1b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
859 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
860 EXPECT_EQ(expected_2, test::ModelStringFromNode(root));
863 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
864 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
865 const BookmarkNode* root = model->bookmark_bar_node();
866 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
867 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
868 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
869 test::AddNodesFromModelString(model, root, model_string);
871 // Validate initial model.
872 std::string actualModelString = test::ModelStringFromNode(root);
873 EXPECT_EQ(model_string, actualModelString);
875 // Pop up a folder menu and a subfolder menu.
876 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
877 ASSERT_TRUE(toFolder);
878 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
879 withObject:toFolder];
880 BookmarkBarFolderController* folderController = [bar_ folderController];
881 EXPECT_TRUE(folderController);
882 NSWindow* toWindow = [folderController window];
883 EXPECT_TRUE(toWindow);
884 NSRect oldToWindowFrame = [toWindow frame];
885 BookmarkButton* toSubfolder =
886 [folderController buttonWithTitleEqualTo:@"4f2f"];
887 ASSERT_TRUE(toSubfolder);
888 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
889 withObject:toSubfolder];
890 BookmarkBarFolderController* subfolderController =
891 [folderController folderController];
892 EXPECT_TRUE(subfolderController);
893 NSWindow* toSubwindow = [subfolderController window];
894 EXPECT_TRUE(toSubwindow);
895 NSRect oldToSubwindowFrame = [toSubwindow frame];
896 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
897 // so it should end up below the target bookmark.
898 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"5b"];
899 ASSERT_TRUE(draggedButton);
900 BookmarkButton* targetButton =
901 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
902 ASSERT_TRUE(targetButton);
903 [subfolderController dragButton:draggedButton
904 to:[targetButton center]
906 // The button should have landed just after "2f".
907 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
908 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
909 "4f2f1b 4f2f2b 4f2f3b 5b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] ");
910 EXPECT_EQ(expected_string, test::ModelStringFromNode(root));
912 // Check button spacing.
913 [folderController validateMenuSpacing];
914 [subfolderController validateMenuSpacing];
916 // Check the window layouts. The folder window should not have changed,
917 // but the subfolder window should have shifted vertically and grown.
918 NSRect newToWindowFrame = [toWindow frame];
919 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
920 NSRect newToSubwindowFrame = [toSubwindow frame];
921 NSRect expectedToSubwindowFrame = oldToSubwindowFrame;
922 expectedToSubwindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
923 expectedToSubwindowFrame.size.height +=
924 bookmarks::kBookmarkFolderButtonHeight;
925 EXPECT_NSRECT_EQ(expectedToSubwindowFrame, newToSubwindowFrame);
928 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) {
929 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
930 const BookmarkNode* root = model->bookmark_bar_node();
931 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
932 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
933 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
934 test::AddNodesFromModelString(model, root, model_string);
936 // Validate initial model.
937 std::string actualModelString = test::ModelStringFromNode(root);
938 EXPECT_EQ(model_string, actualModelString);
940 // Pop up a folder menu.
941 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
942 ASSERT_TRUE(toFolder);
943 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
944 withObject:toFolder];
945 BookmarkBarFolderController* folderController = [bar_ folderController];
946 EXPECT_TRUE(folderController);
947 NSWindow* toWindow = [folderController window];
948 EXPECT_TRUE(toWindow);
949 NSRect oldToWindowFrame = [toWindow frame];
950 // Drag a folder button to the top within the same parent.
951 BookmarkButton* draggedButton =
952 [folderController buttonWithTitleEqualTo:@"4f2f"];
953 ASSERT_TRUE(draggedButton);
954 BookmarkButton* targetButton =
955 [folderController buttonWithTitleEqualTo:@"4f1f"];
956 ASSERT_TRUE(targetButton);
957 [folderController dragButton:draggedButton
958 to:[targetButton top]
960 // The button should have landed above "4f1f".
961 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
962 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f2f:[ 4f2f1b 4f2f2b 4f2f3b ] "
963 "4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
964 EXPECT_EQ(expected_string, test::ModelStringFromNode(root));
966 // The window should not have gone away.
967 EXPECT_TRUE([bar_ folderController]);
969 // The folder window should not have changed.
970 NSRect newToWindowFrame = [toWindow frame];
971 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
973 // Check button spacing.
974 [folderController validateMenuSpacing];
977 TEST_F(BookmarkBarFolderControllerMenuTest, DragParentOntoChild) {
978 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
979 const BookmarkNode* root = model->bookmark_bar_node();
980 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
981 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
982 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
983 test::AddNodesFromModelString(model, root, model_string);
985 // Validate initial model.
986 std::string actualModelString = test::ModelStringFromNode(root);
987 EXPECT_EQ(model_string, actualModelString);
989 // Pop up a folder menu.
990 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
991 ASSERT_TRUE(toFolder);
992 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
993 withObject:toFolder];
994 BookmarkBarFolderController* folderController = [bar_ folderController];
995 EXPECT_TRUE(folderController);
996 NSWindow* toWindow = [folderController window];
997 EXPECT_TRUE(toWindow);
998 // Drag a folder button to one of its children.
999 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"4f"];
1000 ASSERT_TRUE(draggedButton);
1001 BookmarkButton* targetButton =
1002 [folderController buttonWithTitleEqualTo:@"4f3f"];
1003 ASSERT_TRUE(targetButton);
1004 [folderController dragButton:draggedButton
1005 to:[targetButton top]
1007 // The model should not have changed.
1008 EXPECT_EQ(model_string, test::ModelStringFromNode(root));
1010 // Check button spacing.
1011 [folderController validateMenuSpacing];
1014 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) {
1015 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1016 const BookmarkNode* root = model->bookmark_bar_node();
1017 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1018 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
1019 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
1020 test::AddNodesFromModelString(model, root, model_string);
1022 // Validate initial model.
1023 std::string actualModelString = test::ModelStringFromNode(root);
1024 EXPECT_EQ(model_string, actualModelString);
1026 // Pop up a folder menu and a subfolder menu.
1027 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
1028 ASSERT_TRUE(toFolder);
1029 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1030 withObject:toFolder];
1031 BookmarkBarFolderController* folderController = [bar_ folderController];
1032 EXPECT_TRUE(folderController);
1033 BookmarkButton* toSubfolder =
1034 [folderController buttonWithTitleEqualTo:@"4f2f"];
1035 ASSERT_TRUE(toSubfolder);
1036 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1037 withObject:toSubfolder];
1038 BookmarkBarFolderController* subfolderController =
1039 [folderController folderController];
1040 EXPECT_TRUE(subfolderController);
1042 // Drag a subfolder bookmark to the parent folder.
1043 BookmarkButton* draggedButton =
1044 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
1045 ASSERT_TRUE(draggedButton);
1046 BookmarkButton* targetButton =
1047 [folderController buttonWithTitleEqualTo:@"4f2f"];
1048 ASSERT_TRUE(targetButton);
1049 [folderController dragButton:draggedButton
1050 to:[targetButton top]
1052 // The button should have landed above "4f2f".
1053 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1054 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f3b 4f2f:[ "
1055 "4f2f1b 4f2f2b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
1056 EXPECT_EQ(expected_string, test::ModelStringFromNode(root));
1058 // Check button spacing.
1059 [folderController validateMenuSpacing];
1060 // The window should not have gone away.
1061 EXPECT_TRUE([bar_ folderController]);
1062 // The subfolder should have gone away.
1063 EXPECT_FALSE([folderController folderController]);
1066 TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) {
1067 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1068 const BookmarkNode* root = model->bookmark_bar_node();
1069 const std::string model_string(
1070 "a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c ");
1071 test::AddNodesFromModelString(model, root, model_string);
1073 // Validate initial model.
1074 std::string actualModelString = test::ModelStringFromNode(root);
1075 EXPECT_EQ(model_string, actualModelString);
1077 // Pop up a folder menu.
1078 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"b"];
1079 ASSERT_TRUE(toFolder);
1080 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1081 withObject:toFolder];
1082 BookmarkBarFolderController* folderController = [bar_ folderController];
1083 EXPECT_TRUE(folderController);
1084 NSWindow* toWindow = [folderController window];
1085 EXPECT_TRUE(toWindow);
1086 CGFloat oldWidth = NSWidth([toWindow frame]);
1087 // Drag the bookmark with a long name to the folder.
1088 BookmarkButton* draggedButton =
1089 [bar_ buttonWithTitleEqualTo:@"reallyReallyLongBookmarkName"];
1090 ASSERT_TRUE(draggedButton);
1091 BookmarkButton* targetButton =
1092 [folderController buttonWithTitleEqualTo:@"b1"];
1093 ASSERT_TRUE(targetButton);
1094 [folderController dragButton:draggedButton
1095 to:[targetButton center]
1097 // Verify the model change.
1098 const std::string expected_string(
1099 "a b:[ b1 reallyReallyLongBookmarkName b2 b3 ] c ");
1100 EXPECT_EQ(expected_string, test::ModelStringFromNode(root));
1101 // Verify the window grew. Just test a reasonable width gain.
1102 CGFloat newWidth = NSWidth([toWindow frame]);
1103 EXPECT_LT(oldWidth + 30.0, newWidth);
1106 TEST_F(BookmarkBarFolderControllerMenuTest, MoveRemoveAddButtons) {
1107 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1108 const BookmarkNode* root = model->bookmark_bar_node();
1109 const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
1110 test::AddNodesFromModelString(model, root, model_string);
1112 // Validate initial model.
1113 std::string actualModelString = test::ModelStringFromNode(root);
1114 EXPECT_EQ(model_string, actualModelString);
1116 // Pop up a folder menu.
1117 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
1118 ASSERT_TRUE(toFolder);
1119 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1120 withObject:toFolder];
1121 BookmarkBarFolderController* folder = [bar_ folderController];
1122 EXPECT_TRUE(folder);
1124 // Remember how many buttons are showing.
1125 NSArray* buttons = [folder buttons];
1126 NSUInteger oldDisplayedButtons = [buttons count];
1128 // Move a button around a bit.
1129 [folder moveButtonFromIndex:0 toIndex:2];
1130 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:0] title]);
1131 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:1] title]);
1132 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:2] title]);
1133 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1134 [folder moveButtonFromIndex:2 toIndex:0];
1135 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
1136 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
1137 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
1138 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1140 // Add a couple of buttons.
1141 const BookmarkNode* node = root->GetChild(2); // Purloin an existing node.
1142 [folder addButtonForNode:node atIndex:0];
1143 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1144 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
1145 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
1146 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
1147 EXPECT_EQ(oldDisplayedButtons + 1, [buttons count]);
1148 node = root->GetChild(3);
1149 [folder addButtonForNode:node atIndex:-1];
1150 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1151 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
1152 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
1153 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
1154 EXPECT_NSEQ(@"4b", [[buttons objectAtIndex:4] title]);
1155 EXPECT_EQ(oldDisplayedButtons + 2, [buttons count]);
1157 // Remove a couple of buttons.
1158 [folder removeButton:4 animate:NO];
1159 [folder removeButton:1 animate:NO];
1160 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1161 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
1162 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
1163 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1165 // Check button spacing.
1166 [folder validateMenuSpacing];
1169 TEST_F(BookmarkBarFolderControllerMenuTest, ControllerForNode) {
1170 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1171 const BookmarkNode* root = model->bookmark_bar_node();
1172 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
1173 test::AddNodesFromModelString(model, root, model_string);
1175 // Validate initial model.
1176 std::string actualModelString = test::ModelStringFromNode(root);
1177 EXPECT_EQ(model_string, actualModelString);
1179 // Find the main bar controller.
1180 const void* expectedController = bar_;
1181 const void* actualController = [bar_ controllerForNode:root];
1182 EXPECT_EQ(expectedController, actualController);
1184 // Pop up the folder menu.
1185 BookmarkButton* targetFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
1186 ASSERT_TRUE(targetFolder);
1187 [[targetFolder target]
1188 performSelector:@selector(openBookmarkFolderFromButton:)
1189 withObject:targetFolder];
1190 BookmarkBarFolderController* folder = [bar_ folderController];
1191 EXPECT_TRUE(folder);
1193 // Find the folder controller using the folder controller.
1194 const BookmarkNode* targetNode = root->GetChild(1);
1195 expectedController = folder;
1196 actualController = [bar_ controllerForNode:targetNode];
1197 EXPECT_EQ(expectedController, actualController);
1199 // Find the folder controller from the bar.
1200 actualController = [folder controllerForNode:targetNode];
1201 EXPECT_EQ(expectedController, actualController);
1204 TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
1205 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1206 const BookmarkNode* root = model->bookmark_bar_node();
1207 const std::string model_string("1b 2b 3b ");
1208 test::AddNodesFromModelString(model, root, model_string);
1210 // Validate initial model.
1211 std::string actualModelString = test::ModelStringFromNode(root);
1212 EXPECT_EQ(model_string, actualModelString);
1214 const BookmarkNode* parent = model->bookmark_bar_node();
1215 const BookmarkNode* folder = model->AddFolder(parent,
1216 parent->child_count(),
1217 ASCIIToUTF16("BIG"));
1219 // Pop open the new folder window and verify it has one (empty) item.
1220 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
1221 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1223 BookmarkBarFolderController* folderController = [bar_ folderController];
1224 EXPECT_TRUE(folderController);
1225 NSWindow* folderWindow = [folderController window];
1226 EXPECT_TRUE(folderWindow);
1227 CGFloat expectedHeight = (CGFloat)bookmarks::kBookmarkFolderButtonHeight +
1228 (2*bookmarks::kBookmarkVerticalPadding);
1229 NSRect windowFrame = [folderWindow frame];
1230 CGFloat windowHeight = NSHeight(windowFrame);
1231 EXPECT_CGFLOAT_EQ(expectedHeight, windowHeight);
1232 EXPECT_FALSE([folderController canScrollUp]);
1233 EXPECT_FALSE([folderController canScrollDown]);
1235 // Now add a real bookmark and reopen.
1236 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("a"),
1237 GURL("http://a.com/"));
1238 folderController = [bar_ folderController];
1239 EXPECT_TRUE(folderController);
1240 NSView* folderView = [folderController folderView];
1241 EXPECT_TRUE(folderView);
1242 NSRect menuFrame = [folderView frame];
1243 NSView* visibleView = [folderController visibleView];
1244 NSRect visibleFrame = [visibleView frame];
1245 NSScrollView* scrollView = [folderController scrollView];
1246 NSRect scrollFrame = [scrollView frame];
1248 // Determine the margins between the scroll frame and the visible frame.
1249 CGFloat widthDelta = NSWidth(visibleFrame) - NSWidth(scrollFrame);
1251 CGFloat menuHeight = NSHeight(menuFrame);
1252 EXPECT_CGFLOAT_EQ(expectedHeight, menuHeight);
1253 CGFloat scrollerWidth = NSWidth(scrollFrame);
1254 button = [folderController buttonWithTitleEqualTo:@"a"];
1255 CGFloat buttonWidth = NSWidth([button frame]);
1256 EXPECT_CGFLOAT_EQ(scrollerWidth, buttonWidth);
1257 CGFloat visibleWidth = NSWidth(visibleFrame);
1258 EXPECT_CGFLOAT_EQ(visibleWidth - widthDelta, buttonWidth);
1259 EXPECT_LT(scrollerWidth, NSWidth([folderView frame]));
1261 // Add a wider bookmark and make sure the button widths match.
1262 int reallyWideButtonNumber = folder->child_count();
1263 model->AddURL(folder, reallyWideButtonNumber,
1264 ASCIIToUTF16("A really, really, really, really, really, "
1265 "really long name"),
1266 GURL("http://www.google.com/a"));
1267 BookmarkButton* bigButton =
1268 [folderController buttonWithTitleEqualTo:
1269 @"A really, really, really, really, really, really long name"];
1270 EXPECT_TRUE(bigButton);
1271 CGFloat buttonWidthB = NSWidth([bigButton frame]);
1272 EXPECT_LT(buttonWidth, buttonWidthB);
1273 // Add a bunch of bookmarks until the window becomes scrollable, then check
1274 // for a scroll up arrow.
1275 NSUInteger tripWire = 0; // Prevent a runaway.
1276 while (![folderController canScrollUp] && ++tripWire < 1000) {
1277 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("B"),
1278 GURL("http://b.com/"));
1280 EXPECT_TRUE([folderController canScrollUp]);
1282 // Remove one bookmark and make sure the scroll down arrow has been removed.
1283 // We'll remove the really long node so we can see if the buttons get resized.
1284 scrollerWidth = NSWidth([folderView frame]);
1285 buttonWidth = NSWidth([button frame]);
1286 model->Remove(folder, reallyWideButtonNumber);
1287 EXPECT_FALSE([folderController canScrollUp]);
1288 EXPECT_FALSE([folderController canScrollDown]);
1290 // Check the size. It should have reduced.
1291 EXPECT_GT(scrollerWidth, NSWidth([folderView frame]));
1292 EXPECT_GT(buttonWidth, NSWidth([button frame]));
1294 // Check button spacing.
1295 [folderController validateMenuSpacing];
1298 // See http://crbug.com/46101
1299 TEST_F(BookmarkBarFolderControllerMenuTest, HoverThenDeleteBookmark) {
1300 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1301 const BookmarkNode* root = model->bookmark_bar_node();
1302 const BookmarkNode* folder = model->AddFolder(root,
1303 root->child_count(),
1304 ASCIIToUTF16("BIG"));
1305 for (int i = 0; i < kLotsOfNodesCount; i++)
1306 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("kid"),
1307 GURL("http://kid.com/smile"));
1309 // Pop open the new folder window and hover one of its kids.
1310 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
1311 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1313 BookmarkBarFolderController* bbfc = [bar_ folderController];
1314 NSArray* buttons = [bbfc buttons];
1316 // Hover over a button and verify that it is now known.
1317 button = [buttons objectAtIndex:3];
1318 BookmarkButton* buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1319 EXPECT_FALSE(buttonThatMouseIsIn);
1320 [bbfc mouseEnteredButton:button event:nil];
1321 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1322 EXPECT_EQ(button, buttonThatMouseIsIn);
1324 // Delete the bookmark and verify that it is now not known.
1325 model->Remove(folder, 3);
1326 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1327 EXPECT_FALSE(buttonThatMouseIsIn);
1330 // Just like a BookmarkBarFolderController but intercedes when providing
1331 // pasteboard drag data.
1332 @interface BookmarkBarFolderControllerDragData : BookmarkBarFolderController {
1333 const BookmarkNode* dragDataNode_; // Weak
1335 - (void)setDragDataNode:(const BookmarkNode*)node;
1338 @implementation BookmarkBarFolderControllerDragData
1340 - (id)initWithParentButton:(BookmarkButton*)button
1341 parentController:(BookmarkBarFolderController*)parentController
1342 barController:(BookmarkBarController*)barController
1343 profile:(Profile*)profile {
1344 if ((self = [super initWithParentButton:button
1345 parentController:parentController
1346 barController:barController
1347 profile:profile])) {
1348 dragDataNode_ = NULL;
1353 - (void)setDragDataNode:(const BookmarkNode*)node {
1354 dragDataNode_ = node;
1357 - (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
1358 std::vector<const BookmarkNode*> dragDataNodes;
1360 dragDataNodes.push_back(dragDataNode_);
1362 return dragDataNodes;
1367 TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
1368 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1369 const BookmarkNode* root = model->bookmark_bar_node();
1370 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1372 test::AddNodesFromModelString(model, root, model_string);
1373 const BookmarkNode* other = model->other_node();
1374 const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
1375 "O4f:[ O4f1b O4f2f ] 05b ");
1376 test::AddNodesFromModelString(model, other, other_string);
1378 // Validate initial model.
1379 std::string actual = test::ModelStringFromNode(root);
1380 EXPECT_EQ(model_string, actual);
1381 actual = test::ModelStringFromNode(other);
1382 EXPECT_EQ(other_string, actual);
1384 // Pop open a folder.
1385 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1386 base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
1387 folderController.reset([[BookmarkBarFolderControllerDragData alloc]
1388 initWithParentButton:button
1389 parentController:nil
1391 profile:profile()]);
1392 BookmarkButton* targetButton =
1393 [folderController buttonWithTitleEqualTo:@"2f1b"];
1394 ASSERT_TRUE(targetButton);
1396 // Gen up some dragging data.
1397 const BookmarkNode* newNode = other->GetChild(2);
1398 [folderController setDragDataNode:newNode];
1399 base::scoped_nsobject<FakedDragInfo> dragInfo([[FakedDragInfo alloc] init]);
1400 [dragInfo setDropLocation:[targetButton top]];
1401 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
1403 // Verify the model.
1404 const std::string expected("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ 2f2f1b "
1405 "2f2f2b 2f2f3b ] 2f3b ] 3b 4b ");
1406 actual = test::ModelStringFromNode(root);
1407 EXPECT_EQ(expected, actual);
1409 // Now drag over a folder button.
1410 targetButton = [folderController buttonWithTitleEqualTo:@"2f2f"];
1411 ASSERT_TRUE(targetButton);
1412 newNode = other->GetChild(2); // Should be O4f.
1413 EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f"));
1414 [folderController setDragDataNode:newNode];
1415 [dragInfo setDropLocation:[targetButton center]];
1416 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
1418 // Verify the model.
1419 const std::string expectedA("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ "
1420 "2f2f1b 2f2f2b 2f2f3b O4f:[ O4f1b O4f2f ] ] "
1422 actual = test::ModelStringFromNode(root);
1423 EXPECT_EQ(expectedA, actual);
1425 // Check button spacing.
1426 [folderController validateMenuSpacing];
1429 TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkDataToTrash) {
1430 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1431 const BookmarkNode* root = model->bookmark_bar_node();
1432 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1434 test::AddNodesFromModelString(model, root, model_string);
1436 // Validate initial model.
1437 std::string actual = test::ModelStringFromNode(root);
1438 EXPECT_EQ(model_string, actual);
1440 const BookmarkNode* folderNode = root->GetChild(1);
1441 int oldFolderChildCount = folderNode->child_count();
1443 // Pop open a folder.
1444 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1445 base::scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
1446 folderController.reset([[BookmarkBarFolderControllerDragData alloc]
1447 initWithParentButton:button
1448 parentController:nil
1450 profile:profile()]);
1452 // Drag a button to the trash.
1453 BookmarkButton* buttonToDelete =
1454 [folderController buttonWithTitleEqualTo:@"2f1b"];
1455 ASSERT_TRUE(buttonToDelete);
1456 EXPECT_TRUE([folderController canDragBookmarkButtonToTrash:buttonToDelete]);
1457 [folderController didDragBookmarkToTrash:buttonToDelete];
1459 // There should be one less button in the folder.
1460 int newFolderChildCount = folderNode->child_count();
1461 EXPECT_EQ(oldFolderChildCount - 1, newFolderChildCount);
1462 // Verify the model.
1463 const std::string expected("1b 2f:[ 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1465 actual = test::ModelStringFromNode(root);
1466 EXPECT_EQ(expected, actual);
1468 // Check button spacing.
1469 [folderController validateMenuSpacing];
1472 TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) {
1473 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1474 const BookmarkNode* root = model->bookmark_bar_node();
1475 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1477 test::AddNodesFromModelString(model, root, model_string);
1479 // Validate initial model.
1480 std::string actual = test::ModelStringFromNode(root);
1481 EXPECT_EQ(model_string, actual);
1483 // Pop open a folder.
1484 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1485 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1487 BookmarkBarFolderController* folderController = [bar_ folderController];
1488 EXPECT_TRUE(folderController);
1489 NSArray* buttons = [folderController buttons];
1490 EXPECT_TRUE(buttons);
1492 // Remember how many buttons are showing.
1493 int oldDisplayedButtons = [buttons count];
1495 BookmarkButton* targetButton =
1496 [folderController buttonWithTitleEqualTo:@"2f1b"];
1497 ASSERT_TRUE(targetButton);
1499 NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/",
1500 @"http://www.b.com/", nil];
1501 NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil];
1502 [folderController addURLs:urls withTitles:titles at:[targetButton top]];
1504 // There should two more buttons in the folder.
1505 int newDisplayedButtons = [buttons count];
1506 EXPECT_EQ(oldDisplayedButtons + 2, newDisplayedButtons);
1507 // Verify the model.
1508 const std::string expected("1b 2f:[ SiteA SiteB 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1509 "2f2f3b ] 2f3b ] 3b 4b ");
1510 actual = test::ModelStringFromNode(root);
1511 EXPECT_EQ(expected, actual);
1513 // Check button spacing.
1514 [folderController validateMenuSpacing];
1517 TEST_F(BookmarkBarFolderControllerMenuTest, DropPositionIndicator) {
1518 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1519 const BookmarkNode* root = model->bookmark_bar_node();
1520 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1522 test::AddNodesFromModelString(model, root, model_string);
1524 // Validate initial model.
1525 std::string actual = test::ModelStringFromNode(root);
1526 EXPECT_EQ(model_string, actual);
1528 // Pop open the folder.
1529 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1530 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1532 BookmarkBarFolderController* folder = [bar_ folderController];
1533 EXPECT_TRUE(folder);
1535 // Test a series of points starting at the top of the folder.
1536 const CGFloat yOffset = 0.5 * bookmarks::kBookmarkVerticalPadding;
1537 BookmarkButton* targetButton = [folder buttonWithTitleEqualTo:@"2f1b"];
1538 ASSERT_TRUE(targetButton);
1539 NSPoint targetPoint = [targetButton top];
1540 CGFloat pos = [folder indicatorPosForDragToPoint:targetPoint];
1541 EXPECT_CGFLOAT_EQ(targetPoint.y + yOffset, pos);
1542 pos = [folder indicatorPosForDragToPoint:[targetButton bottom]];
1543 targetButton = [folder buttonWithTitleEqualTo:@"2f2f"];
1544 EXPECT_CGFLOAT_EQ([targetButton top].y + yOffset, pos);
1545 pos = [folder indicatorPosForDragToPoint:NSMakePoint(10,0)];
1546 targetButton = [folder buttonWithTitleEqualTo:@"2f3b"];
1547 EXPECT_CGFLOAT_EQ([targetButton bottom].y - yOffset, pos);
1550 @interface BookmarkBarControllerNoDelete : BookmarkBarController
1551 - (IBAction)deleteBookmark:(id)sender;
1554 @implementation BookmarkBarControllerNoDelete
1555 - (IBAction)deleteBookmark:(id)sender {
1560 class BookmarkBarFolderControllerClosingTest : public
1561 BookmarkBarFolderControllerMenuTest {
1563 virtual void SetUp() {
1564 BookmarkBarFolderControllerMenuTest::SetUp();
1565 ASSERT_TRUE(browser());
1567 bar_.reset([[BookmarkBarControllerNoDelete alloc]
1568 initWithBrowser:browser()
1569 initialWidth:NSWidth([parent_view_ frame])
1571 resizeDelegate:resizeDelegate_.get()]);
1572 InstallAndToggleBar(bar_.get());
1576 TEST_F(BookmarkBarFolderControllerClosingTest, DeleteClosesFolder) {
1577 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
1578 const BookmarkNode* root = model->bookmark_bar_node();
1579 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b ] "
1581 test::AddNodesFromModelString(model, root, model_string);
1583 // Validate initial model.
1584 std::string actualModelString = test::ModelStringFromNode(root);
1585 EXPECT_EQ(model_string, actualModelString);
1587 // Open the folder menu and submenu.
1588 BookmarkButton* target = [bar_ buttonWithTitleEqualTo:@"2f"];
1589 ASSERT_TRUE(target);
1590 [[target target] performSelector:@selector(openBookmarkFolderFromButton:)
1592 BookmarkBarFolderController* folder = [bar_ folderController];
1593 EXPECT_TRUE(folder);
1594 BookmarkButton* subTarget = [folder buttonWithTitleEqualTo:@"2f2f"];
1595 ASSERT_TRUE(subTarget);
1596 [[subTarget target] performSelector:@selector(openBookmarkFolderFromButton:)
1597 withObject:subTarget];
1598 BookmarkBarFolderController* subFolder = [folder folderController];
1599 EXPECT_TRUE(subFolder);
1601 // Delete the folder node and verify the window closed down by looking
1602 // for its controller again.
1603 DeleteBookmark([folder parentButton], profile());
1604 EXPECT_FALSE([folder folderController]);
1607 // TODO(jrg): draggingEntered: and draggingExited: trigger timers so
1608 // they are hard to test. Factor out "fire timers" into routines
1609 // which can be overridden to fire immediately to make behavior
1611 // There is a similar problem with mouseEnteredButton: and
1612 // mouseExitedButton:.