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