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

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

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

Powered by Google App Engine
This is Rietveld 408576698