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. 4 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_folder_controller.h" 11#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h" 12#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" 13#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" 14#include "chrome/browser/ui/cocoa/cocoa_profile_test.h" 15#import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 16#import "chrome/browser/ui/cocoa/url_drop_target.h" 17#include "chrome/test/base/testing_profile.h" 18#include "components/bookmarks/browser/bookmark_model.h" 19#include "components/bookmarks/test/bookmark_test_helpers.h" 20#include "testing/gtest/include/gtest/gtest.h" 21#include "testing/platform_test.h" 22#import "third_party/mozilla/NSPasteboard+Utils.h" 23#import "third_party/ocmock/OCMock/OCMock.h" 24#import "third_party/ocmock/ocmock_extensions.h" 25 26// Allows us to verify BookmarkBarFolderView. 27@interface BookmarkBarFolderView(TestingAPI) 28 29@property(readonly, nonatomic) BOOL dropIndicatorShown; 30@property(readonly, nonatomic) CGFloat dropIndicatorPosition; 31 32-(void)setController:(id<BookmarkButtonControllerProtocol>)controller; 33 34@end 35 36@implementation BookmarkBarFolderView(TestingAPI) 37 38-(void)setController:(id<BookmarkButtonControllerProtocol>)controller { 39 controller_ = controller; 40} 41 42-(BOOL)dropIndicatorShown { 43 return dropIndicatorShown_; 44} 45 46-(CGFloat)dropIndicatorPosition { 47 return NSMinY([dropIndicator_ frame]); 48} 49 50@end 51 52namespace { 53 54// Some values used for mocks and fakes. 55const CGFloat kFakeIndicatorPos = 7.0; 56const NSPoint kPoint = {10, 10}; 57 58class BookmarkBarFolderViewTest : public CocoaProfileTest { 59 public: 60 virtual void SetUp() { 61 CocoaProfileTest::SetUp(); 62 63 view_.reset([[BookmarkBarFolderView alloc] init]); 64 65 mock_controller_.reset(GetMockController( 66 YES, BookmarkModelFactory::GetForProfile(profile()))); 67 68 mock_button_.reset(GetMockButton(mock_controller_.get())); 69 [view_ awakeFromNib]; 70 [view_ setController:mock_controller_]; 71 } 72 73 virtual void TearDown() { 74 [mock_controller_ verify]; 75 CocoaProfileTest::TearDown(); 76 } 77 78 id GetFakePasteboardForType(NSString* dataType) { 79 id pasteboard = [OCMockObject mockForClass:[NSPasteboard class]]; 80 if ([dataType isEqualToString:kBookmarkButtonDragType]) { 81 BookmarkButton* button = mock_button_.get(); 82 [[[pasteboard stub] 83 andReturn:[NSData dataWithBytes:&button length:sizeof(button)]] 84 dataForType:dataType]; 85 } else { 86 [[[pasteboard stub] andReturn:[NSData data]] dataForType:dataType]; 87 } 88 [[[pasteboard stub] andReturn:nil] dataForType:OCMOCK_ANY]; 89 [[[pasteboard stub] andReturnBool:YES] containsURLData]; 90 [[pasteboard stub] getURLs:[OCMArg setTo:nil] 91 andTitles:[OCMArg setTo:nil] 92 convertingFilenames:YES]; 93 return pasteboard; 94 } 95 96 id GetFakeDragInfoForType(NSString* dataType) { 97 // Need something non-nil to return as the draggingSource. 98 id source = [OCMockObject mockForClass:[NSObject class]]; 99 id drag_info = [OCMockObject mockForProtocol:@protocol(NSDraggingInfo)]; 100 id pasteboard = GetFakePasteboardForType(dataType); 101 [[[drag_info stub] andReturn:pasteboard] draggingPasteboard]; 102 [[[drag_info stub] andReturnNSPoint:kPoint] draggingLocation]; 103 [[[drag_info stub] andReturn:source] draggingSource]; 104 [[[drag_info stub] 105 andReturnUnsignedInteger:NSDragOperationCopy | NSDragOperationMove] 106 draggingSourceOperationMask]; 107 return drag_info; 108 } 109 110 id GetMockController(BOOL show_indicator, BookmarkModel* model) { 111 id mock_controller = 112 [OCMockObject mockForClass:[BookmarkBarFolderController class]]; 113 [[[mock_controller stub] andReturnBool:YES] 114 draggingAllowed:OCMOCK_ANY]; 115 [[[mock_controller stub] andReturnBool:show_indicator] 116 shouldShowIndicatorShownForPoint:kPoint]; 117 [[[mock_controller stub] andReturnCGFloat:kFakeIndicatorPos] 118 indicatorPosForDragToPoint:kPoint]; 119 [[[mock_controller stub] andReturnValue:OCMOCK_VALUE(model)] bookmarkModel]; 120 return [mock_controller retain]; 121 } 122 123 id GetMockButton(id mock_controller) { 124 BookmarkModel* bookmark_model = 125 BookmarkModelFactory::GetForProfile(profile()); 126 const BookmarkNode* node = 127 bookmark_model->AddURL(bookmark_model->bookmark_bar_node(), 128 0, 129 base::ASCIIToUTF16("Test Bookmark"), 130 GURL("http://www.exmaple.com")); 131 132 id mock_button = [OCMockObject mockForClass:[BookmarkButton class]]; 133 [[[mock_button stub] andReturnValue:OCMOCK_VALUE(node)] bookmarkNode]; 134 return [mock_button retain]; 135 } 136 137 base::scoped_nsobject<id> mock_controller_; 138 base::scoped_nsobject<BookmarkBarFolderView> view_; 139 base::scoped_nsobject<id> mock_button_; 140}; 141 142TEST_F(BookmarkBarFolderViewTest, BookmarkButtonDragAndDrop) { 143 id drag_info = GetFakeDragInfoForType(kBookmarkButtonDragType); 144 [[[mock_controller_ expect] andReturnUnsignedInteger:NSDragOperationNone] 145 draggingEntered:drag_info]; 146 [[[mock_controller_ expect] andReturnBool:NO] dragBookmarkData:drag_info]; 147 [[[mock_controller_ expect] andReturnBool:YES] dragButton:OCMOCK_ANY 148 to:kPoint 149 copy:NO]; 150 151 EXPECT_EQ([view_ draggingEntered:drag_info], NSDragOperationMove); 152 EXPECT_TRUE([view_ performDragOperation:drag_info]); 153} 154 155// When dragging bookmarks across profiles, we should always copy, never move. 156TEST_F(BookmarkBarFolderViewTest, BookmarkButtonDragAndDropAcrossProfiles) { 157 // |other_profile| is owned by the |testing_profile_manager|. 158 TestingProfile* other_profile = 159 testing_profile_manager()->CreateTestingProfile("other"); 160 other_profile->CreateBookmarkModel(true); 161 test::WaitForBookmarkModelToLoad( 162 BookmarkModelFactory::GetForProfile(other_profile)); 163 164 mock_controller_.reset(GetMockController( 165 YES, BookmarkModelFactory::GetForProfile(other_profile))); 166 [view_ setController:mock_controller_]; 167 168 id drag_info = GetFakeDragInfoForType(kBookmarkButtonDragType); 169 [[[mock_controller_ expect] andReturnUnsignedInteger:NSDragOperationNone] 170 draggingEntered:drag_info]; 171 [[[mock_controller_ expect] andReturnBool:NO] dragBookmarkData:drag_info]; 172 [[[mock_controller_ expect] andReturnBool:YES] dragButton:OCMOCK_ANY 173 to:kPoint 174 copy:YES]; 175 176 EXPECT_EQ([view_ draggingEntered:drag_info], NSDragOperationMove); 177 EXPECT_TRUE([view_ performDragOperation:drag_info]); 178} 179 180TEST_F(BookmarkBarFolderViewTest, URLDragAndDrop) { 181 NSArray* dragTypes = [URLDropTargetHandler handledDragTypes]; 182 for (NSString* type in dragTypes) { 183 id drag_info = GetFakeDragInfoForType(type); 184 [[[mock_controller_ expect] andReturnUnsignedInteger:NSDragOperationNone] 185 draggingEntered:drag_info]; 186 [[[mock_controller_ expect] andReturnBool:NO] dragBookmarkData:drag_info]; 187 [[[mock_controller_ expect] andReturnBool:YES] addURLs:OCMOCK_ANY 188 withTitles:OCMOCK_ANY 189 at:kPoint]; 190 EXPECT_EQ([view_ draggingEntered:drag_info], NSDragOperationMove); 191 EXPECT_TRUE([view_ performDragOperation:drag_info]); 192 [mock_controller_ verify]; 193 } 194} 195 196TEST_F(BookmarkBarFolderViewTest, BookmarkButtonDropIndicator) { 197 id drag_info = GetFakeDragInfoForType(kBookmarkButtonDragType); 198 [[[mock_controller_ expect] andReturnUnsignedInteger:NSDragOperationNone] 199 draggingEntered:drag_info]; 200 EXPECT_EQ([view_ draggingEntered:drag_info], NSDragOperationMove); 201 [mock_controller_ verify]; 202 EXPECT_TRUE([view_ dropIndicatorShown]); 203 EXPECT_EQ([view_ dropIndicatorPosition], kFakeIndicatorPos); 204 mock_controller_.reset(GetMockController( 205 NO, BookmarkModelFactory::GetForProfile(profile()))); 206 [view_ setController:mock_controller_]; 207 [[[mock_controller_ expect] andReturnUnsignedInteger:NSDragOperationNone] 208 draggingEntered:drag_info]; 209 EXPECT_EQ([view_ draggingEntered:drag_info], NSDragOperationMove); 210 EXPECT_FALSE([view_ dropIndicatorShown]); 211} 212 213} // namespace 214