Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1347)

Side by Side Diff: chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm

Issue 8141003: [Mac] Restore the old bookmark menus now that the experiment is over. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import <Cocoa/Cocoa.h> 5 #import <Cocoa/Cocoa.h>
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/memory/scoped_nsobject.h" 8 #include "base/memory/scoped_nsobject.h"
9 #include "base/utf_string_conversions.h" 9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/bookmarks/bookmark_model.h" 10 #include "chrome/browser/bookmarks/bookmark_model.h"
11 #import "chrome/browser/ui/cocoa/animation_utils.h"
11 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h" 12 #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_controller.h"
14 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
13 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" 15 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
14 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
15 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
16 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h" 16 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h"
17 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h" 17 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
18 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 18 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
19 #import "chrome/browser/ui/cocoa/view_resizer_pong.h" 19 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
20 #include "chrome/test/base/model_test_utils.h" 20 #include "chrome/test/base/model_test_utils.h"
21 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
22 #import "testing/gtest_mac.h" 22 #import "testing/gtest_mac.h"
23 #include "testing/platform_test.h" 23 #include "testing/platform_test.h"
24 24
25 // Add a redirect to make testing easier.
26 @interface BookmarkBarFolderController(MakeTestingEasier)
27 - (IBAction)openBookmarkFolderFromButton:(id)sender;
28 - (void)validateMenuSpacing;
29 @end
30
31 @implementation BookmarkBarFolderController(MakeTestingEasier)
32 - (IBAction)openBookmarkFolderFromButton:(id)sender {
33 [[self folderTarget] openBookmarkFolderFromButton:sender];
34 }
35
36 // Utility function to verify that the buttons in this folder are all
37 // evenly spaced in a progressive manner.
38 - (void)validateMenuSpacing {
39 BOOL firstButton = YES;
40 CGFloat lastVerticalOffset = 0.0;
41 for (BookmarkButton* button in [self buttons]) {
42 if (firstButton) {
43 firstButton = NO;
44 lastVerticalOffset = [button frame].origin.y;
45 } else {
46 CGFloat nextVerticalOffset = [button frame].origin.y;
47 EXPECT_CGFLOAT_EQ(lastVerticalOffset -
48 bookmarks::kBookmarkFolderButtonHeight,
49 nextVerticalOffset);
50 lastVerticalOffset = nextVerticalOffset;
51 }
52 }
53 }
54 @end
55
56 // Don't use a high window level when running unit tests -- it'll
57 // interfere with anything else you are working on.
58 // For testing.
59 @interface BookmarkBarFolderControllerNoLevel : BookmarkBarFolderController
60 @end
61
62 @implementation BookmarkBarFolderControllerNoLevel
63 - (void)configureWindowLevel {
64 // Intentionally empty.
65 }
66 @end
67
68 @interface BookmarkBarFolderControllerPong : BookmarkBarFolderController {
69 BOOL childFolderWillShow_;
70 BOOL childFolderWillClose_;
71 }
72 @property (nonatomic, readonly) BOOL childFolderWillShow;
73 @property (nonatomic, readonly) BOOL childFolderWillClose;
74 @end
75
76 @implementation BookmarkBarFolderControllerPong
77 @synthesize childFolderWillShow = childFolderWillShow_;
78 @synthesize childFolderWillClose = childFolderWillClose_;
79
80 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
81 childFolderWillShow_ = YES;
82 }
83
84 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
85 childFolderWillClose_ = YES;
86 }
87
88 // We don't have a real BookmarkBarController as our parent root so
89 // we fake this one out.
90 - (void)closeAllBookmarkFolders {
91 [self closeBookmarkFolder:self];
92 }
93
94 @end
95
25 namespace { 96 namespace {
26 const int kLotsOfNodesCount = 150; 97 const int kLotsOfNodesCount = 150;
27 }; 98 };
28 99
100 // Redirect certain calls so they can be seen by tests.
101
102 @interface BookmarkBarControllerChildFolderRedirect : BookmarkBarController {
103 BookmarkBarFolderController* childFolderDelegate_;
104 }
105 @property (nonatomic, assign) BookmarkBarFolderController* childFolderDelegate;
106 @end
107
108 @implementation BookmarkBarControllerChildFolderRedirect
109
110 @synthesize childFolderDelegate = childFolderDelegate_;
111
112 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
113 [childFolderDelegate_ childFolderWillShow:child];
114 }
115
116 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
117 [childFolderDelegate_ childFolderWillClose:child];
118 }
119
120 @end
121
122
29 class BookmarkBarFolderControllerTest : public CocoaProfileTest { 123 class BookmarkBarFolderControllerTest : public CocoaProfileTest {
30 public: 124 public:
31 BookmarkModel* GetModel() { 125 scoped_nsobject<BookmarkBarControllerChildFolderRedirect> bar_;
32 return profile()->GetBookmarkModel(); 126 const BookmarkNode* folderA_; // Owned by model.
33 } 127 const BookmarkNode* longTitleNode_; // Owned by model.
34 128
35 BookmarkBarFolderController* CreateController(const BookmarkNode* node) { 129 virtual void SetUp() {
36 // The button will be owned by the controller. 130 CocoaProfileTest::SetUp();
37 scoped_nsobject<BookmarkButton> button( 131 ASSERT_TRUE(profile());
38 [[BookmarkButton alloc] initWithFrame:NSMakeRect(0, 0, 500, 500)]); 132
39 scoped_nsobject<BookmarkButtonCell> cell( 133 CreateModel();
40 [[BookmarkButtonCell alloc] initTextCell:@"foo"]); 134 }
41 [button setCell:cell]; 135
42 [cell setBookmarkNode:node]; 136 void CreateModel() {
43 137 BookmarkModel* model = profile()->GetBookmarkModel();
44 BookmarkModel* model = GetModel(); 138 const BookmarkNode* parent = model->bookmark_bar_node();
45 return [[BookmarkBarFolderController alloc] initWithParentButton:button 139 const BookmarkNode* folderA = model->AddFolder(parent,
46 bookmarkModel:model 140 parent->child_count(),
47 barController:nil]; 141 ASCIIToUTF16("folder"));
48 } 142 folderA_ = folderA;
49 143 model->AddFolder(parent, parent->child_count(),
50 NSMenu* GetMenu(BookmarkBarFolderController* controller) { 144 ASCIIToUTF16("sibbling folder"));
51 return [[controller menuBridge]->controller() menu]; 145 const BookmarkNode* folderB = model->AddFolder(folderA,
146 folderA->child_count(),
147 ASCIIToUTF16("subfolder 1"));
148 model->AddFolder(folderA,
149 folderA->child_count(),
150 ASCIIToUTF16("subfolder 2"));
151 model->AddURL(folderA, folderA->child_count(), ASCIIToUTF16("title a"),
152 GURL("http://www.google.com/a"));
153 longTitleNode_ = model->AddURL(
154 folderA, folderA->child_count(),
155 ASCIIToUTF16("title super duper long long whoa momma title you betcha"),
156 GURL("http://www.google.com/b"));
157 model->AddURL(folderB, folderB->child_count(), ASCIIToUTF16("t"),
158 GURL("http://www.google.com/c"));
159
160 bar_.reset(
161 [[BookmarkBarControllerChildFolderRedirect alloc]
162 initWithBrowser:browser()
163 initialWidth:300
164 delegate:nil
165 resizeDelegate:nil]);
166 [bar_ loaded:model];
167 // Make parent frame for bookmark bar then open it.
168 NSRect frame = [[test_window() contentView] frame];
169 frame = NSMakeRect(frame.origin.x,
170 frame.size.height - bookmarks::kNTPBookmarkBarHeight,
171 frame.size.width, bookmarks::kNTPBookmarkBarHeight);
172 NSView* fakeToolbarView = [[[NSView alloc] initWithFrame:frame]
173 autorelease];
174 [[test_window() contentView] addSubview:fakeToolbarView];
175 [fakeToolbarView addSubview:[bar_ view]];
176 [bar_ setBookmarkBarEnabled:YES];
177 }
178
179 // Remove the bookmark with the long title.
180 void RemoveLongTitleNode() {
181 BookmarkModel* model = profile()->GetBookmarkModel();
182 model->Remove(longTitleNode_->parent(),
183 longTitleNode_->parent()->GetIndexOf(longTitleNode_));
184 }
185
186 // Add LOTS of nodes to our model if needed (e.g. scrolling).
187 // Returns the number of nodes added.
188 int AddLotsOfNodes() {
189 BookmarkModel* model = profile()->GetBookmarkModel();
190 for (int i = 0; i < kLotsOfNodesCount; i++) {
191 model->AddURL(folderA_, folderA_->child_count(),
192 ASCIIToUTF16("repeated title"),
193 GURL("http://www.google.com/repeated/url"));
194 }
195 return kLotsOfNodesCount;
196 }
197
198 // Return a simple BookmarkBarFolderController.
199 BookmarkBarFolderControllerPong* SimpleBookmarkBarFolderController() {
200 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
201 BookmarkBarFolderControllerPong* c =
202 [[BookmarkBarFolderControllerPong alloc]
203 initWithParentButton:parentButton
204 parentController:nil
205 barController:bar_];
206 [c window]; // Force nib load.
207 return c;
52 } 208 }
53 }; 209 };
54 210
55 TEST_F(BookmarkBarFolderControllerTest, SimpleFolder) { 211 TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) {
56 // Create the model. 212 scoped_nsobject<BookmarkBarFolderController> bbfc;
57 BookmarkModel* model = GetModel(); 213 bbfc.reset(SimpleBookmarkBarFolderController());
58 const BookmarkNode* root = model->bookmark_bar_node(); 214
59 215 // Make sure none of the buttons overlap, that all are inside
60 model->AddURL(root, root->child_count(), ASCIIToUTF16("ignored"), 216 // the content frame, and their cells are of the proper class.
61 GURL("http://example.com")); 217 NSArray* buttons = [bbfc buttons];
62 218 EXPECT_TRUE([buttons count]);
63 const BookmarkNode* folder = model->AddFolder(root, root->child_count(), 219 for (unsigned int i = 0; i < ([buttons count]-1); i++) {
64 ASCIIToUTF16("folder")); 220 EXPECT_FALSE(NSContainsRect([[buttons objectAtIndex:i] frame],
65 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("item 1"), 221 [[buttons objectAtIndex:i+1] frame]));
66 GURL("http://www.google.com/")); 222 }
67 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("item 2"), 223 Class cellClass = [BookmarkBarFolderButtonCell class];
68 GURL("http://www.chromium.org/")); 224 for (BookmarkButton* button in buttons) {
69 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("item 3"), 225 NSRect r = [[bbfc folderView] convertRect:[button frame] fromView:button];
70 GURL("http://build.chromium.org/")); 226 // TODO(jrg): remove this adjustment.
71 227 NSRect bigger = NSInsetRect([[bbfc folderView] frame], -2, 0);
72 model->AddURL(root, root->child_count(), ASCIIToUTF16("ignored 2"), 228 EXPECT_TRUE(NSContainsRect(bigger, r));
73 GURL("http://example2.com")); 229 EXPECT_TRUE([[button cell] isKindOfClass:cellClass]);
74 230 }
75 // Create the controller and menu. 231
76 scoped_nsobject<BookmarkBarFolderController> bbfc(CreateController(folder)); 232 // Confirm folder buttons have no tooltip. The important thing
77 CloseFolderAfterDelay(bbfc, 0.1); 233 // really is that we insure folders and non-folders are treated
78 [bbfc openMenu]; 234 // differently; not sure of any other generic way to do this.
79 235 for (BookmarkButton* button in buttons) {
80 NSArray* items = [GetMenu(bbfc) itemArray]; 236 if ([button isFolder])
81 ASSERT_EQ(3u, [items count]); 237 EXPECT_FALSE([button toolTip]);
82 238 else
83 EXPECT_NSEQ(@"item 1", [[items objectAtIndex:0] title]); 239 EXPECT_TRUE([button toolTip]);
84 EXPECT_NSEQ(@"item 2", [[items objectAtIndex:1] title]); 240 }
85 EXPECT_NSEQ(@"item 3", [[items objectAtIndex:2] title]); 241 }
86 } 242
87 243 // Make sure closing of the window releases the controller.
88 TEST_F(BookmarkBarFolderControllerTest, NestedFolder) { 244 // (e.g. valgrind shouldn't complain if we do this).
89 // Create the model. 245 TEST_F(BookmarkBarFolderControllerTest, ReleaseOnClose) {
90 BookmarkModel* model = GetModel(); 246 scoped_nsobject<BookmarkBarFolderController> bbfc;
91 const BookmarkNode* root = model->bookmark_bar_node(); 247 bbfc.reset(SimpleBookmarkBarFolderController());
92 248 EXPECT_TRUE(bbfc.get());
93 model->AddURL(root, root->child_count(), ASCIIToUTF16("ignored"), 249
94 GURL("http://example.com")); 250 [bbfc retain]; // stop the scoped_nsobject from doing anything
95 model->AddURL(root, root->child_count(), ASCIIToUTF16("ignored 2"), 251 [[bbfc window] close]; // trigger an autorelease of bbfc.get()
96 GURL("http://example2.com")); 252 }
97 253
98 const BookmarkNode* folder = model->AddFolder(root, root->child_count(), 254 TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
99 ASCIIToUTF16("folder")); 255 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
100 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("item 1"), 256 EXPECT_TRUE(parentButton);
101 GURL("http://www.google.com/")); 257
102 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("item 2"), 258 // If parent is a BookmarkBarController, grow down.
103 GURL("http://www.chromium.org/")); 259 scoped_nsobject<BookmarkBarFolderController> bbfc;
104 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("item 3"), 260 bbfc.reset([[BookmarkBarFolderController alloc]
105 GURL("http://build.chromium.org/")); 261 initWithParentButton:parentButton
106 const BookmarkNode* subfolder = model->AddFolder(folder, 262 parentController:nil
107 folder->child_count(), ASCIIToUTF16("subfolder")); 263 barController:bar_]);
108 model->AddURL(folder, folder->child_count(), ASCIIToUTF16("item 4"), 264 [bbfc window];
109 GURL("http://dev.chromium.org/")); 265 NSPoint pt = [bbfc windowTopLeftForWidth:0 height:100]; // screen coords
110 266 NSPoint buttonOriginInScreen =
111 model->AddURL(subfolder, subfolder->child_count(), ASCIIToUTF16("subitem 1"), 267 [[parentButton window]
112 GURL("http://gmail.com")); 268 convertBaseToScreen:[parentButton
113 model->AddURL(subfolder, subfolder->child_count(), ASCIIToUTF16("subitem 2"), 269 convertRectToBase:[parentButton frame]].origin];
114 GURL("http://google.com/+")); 270 // Within margin
115 271 EXPECT_LE(abs(pt.x - buttonOriginInScreen.x),
116 // Create the controller and menu. 272 bookmarks::kBookmarkMenuOverlap+1);
117 scoped_nsobject<BookmarkBarFolderController> bbfc(CreateController(folder)); 273 EXPECT_LE(abs(pt.y - buttonOriginInScreen.y),
118 CloseFolderAfterDelay(bbfc, 0.1); 274 bookmarks::kBookmarkMenuOverlap+1);
119 [bbfc openMenu]; 275
120 276 // Make sure we see the window shift left if it spills off the screen
121 NSArray* items = [GetMenu(bbfc) itemArray]; 277 pt = [bbfc windowTopLeftForWidth:0 height:100];
122 ASSERT_EQ(5u, [items count]); 278 NSPoint shifted = [bbfc windowTopLeftForWidth:9999999 height:100];
123 279 EXPECT_LT(shifted.x, pt.x);
124 EXPECT_NSEQ(@"item 1", [[items objectAtIndex:0] title]); 280
125 EXPECT_NSEQ(@"item 2", [[items objectAtIndex:1] title]); 281 // If parent is a BookmarkBarFolderController, grow right.
126 EXPECT_NSEQ(@"item 3", [[items objectAtIndex:2] title]); 282 scoped_nsobject<BookmarkBarFolderController> bbfc2;
127 EXPECT_NSEQ(@"subfolder", [[items objectAtIndex:3] title]); 283 bbfc2.reset([[BookmarkBarFolderController alloc]
128 EXPECT_NSEQ(@"item 4", [[items objectAtIndex:4] title]); 284 initWithParentButton:[[bbfc buttons] objectAtIndex:0]
129 285 parentController:bbfc.get()
130 NSArray* subitems = [[[items objectAtIndex:3] submenu] itemArray]; 286 barController:bar_]);
131 ASSERT_EQ(2u, [subitems count]); 287 [bbfc2 window];
132 EXPECT_NSEQ(@"subitem 1", [[subitems objectAtIndex:0] title]); 288 pt = [bbfc2 windowTopLeftForWidth:0 height:100];
133 EXPECT_NSEQ(@"subitem 2", [[subitems objectAtIndex:1] title]); 289 // We're now overlapping the window a bit.
134 } 290 EXPECT_EQ(pt.x, NSMaxX([[bbfc.get() window] frame]) -
135 291 bookmarks::kBookmarkMenuOverlap);
136 TEST_F(BookmarkBarFolderControllerTest, OffTheSide) { 292 }
137 // Create the model. 293
138 BookmarkModel* model = GetModel(); 294 // Confirm we grow right until end of screen, then start growing left
139 const BookmarkNode* root = model->bookmark_bar_node(); 295 // until end of screen again, then right.
140 296 TEST_F(BookmarkBarFolderControllerTest, PositionRightLeftRight) {
141 model->AddURL(root, root->child_count(), ASCIIToUTF16("item 1"), 297 BookmarkModel* model = profile()->GetBookmarkModel();
142 GURL("http://example.com")); 298 const BookmarkNode* parent = model->bookmark_bar_node();
143 model->AddURL(root, root->child_count(), ASCIIToUTF16("item 2"), 299 const BookmarkNode* folder = parent;
144 GURL("http://www.google.com/")); 300
145 model->AddURL(root, root->child_count(), ASCIIToUTF16("item 3"), 301 const int count = 100;
146 GURL("http://www.chromium.org/")); 302 int i;
147 model->AddURL(root, root->child_count(), ASCIIToUTF16("item 4"), 303 // Make some super duper deeply nested folders.
148 GURL("http://build.chromium.org/")); 304 for (i = 0; i < count; i++) {
149 model->AddURL(root, root->child_count(), ASCIIToUTF16("item 5"), 305 folder = model->AddFolder(folder, 0, ASCIIToUTF16("nested folder"));
150 GURL("http://example2.com")); 306 }
151 307
152 // Create the controller and menu. 308 // Setup initial state for opening all folders.
153 scoped_nsobject<BookmarkBarFolderController> bbfc(CreateController(root)); 309 folder = parent;
154 CloseFolderAfterDelay(bbfc, 0.1); 310 BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
155 [bbfc openMenu]; 311 BookmarkBarFolderController* parentController = nil;
156 312 EXPECT_TRUE(parentButton);
157 NSArray* items = [GetMenu(bbfc) itemArray]; 313
158 ASSERT_EQ(5u, [items count]); 314 // Open them all.
159 315 scoped_nsobject<NSMutableArray> folder_controller_array;
160 EXPECT_NSEQ(@"item 1", [[items objectAtIndex:0] title]); 316 folder_controller_array.reset([[NSMutableArray array] retain]);
161 EXPECT_NSEQ(@"item 2", [[items objectAtIndex:1] title]); 317 for (i=0; i<count; i++) {
162 EXPECT_NSEQ(@"item 3", [[items objectAtIndex:2] title]); 318 BookmarkBarFolderControllerNoLevel* bbfcl =
163 EXPECT_NSEQ(@"item 4", [[items objectAtIndex:3] title]); 319 [[BookmarkBarFolderControllerNoLevel alloc]
164 EXPECT_NSEQ(@"item 5", [[items objectAtIndex:4] title]); 320 initWithParentButton:parentButton
165 321 parentController:parentController
166 [bbfc setOffTheSideNodeStartIndex:1]; 322 barController:bar_];
167 CloseFolderAfterDelay(bbfc, 0.1); 323 [folder_controller_array addObject:bbfcl];
168 [bbfc openMenu]; 324 [bbfcl autorelease];
169 items = [GetMenu(bbfc) itemArray]; 325 [bbfcl window];
170 ASSERT_EQ(4u, [items count]); 326 parentController = bbfcl;
171 EXPECT_NSEQ(@"item 2", [[items objectAtIndex:0] title]); 327 parentButton = [[bbfcl buttons] objectAtIndex:0];
172 328 }
173 [bbfc setOffTheSideNodeStartIndex:4]; 329
174 CloseFolderAfterDelay(bbfc, 0.1); 330 // Make vector of all x positions.
175 [bbfc openMenu]; 331 std::vector<CGFloat> leftPositions;
176 items = [GetMenu(bbfc) itemArray]; 332 for (i=0; i<count; i++) {
177 ASSERT_EQ(1u, [items count]); 333 CGFloat x = [[[folder_controller_array objectAtIndex:i] window]
178 EXPECT_NSEQ(@"item 5", [[items objectAtIndex:0] title]); 334 frame].origin.x;
179 335 leftPositions.push_back(x);
180 [bbfc setOffTheSideNodeStartIndex:0]; 336 }
181 CloseFolderAfterDelay(bbfc, 0.1); 337
182 [bbfc openMenu]; 338 // Make sure the first few grow right.
183 items = [GetMenu(bbfc) itemArray]; 339 for (i=0; i<3; i++)
184 EXPECT_EQ(5u, [items count]); 340 EXPECT_TRUE(leftPositions[i+1] > leftPositions[i]);
185 } 341
342 // Look for the first "grow left".
343 while (leftPositions[i] > leftPositions[i-1])
344 i++;
345 // Confirm the next few also grow left.
346 int j;
347 for (j=i; j<i+3; j++)
348 EXPECT_TRUE(leftPositions[j+1] < leftPositions[j]);
349 i = j;
350
351 // Finally, confirm we see a "grow right" once more.
352 while (leftPositions[i] < leftPositions[i-1])
353 i++;
354 // (No need to EXPECT a final "grow right"; if we didn't find one
355 // we'd get a C++ array bounds exception).
356 }
357
358 TEST_F(BookmarkBarFolderControllerTest, DropDestination) {
359 scoped_nsobject<BookmarkBarFolderController> bbfc;
360 bbfc.reset(SimpleBookmarkBarFolderController());
361 EXPECT_TRUE(bbfc.get());
362
363 // Confirm "off the top" and "off the bottom" match no buttons.
364 NSPoint p = NSMakePoint(NSMidX([[bbfc folderView] frame]), 10000);
365 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
366 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
367 p = NSMakePoint(NSMidX([[bbfc folderView] frame]), -1);
368 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
369 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
370
371 // Confirm "right in the center" (give or take a pixel) is a match,
372 // and confirm "just barely in the button" is not. Anything more
373 // specific seems likely to be tweaked. We don't loop over all
374 // buttons because the scroll view makes them not visible.
375 for (BookmarkButton* button in [bbfc buttons]) {
376 CGFloat x = NSMidX([button frame]);
377 CGFloat y = NSMidY([button frame]);
378 // Somewhere near the center: a match (but only if a folder!)
379 if ([button isFolder]) {
380 EXPECT_EQ(button,
381 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
382 EXPECT_EQ(button,
383 [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
384 EXPECT_FALSE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
385 } else {
386 // If not a folder we don't drop into it.
387 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
388 EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
389 EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
390 }
391 }
392 }
393
394 TEST_F(BookmarkBarFolderControllerTest, OpenFolder) {
395 scoped_nsobject<BookmarkBarFolderController> bbfc;
396 bbfc.reset(SimpleBookmarkBarFolderController());
397 EXPECT_TRUE(bbfc.get());
398
399 EXPECT_FALSE([bbfc folderController]);
400 BookmarkButton* button = [[bbfc buttons] objectAtIndex:0];
401 [bbfc openBookmarkFolderFromButton:button];
402 id controller = [bbfc folderController];
403 EXPECT_TRUE(controller);
404 EXPECT_EQ([controller parentButton], button);
405
406 // Click the same one --> it gets closed.
407 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
408 EXPECT_FALSE([bbfc folderController]);
409
410 // Open a new one --> change.
411 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:1]];
412 EXPECT_NE(controller, [bbfc folderController]);
413 EXPECT_NE([[bbfc folderController] parentButton], button);
414
415 // Close it --> all gone!
416 [bbfc closeBookmarkFolder:nil];
417 EXPECT_FALSE([bbfc folderController]);
418 }
419
420 TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) {
421 scoped_nsobject<BookmarkBarFolderControllerPong> bbfc;
422 bbfc.reset(SimpleBookmarkBarFolderController());
423 EXPECT_TRUE(bbfc.get());
424 [bar_ setChildFolderDelegate:bbfc.get()];
425
426 EXPECT_FALSE([bbfc childFolderWillShow]);
427 [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
428 EXPECT_TRUE([bbfc childFolderWillShow]);
429
430 EXPECT_FALSE([bbfc childFolderWillClose]);
431 [bbfc closeBookmarkFolder:nil];
432 EXPECT_TRUE([bbfc childFolderWillClose]);
433
434 [bar_ setChildFolderDelegate:nil];
435 }
436
437 // Make sure bookmark folders have variable widths.
438 TEST_F(BookmarkBarFolderControllerTest, ChildFolderWidth) {
439 scoped_nsobject<BookmarkBarFolderController> bbfc;
440
441 bbfc.reset(SimpleBookmarkBarFolderController());
442 EXPECT_TRUE(bbfc.get());
443 [bbfc showWindow:bbfc.get()];
444 CGFloat wideWidth = NSWidth([[bbfc window] frame]);
445
446 RemoveLongTitleNode();
447 bbfc.reset(SimpleBookmarkBarFolderController());
448 EXPECT_TRUE(bbfc.get());
449 CGFloat thinWidth = NSWidth([[bbfc window] frame]);
450
451 // Make sure window size changed as expected.
452 EXPECT_GT(wideWidth, thinWidth);
453 }
454
455 // Simple scrolling tests.
456 // Currently flaky due to a changed definition of the correct menu boundaries.
457 TEST_F(BookmarkBarFolderControllerTest, DISABLED_SimpleScroll) {
458 scoped_nsobject<BookmarkBarFolderController> bbfc;
459 NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
460 CGFloat screenHeight = NSHeight(screenFrame);
461 int nodecount = AddLotsOfNodes();
462 bbfc.reset(SimpleBookmarkBarFolderController());
463 EXPECT_TRUE(bbfc.get());
464 [bbfc showWindow:bbfc.get()];
465 NSWindow* window = [bbfc window];
466
467 // The window should be shorter than the screen but reach exactly to the
468 // bottom of the screen since it's scrollable.
469 EXPECT_LT(NSHeight([window frame]), screenHeight);
470 EXPECT_CGFLOAT_EQ(0.0, [window frame].origin.y);
471
472 // Initially, should show scroll-up but not scroll-down.
473 EXPECT_TRUE([bbfc canScrollUp]);
474 EXPECT_FALSE([bbfc canScrollDown]);
475
476 // Scroll up a bit. Make sure the window has gotten bigger each time.
477 // Also, for each scroll, make sure our hit test finds a new button
478 // (to confirm the content area changed).
479 NSView* savedHit = nil;
480 NSScrollView* scrollView = [bbfc scrollView];
481
482 // Find the next-to-last button showing at the bottom of the window and
483 // use its center for hit testing.
484 BookmarkButton* targetButton = nil;
485 NSPoint scrollPoint = [scrollView documentVisibleRect].origin;
486 for (BookmarkButton* button in [bbfc buttons]) {
487 NSRect buttonFrame = [button frame];
488 buttonFrame.origin.y -= scrollPoint.y;
489 if (buttonFrame.origin.y < 0.0)
490 break;
491 targetButton = button;
492 }
493 EXPECT_TRUE(targetButton != nil);
494 NSPoint hitPoint = [targetButton frame].origin;
495 hitPoint.x += 50.0;
496 hitPoint.y += (bookmarks::kBookmarkFolderButtonHeight / 2.0) - scrollPoint.y;
497 hitPoint = [targetButton convertPoint:hitPoint toView:scrollView];
498
499 for (int i = 0; i < 3; i++) {
500 CGFloat height = NSHeight([window frame]);
501 [bbfc performOneScroll:60];
502 EXPECT_GT(NSHeight([window frame]), height);
503 NSView* hit = [scrollView hitTest:hitPoint];
504 // We should hit a bookmark button.
505 EXPECT_TRUE([[hit className] isEqualToString:@"BookmarkButton"]);
506 EXPECT_NE(hit, savedHit);
507 savedHit = hit;
508 }
509
510 // Keep scrolling up; make sure we never get bigger than the screen.
511 // Also confirm we never scroll the window off the screen.
512 bool bothAtOnce = false;
513 while ([bbfc canScrollUp]) {
514 [bbfc performOneScroll:60];
515 EXPECT_TRUE(NSContainsRect([[NSScreen mainScreen] frame], [window frame]));
516 // Make sure, sometime during our scroll, we have the ability to
517 // scroll in either direction.
518 if ([bbfc canScrollUp] &&
519 [bbfc canScrollDown])
520 bothAtOnce = true;
521 }
522 EXPECT_TRUE(bothAtOnce);
523
524 // Once we've scrolled to the end, our only option should be to scroll back.
525 EXPECT_FALSE([bbfc canScrollUp]);
526 EXPECT_TRUE([bbfc canScrollDown]);
527
528 NSRect wholeScreenRect = [[NSScreen mainScreen] frame];
529
530 // Now scroll down and make sure the window size does not change.
531 // Also confirm we never scroll the window off the screen the other
532 // way.
533 for (int i = 0; i < nodecount+50; ++i) {
534 [bbfc performOneScroll:-60];
535 // Once we can no longer scroll down the window height changes.
536 if (![bbfc canScrollDown])
537 break;
538 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame]));
539 }
540
541 EXPECT_GT(NSHeight(wholeScreenRect), NSHeight([window frame]));
542 EXPECT_TRUE(NSContainsRect(wholeScreenRect, [window frame]));
543 }
544
545 // Folder menu sizing and placement while deleting bookmarks
546 // and scrolling tests.
547 TEST_F(BookmarkBarFolderControllerTest, MenuPlacementWhileScrollingDeleting) {
548 scoped_nsobject<BookmarkBarFolderController> bbfc;
549 AddLotsOfNodes();
550 bbfc.reset(SimpleBookmarkBarFolderController());
551 [bbfc showWindow:bbfc.get()];
552 NSWindow* menuWindow = [bbfc window];
553 BookmarkBarFolderController* folder = [bar_ folderController];
554 NSArray* buttons = [folder buttons];
555
556 // Before scrolling any, delete a bookmark and make sure the window top has
557 // not moved. Pick a button which is near the top and visible.
558 CGFloat oldTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
559 BookmarkButton* button = [buttons objectAtIndex:3];
560 [folder deleteBookmark:button];
561 CGFloat newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
562 EXPECT_CGFLOAT_EQ(oldTop, newTop);
563
564 // Scroll so that both the top and bottom scroll arrows show, make sure
565 // the top of the window has moved up, then delete a visible button and
566 // make sure the top has not moved.
567 oldTop = newTop;
568 const CGFloat scrollOneBookmark = bookmarks::kBookmarkFolderButtonHeight +
569 bookmarks::kBookmarkVerticalPadding;
570 NSUInteger buttonCounter = 0;
571 NSUInteger extraButtonLimit = 3;
572 while (![bbfc canScrollDown] || extraButtonLimit > 0) {
573 [bbfc performOneScroll:scrollOneBookmark];
574 ++buttonCounter;
575 if ([bbfc canScrollDown])
576 --extraButtonLimit;
577 }
578 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
579 EXPECT_NE(oldTop, newTop);
580 oldTop = newTop;
581 button = [buttons objectAtIndex:buttonCounter + 3];
582 [folder deleteBookmark:button];
583 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
584 EXPECT_CGFLOAT_EQ(oldTop, newTop);
585
586 // Scroll so that the top scroll arrow is no longer showing, make sure
587 // the top of the window has not moved, then delete a visible button and
588 // make sure the top has not moved.
589 while ([bbfc canScrollDown]) {
590 [bbfc performOneScroll:-scrollOneBookmark];
591 --buttonCounter;
592 }
593 button = [buttons objectAtIndex:buttonCounter + 3];
594 [folder deleteBookmark:button];
595 newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
596 EXPECT_CGFLOAT_EQ(oldTop - bookmarks::kScrollWindowVerticalMargin, newTop);
597 }
598
599 @interface FakedDragInfo : NSObject {
600 @public
601 NSPoint dropLocation_;
602 NSDragOperation sourceMask_;
603 }
604 @property (nonatomic, assign) NSPoint dropLocation;
605 - (void)setDraggingSourceOperationMask:(NSDragOperation)mask;
606 @end
607
608 @implementation FakedDragInfo
609
610 @synthesize dropLocation = dropLocation_;
611
612 - (id)init {
613 if ((self = [super init])) {
614 dropLocation_ = NSZeroPoint;
615 sourceMask_ = NSDragOperationMove;
616 }
617 return self;
618 }
619
620 // NSDraggingInfo protocol functions.
621
622 - (id)draggingPasteboard {
623 return self;
624 }
625
626 - (id)draggingSource {
627 return self;
628 }
629
630 - (NSDragOperation)draggingSourceOperationMask {
631 return sourceMask_;
632 }
633
634 - (NSPoint)draggingLocation {
635 return dropLocation_;
636 }
637
638 // Other functions.
639
640 - (void)setDraggingSourceOperationMask:(NSDragOperation)mask {
641 sourceMask_ = mask;
642 }
643
644 @end
645
646
647 class BookmarkBarFolderControllerMenuTest : public CocoaProfileTest {
648 public:
649 scoped_nsobject<NSView> parent_view_;
650 scoped_nsobject<ViewResizerPong> resizeDelegate_;
651 scoped_nsobject<BookmarkBarController> bar_;
652
653 virtual void SetUp() {
654 CocoaProfileTest::SetUp();
655 ASSERT_TRUE(browser());
656
657 resizeDelegate_.reset([[ViewResizerPong alloc] init]);
658 NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
659 parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
660 [parent_view_ setHidden:YES];
661 bar_.reset([[BookmarkBarController alloc]
662 initWithBrowser:browser()
663 initialWidth:NSWidth(parent_frame)
664 delegate:nil
665 resizeDelegate:resizeDelegate_.get()]);
666 InstallAndToggleBar(bar_.get());
667 }
668
669 void InstallAndToggleBar(BookmarkBarController* bar) {
670 // Force loading of the nib.
671 [bar view];
672 // Awkwardness to look like we've been installed.
673 [parent_view_ addSubview:[bar view]];
674 NSRect frame = [[[bar view] superview] frame];
675 frame.origin.y = 400;
676 [[[bar view] superview] setFrame:frame];
677
678 // Make sure it's on in a window so viewDidMoveToWindow is called
679 [[test_window() contentView] addSubview:parent_view_];
680
681 // Make sure it's open so certain things aren't no-ops.
682 [bar updateAndShowNormalBar:YES
683 showDetachedBar:NO
684 withAnimation:NO];
685 }
686 };
687
688 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
689 WithNoAnimation at_all;
690 BookmarkModel& model(*profile()->GetBookmarkModel());
691 const BookmarkNode* root = model.bookmark_bar_node();
692 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
693 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
694 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
695 model_test_utils::AddNodesFromModelString(model, root, model_string);
696
697 // Validate initial model.
698 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
699 EXPECT_EQ(model_string, actualModelString);
700
701 // Pop up a folder menu and drag in a button from the bar.
702 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
703 NSRect oldToFolderFrame = [toFolder frame];
704 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
705 withObject:toFolder];
706 BookmarkBarFolderController* folderController = [bar_ folderController];
707 EXPECT_TRUE(folderController);
708 NSWindow* toWindow = [folderController window];
709 EXPECT_TRUE(toWindow);
710 NSRect oldToWindowFrame = [toWindow frame];
711 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
712 // so it should end up below the target bookmark.
713 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
714 ASSERT_TRUE(draggedButton);
715 CGFloat horizontalShift =
716 NSWidth([draggedButton frame]) + bookmarks::kBookmarkHorizontalPadding;
717 BookmarkButton* targetButton =
718 [folderController buttonWithTitleEqualTo:@"2f1b"];
719 ASSERT_TRUE(targetButton);
720 [folderController dragButton:draggedButton
721 to:[targetButton center]
722 copy:NO];
723 // The button should have landed just after "2f1b".
724 const std::string expected_string("2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
725 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
726 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
727 EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
728
729 // Verify the window still appears by looking for its controller.
730 EXPECT_TRUE([bar_ folderController]);
731
732 // Gather the new frames.
733 NSRect newToFolderFrame = [toFolder frame];
734 NSRect newToWindowFrame = [toWindow frame];
735 // The toFolder should have shifted left horizontally but not vertically.
736 NSRect expectedToFolderFrame =
737 NSOffsetRect(oldToFolderFrame, -horizontalShift, 0);
738 EXPECT_NSRECT_EQ(expectedToFolderFrame, newToFolderFrame);
739 // The toWindow should have shifted left horizontally, down vertically,
740 // and grown vertically.
741 NSRect expectedToWindowFrame = oldToWindowFrame;
742 expectedToWindowFrame.origin.x -= horizontalShift;
743 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
744 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight;
745 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
746
747 // Check button spacing.
748 [folderController validateMenuSpacing];
749
750 // Move the button back to the bar at the beginning.
751 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
752 ASSERT_TRUE(draggedButton);
753 targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
754 ASSERT_TRUE(targetButton);
755 [bar_ dragButton:draggedButton
756 to:[targetButton left]
757 copy:NO];
758 EXPECT_EQ(model_string, model_test_utils::ModelStringFromNode(root));
759 // Don't check the folder window since it's not supposed to be showing.
760 }
761
762 TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
763 BookmarkModel& model(*profile()->GetBookmarkModel());
764 const BookmarkNode* root = model.bookmark_bar_node();
765 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
766 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
767 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
768 model_test_utils::AddNodesFromModelString(model, root, model_string);
769
770 // Validate initial model.
771 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
772 EXPECT_EQ(model_string, actualModelString);
773
774 // Pop up a folder menu and copy in a button from the bar.
775 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
776 ASSERT_TRUE(toFolder);
777 NSRect oldToFolderFrame = [toFolder frame];
778 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
779 withObject:toFolder];
780 BookmarkBarFolderController* folderController = [bar_ folderController];
781 EXPECT_TRUE(folderController);
782 NSWindow* toWindow = [folderController window];
783 EXPECT_TRUE(toWindow);
784 NSRect oldToWindowFrame = [toWindow frame];
785 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
786 // so it should end up below the target bookmark.
787 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
788 ASSERT_TRUE(draggedButton);
789 BookmarkButton* targetButton =
790 [folderController buttonWithTitleEqualTo:@"2f1b"];
791 ASSERT_TRUE(targetButton);
792 [folderController dragButton:draggedButton
793 to:[targetButton center]
794 copy:YES];
795 // The button should have landed just after "2f1b".
796 const std::string expected_1("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
797 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
798 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
799 EXPECT_EQ(expected_1, model_test_utils::ModelStringFromNode(root));
800
801 // Gather the new frames.
802 NSRect newToFolderFrame = [toFolder frame];
803 NSRect newToWindowFrame = [toWindow frame];
804 // The toFolder should have shifted.
805 EXPECT_NSRECT_EQ(oldToFolderFrame, newToFolderFrame);
806 // The toWindow should have shifted down vertically and grown vertically.
807 NSRect expectedToWindowFrame = oldToWindowFrame;
808 expectedToWindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
809 expectedToWindowFrame.size.height += bookmarks::kBookmarkFolderButtonHeight;
810 EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
811
812 // Copy the button back to the bar after "3b".
813 draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
814 ASSERT_TRUE(draggedButton);
815 targetButton = [bar_ buttonWithTitleEqualTo:@"4f"];
816 ASSERT_TRUE(targetButton);
817 [bar_ dragButton:draggedButton
818 to:[targetButton left]
819 copy:YES];
820 const std::string expected_2("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
821 "2f2f2b 2f2f3b ] 2f3b ] 3b 1b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
822 "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
823 EXPECT_EQ(expected_2, model_test_utils::ModelStringFromNode(root));
824 }
825
826 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
827 BookmarkModel& model(*profile()->GetBookmarkModel());
828 const BookmarkNode* root = model.bookmark_bar_node();
829 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
830 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
831 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
832 model_test_utils::AddNodesFromModelString(model, root, model_string);
833
834 // Validate initial model.
835 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
836 EXPECT_EQ(model_string, actualModelString);
837
838 // Pop up a folder menu and a subfolder menu.
839 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
840 ASSERT_TRUE(toFolder);
841 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
842 withObject:toFolder];
843 BookmarkBarFolderController* folderController = [bar_ folderController];
844 EXPECT_TRUE(folderController);
845 NSWindow* toWindow = [folderController window];
846 EXPECT_TRUE(toWindow);
847 NSRect oldToWindowFrame = [toWindow frame];
848 BookmarkButton* toSubfolder =
849 [folderController buttonWithTitleEqualTo:@"4f2f"];
850 ASSERT_TRUE(toSubfolder);
851 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
852 withObject:toSubfolder];
853 BookmarkBarFolderController* subfolderController =
854 [folderController folderController];
855 EXPECT_TRUE(subfolderController);
856 NSWindow* toSubwindow = [subfolderController window];
857 EXPECT_TRUE(toSubwindow);
858 NSRect oldToSubwindowFrame = [toSubwindow frame];
859 // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
860 // so it should end up below the target bookmark.
861 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"5b"];
862 ASSERT_TRUE(draggedButton);
863 BookmarkButton* targetButton =
864 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
865 ASSERT_TRUE(targetButton);
866 [subfolderController dragButton:draggedButton
867 to:[targetButton center]
868 copy:NO];
869 // The button should have landed just after "2f".
870 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
871 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
872 "4f2f1b 4f2f2b 4f2f3b 5b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] ");
873 EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
874
875 // Check button spacing.
876 [folderController validateMenuSpacing];
877 [subfolderController validateMenuSpacing];
878
879 // Check the window layouts. The folder window should not have changed,
880 // but the subfolder window should have shifted vertically and grown.
881 NSRect newToWindowFrame = [toWindow frame];
882 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
883 NSRect newToSubwindowFrame = [toSubwindow frame];
884 NSRect expectedToSubwindowFrame = oldToSubwindowFrame;
885 expectedToSubwindowFrame.origin.y -= bookmarks::kBookmarkFolderButtonHeight;
886 expectedToSubwindowFrame.size.height +=
887 bookmarks::kBookmarkFolderButtonHeight;
888 EXPECT_NSRECT_EQ(expectedToSubwindowFrame, newToSubwindowFrame);
889 }
890
891 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) {
892 BookmarkModel& model(*profile()->GetBookmarkModel());
893 const BookmarkNode* root = model.bookmark_bar_node();
894 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
895 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
896 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
897 model_test_utils::AddNodesFromModelString(model, root, model_string);
898
899 // Validate initial model.
900 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
901 EXPECT_EQ(model_string, actualModelString);
902
903 // Pop up a folder menu.
904 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
905 ASSERT_TRUE(toFolder);
906 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
907 withObject:toFolder];
908 BookmarkBarFolderController* folderController = [bar_ folderController];
909 EXPECT_TRUE(folderController);
910 NSWindow* toWindow = [folderController window];
911 EXPECT_TRUE(toWindow);
912 NSRect oldToWindowFrame = [toWindow frame];
913 // Drag a folder button to the top within the same parent.
914 BookmarkButton* draggedButton =
915 [folderController buttonWithTitleEqualTo:@"4f2f"];
916 ASSERT_TRUE(draggedButton);
917 BookmarkButton* targetButton =
918 [folderController buttonWithTitleEqualTo:@"4f1f"];
919 ASSERT_TRUE(targetButton);
920 [folderController dragButton:draggedButton
921 to:[targetButton top]
922 copy:NO];
923 // The button should have landed above "4f1f".
924 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
925 "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f2f:[ 4f2f1b 4f2f2b 4f2f3b ] "
926 "4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
927 EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
928
929 // The window should not have gone away.
930 EXPECT_TRUE([bar_ folderController]);
931
932 // The folder window should not have changed.
933 NSRect newToWindowFrame = [toWindow frame];
934 EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
935
936 // Check button spacing.
937 [folderController validateMenuSpacing];
938 }
939
940 TEST_F(BookmarkBarFolderControllerMenuTest, DragParentOntoChild) {
941 BookmarkModel& model(*profile()->GetBookmarkModel());
942 const BookmarkNode* root = model.bookmark_bar_node();
943 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
944 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
945 "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
946 model_test_utils::AddNodesFromModelString(model, root, model_string);
947
948 // Validate initial model.
949 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
950 EXPECT_EQ(model_string, actualModelString);
951
952 // Pop up a folder menu.
953 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
954 ASSERT_TRUE(toFolder);
955 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
956 withObject:toFolder];
957 BookmarkBarFolderController* folderController = [bar_ folderController];
958 EXPECT_TRUE(folderController);
959 NSWindow* toWindow = [folderController window];
960 EXPECT_TRUE(toWindow);
961 // Drag a folder button to one of its children.
962 BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"4f"];
963 ASSERT_TRUE(draggedButton);
964 BookmarkButton* targetButton =
965 [folderController buttonWithTitleEqualTo:@"4f3f"];
966 ASSERT_TRUE(targetButton);
967 [folderController dragButton:draggedButton
968 to:[targetButton top]
969 copy:NO];
970 // The model should not have changed.
971 EXPECT_EQ(model_string, model_test_utils::ModelStringFromNode(root));
972
973 // Check button spacing.
974 [folderController validateMenuSpacing];
975 }
976
977 TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) {
978 BookmarkModel& model(*profile()->GetBookmarkModel());
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 model_test_utils::AddNodesFromModelString(model, root, model_string);
984
985 // Validate initial model.
986 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
987 EXPECT_EQ(model_string, actualModelString);
988
989 // Pop up a folder menu and a subfolder 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 BookmarkButton* toSubfolder =
997 [folderController buttonWithTitleEqualTo:@"4f2f"];
998 ASSERT_TRUE(toSubfolder);
999 [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1000 withObject:toSubfolder];
1001 BookmarkBarFolderController* subfolderController =
1002 [folderController folderController];
1003 EXPECT_TRUE(subfolderController);
1004
1005 // Drag a subfolder bookmark to the parent folder.
1006 BookmarkButton* draggedButton =
1007 [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
1008 ASSERT_TRUE(draggedButton);
1009 BookmarkButton* targetButton =
1010 [folderController buttonWithTitleEqualTo:@"4f2f"];
1011 ASSERT_TRUE(targetButton);
1012 [folderController dragButton:draggedButton
1013 to:[targetButton top]
1014 copy:NO];
1015 // The button should have landed above "4f2f".
1016 const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1017 "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f3b 4f2f:[ "
1018 "4f2f1b 4f2f2b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
1019 EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
1020
1021 // Check button spacing.
1022 [folderController validateMenuSpacing];
1023 // The window should not have gone away.
1024 EXPECT_TRUE([bar_ folderController]);
1025 // The subfolder should have gone away.
1026 EXPECT_FALSE([folderController folderController]);
1027 }
1028
1029 TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) {
1030 BookmarkModel& model(*profile()->GetBookmarkModel());
1031 const BookmarkNode* root = model.bookmark_bar_node();
1032 const std::string
1033 model_string("a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c ");
1034 model_test_utils::AddNodesFromModelString(model, root, model_string);
1035
1036 // Validate initial model.
1037 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
1038 EXPECT_EQ(model_string, actualModelString);
1039
1040 // Pop up a folder menu.
1041 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"b"];
1042 ASSERT_TRUE(toFolder);
1043 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1044 withObject:toFolder];
1045 BookmarkBarFolderController* folderController = [bar_ folderController];
1046 EXPECT_TRUE(folderController);
1047 NSWindow* toWindow = [folderController window];
1048 EXPECT_TRUE(toWindow);
1049 CGFloat oldWidth = NSWidth([toWindow frame]);
1050 // Drag the bookmark with a long name to the folder.
1051 BookmarkButton* draggedButton =
1052 [bar_ buttonWithTitleEqualTo:@"reallyReallyLongBookmarkName"];
1053 ASSERT_TRUE(draggedButton);
1054 BookmarkButton* targetButton =
1055 [folderController buttonWithTitleEqualTo:@"b1"];
1056 ASSERT_TRUE(targetButton);
1057 [folderController dragButton:draggedButton
1058 to:[targetButton center]
1059 copy:NO];
1060 // Verify the model change.
1061 const std::string
1062 expected_string("a b:[ b1 reallyReallyLongBookmarkName b2 b3 ] c ");
1063 EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
1064 // Verify the window grew. Just test a reasonable width gain.
1065 CGFloat newWidth = NSWidth([toWindow frame]);
1066 EXPECT_LT(oldWidth + 30.0, newWidth);
1067 }
1068
1069 TEST_F(BookmarkBarFolderControllerMenuTest, MoveRemoveAddButtons) {
1070 BookmarkModel& model(*profile()->GetBookmarkModel());
1071 const BookmarkNode* root = model.bookmark_bar_node();
1072 const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
1073 model_test_utils::AddNodesFromModelString(model, root, model_string);
1074
1075 // Validate initial model.
1076 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
1077 EXPECT_EQ(model_string, actualModelString);
1078
1079 // Pop up a folder menu.
1080 BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
1081 ASSERT_TRUE(toFolder);
1082 [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
1083 withObject:toFolder];
1084 BookmarkBarFolderController* folder = [bar_ folderController];
1085 EXPECT_TRUE(folder);
1086
1087 // Remember how many buttons are showing.
1088 NSArray* buttons = [folder buttons];
1089 NSUInteger oldDisplayedButtons = [buttons count];
1090
1091 // Move a button around a bit.
1092 [folder moveButtonFromIndex:0 toIndex:2];
1093 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:0] title]);
1094 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:1] title]);
1095 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:2] title]);
1096 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1097 [folder moveButtonFromIndex:2 toIndex:0];
1098 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
1099 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
1100 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
1101 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1102
1103 // Add a couple of buttons.
1104 const BookmarkNode* node = root->GetChild(2); // Purloin an existing node.
1105 [folder addButtonForNode:node atIndex:0];
1106 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1107 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
1108 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
1109 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
1110 EXPECT_EQ(oldDisplayedButtons + 1, [buttons count]);
1111 node = root->GetChild(3);
1112 [folder addButtonForNode:node atIndex:-1];
1113 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1114 EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
1115 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
1116 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
1117 EXPECT_NSEQ(@"4b", [[buttons objectAtIndex:4] title]);
1118 EXPECT_EQ(oldDisplayedButtons + 2, [buttons count]);
1119
1120 // Remove a couple of buttons.
1121 [folder removeButton:4 animate:NO];
1122 [folder removeButton:1 animate:NO];
1123 EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
1124 EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
1125 EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
1126 EXPECT_EQ(oldDisplayedButtons, [buttons count]);
1127
1128 // Check button spacing.
1129 [folder validateMenuSpacing];
1130 }
1131
1132 TEST_F(BookmarkBarFolderControllerMenuTest, ControllerForNode) {
1133 BookmarkModel& model(*profile()->GetBookmarkModel());
1134 const BookmarkNode* root = model.bookmark_bar_node();
1135 const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
1136 model_test_utils::AddNodesFromModelString(model, root, model_string);
1137
1138 // Validate initial model.
1139 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
1140 EXPECT_EQ(model_string, actualModelString);
1141
1142 // Find the main bar controller.
1143 const void* expectedController = bar_;
1144 const void* actualController = [bar_ controllerForNode:root];
1145 EXPECT_EQ(expectedController, actualController);
1146
1147 // Pop up the folder menu.
1148 BookmarkButton* targetFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
1149 ASSERT_TRUE(targetFolder);
1150 [[targetFolder target]
1151 performSelector:@selector(openBookmarkFolderFromButton:)
1152 withObject:targetFolder];
1153 BookmarkBarFolderController* folder = [bar_ folderController];
1154 EXPECT_TRUE(folder);
1155
1156 // Find the folder controller using the folder controller.
1157 const BookmarkNode* targetNode = root->GetChild(1);
1158 expectedController = folder;
1159 actualController = [bar_ controllerForNode:targetNode];
1160 EXPECT_EQ(expectedController, actualController);
1161
1162 // Find the folder controller from the bar.
1163 actualController = [folder controllerForNode:targetNode];
1164 EXPECT_EQ(expectedController, actualController);
1165 }
1166
1167 TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
1168 BookmarkModel& model(*profile()->GetBookmarkModel());
1169 const BookmarkNode* root = model.bookmark_bar_node();
1170 const std::string model_string("1b 2b 3b ");
1171 model_test_utils::AddNodesFromModelString(model, root, model_string);
1172
1173 // Validate initial model.
1174 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
1175 EXPECT_EQ(model_string, actualModelString);
1176
1177 const BookmarkNode* parent = model.bookmark_bar_node();
1178 const BookmarkNode* folder = model.AddFolder(parent,
1179 parent->child_count(),
1180 ASCIIToUTF16("BIG"));
1181
1182 // Pop open the new folder window and verify it has one (empty) item.
1183 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
1184 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1185 withObject:button];
1186 BookmarkBarFolderController* folderController = [bar_ folderController];
1187 EXPECT_TRUE(folderController);
1188 NSWindow* folderWindow = [folderController window];
1189 EXPECT_TRUE(folderWindow);
1190 CGFloat expectedHeight = (CGFloat)bookmarks::kBookmarkFolderButtonHeight +
1191 (2*bookmarks::kBookmarkVerticalPadding);
1192 NSRect windowFrame = [folderWindow frame];
1193 CGFloat windowHeight = NSHeight(windowFrame);
1194 EXPECT_CGFLOAT_EQ(expectedHeight, windowHeight);
1195 EXPECT_FALSE([folderController canScrollUp]);
1196 EXPECT_FALSE([folderController canScrollDown]);
1197
1198 // Now add a real bookmark and reopen.
1199 model.AddURL(folder, folder->child_count(), ASCIIToUTF16("a"),
1200 GURL("http://a.com/"));
1201 folderController = [bar_ folderController];
1202 EXPECT_TRUE(folderController);
1203 NSView* folderView = [folderController folderView];
1204 EXPECT_TRUE(folderView);
1205 NSRect menuFrame = [folderView frame];
1206 NSView* visibleView = [folderController visibleView];
1207 NSRect visibleFrame = [visibleView frame];
1208 NSScrollView* scrollView = [folderController scrollView];
1209 NSRect scrollFrame = [scrollView frame];
1210
1211 // Determine the margins between the scroll frame and the visible frame.
1212 CGFloat widthDelta = NSWidth(visibleFrame) - NSWidth(scrollFrame);
1213
1214 CGFloat menuHeight = NSHeight(menuFrame);
1215 EXPECT_CGFLOAT_EQ(expectedHeight, menuHeight);
1216 CGFloat scrollerWidth = NSWidth(scrollFrame);
1217 button = [folderController buttonWithTitleEqualTo:@"a"];
1218 CGFloat buttonWidth = NSWidth([button frame]);
1219 EXPECT_CGFLOAT_EQ(scrollerWidth, buttonWidth);
1220 CGFloat visibleWidth = NSWidth(visibleFrame);
1221 EXPECT_CGFLOAT_EQ(visibleWidth - widthDelta, buttonWidth);
1222 EXPECT_LT(scrollerWidth, NSWidth([folderView frame]));
1223
1224 // Add a wider bookmark and make sure the button widths match.
1225 int reallyWideButtonNumber = folder->child_count();
1226 model.AddURL(folder, reallyWideButtonNumber,
1227 ASCIIToUTF16("A really, really, really, really, really, "
1228 "really long name"),
1229 GURL("http://www.google.com/a"));
1230 BookmarkButton* bigButton =
1231 [folderController buttonWithTitleEqualTo:
1232 @"A really, really, really, really, really, really long name"];
1233 EXPECT_TRUE(bigButton);
1234 CGFloat buttonWidthB = NSWidth([bigButton frame]);
1235 EXPECT_LT(buttonWidth, buttonWidthB);
1236 // Add a bunch of bookmarks until the window becomes scrollable, then check
1237 // for a scroll up arrow.
1238 NSUInteger tripWire = 0; // Prevent a runaway.
1239 while (![folderController canScrollUp] && ++tripWire < 1000) {
1240 model.AddURL(folder, folder->child_count(), ASCIIToUTF16("B"),
1241 GURL("http://b.com/"));
1242 }
1243 EXPECT_TRUE([folderController canScrollUp]);
1244
1245 // Remove one bookmark and make sure the scroll down arrow has been removed.
1246 // We'll remove the really long node so we can see if the buttons get resized.
1247 scrollerWidth = NSWidth([folderView frame]);
1248 buttonWidth = NSWidth([button frame]);
1249 model.Remove(folder, reallyWideButtonNumber);
1250 EXPECT_FALSE([folderController canScrollUp]);
1251 EXPECT_FALSE([folderController canScrollDown]);
1252
1253 // Check the size. It should have reduced.
1254 EXPECT_GT(scrollerWidth, NSWidth([folderView frame]));
1255 EXPECT_GT(buttonWidth, NSWidth([button frame]));
1256
1257 // Check button spacing.
1258 [folderController validateMenuSpacing];
1259 }
1260
1261 // See http://crbug.com/46101
1262 TEST_F(BookmarkBarFolderControllerMenuTest, HoverThenDeleteBookmark) {
1263 BookmarkModel& model(*profile()->GetBookmarkModel());
1264 const BookmarkNode* root = model.bookmark_bar_node();
1265 const BookmarkNode* folder = model.AddFolder(root,
1266 root->child_count(),
1267 ASCIIToUTF16("BIG"));
1268 for (int i = 0; i < kLotsOfNodesCount; i++)
1269 model.AddURL(folder, folder->child_count(), ASCIIToUTF16("kid"),
1270 GURL("http://kid.com/smile"));
1271
1272 // Pop open the new folder window and hover one of its kids.
1273 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
1274 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1275 withObject:button];
1276 BookmarkBarFolderController* bbfc = [bar_ folderController];
1277 NSArray* buttons = [bbfc buttons];
1278
1279 // Hover over a button and verify that it is now known.
1280 button = [buttons objectAtIndex:3];
1281 BookmarkButton* buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1282 EXPECT_FALSE(buttonThatMouseIsIn);
1283 [bbfc mouseEnteredButton:button event:nil];
1284 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1285 EXPECT_EQ(button, buttonThatMouseIsIn);
1286
1287 // Delete the bookmark and verify that it is now not known.
1288 model.Remove(folder, 3);
1289 buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
1290 EXPECT_FALSE(buttonThatMouseIsIn);
1291 }
1292
1293 // Just like a BookmarkBarFolderController but intercedes when providing
1294 // pasteboard drag data.
1295 @interface BookmarkBarFolderControllerDragData : BookmarkBarFolderController {
1296 const BookmarkNode* dragDataNode_; // Weak
1297 }
1298 - (void)setDragDataNode:(const BookmarkNode*)node;
1299 @end
1300
1301 @implementation BookmarkBarFolderControllerDragData
1302
1303 - (id)initWithParentButton:(BookmarkButton*)button
1304 parentController:(BookmarkBarFolderController*)parentController
1305 barController:(BookmarkBarController*)barController {
1306 if ((self = [super initWithParentButton:button
1307 parentController:parentController
1308 barController:barController])) {
1309 dragDataNode_ = NULL;
1310 }
1311 return self;
1312 }
1313
1314 - (void)setDragDataNode:(const BookmarkNode*)node {
1315 dragDataNode_ = node;
1316 }
1317
1318 - (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
1319 std::vector<const BookmarkNode*> dragDataNodes;
1320 if(dragDataNode_) {
1321 dragDataNodes.push_back(dragDataNode_);
1322 }
1323 return dragDataNodes;
1324 }
1325
1326 @end
1327
1328 TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
1329 BookmarkModel& model(*profile()->GetBookmarkModel());
1330 const BookmarkNode* root = model.bookmark_bar_node();
1331 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1332 "2f3b ] 3b 4b ");
1333 model_test_utils::AddNodesFromModelString(model, root, model_string);
1334 const BookmarkNode* other = model.other_node();
1335 const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
1336 "O4f:[ O4f1b O4f2f ] 05b ");
1337 model_test_utils::AddNodesFromModelString(model, other, other_string);
1338
1339 // Validate initial model.
1340 std::string actual = model_test_utils::ModelStringFromNode(root);
1341 EXPECT_EQ(model_string, actual);
1342 actual = model_test_utils::ModelStringFromNode(other);
1343 EXPECT_EQ(other_string, actual);
1344
1345 // Pop open a folder.
1346 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1347 scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
1348 folderController.reset([[BookmarkBarFolderControllerDragData alloc]
1349 initWithParentButton:button
1350 parentController:nil
1351 barController:bar_]);
1352 BookmarkButton* targetButton =
1353 [folderController buttonWithTitleEqualTo:@"2f1b"];
1354 ASSERT_TRUE(targetButton);
1355
1356 // Gen up some dragging data.
1357 const BookmarkNode* newNode = other->GetChild(2);
1358 [folderController setDragDataNode:newNode];
1359 scoped_nsobject<FakedDragInfo> dragInfo([[FakedDragInfo alloc] init]);
1360 [dragInfo setDropLocation:[targetButton top]];
1361 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
1362
1363 // Verify the model.
1364 const std::string expected("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ 2f2f1b "
1365 "2f2f2b 2f2f3b ] 2f3b ] 3b 4b ");
1366 actual = model_test_utils::ModelStringFromNode(root);
1367 EXPECT_EQ(expected, actual);
1368
1369 // Now drag over a folder button.
1370 targetButton = [folderController buttonWithTitleEqualTo:@"2f2f"];
1371 ASSERT_TRUE(targetButton);
1372 newNode = other->GetChild(2); // Should be O4f.
1373 EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f"));
1374 [folderController setDragDataNode:newNode];
1375 [dragInfo setDropLocation:[targetButton center]];
1376 [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
1377
1378 // Verify the model.
1379 const std::string expectedA("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ "
1380 "2f2f1b 2f2f2b 2f2f3b O4f:[ O4f1b O4f2f ] ] "
1381 "2f3b ] 3b 4b ");
1382 actual = model_test_utils::ModelStringFromNode(root);
1383 EXPECT_EQ(expectedA, actual);
1384
1385 // Check button spacing.
1386 [folderController validateMenuSpacing];
1387 }
1388
1389 TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkDataToTrash) {
1390 BookmarkModel& model(*profile()->GetBookmarkModel());
1391 const BookmarkNode* root = model.bookmark_bar_node();
1392 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1393 "2f3b ] 3b 4b ");
1394 model_test_utils::AddNodesFromModelString(model, root, model_string);
1395
1396 // Validate initial model.
1397 std::string actual = model_test_utils::ModelStringFromNode(root);
1398 EXPECT_EQ(model_string, actual);
1399
1400 const BookmarkNode* folderNode = root->GetChild(1);
1401 int oldFolderChildCount = folderNode->child_count();
1402
1403 // Pop open a folder.
1404 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1405 scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
1406 folderController.reset([[BookmarkBarFolderControllerDragData alloc]
1407 initWithParentButton:button
1408 parentController:nil
1409 barController:bar_]);
1410
1411 // Drag a button to the trash.
1412 BookmarkButton* buttonToDelete =
1413 [folderController buttonWithTitleEqualTo:@"2f1b"];
1414 ASSERT_TRUE(buttonToDelete);
1415 EXPECT_TRUE([folderController canDragBookmarkButtonToTrash:buttonToDelete]);
1416 [folderController didDragBookmarkToTrash:buttonToDelete];
1417
1418 // There should be one less button in the folder.
1419 int newFolderChildCount = folderNode->child_count();
1420 EXPECT_EQ(oldFolderChildCount - 1, newFolderChildCount);
1421 // Verify the model.
1422 const std::string expected("1b 2f:[ 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1423 "2f3b ] 3b 4b ");
1424 actual = model_test_utils::ModelStringFromNode(root);
1425 EXPECT_EQ(expected, actual);
1426
1427 // Check button spacing.
1428 [folderController validateMenuSpacing];
1429 }
1430
1431 TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) {
1432 BookmarkModel& model(*profile()->GetBookmarkModel());
1433 const BookmarkNode* root = model.bookmark_bar_node();
1434 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1435 "2f3b ] 3b 4b ");
1436 model_test_utils::AddNodesFromModelString(model, root, model_string);
1437
1438 // Validate initial model.
1439 std::string actual = model_test_utils::ModelStringFromNode(root);
1440 EXPECT_EQ(model_string, actual);
1441
1442 // Pop open a folder.
1443 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1444 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1445 withObject:button];
1446 BookmarkBarFolderController* folderController = [bar_ folderController];
1447 EXPECT_TRUE(folderController);
1448 NSArray* buttons = [folderController buttons];
1449 EXPECT_TRUE(buttons);
1450
1451 // Remember how many buttons are showing.
1452 int oldDisplayedButtons = [buttons count];
1453
1454 BookmarkButton* targetButton =
1455 [folderController buttonWithTitleEqualTo:@"2f1b"];
1456 ASSERT_TRUE(targetButton);
1457
1458 NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/",
1459 @"http://www.b.com/", nil];
1460 NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil];
1461 [folderController addURLs:urls withTitles:titles at:[targetButton top]];
1462
1463 // There should two more buttons in the folder.
1464 int newDisplayedButtons = [buttons count];
1465 EXPECT_EQ(oldDisplayedButtons + 2, newDisplayedButtons);
1466 // Verify the model.
1467 const std::string expected("1b 2f:[ SiteA SiteB 2f1b 2f2f:[ 2f2f1b 2f2f2b "
1468 "2f2f3b ] 2f3b ] 3b 4b ");
1469 actual = model_test_utils::ModelStringFromNode(root);
1470 EXPECT_EQ(expected, actual);
1471
1472 // Check button spacing.
1473 [folderController validateMenuSpacing];
1474 }
1475
1476 TEST_F(BookmarkBarFolderControllerMenuTest, DropPositionIndicator) {
1477 BookmarkModel& model(*profile()->GetBookmarkModel());
1478 const BookmarkNode* root = model.bookmark_bar_node();
1479 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
1480 "2f3b ] 3b 4b ");
1481 model_test_utils::AddNodesFromModelString(model, root, model_string);
1482
1483 // Validate initial model.
1484 std::string actual = model_test_utils::ModelStringFromNode(root);
1485 EXPECT_EQ(model_string, actual);
1486
1487 // Pop open the folder.
1488 BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
1489 [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
1490 withObject:button];
1491 BookmarkBarFolderController* folder = [bar_ folderController];
1492 EXPECT_TRUE(folder);
1493
1494 // Test a series of points starting at the top of the folder.
1495 const CGFloat yOffset = 0.5 * bookmarks::kBookmarkVerticalPadding;
1496 BookmarkButton* targetButton = [folder buttonWithTitleEqualTo:@"2f1b"];
1497 ASSERT_TRUE(targetButton);
1498 NSPoint targetPoint = [targetButton top];
1499 CGFloat pos = [folder indicatorPosForDragToPoint:targetPoint];
1500 EXPECT_CGFLOAT_EQ(targetPoint.y + yOffset, pos);
1501 pos = [folder indicatorPosForDragToPoint:[targetButton bottom]];
1502 targetButton = [folder buttonWithTitleEqualTo:@"2f2f"];
1503 EXPECT_CGFLOAT_EQ([targetButton top].y + yOffset, pos);
1504 pos = [folder indicatorPosForDragToPoint:NSMakePoint(10,0)];
1505 targetButton = [folder buttonWithTitleEqualTo:@"2f3b"];
1506 EXPECT_CGFLOAT_EQ([targetButton bottom].y - yOffset, pos);
1507 }
1508
1509 @interface BookmarkBarControllerNoDelete : BookmarkBarController
1510 - (IBAction)deleteBookmark:(id)sender;
1511 @end
1512
1513 @implementation BookmarkBarControllerNoDelete
1514 - (IBAction)deleteBookmark:(id)sender {
1515 // NOP
1516 }
1517 @end
1518
1519 class BookmarkBarFolderControllerClosingTest : public
1520 BookmarkBarFolderControllerMenuTest {
1521 public:
1522 virtual void SetUp() {
1523 BookmarkBarFolderControllerMenuTest::SetUp();
1524 ASSERT_TRUE(browser());
1525
1526 bar_.reset([[BookmarkBarControllerNoDelete alloc]
1527 initWithBrowser:browser()
1528 initialWidth:NSWidth([parent_view_ frame])
1529 delegate:nil
1530 resizeDelegate:resizeDelegate_.get()]);
1531 InstallAndToggleBar(bar_.get());
1532 }
1533 };
1534
1535 TEST_F(BookmarkBarFolderControllerClosingTest, DeleteClosesFolder) {
1536 BookmarkModel& model(*profile()->GetBookmarkModel());
1537 const BookmarkNode* root = model.bookmark_bar_node();
1538 const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b ] "
1539 "2f3b ] 3b ");
1540 model_test_utils::AddNodesFromModelString(model, root, model_string);
1541
1542 // Validate initial model.
1543 std::string actualModelString = model_test_utils::ModelStringFromNode(root);
1544 EXPECT_EQ(model_string, actualModelString);
1545
1546 // Open the folder menu and submenu.
1547 BookmarkButton* target = [bar_ buttonWithTitleEqualTo:@"2f"];
1548 ASSERT_TRUE(target);
1549 [[target target] performSelector:@selector(openBookmarkFolderFromButton:)
1550 withObject:target];
1551 BookmarkBarFolderController* folder = [bar_ folderController];
1552 EXPECT_TRUE(folder);
1553 BookmarkButton* subTarget = [folder buttonWithTitleEqualTo:@"2f2f"];
1554 ASSERT_TRUE(subTarget);
1555 [[subTarget target] performSelector:@selector(openBookmarkFolderFromButton:)
1556 withObject:subTarget];
1557 BookmarkBarFolderController* subFolder = [folder folderController];
1558 EXPECT_TRUE(subFolder);
1559
1560 // Delete the folder node and verify the window closed down by looking
1561 // for its controller again.
1562 [folder deleteBookmark:folder];
1563 EXPECT_FALSE([folder folderController]);
1564 }
1565
1566 // TODO(jrg): draggingEntered: and draggingExited: trigger timers so
1567 // they are hard to test. Factor out "fire timers" into routines
1568 // which can be overridden to fire immediately to make behavior
1569 // confirmable.
1570 // There is a similar problem with mouseEnteredButton: and
1571 // mouseExitedButton:.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698