1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/mac/scoped_nsobject.h"
6 #include "base/strings/string16.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
9 #include "chrome/browser/profiles/profile.h"
10 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
11 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa.h"
12 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
13 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
14 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
15 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
16 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
17 #import "chrome/browser/ui/cocoa/url_drop_target.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "components/bookmarks/browser/bookmark_model.h"
20 #include "components/bookmarks/test/bookmark_test_helpers.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "testing/platform_test.h"
23 #import "third_party/mozilla/NSPasteboard+Utils.h"
25 using bookmarks::BookmarkModel;
26 using bookmarks::BookmarkNode;
30 // Some values used for mocks and fakes.
31 const CGFloat kFakeIndicatorPos = 7.0;
32 const NSPoint kPoint = {10, 10};
36 // Fake DraggingInfo, fake BookmarkBarController, fake NSPasteboard...
37 @interface FakeBookmarkDraggingInfo : NSObject {
39 BOOL dragButtonToPong_;
40 BOOL dragButtonToShouldCopy_;
42 BOOL dragBookmarkDataPong_;
43 BOOL dropIndicatorShown_;
44 BOOL draggingEnteredCalled_;
45 // Only mock one type of drag data at a time.
46 NSString* dragDataType_;
47 BookmarkButton* button_; // weak
48 BookmarkModel* bookmarkModel_; // weak
51 @property (nonatomic) BOOL dropIndicatorShown;
52 @property (nonatomic) BOOL draggingEnteredCalled;
53 @property (nonatomic, copy) NSString* dragDataType;
54 @property (nonatomic, assign) BookmarkButton* button;
55 @property (nonatomic, assign) BookmarkModel* bookmarkModel;
58 @implementation FakeBookmarkDraggingInfo
60 @synthesize dropIndicatorShown = dropIndicatorShown_;
61 @synthesize draggingEnteredCalled = draggingEnteredCalled_;
62 @synthesize dragDataType = dragDataType_;
63 @synthesize button = button_;
64 @synthesize bookmarkModel = bookmarkModel_;
67 if ((self = [super init])) {
68 dropIndicatorShown_ = YES;
74 [dragDataType_ release];
79 [dragDataType_ release];
81 dragButtonToPong_ = NO;
83 dragBookmarkDataPong_ = NO;
84 dropIndicatorShown_ = YES;
85 draggingEnteredCalled_ = NO;
86 draggingSource_ = self;
89 - (void)setDraggingSource:(id)draggingSource {
90 draggingSource_ = draggingSource;
93 // NSDragInfo mocking functions.
95 - (id)draggingPasteboard {
99 // So we can look local.
100 - (id)draggingSource {
101 return draggingSource_;
104 - (NSDragOperation)draggingSourceOperationMask {
105 return NSDragOperationCopy | NSDragOperationMove;
108 - (NSPoint)draggingLocation {
112 // NSPasteboard mocking functions.
114 - (BOOL)containsURLData {
115 NSArray* urlTypes = [URLDropTargetHandler handledDragTypes];
117 return [urlTypes containsObject:dragDataType_];
121 - (NSData*)dataForType:(NSString*)type {
122 if (dragDataType_ && [dragDataType_ isEqualToString:type]) {
124 return [NSData dataWithBytes:&button_ length:sizeof(button_)];
126 return [NSData data]; // Return something, anything.
131 // Fake a controller for callback ponging
133 - (BOOL)dragButton:(BookmarkButton*)button to:(NSPoint)point copy:(BOOL)copy {
134 dragButtonToPong_ = YES;
135 dragButtonToShouldCopy_ = copy;
139 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
144 - (void)getURLs:(NSArray**)outUrls
145 andTitles:(NSArray**)outTitles
146 convertingFilenames:(BOOL)convertFilenames {
149 - (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
150 dragBookmarkDataPong_ = YES;
154 - (BOOL)canEditBookmarks {
158 // Confirm the pongs.
160 - (BOOL)dragButtonToPong {
161 return dragButtonToPong_;
164 - (BOOL)dragButtonToShouldCopy {
165 return dragButtonToShouldCopy_;
168 - (BOOL)dragURLsPong {
169 return dragURLsPong_;
172 - (BOOL)dragBookmarkDataPong {
173 return dragBookmarkDataPong_;
176 - (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
177 return kFakeIndicatorPos;
180 - (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
181 return dropIndicatorShown_;
184 - (BOOL)draggingAllowed:(id<NSDraggingInfo>)info {
188 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
189 draggingEnteredCalled_ = YES;
190 return NSDragOperationNone;
193 - (void)setDropInsertionPos:(CGFloat)where {
196 - (void)clearDropInsertionPos {
203 class BookmarkBarViewTest : public CocoaProfileTest {
205 void SetUp() override {
206 CocoaProfileTest::SetUp();
207 view_.reset([[BookmarkBarView alloc] init]);
210 base::scoped_nsobject<BookmarkBarView> view_;
213 TEST_F(BookmarkBarViewTest, CanDragWindow) {
214 EXPECT_FALSE([view_ mouseDownCanMoveWindow]);
217 TEST_F(BookmarkBarViewTest, BookmarkButtonDragAndDrop) {
218 base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
219 [[FakeBookmarkDraggingInfo alloc] init]);
220 [view_ setController:info.get()];
223 BookmarkModel* bookmark_model =
224 BookmarkModelFactory::GetForProfile(profile());
225 const BookmarkNode* node =
226 bookmark_model->AddURL(bookmark_model->bookmark_bar_node(),
228 base::ASCIIToUTF16("Test Bookmark"),
229 GURL("http://www.exmaple.com"));
231 base::scoped_nsobject<BookmarkButtonCell> button_cell(
232 [[BookmarkButtonCell buttonCellForNode:node
235 menuController:nil] retain]);
236 base::scoped_nsobject<BookmarkButton> dragged_button(
237 [[BookmarkButton alloc] init]);
238 [dragged_button setCell:button_cell];
239 [info setDraggingSource:dragged_button.get()];
240 [info setDragDataType:kBookmarkButtonDragType];
241 [info setButton:dragged_button.get()];
242 [info setBookmarkModel:bookmark_model];
243 EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
244 EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
245 EXPECT_TRUE([info dragButtonToPong]);
246 EXPECT_FALSE([info dragButtonToShouldCopy]);
247 EXPECT_FALSE([info dragURLsPong]);
248 EXPECT_TRUE([info dragBookmarkDataPong]);
251 // When dragging bookmarks across profiles, we should always copy, never move.
252 TEST_F(BookmarkBarViewTest, BookmarkButtonDragAndDropAcrossProfiles) {
253 base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
254 [[FakeBookmarkDraggingInfo alloc] init]);
255 [view_ setController:info.get()];
258 // |other_profile| is owned by the |testing_profile_manager|.
259 TestingProfile* other_profile =
260 testing_profile_manager()->CreateTestingProfile("other");
261 other_profile->CreateBookmarkModel(true);
263 BookmarkModel* bookmark_model =
264 BookmarkModelFactory::GetForProfile(profile());
265 bookmarks::test::WaitForBookmarkModelToLoad(bookmark_model);
267 const BookmarkNode* node =
268 bookmark_model->AddURL(bookmark_model->bookmark_bar_node(),
270 base::ASCIIToUTF16("Test Bookmark"),
271 GURL("http://www.exmaple.com"));
273 base::scoped_nsobject<BookmarkButtonCell> button_cell(
274 [[BookmarkButtonCell buttonCellForNode:node
277 menuController:nil] retain]);
278 base::scoped_nsobject<BookmarkButton> dragged_button(
279 [[BookmarkButton alloc] init]);
280 [dragged_button setCell:button_cell];
281 [info setDraggingSource:dragged_button.get()];
282 [info setDragDataType:kBookmarkButtonDragType];
283 [info setButton:dragged_button.get()];
284 [info setBookmarkModel:BookmarkModelFactory::GetForProfile(other_profile)];
285 EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
286 EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
287 EXPECT_TRUE([info dragButtonToPong]);
288 EXPECT_TRUE([info dragButtonToShouldCopy]);
289 EXPECT_FALSE([info dragURLsPong]);
290 EXPECT_TRUE([info dragBookmarkDataPong]);
293 TEST_F(BookmarkBarViewTest, URLDragAndDrop) {
294 base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
295 [[FakeBookmarkDraggingInfo alloc] init]);
296 [view_ setController:info.get()];
299 NSArray* dragTypes = [URLDropTargetHandler handledDragTypes];
300 for (NSString* type in dragTypes) {
301 [info setDragDataType:type];
302 EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationCopy);
303 EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
304 EXPECT_FALSE([info dragButtonToPong]);
305 EXPECT_TRUE([info dragURLsPong]);
306 EXPECT_TRUE([info dragBookmarkDataPong]);
311 TEST_F(BookmarkBarViewTest, BookmarkButtonDropIndicator) {
312 base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
313 [[FakeBookmarkDraggingInfo alloc] init]);
314 [view_ setController:info.get()];
317 base::scoped_nsobject<BookmarkButton> dragged_button(
318 [[BookmarkButton alloc] init]);
319 [info setDraggingSource:dragged_button.get()];
320 [info setDragDataType:kBookmarkButtonDragType];
321 EXPECT_FALSE([info draggingEnteredCalled]);
322 EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
323 EXPECT_TRUE([info draggingEnteredCalled]); // Ensure controller pinged.
324 EXPECT_TRUE([view_ dropIndicatorShown]);
325 EXPECT_EQ([view_ dropIndicatorPosition], kFakeIndicatorPos);
327 [info setDropIndicatorShown:NO];
328 EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
329 EXPECT_FALSE([view_ dropIndicatorShown]);