Home | History | Annotate | Download | only in bookmarks
      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_controller.h"
     12 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h"
     13 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
     14 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
     15 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
     16 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
     17 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
     18 #import "chrome/browser/ui/cocoa/url_drop_target.h"
     19 #include "chrome/test/base/ui_test_utils.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 #include "testing/platform_test.h"
     22 #import "third_party/mozilla/NSPasteboard+Utils.h"
     23 
     24 namespace {
     25 // Some values used for mocks and fakes.
     26 const CGFloat kFakeIndicatorPos = 7.0;
     27 const NSPoint kPoint = {10, 10};
     28 };
     29 
     30 // Fake DraggingInfo, fake BookmarkBarController, fake NSPasteboard...
     31 @interface FakeBookmarkDraggingInfo : NSObject {
     32  @public
     33   BOOL dragButtonToPong_;
     34   BOOL dragButtonToShouldCopy_;
     35   BOOL dragURLsPong_;
     36   BOOL dragBookmarkDataPong_;
     37   BOOL dropIndicatorShown_;
     38   BOOL draggingEnteredCalled_;
     39   // Only mock one type of drag data at a time.
     40   NSString* dragDataType_;
     41   BookmarkButton* button_;  // weak
     42   BookmarkModel* bookmarkModel_;  // weak
     43   id draggingSource_;
     44 }
     45 @property (nonatomic) BOOL dropIndicatorShown;
     46 @property (nonatomic) BOOL draggingEnteredCalled;
     47 @property (nonatomic, copy) NSString* dragDataType;
     48 @property (nonatomic, assign) BookmarkButton* button;
     49 @property (nonatomic, assign) BookmarkModel* bookmarkModel;
     50 @end
     51 
     52 @implementation FakeBookmarkDraggingInfo
     53 
     54 @synthesize dropIndicatorShown = dropIndicatorShown_;
     55 @synthesize draggingEnteredCalled = draggingEnteredCalled_;
     56 @synthesize dragDataType = dragDataType_;
     57 @synthesize button = button_;
     58 @synthesize bookmarkModel = bookmarkModel_;
     59 
     60 - (id)init {
     61   if ((self = [super init])) {
     62     dropIndicatorShown_ = YES;
     63   }
     64   return self;
     65 }
     66 
     67 - (void)dealloc {
     68   [dragDataType_ release];
     69   [super dealloc];
     70 }
     71 
     72 - (void)reset {
     73   [dragDataType_ release];
     74   dragDataType_ = nil;
     75   dragButtonToPong_ = NO;
     76   dragURLsPong_ = NO;
     77   dragBookmarkDataPong_ = NO;
     78   dropIndicatorShown_ = YES;
     79   draggingEnteredCalled_ = NO;
     80   draggingSource_ = self;
     81 }
     82 
     83 - (void)setDraggingSource:(id)draggingSource {
     84   draggingSource_ = draggingSource;
     85 }
     86 
     87 // NSDragInfo mocking functions.
     88 
     89 - (id)draggingPasteboard {
     90   return self;
     91 }
     92 
     93 // So we can look local.
     94 - (id)draggingSource {
     95   return draggingSource_;
     96 }
     97 
     98 - (NSDragOperation)draggingSourceOperationMask {
     99   return NSDragOperationCopy | NSDragOperationMove;
    100 }
    101 
    102 - (NSPoint)draggingLocation {
    103   return kPoint;
    104 }
    105 
    106 // NSPasteboard mocking functions.
    107 
    108 - (BOOL)containsURLData {
    109   NSArray* urlTypes = [URLDropTargetHandler handledDragTypes];
    110   if (dragDataType_)
    111     return [urlTypes containsObject:dragDataType_];
    112   return NO;
    113 }
    114 
    115 - (NSData*)dataForType:(NSString*)type {
    116   if (dragDataType_ && [dragDataType_ isEqualToString:type]) {
    117     if (button_)
    118       return [NSData dataWithBytes:&button_ length:sizeof(button_)];
    119     else
    120       return [NSData data];  // Return something, anything.
    121   }
    122   return nil;
    123 }
    124 
    125 // Fake a controller for callback ponging
    126 
    127 - (BOOL)dragButton:(BookmarkButton*)button to:(NSPoint)point copy:(BOOL)copy {
    128   dragButtonToPong_ = YES;
    129   dragButtonToShouldCopy_ = copy;
    130   return YES;
    131 }
    132 
    133 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
    134   dragURLsPong_ = YES;
    135   return YES;
    136 }
    137 
    138 - (void)getURLs:(NSArray**)outUrls
    139     andTitles:(NSArray**)outTitles
    140     convertingFilenames:(BOOL)convertFilenames {
    141 }
    142 
    143 - (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
    144   dragBookmarkDataPong_ = YES;
    145   return NO;
    146 }
    147 
    148 - (BOOL)canEditBookmarks {
    149   return YES;
    150 }
    151 
    152 // Confirm the pongs.
    153 
    154 - (BOOL)dragButtonToPong {
    155   return dragButtonToPong_;
    156 }
    157 
    158 - (BOOL)dragButtonToShouldCopy {
    159   return dragButtonToShouldCopy_;
    160 }
    161 
    162 - (BOOL)dragURLsPong {
    163   return dragURLsPong_;
    164 }
    165 
    166 - (BOOL)dragBookmarkDataPong {
    167   return dragBookmarkDataPong_;
    168 }
    169 
    170 - (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
    171   return kFakeIndicatorPos;
    172 }
    173 
    174 - (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
    175   return dropIndicatorShown_;
    176 }
    177 
    178 - (BOOL)draggingAllowed:(id<NSDraggingInfo>)info {
    179   return YES;
    180 }
    181 
    182 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
    183   draggingEnteredCalled_ = YES;
    184   return NSDragOperationNone;
    185 }
    186 
    187 - (void)setDropInsertionPos:(CGFloat)where {
    188 }
    189 
    190 - (void)clearDropInsertionPos {
    191 }
    192 
    193 @end
    194 
    195 namespace {
    196 
    197 class BookmarkBarViewTest : public CocoaProfileTest {
    198  public:
    199   virtual void SetUp() {
    200     CocoaProfileTest::SetUp();
    201     view_.reset([[BookmarkBarView alloc] init]);
    202   }
    203 
    204   base::scoped_nsobject<BookmarkBarView> view_;
    205 };
    206 
    207 TEST_F(BookmarkBarViewTest, CanDragWindow) {
    208   EXPECT_FALSE([view_ mouseDownCanMoveWindow]);
    209 }
    210 
    211 TEST_F(BookmarkBarViewTest, BookmarkButtonDragAndDrop) {
    212   base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
    213       [[FakeBookmarkDraggingInfo alloc] init]);
    214   [view_ setController:info.get()];
    215   [info reset];
    216 
    217   BookmarkModel* bookmark_model =
    218       BookmarkModelFactory::GetForProfile(profile());
    219   const BookmarkNode* node =
    220       bookmark_model->AddURL(bookmark_model->bookmark_bar_node(),
    221                              0,
    222                              ASCIIToUTF16("Test Bookmark"),
    223                              GURL("http://www.exmaple.com"));
    224 
    225   base::scoped_nsobject<BookmarkButtonCell> button_cell(
    226       [[BookmarkButtonCell buttonCellForNode:node
    227                                         text:nil
    228                                        image:nil
    229                               menuController:nil] retain]);
    230   base::scoped_nsobject<BookmarkButton> dragged_button(
    231       [[BookmarkButton alloc] init]);
    232   [dragged_button setCell:button_cell];
    233   [info setDraggingSource:dragged_button.get()];
    234   [info setDragDataType:kBookmarkButtonDragType];
    235   [info setButton:dragged_button.get()];
    236   [info setBookmarkModel:bookmark_model];
    237   EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
    238   EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
    239   EXPECT_TRUE([info dragButtonToPong]);
    240   EXPECT_FALSE([info dragButtonToShouldCopy]);
    241   EXPECT_FALSE([info dragURLsPong]);
    242   EXPECT_TRUE([info dragBookmarkDataPong]);
    243 }
    244 
    245 // When dragging bookmarks across profiles, we should always copy, never move.
    246 TEST_F(BookmarkBarViewTest, BookmarkButtonDragAndDropAcrossProfiles) {
    247   base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
    248       [[FakeBookmarkDraggingInfo alloc] init]);
    249   [view_ setController:info.get()];
    250   [info reset];
    251 
    252   // |other_profile| is owned by the |testing_profile_manager|.
    253   TestingProfile* other_profile =
    254       testing_profile_manager()->CreateTestingProfile("other");
    255   other_profile->CreateBookmarkModel(true);
    256 
    257   BookmarkModel* bookmark_model =
    258       BookmarkModelFactory::GetForProfile(profile());
    259   ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model);
    260 
    261   const BookmarkNode* node =
    262       bookmark_model->AddURL(bookmark_model->bookmark_bar_node(),
    263                              0,
    264                              ASCIIToUTF16("Test Bookmark"),
    265                              GURL("http://www.exmaple.com"));
    266 
    267   base::scoped_nsobject<BookmarkButtonCell> button_cell(
    268       [[BookmarkButtonCell buttonCellForNode:node
    269                                         text:nil
    270                                        image:nil
    271                               menuController:nil] retain]);
    272   base::scoped_nsobject<BookmarkButton> dragged_button(
    273       [[BookmarkButton alloc] init]);
    274   [dragged_button setCell:button_cell];
    275   [info setDraggingSource:dragged_button.get()];
    276   [info setDragDataType:kBookmarkButtonDragType];
    277   [info setButton:dragged_button.get()];
    278   [info setBookmarkModel:BookmarkModelFactory::GetForProfile(other_profile)];
    279   EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
    280   EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
    281   EXPECT_TRUE([info dragButtonToPong]);
    282   EXPECT_TRUE([info dragButtonToShouldCopy]);
    283   EXPECT_FALSE([info dragURLsPong]);
    284   EXPECT_TRUE([info dragBookmarkDataPong]);
    285 }
    286 
    287 TEST_F(BookmarkBarViewTest, URLDragAndDrop) {
    288   base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
    289       [[FakeBookmarkDraggingInfo alloc] init]);
    290   [view_ setController:info.get()];
    291   [info reset];
    292 
    293   NSArray* dragTypes = [URLDropTargetHandler handledDragTypes];
    294   for (NSString* type in dragTypes) {
    295     [info setDragDataType:type];
    296     EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationCopy);
    297     EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
    298     EXPECT_FALSE([info dragButtonToPong]);
    299     EXPECT_TRUE([info dragURLsPong]);
    300     EXPECT_TRUE([info dragBookmarkDataPong]);
    301     [info reset];
    302   }
    303 }
    304 
    305 TEST_F(BookmarkBarViewTest, BookmarkButtonDropIndicator) {
    306   base::scoped_nsobject<FakeBookmarkDraggingInfo> info(
    307       [[FakeBookmarkDraggingInfo alloc] init]);
    308   [view_ setController:info.get()];
    309   [info reset];
    310 
    311   base::scoped_nsobject<BookmarkButton> dragged_button(
    312       [[BookmarkButton alloc] init]);
    313   [info setDraggingSource:dragged_button.get()];
    314   [info setDragDataType:kBookmarkButtonDragType];
    315   EXPECT_FALSE([info draggingEnteredCalled]);
    316   EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
    317   EXPECT_TRUE([info draggingEnteredCalled]);  // Ensure controller pinged.
    318   EXPECT_TRUE([view_ dropIndicatorShown]);
    319   EXPECT_EQ([view_ dropIndicatorPosition], kFakeIndicatorPos);
    320 
    321   [info setDropIndicatorShown:NO];
    322   EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
    323   EXPECT_FALSE([view_ dropIndicatorShown]);
    324 }
    325 
    326 }  // namespace
    327