| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009 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/scoped_nsobject.h" | |
| 8 #import "chrome/browser/ui/cocoa/tab_controller.h" | |
| 9 #import "chrome/browser/ui/cocoa/tab_controller_target.h" | |
| 10 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h" | |
| 11 #include "testing/gtest/include/gtest/gtest.h" | |
| 12 #import "testing/gtest_mac.h" | |
| 13 #include "testing/platform_test.h" | |
| 14 | |
| 15 // Implements the target interface for the tab, which gets sent messages when | |
| 16 // the tab is clicked on by the user and when its close box is clicked. | |
| 17 @interface TabControllerTestTarget : NSObject<TabControllerTarget> { | |
| 18 @private | |
| 19 bool selected_; | |
| 20 bool closed_; | |
| 21 } | |
| 22 - (bool)selected; | |
| 23 - (bool)closed; | |
| 24 @end | |
| 25 | |
| 26 @implementation TabControllerTestTarget | |
| 27 - (bool)selected { | |
| 28 return selected_; | |
| 29 } | |
| 30 - (bool)closed { | |
| 31 return closed_; | |
| 32 } | |
| 33 - (void)selectTab:(id)sender { | |
| 34 selected_ = true; | |
| 35 } | |
| 36 - (void)closeTab:(id)sender { | |
| 37 closed_ = true; | |
| 38 } | |
| 39 - (void)mouseTimer:(NSTimer*)timer { | |
| 40 // Fire the mouseUp to break the TabView drag loop. | |
| 41 NSEvent* current = [NSApp currentEvent]; | |
| 42 NSWindow* window = [timer userInfo]; | |
| 43 NSEvent* up = [NSEvent mouseEventWithType:NSLeftMouseUp | |
| 44 location:[current locationInWindow] | |
| 45 modifierFlags:0 | |
| 46 timestamp:[current timestamp] | |
| 47 windowNumber:[window windowNumber] | |
| 48 context:nil | |
| 49 eventNumber:0 | |
| 50 clickCount:1 | |
| 51 pressure:1.0]; | |
| 52 [window postEvent:up atStart:YES]; | |
| 53 } | |
| 54 - (void)commandDispatch:(TabStripModel::ContextMenuCommand)command | |
| 55 forController:(TabController*)controller { | |
| 56 } | |
| 57 - (BOOL)isCommandEnabled:(TabStripModel::ContextMenuCommand)command | |
| 58 forController:(TabController*)controller { | |
| 59 return NO; | |
| 60 } | |
| 61 @end | |
| 62 | |
| 63 namespace { | |
| 64 | |
| 65 CGFloat LeftMargin(NSRect superFrame, NSRect subFrame) { | |
| 66 return NSMinX(subFrame) - NSMinX(superFrame); | |
| 67 } | |
| 68 | |
| 69 CGFloat RightMargin(NSRect superFrame, NSRect subFrame) { | |
| 70 return NSMaxX(superFrame) - NSMaxX(subFrame); | |
| 71 } | |
| 72 | |
| 73 // The dragging code in TabView makes heavy use of autorelease pools so | |
| 74 // inherit from CocoaTest to have one created for us. | |
| 75 class TabControllerTest : public CocoaTest { | |
| 76 public: | |
| 77 TabControllerTest() { } | |
| 78 }; | |
| 79 | |
| 80 // Tests creating the controller, sticking it in a window, and removing it. | |
| 81 TEST_F(TabControllerTest, Creation) { | |
| 82 NSWindow* window = test_window(); | |
| 83 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 84 [[window contentView] addSubview:[controller view]]; | |
| 85 EXPECT_TRUE([controller tabView]); | |
| 86 EXPECT_EQ([[controller view] window], window); | |
| 87 [[controller view] display]; // Test drawing to ensure nothing leaks/crashes. | |
| 88 [[controller view] removeFromSuperview]; | |
| 89 } | |
| 90 | |
| 91 // Tests sending it a close message and ensuring that the target/action get | |
| 92 // called. Mimics the user clicking on the close button in the tab. | |
| 93 TEST_F(TabControllerTest, Close) { | |
| 94 NSWindow* window = test_window(); | |
| 95 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 96 [[window contentView] addSubview:[controller view]]; | |
| 97 | |
| 98 scoped_nsobject<TabControllerTestTarget> target( | |
| 99 [[TabControllerTestTarget alloc] init]); | |
| 100 EXPECT_FALSE([target closed]); | |
| 101 [controller setTarget:target]; | |
| 102 EXPECT_EQ(target.get(), [controller target]); | |
| 103 | |
| 104 [controller closeTab:nil]; | |
| 105 EXPECT_TRUE([target closed]); | |
| 106 | |
| 107 [[controller view] removeFromSuperview]; | |
| 108 } | |
| 109 | |
| 110 // Tests setting the |selected| property via code. | |
| 111 TEST_F(TabControllerTest, APISelection) { | |
| 112 NSWindow* window = test_window(); | |
| 113 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 114 [[window contentView] addSubview:[controller view]]; | |
| 115 | |
| 116 EXPECT_FALSE([controller selected]); | |
| 117 [controller setSelected:YES]; | |
| 118 EXPECT_TRUE([controller selected]); | |
| 119 | |
| 120 [[controller view] removeFromSuperview]; | |
| 121 } | |
| 122 | |
| 123 // Tests that setting the title of a tab sets the tooltip as well. | |
| 124 TEST_F(TabControllerTest, ToolTip) { | |
| 125 NSWindow* window = test_window(); | |
| 126 | |
| 127 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 128 [[window contentView] addSubview:[controller view]]; | |
| 129 | |
| 130 EXPECT_TRUE([[controller toolTip] length] == 0); | |
| 131 NSString *tooltip_string = @"Some text to use as a tab title"; | |
| 132 [controller setTitle:tooltip_string]; | |
| 133 EXPECT_NSEQ(tooltip_string, [controller toolTip]); | |
| 134 } | |
| 135 | |
| 136 // Tests setting the |loading| property via code. | |
| 137 TEST_F(TabControllerTest, Loading) { | |
| 138 NSWindow* window = test_window(); | |
| 139 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 140 [[window contentView] addSubview:[controller view]]; | |
| 141 | |
| 142 EXPECT_EQ(kTabDone, [controller loadingState]); | |
| 143 [controller setLoadingState:kTabWaiting]; | |
| 144 EXPECT_EQ(kTabWaiting, [controller loadingState]); | |
| 145 [controller setLoadingState:kTabLoading]; | |
| 146 EXPECT_EQ(kTabLoading, [controller loadingState]); | |
| 147 [controller setLoadingState:kTabDone]; | |
| 148 EXPECT_EQ(kTabDone, [controller loadingState]); | |
| 149 | |
| 150 [[controller view] removeFromSuperview]; | |
| 151 } | |
| 152 | |
| 153 // Tests selecting the tab with the mouse click and ensuring the target/action | |
| 154 // get called. | |
| 155 TEST_F(TabControllerTest, UserSelection) { | |
| 156 NSWindow* window = test_window(); | |
| 157 | |
| 158 // Create a tab at a known location in the window that we can click on | |
| 159 // to activate selection. | |
| 160 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 161 [[window contentView] addSubview:[controller view]]; | |
| 162 NSRect frame = [[controller view] frame]; | |
| 163 frame.size.width = [TabController minTabWidth]; | |
| 164 frame.origin = NSMakePoint(0, 0); | |
| 165 [[controller view] setFrame:frame]; | |
| 166 | |
| 167 // Set the target and action. | |
| 168 scoped_nsobject<TabControllerTestTarget> target( | |
| 169 [[TabControllerTestTarget alloc] init]); | |
| 170 EXPECT_FALSE([target selected]); | |
| 171 [controller setTarget:target]; | |
| 172 [controller setAction:@selector(selectTab:)]; | |
| 173 EXPECT_EQ(target.get(), [controller target]); | |
| 174 EXPECT_EQ(@selector(selectTab:), [controller action]); | |
| 175 | |
| 176 // In order to track a click, we have to fake a mouse down and a mouse | |
| 177 // up, but the down goes into a tight drag loop. To break the loop, we have | |
| 178 // to fire a timer that sends a mouse up event while the "drag" is ongoing. | |
| 179 [NSTimer scheduledTimerWithTimeInterval:0.1 | |
| 180 target:target.get() | |
| 181 selector:@selector(mouseTimer:) | |
| 182 userInfo:window | |
| 183 repeats:NO]; | |
| 184 NSEvent* current = [NSApp currentEvent]; | |
| 185 NSPoint click_point = NSMakePoint(frame.size.width / 2, | |
| 186 frame.size.height / 2); | |
| 187 NSEvent* down = [NSEvent mouseEventWithType:NSLeftMouseDown | |
| 188 location:click_point | |
| 189 modifierFlags:0 | |
| 190 timestamp:[current timestamp] | |
| 191 windowNumber:[window windowNumber] | |
| 192 context:nil | |
| 193 eventNumber:0 | |
| 194 clickCount:1 | |
| 195 pressure:1.0]; | |
| 196 [[controller view] mouseDown:down]; | |
| 197 | |
| 198 // Check our target was told the tab got selected. | |
| 199 EXPECT_TRUE([target selected]); | |
| 200 | |
| 201 [[controller view] removeFromSuperview]; | |
| 202 } | |
| 203 | |
| 204 TEST_F(TabControllerTest, IconCapacity) { | |
| 205 NSWindow* window = test_window(); | |
| 206 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 207 [[window contentView] addSubview:[controller view]]; | |
| 208 int cap = [controller iconCapacity]; | |
| 209 EXPECT_GE(cap, 1); | |
| 210 | |
| 211 NSRect frame = [[controller view] frame]; | |
| 212 frame.size.width += 500; | |
| 213 [[controller view] setFrame:frame]; | |
| 214 int newcap = [controller iconCapacity]; | |
| 215 EXPECT_GT(newcap, cap); | |
| 216 } | |
| 217 | |
| 218 TEST_F(TabControllerTest, ShouldShowIcon) { | |
| 219 NSWindow* window = test_window(); | |
| 220 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 221 [[window contentView] addSubview:[controller view]]; | |
| 222 int cap = [controller iconCapacity]; | |
| 223 EXPECT_GT(cap, 0); | |
| 224 | |
| 225 // Tab is minimum width, both icon and close box should be hidden. | |
| 226 NSRect frame = [[controller view] frame]; | |
| 227 frame.size.width = [TabController minTabWidth]; | |
| 228 [[controller view] setFrame:frame]; | |
| 229 EXPECT_FALSE([controller shouldShowIcon]); | |
| 230 EXPECT_FALSE([controller shouldShowCloseButton]); | |
| 231 | |
| 232 // Setting the icon when tab is at min width should not show icon (bug 18359). | |
| 233 scoped_nsobject<NSView> newIcon( | |
| 234 [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 16, 16)]); | |
| 235 [controller setIconView:newIcon.get()]; | |
| 236 EXPECT_TRUE([newIcon isHidden]); | |
| 237 | |
| 238 // Tab is at selected minimum width. Since it's selected, the close box | |
| 239 // should be visible. | |
| 240 [controller setSelected:YES]; | |
| 241 frame = [[controller view] frame]; | |
| 242 frame.size.width = [TabController minSelectedTabWidth]; | |
| 243 [[controller view] setFrame:frame]; | |
| 244 EXPECT_FALSE([controller shouldShowIcon]); | |
| 245 EXPECT_TRUE([newIcon isHidden]); | |
| 246 EXPECT_TRUE([controller shouldShowCloseButton]); | |
| 247 | |
| 248 // Test expanding the tab to max width and ensure the icon and close box | |
| 249 // get put back, even when de-selected. | |
| 250 frame.size.width = [TabController maxTabWidth]; | |
| 251 [[controller view] setFrame:frame]; | |
| 252 EXPECT_TRUE([controller shouldShowIcon]); | |
| 253 EXPECT_FALSE([newIcon isHidden]); | |
| 254 EXPECT_TRUE([controller shouldShowCloseButton]); | |
| 255 [controller setSelected:NO]; | |
| 256 EXPECT_TRUE([controller shouldShowIcon]); | |
| 257 EXPECT_TRUE([controller shouldShowCloseButton]); | |
| 258 | |
| 259 cap = [controller iconCapacity]; | |
| 260 EXPECT_GT(cap, 0); | |
| 261 } | |
| 262 | |
| 263 TEST_F(TabControllerTest, Menu) { | |
| 264 NSWindow* window = test_window(); | |
| 265 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 266 [[window contentView] addSubview:[controller view]]; | |
| 267 int cap = [controller iconCapacity]; | |
| 268 EXPECT_GT(cap, 0); | |
| 269 | |
| 270 // Asking the view for its menu should yield a valid menu. | |
| 271 NSMenu* menu = [[controller view] menu]; | |
| 272 EXPECT_TRUE(menu); | |
| 273 EXPECT_GT([menu numberOfItems], 0); | |
| 274 } | |
| 275 | |
| 276 // Tests that the title field is correctly positioned and sized when the | |
| 277 // view is resized. | |
| 278 TEST_F(TabControllerTest, TitleViewLayout) { | |
| 279 NSWindow* window = test_window(); | |
| 280 | |
| 281 scoped_nsobject<TabController> controller([[TabController alloc] init]); | |
| 282 [[window contentView] addSubview:[controller view]]; | |
| 283 NSRect tabFrame = [[controller view] frame]; | |
| 284 tabFrame.size.width = [TabController maxTabWidth]; | |
| 285 [[controller view] setFrame:tabFrame]; | |
| 286 | |
| 287 const NSRect originalTabFrame = [[controller view] frame]; | |
| 288 const NSRect originalIconFrame = [[controller iconView] frame]; | |
| 289 const NSRect originalCloseFrame = [[controller closeButton] frame]; | |
| 290 const NSRect originalTitleFrame = [[controller titleView] frame]; | |
| 291 | |
| 292 // Sanity check the start state. | |
| 293 EXPECT_FALSE([[controller iconView] isHidden]); | |
| 294 EXPECT_FALSE([[controller closeButton] isHidden]); | |
| 295 EXPECT_GT(NSWidth([[controller view] frame]), | |
| 296 NSWidth([[controller titleView] frame])); | |
| 297 | |
| 298 // Resize the tab so that that the it shrinks. | |
| 299 tabFrame.size.width = [TabController minTabWidth]; | |
| 300 [[controller view] setFrame:tabFrame]; | |
| 301 | |
| 302 // The icon view and close button should be hidden and the title view should | |
| 303 // be resize to take up their space. | |
| 304 EXPECT_TRUE([[controller iconView] isHidden]); | |
| 305 EXPECT_TRUE([[controller closeButton] isHidden]); | |
| 306 EXPECT_GT(NSWidth([[controller view] frame]), | |
| 307 NSWidth([[controller titleView] frame])); | |
| 308 EXPECT_EQ(LeftMargin(originalTabFrame, originalIconFrame), | |
| 309 LeftMargin([[controller view] frame], | |
| 310 [[controller titleView] frame])); | |
| 311 EXPECT_EQ(RightMargin(originalTabFrame, originalCloseFrame), | |
| 312 RightMargin([[controller view] frame], | |
| 313 [[controller titleView] frame])); | |
| 314 | |
| 315 // Resize the tab so that that the it grows. | |
| 316 tabFrame.size.width = [TabController maxTabWidth] * 0.75; | |
| 317 [[controller view] setFrame:tabFrame]; | |
| 318 | |
| 319 // The icon view and close button should be visible again and the title view | |
| 320 // should be resized to make room for them. | |
| 321 EXPECT_FALSE([[controller iconView] isHidden]); | |
| 322 EXPECT_FALSE([[controller closeButton] isHidden]); | |
| 323 EXPECT_GT(NSWidth([[controller view] frame]), | |
| 324 NSWidth([[controller titleView] frame])); | |
| 325 EXPECT_EQ(LeftMargin(originalTabFrame, originalTitleFrame), | |
| 326 LeftMargin([[controller view] frame], | |
| 327 [[controller titleView] frame])); | |
| 328 EXPECT_EQ(RightMargin(originalTabFrame, originalTitleFrame), | |
| 329 RightMargin([[controller view] frame], | |
| 330 [[controller titleView] frame])); | |
| 331 } | |
| 332 | |
| 333 } // namespace | |
| OLD | NEW |