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 #import "chrome/browser/ui/cocoa/clickhold_button_cell.h" 7 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 8 #import "chrome/browser/ui/cocoa/menu_button.h" 9 10 @interface MenuButtonTestDelegate : NSObject<NSMenuDelegate> { 11 @private 12 base::scoped_nsobject<NSMenu> menu_; 13 BOOL open_; 14 BOOL didOpen_; 15 } 16 - (BOOL)isOpen; 17 - (BOOL)didOpen; 18 @end 19 20 @implementation MenuButtonTestDelegate 21 - (id)initWithMenu:(NSMenu*)menu { 22 if ((self = [super init])) { 23 menu_.reset([menu retain]); 24 } 25 return self; 26 } 27 28 - (BOOL)isOpen { 29 return open_; 30 } 31 32 - (BOOL)didOpen { 33 return didOpen_; 34 } 35 36 - (void)menuWillOpen:(NSMenu*)menu { 37 EXPECT_EQ(menu_.get(), menu); 38 EXPECT_FALSE(open_); 39 open_ = YES; 40 didOpen_ = YES; 41 NSArray* modes = [NSArray arrayWithObjects:NSEventTrackingRunLoopMode, 42 NSDefaultRunLoopMode, 43 nil]; 44 [menu performSelector:@selector(cancelTracking) 45 withObject:nil 46 afterDelay:0.1 47 inModes:modes]; 48 } 49 50 - (void)menuDidClose:(NSMenu*)menu { 51 EXPECT_EQ(menu_.get(), menu); 52 EXPECT_TRUE(open_); 53 open_ = NO; 54 } 55 @end 56 57 namespace { 58 59 class MenuButtonTest : public CocoaTest { 60 public: 61 MenuButtonTest() { 62 NSRect frame = NSMakeRect(0, 0, 50, 30); 63 base::scoped_nsobject<MenuButton> button( 64 [[MenuButton alloc] initWithFrame:frame]); 65 button_ = button.get(); 66 base::scoped_nsobject<ClickHoldButtonCell> cell( 67 [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]); 68 [button_ setCell:cell.get()]; 69 [[test_window() contentView] addSubview:button_]; 70 } 71 72 NSMenu* CreateMenu() { 73 NSMenu* menu = [[NSMenu alloc] initWithTitle:@""]; 74 [menu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0]; 75 [menu insertItemWithTitle:@"foo" action:nil keyEquivalent:@"" atIndex:1]; 76 [menu insertItemWithTitle:@"bar" action:nil keyEquivalent:@"" atIndex:2]; 77 [menu insertItemWithTitle:@"baz" action:nil keyEquivalent:@"" atIndex:3]; 78 return menu; 79 } 80 81 NSEvent* MouseDownEvent(NSEventType eventType) { 82 NSPoint location; 83 location.x = location.y = 0; 84 NSGraphicsContext* context = [NSGraphicsContext currentContext]; 85 NSEvent* event = [NSEvent mouseEventWithType:eventType 86 location:location 87 modifierFlags:0 88 timestamp:0 89 windowNumber:0 90 context:context 91 eventNumber:0 92 clickCount:1 93 pressure:0.0F]; 94 95 return event; 96 } 97 98 MenuButton* button_; 99 }; 100 101 TEST_VIEW(MenuButtonTest, button_); 102 103 // Test assigning a menu, again mostly to ensure nothing leaks or crashes. 104 TEST_F(MenuButtonTest, MenuAssign) { 105 base::scoped_nsobject<NSMenu> menu(CreateMenu()); 106 ASSERT_TRUE(menu.get()); 107 108 [button_ setAttachedMenu:menu]; 109 EXPECT_TRUE([button_ attachedMenu]); 110 } 111 112 TEST_F(MenuButtonTest, OpenOnClick) { 113 base::scoped_nsobject<NSMenu> menu(CreateMenu()); 114 ASSERT_TRUE(menu.get()); 115 116 base::scoped_nsobject<MenuButtonTestDelegate> delegate( 117 [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]); 118 ASSERT_TRUE(delegate.get()); 119 120 [menu setDelegate:delegate.get()]; 121 [button_ setAttachedMenu:menu]; 122 [button_ setOpenMenuOnClick:YES]; 123 124 EXPECT_FALSE([delegate isOpen]); 125 EXPECT_FALSE([delegate didOpen]); 126 127 // Should open the menu. 128 [button_ performClick:nil]; 129 130 EXPECT_TRUE([delegate didOpen]); 131 EXPECT_FALSE([delegate isOpen]); 132 } 133 134 TEST_F(MenuButtonTest, OpenOnRightClick) { 135 base::scoped_nsobject<NSMenu> menu(CreateMenu()); 136 ASSERT_TRUE(menu.get()); 137 138 base::scoped_nsobject<MenuButtonTestDelegate> delegate( 139 [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]); 140 ASSERT_TRUE(delegate.get()); 141 142 [menu setDelegate:delegate.get()]; 143 [button_ setAttachedMenu:menu]; 144 [button_ setOpenMenuOnClick:YES]; 145 // Right click is enabled. 146 [button_ setOpenMenuOnRightClick:YES]; 147 148 EXPECT_FALSE([delegate isOpen]); 149 EXPECT_FALSE([delegate didOpen]); 150 151 // Should open the menu. 152 NSEvent* event = MouseDownEvent(NSRightMouseDown); 153 [button_ rightMouseDown:event]; 154 155 EXPECT_TRUE([delegate didOpen]); 156 EXPECT_FALSE([delegate isOpen]); 157 } 158 159 TEST_F(MenuButtonTest, DontOpenOnRightClickWithoutSetRightClick) { 160 base::scoped_nsobject<NSMenu> menu(CreateMenu()); 161 ASSERT_TRUE(menu.get()); 162 163 base::scoped_nsobject<MenuButtonTestDelegate> delegate( 164 [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]); 165 ASSERT_TRUE(delegate.get()); 166 167 [menu setDelegate:delegate.get()]; 168 [button_ setAttachedMenu:menu]; 169 [button_ setOpenMenuOnClick:YES]; 170 171 EXPECT_FALSE([delegate isOpen]); 172 EXPECT_FALSE([delegate didOpen]); 173 174 // Should not open the menu. 175 NSEvent* event = MouseDownEvent(NSRightMouseDown); 176 [button_ rightMouseDown:event]; 177 178 EXPECT_FALSE([delegate didOpen]); 179 EXPECT_FALSE([delegate isOpen]); 180 181 // Should open the menu in this case. 182 [button_ performClick:nil]; 183 184 EXPECT_TRUE([delegate didOpen]); 185 EXPECT_FALSE([delegate isOpen]); 186 } 187 188 } // namespace 189