OLD | NEW |
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:. | |
OLD | NEW |