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 #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"
10 @interface MenuButtonTestDelegate : NSObject<NSMenuDelegate> {
12 base::scoped_nsobject<NSMenu> menu_;
20 @implementation MenuButtonTestDelegate
21 - (id)initWithMenu:(NSMenu*)menu {
22 if ((self = [super init])) {
23 menu_.reset([menu retain]);
36 - (void)menuWillOpen:(NSMenu*)menu {
37 EXPECT_EQ(menu_.get(), menu);
41 NSArray* modes = [NSArray arrayWithObjects:NSEventTrackingRunLoopMode,
44 [menu performSelector:@selector(cancelTracking)
50 - (void)menuDidClose:(NSMenu*)menu {
51 EXPECT_EQ(menu_.get(), menu);
59 class MenuButtonTest : public CocoaTest {
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_];
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];
81 NSEvent* MouseEvent(NSEventType eventType) {
84 location = [button_ frame].origin;
86 location.x = location.y = 0;
88 NSGraphicsContext* context = [NSGraphicsContext currentContext];
89 NSEvent* event = [NSEvent mouseEventWithType:eventType
93 windowNumber:[test_window() windowNumber]
105 TEST_VIEW(MenuButtonTest, button_);
107 // Test assigning a menu, again mostly to ensure nothing leaks or crashes.
108 TEST_F(MenuButtonTest, MenuAssign) {
109 base::scoped_nsobject<NSMenu> menu(CreateMenu());
110 ASSERT_TRUE(menu.get());
112 [button_ setAttachedMenu:menu];
113 EXPECT_TRUE([button_ attachedMenu]);
116 TEST_F(MenuButtonTest, OpenOnClick) {
117 base::scoped_nsobject<NSMenu> menu(CreateMenu());
118 ASSERT_TRUE(menu.get());
120 base::scoped_nsobject<MenuButtonTestDelegate> delegate(
121 [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]);
122 ASSERT_TRUE(delegate.get());
124 [menu setDelegate:delegate.get()];
125 [button_ setAttachedMenu:menu];
126 [button_ setOpenMenuOnClick:YES];
128 EXPECT_FALSE([delegate isOpen]);
129 EXPECT_FALSE([delegate didOpen]);
131 // Should open the menu.
132 [button_ performClick:nil];
134 EXPECT_TRUE([delegate didOpen]);
135 EXPECT_FALSE([delegate isOpen]);
138 // Test classic Mac menu behavior.
139 TEST_F(MenuButtonTest, DISABLED_OpenOnClickAndHold) {
140 base::scoped_nsobject<NSMenu> menu(CreateMenu());
141 ASSERT_TRUE(menu.get());
143 base::scoped_nsobject<MenuButtonTestDelegate> delegate(
144 [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]);
145 ASSERT_TRUE(delegate.get());
147 [menu setDelegate:delegate.get()];
148 [button_ setAttachedMenu:menu];
149 [button_ setOpenMenuOnClick:YES];
151 EXPECT_FALSE([delegate isOpen]);
152 EXPECT_FALSE([delegate didOpen]);
154 // Should open the menu.
155 NSEvent* event = MouseEvent(NSLeftMouseDown);
156 [test_window() sendEvent:event];
158 EXPECT_TRUE([delegate didOpen]);
159 EXPECT_FALSE([delegate isOpen]);
162 TEST_F(MenuButtonTest, OpenOnRightClick) {
163 base::scoped_nsobject<NSMenu> menu(CreateMenu());
164 ASSERT_TRUE(menu.get());
166 base::scoped_nsobject<MenuButtonTestDelegate> delegate(
167 [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]);
168 ASSERT_TRUE(delegate.get());
170 [menu setDelegate:delegate.get()];
171 [button_ setAttachedMenu:menu];
172 [button_ setOpenMenuOnClick:YES];
173 // Right click is enabled.
174 [button_ setOpenMenuOnRightClick:YES];
176 EXPECT_FALSE([delegate isOpen]);
177 EXPECT_FALSE([delegate didOpen]);
179 // Should open the menu.
180 NSEvent* event = MouseEvent(NSRightMouseDown);
181 [button_ rightMouseDown:event];
183 EXPECT_TRUE([delegate didOpen]);
184 EXPECT_FALSE([delegate isOpen]);
187 TEST_F(MenuButtonTest, DontOpenOnRightClickWithoutSetRightClick) {
188 base::scoped_nsobject<NSMenu> menu(CreateMenu());
189 ASSERT_TRUE(menu.get());
191 base::scoped_nsobject<MenuButtonTestDelegate> delegate(
192 [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]);
193 ASSERT_TRUE(delegate.get());
195 [menu setDelegate:delegate.get()];
196 [button_ setAttachedMenu:menu];
197 [button_ setOpenMenuOnClick:YES];
199 EXPECT_FALSE([delegate isOpen]);
200 EXPECT_FALSE([delegate didOpen]);
202 // Should not open the menu.
203 NSEvent* event = MouseEvent(NSRightMouseDown);
204 [button_ rightMouseDown:event];
206 EXPECT_FALSE([delegate didOpen]);
207 EXPECT_FALSE([delegate isOpen]);
209 // Should open the menu in this case.
210 [button_ performClick:nil];
212 EXPECT_TRUE([delegate didOpen]);
213 EXPECT_FALSE([delegate isOpen]);
216 TEST_F(MenuButtonTest, OpenOnAccessibilityPerformAction) {
217 base::scoped_nsobject<NSMenu> menu(CreateMenu());
218 ASSERT_TRUE(menu.get());
220 base::scoped_nsobject<MenuButtonTestDelegate> delegate(
221 [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]);
222 ASSERT_TRUE(delegate.get());
224 [menu setDelegate:delegate.get()];
225 [button_ setAttachedMenu:menu];
226 NSCell* buttonCell = [button_ cell];
228 EXPECT_FALSE([delegate isOpen]);
229 EXPECT_FALSE([delegate didOpen]);
231 [button_ setOpenMenuOnClick:YES];
233 // NSAccessibilityShowMenuAction should not be available but
234 // NSAccessibilityPressAction should.
235 NSArray* actionNames = [buttonCell accessibilityActionNames];
236 EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]);
237 EXPECT_TRUE([actionNames containsObject:NSAccessibilityPressAction]);
239 [button_ setOpenMenuOnClick:NO];
241 // NSAccessibilityPressAction should not be the one used to open the menu now.
242 actionNames = [buttonCell accessibilityActionNames];
243 EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]);
244 EXPECT_TRUE([actionNames containsObject:NSAccessibilityPressAction]);
246 [buttonCell accessibilityPerformAction:NSAccessibilityShowMenuAction];
247 EXPECT_TRUE([delegate didOpen]);
248 EXPECT_FALSE([delegate isOpen]);
251 TEST_F(MenuButtonTest, OpenOnAccessibilityPerformActionWithSetRightClick) {
252 base::scoped_nsobject<NSMenu> menu(CreateMenu());
253 ASSERT_TRUE(menu.get());
255 base::scoped_nsobject<MenuButtonTestDelegate> delegate(
256 [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]);
257 ASSERT_TRUE(delegate.get());
259 [menu setDelegate:delegate.get()];
260 [button_ setAttachedMenu:menu];
261 NSCell* buttonCell = [button_ cell];
263 EXPECT_FALSE([delegate isOpen]);
264 EXPECT_FALSE([delegate didOpen]);
266 [button_ setOpenMenuOnClick:YES];
268 // Command to open the menu should not be available.
269 NSArray* actionNames = [buttonCell accessibilityActionNames];
270 EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]);
272 [button_ setOpenMenuOnRightClick:YES];
274 // Command to open the menu should now become available.
275 actionNames = [buttonCell accessibilityActionNames];
276 EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]);
278 [button_ setOpenMenuOnClick:NO];
280 // Command should still be available, even when both click + hold and right
281 // click are turned on.
282 actionNames = [buttonCell accessibilityActionNames];
283 EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]);
285 [buttonCell accessibilityPerformAction:NSAccessibilityShowMenuAction];
286 EXPECT_TRUE([delegate didOpen]);
287 EXPECT_FALSE([delegate isOpen]);