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 |