1 // Copyright (c) 2011 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 #import <Cocoa/Cocoa.h> 6 7 #import "base/memory/scoped_nsobject.h" 8 #include "chrome/app/chrome_command_ids.h" 9 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 10 #import "chrome/browser/ui/cocoa/test_event_utils.h" 11 #import "chrome/browser/ui/cocoa/toolbar/toolbar_button.h" 12 #import "testing/gtest_mac.h" 13 14 @interface TestableToolbarButton : ToolbarButton { 15 @private 16 NSInteger numOfClick_; 17 NSInteger lastCommand_; 18 } 19 20 @property(assign, nonatomic) NSInteger numOfClick; 21 @property(assign, nonatomic) NSInteger lastCommand; 22 23 - (id)initWithFrame:(NSRect)frame; 24 - (void)doAction:(id)sender; 25 @end 26 27 @implementation TestableToolbarButton 28 29 @synthesize numOfClick = numOfClick_; 30 @synthesize lastCommand = lastCommand_; 31 32 - (id)initWithFrame:(NSRect)frame { 33 if ((self = [super initWithFrame:frame])) { 34 lastCommand_ = IDC_STOP; 35 } 36 return self; 37 } 38 39 - (void)doAction:(id)sender { 40 lastCommand_ = [sender tag]; 41 if (lastCommand_ == [self tag]) 42 ++numOfClick_; 43 } 44 45 - (BOOL)shouldHandleEvent:(NSEvent*)theEvent { 46 return handleMiddleClick_; 47 } 48 49 @end 50 51 namespace { 52 53 class ToolbarButtonTest : public CocoaTest { 54 public: 55 ToolbarButtonTest() { 56 NSRect frame = NSMakeRect(0, 0, 20, 20); 57 scoped_nsobject<TestableToolbarButton> button( 58 [[TestableToolbarButton alloc] initWithFrame:frame]); 59 button_ = button.get(); 60 61 [button_ setTag:IDC_HOME]; 62 [button_ setTarget:button_]; 63 [button_ setAction:@selector(doAction:)]; 64 [[test_window() contentView] addSubview:button_]; 65 66 NSRect bounds = [button_ bounds]; 67 NSPoint mid_point = NSMakePoint(NSMidX(bounds), NSMidY(bounds)); 68 NSPoint out_point = NSMakePoint(bounds.origin.x - 10, 69 bounds.origin.y - 10); 70 left_down_in_view = 71 test_event_utils::MouseEventAtPoint(mid_point, NSLeftMouseDown, 0); 72 left_up_in_view = 73 test_event_utils::MouseEventAtPoint(mid_point, NSLeftMouseUp, 0); 74 right_down_in_view = 75 test_event_utils::MouseEventAtPoint(mid_point, NSRightMouseDown, 0); 76 right_up_in_view = 77 test_event_utils::MouseEventAtPoint(mid_point, NSRightMouseUp, 0); 78 other_down_in_view = 79 test_event_utils::MouseEventAtPoint(mid_point, NSOtherMouseDown, 0); 80 other_dragged_in_view = 81 test_event_utils::MouseEventAtPoint(mid_point, NSOtherMouseDragged, 0); 82 other_up_in_view = 83 test_event_utils::MouseEventAtPoint(mid_point, NSOtherMouseUp, 0); 84 other_down_out_view = 85 test_event_utils::MouseEventAtPoint(out_point, NSOtherMouseDown, 0); 86 other_dragged_out_view = 87 test_event_utils::MouseEventAtPoint(out_point, NSOtherMouseDragged, 0); 88 other_up_out_view = 89 test_event_utils::MouseEventAtPoint(out_point, NSOtherMouseUp, 0); 90 } 91 92 TestableToolbarButton* button_; 93 NSEvent* left_down_in_view; 94 NSEvent* left_up_in_view; 95 NSEvent* right_down_in_view; 96 NSEvent* right_up_in_view; 97 NSEvent* other_down_in_view; 98 NSEvent* other_dragged_in_view; 99 NSEvent* other_up_in_view; 100 NSEvent* other_down_out_view; 101 NSEvent* other_dragged_out_view; 102 NSEvent* other_up_out_view; 103 }; 104 105 TEST_VIEW(ToolbarButtonTest, button_) 106 107 TEST_F(ToolbarButtonTest, DoesNotSwallowClicksOnNO) { 108 // Middle button being down doesn't swallow right button clicks. But 109 // ToolbarButton doesn't handle right button events. 110 [button_ otherMouseDown:other_down_in_view]; 111 EXPECT_EQ(NSOffState, [button_ state]); 112 [button_ rightMouseDown:right_down_in_view]; 113 EXPECT_EQ(NSOffState, [button_ state]); 114 [button_ rightMouseUp:right_up_in_view]; 115 EXPECT_EQ(NSOffState, [button_ state]); 116 EXPECT_EQ(0, [button_ numOfClick]); 117 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 118 [button_ otherMouseUp:other_up_in_view]; 119 EXPECT_EQ(NSOffState, [button_ state]); 120 EXPECT_EQ(0, [button_ numOfClick]); 121 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 122 123 // Middle button being down doesn't swallows left button clicks. 124 [button_ otherMouseDown:other_down_in_view]; 125 EXPECT_EQ(NSOffState, [button_ state]); 126 [NSApp postEvent:left_up_in_view atStart:YES]; 127 [button_ mouseDown:left_down_in_view]; 128 EXPECT_EQ(1, [button_ numOfClick]); 129 EXPECT_EQ(IDC_HOME, [button_ lastCommand]); 130 [button_ otherMouseUp:other_up_in_view]; 131 EXPECT_EQ(1, [button_ numOfClick]); 132 EXPECT_EQ(IDC_HOME, [button_ lastCommand]); 133 } 134 135 TEST_F(ToolbarButtonTest, WithoutMouseDownOnNO) { 136 // Middle button mouse up without leading mouse down in the view. 137 [button_ otherMouseUp:other_up_in_view]; 138 EXPECT_EQ(NSOffState, [button_ state]); 139 EXPECT_EQ(0, [button_ numOfClick]); 140 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 141 142 // Middle button mouse dragged in the view and up without leading mouse down. 143 [button_ otherMouseDragged:other_dragged_in_view]; 144 EXPECT_EQ(NSOffState, [button_ state]); 145 [button_ otherMouseUp:other_up_in_view]; 146 EXPECT_EQ(NSOffState, [button_ state]); 147 EXPECT_EQ(0, [button_ numOfClick]); 148 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 149 } 150 151 TEST_F(ToolbarButtonTest, MouseClickOnNO) { 152 // Middle button clicking in the view. 153 [button_ otherMouseDown:other_down_in_view]; 154 EXPECT_EQ(NSOffState, [button_ state]); 155 [button_ otherMouseUp:other_up_in_view]; 156 EXPECT_EQ(NSOffState, [button_ state]); 157 EXPECT_EQ(0, [button_ numOfClick]); 158 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 159 160 // Middle button clicking outside of the view. 161 [button_ otherMouseDown:other_down_out_view]; 162 EXPECT_EQ(NSOffState, [button_ state]); 163 [button_ otherMouseUp:other_up_out_view]; 164 EXPECT_EQ(NSOffState, [button_ state]); 165 EXPECT_EQ(0, [button_ numOfClick]); 166 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 167 } 168 169 TEST_F(ToolbarButtonTest, MouseDraggingOnNO) { 170 // Middle button being down in the view and up outside of the view. 171 [button_ otherMouseDown:other_down_in_view]; 172 EXPECT_EQ(NSOffState, [button_ state]); 173 [button_ otherMouseDragged:other_dragged_out_view]; 174 EXPECT_EQ(NSOffState, [button_ state]); 175 [button_ otherMouseUp:other_up_out_view]; 176 EXPECT_EQ(NSOffState, [button_ state]); 177 EXPECT_EQ(0, [button_ numOfClick]); 178 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 179 180 // Middle button being down on the button, move to outside and move on it 181 // again, then up on the button. 182 [button_ otherMouseDown:other_down_in_view]; 183 EXPECT_EQ(NSOffState, [button_ state]); 184 [button_ otherMouseDragged:other_dragged_in_view]; 185 EXPECT_EQ(NSOffState, [button_ state]); 186 [button_ otherMouseUp:other_up_in_view]; 187 EXPECT_EQ(NSOffState, [button_ state]); 188 EXPECT_EQ(0, [button_ numOfClick]); 189 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 190 } 191 192 TEST_F(ToolbarButtonTest, WithoutMouseDownOnYES) { 193 // Enable middle button handling. 194 [button_ setHandleMiddleClick:YES]; 195 196 // Middle button mouse up without leading mouse down in the view. 197 [button_ otherMouseUp:other_up_in_view]; 198 EXPECT_EQ(NSOffState, [button_ state]); 199 EXPECT_EQ(0, [button_ numOfClick]); 200 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 201 202 // Middle button mouse dragged in the view and up without leading mouse down. 203 [button_ otherMouseDragged:other_dragged_in_view]; 204 EXPECT_EQ(NSOffState, [button_ state]); 205 [button_ otherMouseUp:other_up_in_view]; 206 EXPECT_EQ(NSOffState, [button_ state]); 207 EXPECT_EQ(0, [button_ numOfClick]); 208 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 209 } 210 211 TEST_F(ToolbarButtonTest, MouseClickInsideOnYES) { 212 // Enable middle button handling. 213 [button_ setHandleMiddleClick:YES]; 214 215 // Middle button clicking in the view. 216 [button_ otherMouseDown:other_down_in_view]; 217 EXPECT_EQ(NSOnState, [button_ state]); 218 [button_ otherMouseUp:other_up_in_view]; 219 EXPECT_EQ(NSOffState, [button_ state]); 220 EXPECT_EQ(1, [button_ numOfClick]); 221 EXPECT_EQ(IDC_HOME, [button_ lastCommand]); 222 } 223 224 TEST_F(ToolbarButtonTest, MouseClickOutsideOnYES) { 225 // Enable middle button handling. 226 [button_ setHandleMiddleClick:YES]; 227 228 // Middle button clicking outside of the view. 229 [button_ otherMouseDown:other_down_out_view]; 230 EXPECT_EQ(NSOffState, [button_ state]); 231 [button_ otherMouseUp:other_up_out_view]; 232 EXPECT_EQ(NSOffState, [button_ state]); 233 EXPECT_EQ(0, [button_ numOfClick]); 234 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 235 } 236 237 TEST_F(ToolbarButtonTest, MouseDraggingOnYES) { 238 // Enable middle button handling. 239 [button_ setHandleMiddleClick:YES]; 240 241 // Middle button being down in the view and up outside of the view. 242 [button_ otherMouseDown:other_down_in_view]; 243 EXPECT_EQ(NSOnState, [button_ state]); 244 [button_ otherMouseDragged:other_dragged_out_view]; 245 EXPECT_EQ(NSOffState, [button_ state]); 246 [button_ otherMouseUp:other_up_out_view]; 247 EXPECT_EQ(NSOffState, [button_ state]); 248 EXPECT_EQ(0, [button_ numOfClick]); 249 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 250 251 // Middle button being down on the button, move to outside and move on it 252 // again, then up on the button. 253 [button_ otherMouseDown:other_down_in_view]; 254 EXPECT_EQ(NSOnState, [button_ state]); 255 [button_ otherMouseDragged:other_dragged_out_view]; 256 EXPECT_EQ(NSOffState, [button_ state]); 257 [button_ otherMouseDragged:other_dragged_in_view]; 258 EXPECT_EQ(NSOnState, [button_ state]); 259 [button_ otherMouseUp:other_up_in_view]; 260 EXPECT_EQ(NSOffState, [button_ state]); 261 EXPECT_EQ(1, [button_ numOfClick]); 262 EXPECT_EQ(IDC_HOME, [button_ lastCommand]); 263 } 264 265 TEST_F(ToolbarButtonTest, DoesNotSwallowRightClickOnYES) { 266 // Enable middle button handling. 267 [button_ setHandleMiddleClick:YES]; 268 269 // Middle button being down should swallow right button clicks, but 270 // ToolbarButton doesn't swallow it because it doesn't handle right button 271 // events. 272 [button_ otherMouseDown:other_down_in_view]; 273 EXPECT_EQ(NSOnState, [button_ state]); 274 [button_ rightMouseDown:right_down_in_view]; 275 EXPECT_EQ(NSOnState, [button_ state]); 276 [button_ rightMouseUp:right_up_in_view]; 277 EXPECT_EQ(NSOnState, [button_ state]); 278 EXPECT_EQ(0, [button_ numOfClick]); 279 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 280 [button_ otherMouseUp:other_up_in_view]; 281 EXPECT_EQ(NSOffState, [button_ state]); 282 EXPECT_EQ(1, [button_ numOfClick]); 283 EXPECT_EQ(IDC_HOME, [button_ lastCommand]); 284 } 285 286 TEST_F(ToolbarButtonTest, DoesSwallowLeftClickOnYES) { 287 // Enable middle button handling. 288 [button_ setHandleMiddleClick:YES]; 289 290 // Middle button being down swallows left button clicks. 291 [button_ otherMouseDown:other_down_in_view]; 292 EXPECT_EQ(NSOnState, [button_ state]); 293 [NSApp postEvent:left_up_in_view atStart:YES]; 294 [button_ mouseDown:left_down_in_view]; 295 EXPECT_EQ(0, [button_ numOfClick]); 296 EXPECT_EQ(IDC_STOP, [button_ lastCommand]); 297 [button_ otherMouseUp:other_up_in_view]; 298 EXPECT_EQ(1, [button_ numOfClick]); 299 EXPECT_EQ(IDC_HOME, [button_ lastCommand]); 300 } 301 302 } // namespace 303