Home | History | Annotate | Download | only in cocoa
      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 
     64 class 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 
     83 TEST_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 
    102 TEST_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 
    108 TEST_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 
    135 TEST_F(BrowserWindowControllerTest, TestTheme) {
    136   [controller_ userChangedTheme];
    137 }
    138 
    139 TEST_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.
    154 TEST_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 
    172 namespace {
    173 // Verifies that the toolbar, infobar, tab content area, and download shelf
    174 // completely fill the area under the tabstrip.
    175 void 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 
    204 TEST_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.
    331 TEST_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 
    374 TEST_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.
    434 TEST_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 
    447 TEST_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".
    458 TEST_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 
    541 TEST_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.
    562 TEST_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.
    576 TEST_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 
    601 class 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.
    627 static bool IsFrontWindow(NSWindow *window) {
    628   NSWindow* frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
    629   return [frontmostWindow isEqual:window] ||
    630          [[frontmostWindow parentWindow] isEqual:window];
    631 }
    632 
    633 TEST_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.
    645 TEST_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