• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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#include "base/memory/scoped_nsobject.h"
6#include "base/memory/scoped_ptr.h"
7#include "chrome/app/chrome_command_ids.h"
8#include "chrome/browser/prefs/pref_service.h"
9#include "chrome/browser/sync/sync_ui_util.h"
10#include "chrome/browser/ui/browser_window.h"
11#include "chrome/browser/ui/cocoa/browser_test_helper.h"
12#include "chrome/browser/ui/cocoa/browser_window_controller.h"
13#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
14#include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h"
15#include "chrome/common/pref_names.h"
16#include "chrome/test/testing_profile.h"
17#include "grit/generated_resources.h"
18#include "ui/base/l10n/l10n_util_mac.h"
19
20@interface BrowserWindowController (JustForTesting)
21// Already defined in BWC.
22- (void)saveWindowPositionToPrefs:(PrefService*)prefs;
23- (void)layoutSubviews;
24@end
25
26@interface BrowserWindowController (ExposedForTesting)
27// Implementations are below.
28- (NSView*)infoBarContainerView;
29- (NSView*)toolbarView;
30- (NSView*)bookmarkView;
31- (BOOL)bookmarkBarVisible;
32@end
33
34@implementation BrowserWindowController (ExposedForTesting)
35- (NSView*)infoBarContainerView {
36  return [infoBarContainerController_ view];
37}
38
39- (NSView*)toolbarView {
40  return [toolbarController_ view];
41}
42
43- (NSView*)bookmarkView {
44  return [bookmarkBarController_ view];
45}
46
47- (NSView*)findBarView {
48  return [findBarCocoaController_ view];
49}
50
51- (NSSplitView*)devToolsView {
52  return static_cast<NSSplitView*>([devToolsController_ view]);
53}
54
55- (NSView*)sidebarView {
56  return [sidebarController_ view];
57}
58
59- (BOOL)bookmarkBarVisible {
60  return [bookmarkBarController_ isVisible];
61}
62@end
63
64class BrowserWindowControllerTest : public CocoaTest {
65 public:
66  virtual void SetUp() {
67    CocoaTest::SetUp();
68    Browser* browser = browser_helper_.browser();
69    controller_ = [[BrowserWindowController alloc] initWithBrowser:browser
70                                                     takeOwnership:NO];
71  }
72
73  virtual void TearDown() {
74    [controller_ close];
75    CocoaTest::TearDown();
76  }
77
78 public:
79  BrowserTestHelper browser_helper_;
80  BrowserWindowController* controller_;
81};
82
83TEST_F(BrowserWindowControllerTest, TestSaveWindowPosition) {
84  PrefService* prefs = browser_helper_.profile()->GetPrefs();
85  ASSERT_TRUE(prefs != NULL);
86
87  // Check to make sure there is no existing pref for window placement.
88  const DictionaryValue* browser_window_placement =
89      prefs->GetDictionary(prefs::kBrowserWindowPlacement);
90  ASSERT_TRUE(browser_window_placement);
91  EXPECT_TRUE(browser_window_placement->empty());
92
93  // Ask the window to save its position, then check that a preference
94  // exists.
95  [controller_ saveWindowPositionToPrefs:prefs];
96  browser_window_placement =
97      prefs->GetDictionary(prefs::kBrowserWindowPlacement);
98  ASSERT_TRUE(browser_window_placement);
99  EXPECT_FALSE(browser_window_placement->empty());
100}
101
102TEST_F(BrowserWindowControllerTest, TestFullScreenWindow) {
103  // Confirm that |-createFullscreenWindow| doesn't return nil.
104  // See BrowserWindowFullScreenControllerTest for more fullscreen tests.
105  EXPECT_TRUE([controller_ createFullscreenWindow]);
106}
107
108TEST_F(BrowserWindowControllerTest, TestNormal) {
109  // Force the bookmark bar to be shown.
110  browser_helper_.profile()->GetPrefs()->
111      SetBoolean(prefs::kShowBookmarkBar, true);
112  [controller_ updateBookmarkBarVisibilityWithAnimation:NO];
113
114  // Make sure a normal BrowserWindowController is, uh, normal.
115  EXPECT_TRUE([controller_ isNormalWindow]);
116  EXPECT_TRUE([controller_ hasTabStrip]);
117  EXPECT_FALSE([controller_ hasTitleBar]);
118  EXPECT_TRUE([controller_ isBookmarkBarVisible]);
119
120  // And make sure a controller for a pop-up window is not normal.
121  // popup_browser will be owned by its window.
122  Browser *popup_browser(Browser::CreateForType(Browser::TYPE_POPUP,
123                                                browser_helper_.profile()));
124  NSWindow *cocoaWindow = popup_browser->window()->GetNativeHandle();
125  BrowserWindowController* controller =
126      static_cast<BrowserWindowController*>([cocoaWindow windowController]);
127  ASSERT_TRUE([controller isKindOfClass:[BrowserWindowController class]]);
128  EXPECT_FALSE([controller isNormalWindow]);
129  EXPECT_FALSE([controller hasTabStrip]);
130  EXPECT_TRUE([controller hasTitleBar]);
131  EXPECT_FALSE([controller isBookmarkBarVisible]);
132  [controller close];
133}
134
135TEST_F(BrowserWindowControllerTest, TestTheme) {
136  [controller_ userChangedTheme];
137}
138
139TEST_F(BrowserWindowControllerTest, BookmarkBarControllerIndirection) {
140  EXPECT_FALSE([controller_ isBookmarkBarVisible]);
141
142  // Explicitly show the bar. Can't use bookmark_utils::ToggleWhenVisible()
143  // because of the notification issues.
144  browser_helper_.profile()->GetPrefs()->
145      SetBoolean(prefs::kShowBookmarkBar, true);
146
147  [controller_ updateBookmarkBarVisibilityWithAnimation:NO];
148  EXPECT_TRUE([controller_ isBookmarkBarVisible]);
149}
150
151#if 0
152// TODO(jrg): This crashes trying to create the BookmarkBarController, adding
153// an observer to the BookmarkModel.
154TEST_F(BrowserWindowControllerTest, TestIncognitoWidthSpace) {
155  scoped_ptr<TestingProfile> incognito_profile(new TestingProfile());
156  incognito_profile->set_off_the_record(true);
157  scoped_ptr<Browser> browser(new Browser(Browser::TYPE_NORMAL,
158                                          incognito_profile.get()));
159  controller_.reset([[BrowserWindowController alloc]
160                              initWithBrowser:browser.get()
161                                takeOwnership:NO]);
162
163  NSRect tabFrame = [[controller_ tabStripView] frame];
164  [controller_ installIncognitoBadge];
165  NSRect newTabFrame = [[controller_ tabStripView] frame];
166  EXPECT_GT(tabFrame.size.width, newTabFrame.size.width);
167
168  controller_.release();
169}
170#endif
171
172namespace {
173// Verifies that the toolbar, infobar, tab content area, and download shelf
174// completely fill the area under the tabstrip.
175void CheckViewPositions(BrowserWindowController* controller) {
176  NSRect contentView = [[[controller window] contentView] bounds];
177  NSRect tabstrip = [[controller tabStripView] frame];
178  NSRect toolbar = [[controller toolbarView] frame];
179  NSRect infobar = [[controller infoBarContainerView] frame];
180  NSRect contentArea = [[controller tabContentArea] frame];
181  NSRect download = [[[controller downloadShelf] view] frame];
182
183  EXPECT_EQ(NSMinY(contentView), NSMinY(download));
184  EXPECT_EQ(NSMaxY(download), NSMinY(contentArea));
185  EXPECT_EQ(NSMaxY(contentArea), NSMinY(infobar));
186
187  // Bookmark bar frame is random memory when hidden.
188  if ([controller bookmarkBarVisible]) {
189    NSRect bookmark = [[controller bookmarkView] frame];
190    EXPECT_EQ(NSMaxY(infobar), NSMinY(bookmark));
191    EXPECT_EQ(NSMaxY(bookmark), NSMinY(toolbar));
192    EXPECT_FALSE([[controller bookmarkView] isHidden]);
193  } else {
194    EXPECT_EQ(NSMaxY(infobar), NSMinY(toolbar));
195    EXPECT_TRUE([[controller bookmarkView] isHidden]);
196  }
197
198  // Toolbar should start immediately under the tabstrip, but the tabstrip is
199  // not necessarily fixed with respect to the content view.
200  EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar));
201}
202}  // end namespace
203
204TEST_F(BrowserWindowControllerTest, TestAdjustWindowHeight) {
205  NSWindow* window = [controller_ window];
206  NSRect workarea = [[window screen] visibleFrame];
207
208  // Place the window well above the bottom of the screen and try to adjust its
209  // height. It should change appropriately (and only downwards). Then get it to
210  // shrink by the same amount; it should return to its original state.
211  NSRect initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 100,
212                                   200, 200);
213  [window setFrame:initialFrame display:YES];
214  [controller_ resetWindowGrowthState];
215  [controller_ adjustWindowHeightBy:40];
216  NSRect finalFrame = [window frame];
217  EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
218  EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
219  EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
220  [controller_ adjustWindowHeightBy:-40];
221  finalFrame = [window frame];
222  EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
223  EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
224
225  // Place the window at the bottom of the screen and try again.  Its height
226  // should still change, but it should not grow down below the work area; it
227  // should instead move upwards. Then shrink it and make sure it goes back to
228  // the way it was.
229  initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
230  [window setFrame:initialFrame display:YES];
231  [controller_ resetWindowGrowthState];
232  [controller_ adjustWindowHeightBy:40];
233  finalFrame = [window frame];
234  EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
235  EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
236  EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
237  [controller_ adjustWindowHeightBy:-40];
238  finalFrame = [window frame];
239  EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
240  EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
241
242  // Put the window slightly offscreen and try again.  The height should not
243  // change this time.
244  initialFrame = NSMakeRect(workarea.origin.x - 10, 0, 200, 200);
245  [window setFrame:initialFrame display:YES];
246  [controller_ resetWindowGrowthState];
247  [controller_ adjustWindowHeightBy:40];
248  EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
249  [controller_ adjustWindowHeightBy:-40];
250  EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
251
252  // Make the window the same size as the workarea.  Resizing both larger and
253  // smaller should have no effect.
254  [window setFrame:workarea display:YES];
255  [controller_ resetWindowGrowthState];
256  [controller_ adjustWindowHeightBy:40];
257  EXPECT_TRUE(NSEqualRects([window frame], workarea));
258  [controller_ adjustWindowHeightBy:-40];
259  EXPECT_TRUE(NSEqualRects([window frame], workarea));
260
261  // Make the window smaller than the workarea and place it near the bottom of
262  // the workarea.  The window should grow down until it hits the bottom and
263  // then continue to grow up. Then shrink it, and it should return to where it
264  // was.
265  initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 5,
266                            200, 200);
267  [window setFrame:initialFrame display:YES];
268  [controller_ resetWindowGrowthState];
269  [controller_ adjustWindowHeightBy:40];
270  finalFrame = [window frame];
271  EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
272  EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
273  [controller_ adjustWindowHeightBy:-40];
274  finalFrame = [window frame];
275  EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
276  EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
277
278  // Inset the window slightly from the workarea.  It should not grow to be
279  // larger than the workarea. Shrink it; it should return to where it started.
280  initialFrame = NSInsetRect(workarea, 0, 5);
281  [window setFrame:initialFrame display:YES];
282  [controller_ resetWindowGrowthState];
283  [controller_ adjustWindowHeightBy:40];
284  finalFrame = [window frame];
285  EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
286  EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
287  [controller_ adjustWindowHeightBy:-40];
288  finalFrame = [window frame];
289  EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
290  EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
291
292  // Place the window at the bottom of the screen and grow; it should grow
293  // upwards. Move the window off the bottom, then shrink. It should then shrink
294  // from the bottom.
295  initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
296  [window setFrame:initialFrame display:YES];
297  [controller_ resetWindowGrowthState];
298  [controller_ adjustWindowHeightBy:40];
299  finalFrame = [window frame];
300  EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
301  EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
302  EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
303  NSPoint oldOrigin = initialFrame.origin;
304  NSPoint newOrigin = NSMakePoint(oldOrigin.x, oldOrigin.y + 10);
305  [window setFrameOrigin:newOrigin];
306  initialFrame = [window frame];
307  EXPECT_FLOAT_EQ(NSMinY(initialFrame), oldOrigin.y + 10);
308  [controller_ adjustWindowHeightBy:-40];
309  finalFrame = [window frame];
310  EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame) + 40);
311  EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) - 40);
312
313  // Do the "inset" test above, but using multiple calls to
314  // |-adjustWindowHeightBy|; the result should be the same.
315  initialFrame = NSInsetRect(workarea, 0, 5);
316  [window setFrame:initialFrame display:YES];
317  [controller_ resetWindowGrowthState];
318  for (int i = 0; i < 8; i++)
319    [controller_ adjustWindowHeightBy:5];
320  finalFrame = [window frame];
321  EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
322  EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
323  for (int i = 0; i < 8; i++)
324    [controller_ adjustWindowHeightBy:-5];
325  finalFrame = [window frame];
326  EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
327  EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
328}
329
330// Test to make sure resizing and relaying-out subviews works correctly.
331TEST_F(BrowserWindowControllerTest, TestResizeViews) {
332  TabStripView* tabstrip = [controller_ tabStripView];
333  NSView* contentView = [[tabstrip window] contentView];
334  NSView* toolbar = [controller_ toolbarView];
335  NSView* infobar = [controller_ infoBarContainerView];
336
337  // We need to muck with the views a bit to put us in a consistent state before
338  // we start resizing.  In particular, we need to move the tab strip to be
339  // immediately above the content area, since we layout views to be directly
340  // under the tab strip.
341  NSRect tabstripFrame = [tabstrip frame];
342  tabstripFrame.origin.y = NSMaxY([contentView frame]);
343  [tabstrip setFrame:tabstripFrame];
344
345  // The download shelf is created lazily.  Force-create it and set its initial
346  // height to 0.
347  NSView* download = [[controller_ downloadShelf] view];
348  NSRect downloadFrame = [download frame];
349  downloadFrame.size.height = 0;
350  [download setFrame:downloadFrame];
351
352  // Force a layout and check each view's frame.
353  [controller_ layoutSubviews];
354  CheckViewPositions(controller_);
355
356  // Expand the infobar to 60px and recheck
357  [controller_ resizeView:infobar newHeight:60];
358  CheckViewPositions(controller_);
359
360  // Expand the toolbar to 64px and recheck
361  [controller_ resizeView:toolbar newHeight:64];
362  CheckViewPositions(controller_);
363
364  // Add a 30px download shelf and recheck
365  [controller_ resizeView:download newHeight:30];
366  CheckViewPositions(controller_);
367
368  // Shrink the infobar to 0px and toolbar to 39px and recheck
369  [controller_ resizeView:infobar newHeight:0];
370  [controller_ resizeView:toolbar newHeight:39];
371  CheckViewPositions(controller_);
372}
373
374TEST_F(BrowserWindowControllerTest, TestResizeViewsWithBookmarkBar) {
375  // Force a display of the bookmark bar.
376  browser_helper_.profile()->GetPrefs()->
377      SetBoolean(prefs::kShowBookmarkBar, true);
378  [controller_ updateBookmarkBarVisibilityWithAnimation:NO];
379
380  TabStripView* tabstrip = [controller_ tabStripView];
381  NSView* contentView = [[tabstrip window] contentView];
382  NSView* toolbar = [controller_ toolbarView];
383  NSView* bookmark = [controller_ bookmarkView];
384  NSView* infobar = [controller_ infoBarContainerView];
385
386  // We need to muck with the views a bit to put us in a consistent state before
387  // we start resizing.  In particular, we need to move the tab strip to be
388  // immediately above the content area, since we layout views to be directly
389  // under the tab strip.
390  NSRect tabstripFrame = [tabstrip frame];
391  tabstripFrame.origin.y = NSMaxY([contentView frame]);
392  [tabstrip setFrame:tabstripFrame];
393
394  // The download shelf is created lazily.  Force-create it and set its initial
395  // height to 0.
396  NSView* download = [[controller_ downloadShelf] view];
397  NSRect downloadFrame = [download frame];
398  downloadFrame.size.height = 0;
399  [download setFrame:downloadFrame];
400
401  // Force a layout and check each view's frame.
402  [controller_ layoutSubviews];
403  CheckViewPositions(controller_);
404
405  // Add the bookmark bar and recheck.
406  [controller_ resizeView:bookmark newHeight:40];
407  CheckViewPositions(controller_);
408
409  // Expand the infobar to 60px and recheck
410  [controller_ resizeView:infobar newHeight:60];
411  CheckViewPositions(controller_);
412
413  // Expand the toolbar to 64px and recheck
414  [controller_ resizeView:toolbar newHeight:64];
415  CheckViewPositions(controller_);
416
417  // Add a 30px download shelf and recheck
418  [controller_ resizeView:download newHeight:30];
419  CheckViewPositions(controller_);
420
421  // Remove the bookmark bar and recheck
422  browser_helper_.profile()->GetPrefs()->
423      SetBoolean(prefs::kShowBookmarkBar, false);
424  [controller_ resizeView:bookmark newHeight:0];
425  CheckViewPositions(controller_);
426
427  // Shrink the infobar to 0px and toolbar to 39px and recheck
428  [controller_ resizeView:infobar newHeight:0];
429  [controller_ resizeView:toolbar newHeight:39];
430  CheckViewPositions(controller_);
431}
432
433// Make sure, by default, the bookmark bar and the toolbar are the same width.
434TEST_F(BrowserWindowControllerTest, BookmarkBarIsSameWidth) {
435  // Set the pref to the bookmark bar is visible when the toolbar is
436  // first created.
437  browser_helper_.profile()->GetPrefs()->SetBoolean(
438      prefs::kShowBookmarkBar, true);
439
440  // Make sure the bookmark bar is the same width as the toolbar
441  NSView* bookmarkBarView = [controller_ bookmarkView];
442  NSView* toolbarView = [controller_ toolbarView];
443  EXPECT_EQ([toolbarView frame].size.width,
444            [bookmarkBarView frame].size.width);
445}
446
447TEST_F(BrowserWindowControllerTest, TestTopRightForBubble) {
448  NSPoint p = [controller_ bookmarkBubblePoint];
449  NSRect all = [[controller_ window] frame];
450
451  // As a sanity check make sure the point is vaguely in the top right
452  // of the window.
453  EXPECT_GT(p.y, all.origin.y + (all.size.height/2));
454  EXPECT_GT(p.x, all.origin.x + (all.size.width/2));
455}
456
457// By the "zoom frame", we mean what Apple calls the "standard frame".
458TEST_F(BrowserWindowControllerTest, TestZoomFrame) {
459  NSWindow* window = [controller_ window];
460  ASSERT_TRUE(window);
461  NSRect screenFrame = [[window screen] visibleFrame];
462  ASSERT_FALSE(NSIsEmptyRect(screenFrame));
463
464  // Minimum zoomed width is the larger of 60% of available horizontal space or
465  // 60% of available vertical space, subject to available horizontal space.
466  CGFloat minZoomWidth =
467      std::min(std::max((CGFloat)0.6 * screenFrame.size.width,
468                        (CGFloat)0.6 * screenFrame.size.height),
469               screenFrame.size.width);
470
471  // |testFrame| is the size of the window we start out with, and |zoomFrame| is
472  // the one returned by |-windowWillUseStandardFrame:defaultFrame:|.
473  NSRect testFrame;
474  NSRect zoomFrame;
475
476  // 1. Test a case where it zooms the window both horizontally and vertically,
477  // and only moves it vertically. "+ 32", etc. are just arbitrary constants
478  // used to check that the window is moved properly and not just to the origin;
479  // they should be small enough to not shove windows off the screen.
480  testFrame.size.width = 0.5 * minZoomWidth;
481  testFrame.size.height = 0.5 * screenFrame.size.height;
482  testFrame.origin.x = screenFrame.origin.x + 32;  // See above.
483  testFrame.origin.y = screenFrame.origin.y + 23;
484  [window setFrame:testFrame display:NO];
485  zoomFrame = [controller_ windowWillUseStandardFrame:window
486                                         defaultFrame:screenFrame];
487  EXPECT_LE(minZoomWidth, zoomFrame.size.width);
488  EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
489  EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
490  EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
491
492  // 2. Test a case where it zooms the window only horizontally, and only moves
493  // it horizontally.
494  testFrame.size.width = 0.5 * minZoomWidth;
495  testFrame.size.height = screenFrame.size.height;
496  testFrame.origin.x = screenFrame.origin.x + screenFrame.size.width -
497                       testFrame.size.width;
498  testFrame.origin.y = screenFrame.origin.y;
499  [window setFrame:testFrame display:NO];
500  zoomFrame = [controller_ windowWillUseStandardFrame:window
501                                         defaultFrame:screenFrame];
502  EXPECT_LE(minZoomWidth, zoomFrame.size.width);
503  EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
504  EXPECT_EQ(screenFrame.origin.x + screenFrame.size.width -
505            zoomFrame.size.width, zoomFrame.origin.x);
506  EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
507
508  // 3. Test a case where it zooms the window only vertically, and only moves it
509  // vertically.
510  testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
511                                  screenFrame.size.width);
512  testFrame.size.height = 0.3 * screenFrame.size.height;
513  testFrame.origin.x = screenFrame.origin.x + 32;  // See above (in 1.).
514  testFrame.origin.y = screenFrame.origin.y + 123;
515  [window setFrame:testFrame display:NO];
516  zoomFrame = [controller_ windowWillUseStandardFrame:window
517                                         defaultFrame:screenFrame];
518  // Use the actual width of the window frame, since it's subject to rounding.
519  EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
520  EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
521  EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
522  EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
523
524  // 4. Test a case where zooming should do nothing (i.e., we're already at a
525  // zoomed frame).
526  testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
527                                  screenFrame.size.width);
528  testFrame.size.height = screenFrame.size.height;
529  testFrame.origin.x = screenFrame.origin.x + 32;  // See above (in 1.).
530  testFrame.origin.y = screenFrame.origin.y;
531  [window setFrame:testFrame display:NO];
532  zoomFrame = [controller_ windowWillUseStandardFrame:window
533                                         defaultFrame:screenFrame];
534  // Use the actual width of the window frame, since it's subject to rounding.
535  EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
536  EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
537  EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
538  EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
539}
540
541TEST_F(BrowserWindowControllerTest, TestFindBarOnTop) {
542  FindBarBridge bridge;
543  [controller_ addFindBar:bridge.find_bar_cocoa_controller()];
544
545  // Test that the Z-order of the find bar is on top of everything.
546  NSArray* subviews = [[[controller_ window] contentView] subviews];
547  NSUInteger findBar_index =
548      [subviews indexOfObject:[controller_ findBarView]];
549  EXPECT_NE(NSNotFound, findBar_index);
550  NSUInteger toolbar_index =
551      [subviews indexOfObject:[controller_ toolbarView]];
552  EXPECT_NE(NSNotFound, toolbar_index);
553  NSUInteger bookmark_index =
554      [subviews indexOfObject:[controller_ bookmarkView]];
555  EXPECT_NE(NSNotFound, bookmark_index);
556
557  EXPECT_GT(findBar_index, toolbar_index);
558  EXPECT_GT(findBar_index, bookmark_index);
559}
560
561// Tests that the sidebar view and devtools view are both non-opaque.
562TEST_F(BrowserWindowControllerTest, TestSplitViewsAreNotOpaque) {
563  // Add a subview to the sidebar view to mimic what happens when a tab is added
564  // to the window.  NSSplitView only marks itself as non-opaque when one of its
565  // subviews is non-opaque, so the test will not pass without this subview.
566  scoped_nsobject<NSView> view(
567      [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)]);
568  [[controller_ sidebarView] addSubview:view];
569
570  EXPECT_FALSE([[controller_ tabContentArea] isOpaque]);
571  EXPECT_FALSE([[controller_ devToolsView] isOpaque]);
572  EXPECT_FALSE([[controller_ sidebarView] isOpaque]);
573}
574
575// Tests that status bubble's base frame does move when devTools are docked.
576TEST_F(BrowserWindowControllerTest, TestStatusBubblePositioning) {
577  ASSERT_EQ(1U, [[[controller_ devToolsView] subviews] count]);
578
579  NSPoint bubbleOrigin = [controller_ statusBubbleBaseFrame].origin;
580
581  // Add a fake subview to devToolsView to emulate docked devTools.
582  scoped_nsobject<NSView> view(
583      [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)]);
584  [[controller_ devToolsView] addSubview:view];
585  [[controller_ devToolsView] adjustSubviews];
586
587  NSPoint bubbleOriginWithDevTools = [controller_ statusBubbleBaseFrame].origin;
588
589  // Make sure that status bubble frame is moved.
590  EXPECT_FALSE(NSEqualPoints(bubbleOrigin, bubbleOriginWithDevTools));
591}
592
593@interface BrowserWindowControllerFakeFullscreen : BrowserWindowController {
594 @private
595  // We release the window ourselves, so we don't have to rely on the unittest
596  // doing it for us.
597  scoped_nsobject<NSWindow> fullscreenWindow_;
598}
599@end
600
601class BrowserWindowFullScreenControllerTest : public CocoaTest {
602 public:
603  virtual void SetUp() {
604    CocoaTest::SetUp();
605    Browser* browser = browser_helper_.browser();
606    controller_ =
607        [[BrowserWindowControllerFakeFullscreen alloc] initWithBrowser:browser
608                                                         takeOwnership:NO];
609  }
610
611  virtual void TearDown() {
612    [controller_ close];
613    CocoaTest::TearDown();
614  }
615
616 public:
617  BrowserTestHelper browser_helper_;
618  BrowserWindowController* controller_;
619};
620
621@interface BrowserWindowController (PrivateAPI)
622- (BOOL)supportsFullscreen;
623@end
624
625// Check if the window is front most or if one of its child windows (such
626// as a status bubble) is front most.
627static bool IsFrontWindow(NSWindow *window) {
628  NSWindow* frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
629  return [frontmostWindow isEqual:window] ||
630         [[frontmostWindow parentWindow] isEqual:window];
631}
632
633TEST_F(BrowserWindowFullScreenControllerTest, TestFullscreen) {
634  EXPECT_FALSE([controller_ isFullscreen]);
635  [controller_ setFullscreen:YES];
636  EXPECT_TRUE([controller_ isFullscreen]);
637  [controller_ setFullscreen:NO];
638  EXPECT_FALSE([controller_ isFullscreen]);
639}
640
641// If this test fails, it is usually a sign that the bots have some sort of
642// problem (such as a modal dialog up).  This tests is a very useful canary, so
643// please do not mark it as flaky without first verifying that there are no bot
644// problems.
645TEST_F(BrowserWindowFullScreenControllerTest, TestActivate) {
646  EXPECT_FALSE([controller_ isFullscreen]);
647
648  [controller_ activate];
649  EXPECT_TRUE(IsFrontWindow([controller_ window]));
650
651  [controller_ setFullscreen:YES];
652  [controller_ activate];
653  EXPECT_TRUE(IsFrontWindow([controller_ createFullscreenWindow]));
654
655  // We have to cleanup after ourselves by unfullscreening.
656  [controller_ setFullscreen:NO];
657}
658
659@implementation BrowserWindowControllerFakeFullscreen
660// Override |-createFullscreenWindow| to return a dummy window. This isn't
661// needed to pass the test, but because the dummy window is only 100x100, it
662// prevents the real fullscreen window from flashing up and taking over the
663// whole screen. We have to return an actual window because |-layoutSubviews|
664// looks at the window's frame.
665- (NSWindow*)createFullscreenWindow {
666  if (fullscreenWindow_.get())
667    return fullscreenWindow_.get();
668
669  fullscreenWindow_.reset(
670      [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,400,400)
671                                  styleMask:NSBorderlessWindowMask
672                                    backing:NSBackingStoreBuffered
673                                      defer:NO]);
674  return fullscreenWindow_.get();
675}
676@end
677
678/* TODO(???): test other methods of BrowserWindowController */
679