Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / browser_window_controller_unittest.mm
blob891483f8ad5b3fd12f3682cfb9fbded201cad1f8
1 // Copyright 2012 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.
5 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
7 #include "base/mac/mac_util.h"
8 #import "base/mac/scoped_nsobject.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/ui/browser_list.h"
14 #include "chrome/browser/ui/browser_window.h"
15 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
16 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
17 #include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h"
18 #include "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
19 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
20 #include "chrome/browser/ui/host_desktop.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/test/test_utils.h"
25 #include "testing/gmock/include/gmock/gmock.h"
27 using ::testing::Return;
29 @interface BrowserWindowController (JustForTesting)
30 // Already defined in BWC.
31 - (void)saveWindowPositionIfNeeded;
32 - (void)layoutSubviews;
33 @end
35 @interface BrowserWindowController (ExposedForTesting)
36 // Implementations are below.
37 - (NSView*)infoBarContainerView;
38 - (NSView*)toolbarView;
39 - (NSView*)bookmarkView;
40 - (BOOL)bookmarkBarVisible;
41 @end
43 @implementation BrowserWindowController (ExposedForTesting)
44 - (NSView*)infoBarContainerView {
45   return [infoBarContainerController_ view];
48 - (NSView*)toolbarView {
49   return [toolbarController_ view];
52 - (NSView*)bookmarkView {
53   return [bookmarkBarController_ view];
56 - (NSView*)findBarView {
57   return [findBarCocoaController_ view];
60 - (BOOL)bookmarkBarVisible {
61   return [bookmarkBarController_ isVisible];
63 @end
65 class BrowserWindowControllerTest : public CocoaProfileTest {
66  public:
67   void SetUp() override {
68     CocoaProfileTest::SetUp();
69     ASSERT_TRUE(browser());
71     controller_ = [[BrowserWindowController alloc] initWithBrowser:browser()
72                                                      takeOwnership:NO];
73   }
75   void TearDown() override {
76     [controller_ close];
77     CocoaProfileTest::TearDown();
78   }
80  public:
81   BrowserWindowController* controller_;
84 TEST_F(BrowserWindowControllerTest, TestSaveWindowPosition) {
85   PrefService* prefs = profile()->GetPrefs();
86   ASSERT_TRUE(prefs != NULL);
88   // Check to make sure there is no existing pref for window placement.
89   const base::DictionaryValue* browser_window_placement =
90       prefs->GetDictionary(prefs::kBrowserWindowPlacement);
91   ASSERT_TRUE(browser_window_placement);
92   EXPECT_TRUE(browser_window_placement->empty());
94   // Ask the window to save its position, then check that a preference
95   // exists.
96   BrowserList::SetLastActive(browser());
97   [controller_ saveWindowPositionIfNeeded];
98   browser_window_placement =
99       prefs->GetDictionary(prefs::kBrowserWindowPlacement);
100   ASSERT_TRUE(browser_window_placement);
101   EXPECT_FALSE(browser_window_placement->empty());
104 TEST_F(BrowserWindowControllerTest, TestFullScreenWindow) {
105   // Confirm that |-createFullscreenWindow| doesn't return nil.
106   // See BrowserWindowFullScreenControllerTest for more fullscreen tests.
107   EXPECT_TRUE([controller_ createFullscreenWindow]);
110 TEST_F(BrowserWindowControllerTest, TestNormal) {
111   // Force the bookmark bar to be shown.
112   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
113   [controller_ browserWindow]->BookmarkBarStateChanged(
114       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
116   // Make sure a normal BrowserWindowController is, uh, normal.
117   EXPECT_TRUE([controller_ isTabbedWindow]);
118   EXPECT_TRUE([controller_ hasTabStrip]);
119   EXPECT_FALSE([controller_ hasTitleBar]);
120   EXPECT_TRUE([controller_ isBookmarkBarVisible]);
122   // And make sure a controller for a pop-up window is not normal.
123   // popup_browser will be owned by its window.
124   Browser* popup_browser(new Browser(
125       Browser::CreateParams(Browser::TYPE_POPUP, profile(),
126                             chrome::GetActiveDesktop())));
127   NSWindow* cocoaWindow = popup_browser->window()->GetNativeWindow();
128   BrowserWindowController* controller =
129       static_cast<BrowserWindowController*>([cocoaWindow windowController]);
130   ASSERT_TRUE([controller isKindOfClass:[BrowserWindowController class]]);
131   EXPECT_FALSE([controller isTabbedWindow]);
132   EXPECT_FALSE([controller hasTabStrip]);
133   EXPECT_TRUE([controller hasTitleBar]);
134   EXPECT_FALSE([controller isBookmarkBarVisible]);
135   [controller close];
138 TEST_F(BrowserWindowControllerTest, TestSetBounds) {
139   // Create a normal browser with bounds smaller than the minimum.
140   Browser::CreateParams params(Browser::TYPE_TABBED, profile(),
141                                chrome::GetActiveDesktop());
142   params.initial_bounds = gfx::Rect(0, 0, 50, 50);
143   Browser* browser = new Browser(params);
144   NSWindow* cocoaWindow = browser->window()->GetNativeWindow();
145   BrowserWindowController* controller =
146     static_cast<BrowserWindowController*>([cocoaWindow windowController]);
148   ASSERT_TRUE([controller isTabbedWindow]);
149   BrowserWindow* browser_window = [controller browserWindow];
150   EXPECT_EQ(browser_window, browser->window());
151   gfx::Rect bounds = browser_window->GetBounds();
152   EXPECT_EQ(400, bounds.width());
153   EXPECT_EQ(272, bounds.height());
155   // Try to set the bounds smaller than the minimum.
156   browser_window->SetBounds(gfx::Rect(0, 0, 50, 50));
157   bounds = browser_window->GetBounds();
158   EXPECT_EQ(400, bounds.width());
159   EXPECT_EQ(272, bounds.height());
161   [controller close];
164 TEST_F(BrowserWindowControllerTest, TestSetBoundsPopup) {
165   // Create a popup with bounds smaller than the minimum.
166   Browser::CreateParams params(Browser::TYPE_POPUP, profile(),
167                                chrome::GetActiveDesktop());
168   params.initial_bounds = gfx::Rect(0, 0, 50, 50);
169   Browser* browser = new Browser(params);
170   NSWindow* cocoaWindow = browser->window()->GetNativeWindow();
171   BrowserWindowController* controller =
172     static_cast<BrowserWindowController*>([cocoaWindow windowController]);
174   ASSERT_FALSE([controller isTabbedWindow]);
175   BrowserWindow* browser_window = [controller browserWindow];
176   EXPECT_EQ(browser_window, browser->window());
177   gfx::Rect bounds = browser_window->GetBounds();
178   EXPECT_EQ(100, bounds.width());
179   EXPECT_EQ(122, bounds.height());
181   // Try to set the bounds smaller than the minimum.
182   browser_window->SetBounds(gfx::Rect(0, 0, 50, 50));
183   bounds = browser_window->GetBounds();
184   EXPECT_EQ(100, bounds.width());
185   EXPECT_EQ(122, bounds.height());
187   [controller close];
190 TEST_F(BrowserWindowControllerTest, TestTheme) {
191   [controller_ userChangedTheme];
194 TEST_F(BrowserWindowControllerTest, BookmarkBarControllerIndirection) {
195   EXPECT_FALSE([controller_ isBookmarkBarVisible]);
197   // Explicitly show the bar. Can't use chrome::ToggleBookmarkBarWhenVisible()
198   // because of the notification issues.
199   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
201   [controller_ browserWindow]->BookmarkBarStateChanged(
202       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
203   EXPECT_TRUE([controller_ isBookmarkBarVisible]);
206 TEST_F(BrowserWindowControllerTest, BookmarkBarToggleRespectMinWindowHeight) {
207   Browser::CreateParams params(Browser::TYPE_TABBED, profile(),
208                                chrome::GetActiveDesktop());
209   params.initial_bounds = gfx::Rect(0, 0, 50, 280);
210   Browser* browser = new Browser(params);
211   NSWindow* cocoaWindow = browser->window()->GetNativeWindow();
212   BrowserWindowController* controller =
213    static_cast<BrowserWindowController*>([cocoaWindow windowController]);
214   BrowserWindow* browser_window = [controller browserWindow];
215   gfx::Rect bounds = browser_window->GetBounds();
216   EXPECT_EQ(280, bounds.height());
218   // Try to set the bounds smaller than the minimum.
219   // Explicitly show the bar. Can't use chrome::ToggleBookmarkBarWhenVisible()
220   // because of the notification issues.
221   [controller adjustWindowHeightBy:-20];
222   bounds = browser_window->GetBounds();
223   EXPECT_EQ(272, bounds.height());
225   [controller close];
228 #if 0
229 // TODO(jrg): This crashes trying to create the BookmarkBarController, adding
230 // an observer to the BookmarkModel.
231 TEST_F(BrowserWindowControllerTest, TestIncognitoWidthSpace) {
232   scoped_ptr<TestingProfile> incognito_profile(new TestingProfile());
233   incognito_profile->set_off_the_record(true);
234   scoped_ptr<Browser> browser(
235       new Browser(Browser::CreateParams(incognito_profile.get(),
236                                         chrome::GetActiveDesktop()));
237   controller_.reset([[BrowserWindowController alloc]
238                               initWithBrowser:browser.get()
239                                 takeOwnership:NO]);
241   NSRect tabFrame = [[controller_ tabStripView] frame];
242   [controller_ installIncognitoBadge];
243   NSRect newTabFrame = [[controller_ tabStripView] frame];
244   EXPECT_GT(tabFrame.size.width, newTabFrame.size.width);
246   controller_.release();
248 #endif
250 namespace {
252 // Returns the frame of the view in window coordinates.
253 NSRect FrameInWindowForView(NSView* view) {
254   return [[view superview] convertRect:[view frame] toView:nil];
257 // Whether the view's frame is within the bounds of the superview.
258 BOOL ViewContainmentValid(NSView* view) {
259   if (NSIsEmptyRect([view frame]))
260     return YES;
262   return NSContainsRect([[view superview] bounds], [view frame]);
265 // Checks the view hierarchy rooted at |view| to ensure that each view is
266 // properly contained.
267 BOOL ViewHierarchyContainmentValid(NSView* view) {
268   // TODO(erikchen): Fix these views to have correct containment.
269   // http://crbug.com/397665.
270   if ([view isKindOfClass:NSClassFromString(@"DownloadShelfView")])
271     return YES;
272   if ([view isKindOfClass:NSClassFromString(@"BookmarkBarToolbarView")])
273     return YES;
274   if ([view isKindOfClass:NSClassFromString(@"BrowserActionsContainerView")])
275     return YES;
277   if (!ViewContainmentValid(view)) {
278     LOG(ERROR) << "View violates containment: " <<
279         [[view description] UTF8String];
280     return NO;
281   }
283   for (NSView* subview in [view subviews]) {
284     BOOL result = ViewHierarchyContainmentValid(subview);
285     if (!result)
286       return NO;
287   }
289   return YES;
292 // Verifies that the toolbar, infobar, tab content area, and download shelf
293 // completely fill the area under the tabstrip.
294 void CheckViewPositions(BrowserWindowController* controller) {
295   EXPECT_TRUE(ViewHierarchyContainmentValid([[controller window] contentView]));
297   NSRect contentView = FrameInWindowForView([[controller window] contentView]);
298   NSRect tabstrip = FrameInWindowForView([controller tabStripView]);
299   NSRect toolbar = FrameInWindowForView([controller toolbarView]);
300   NSRect infobar = FrameInWindowForView([controller infoBarContainerView]);
301   NSRect tabContent = FrameInWindowForView([controller tabContentArea]);
302   NSRect download = NSZeroRect;
303   if ([[[controller downloadShelf] view] superview])
304     download = [[[controller downloadShelf] view] frame];
306   EXPECT_EQ(NSMinY(contentView), NSMinY(download));
307   EXPECT_EQ(NSMaxY(download), NSMinY(tabContent));
308   EXPECT_EQ(NSMaxY(tabContent), NSMinY(infobar));
310   // Bookmark bar frame is random memory when hidden.
311   if ([controller bookmarkBarVisible]) {
312     NSRect bookmark = [[controller bookmarkView] frame];
313     EXPECT_EQ(NSMaxY(infobar), NSMinY(bookmark));
314     EXPECT_EQ(NSMaxY(bookmark), NSMinY(toolbar));
315     EXPECT_FALSE([[controller bookmarkView] isHidden]);
316   } else {
317     EXPECT_EQ(NSMaxY(infobar), NSMinY(toolbar));
318     EXPECT_TRUE([[controller bookmarkView] isHidden]);
319   }
321   // Toolbar should start immediately under the tabstrip, but the tabstrip is
322   // not necessarily fixed with respect to the content view.
323   EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar));
326 }  // end namespace
328 TEST_F(BrowserWindowControllerTest, TestAdjustWindowHeight) {
329   NSWindow* window = [controller_ window];
330   NSRect workarea = [[window screen] visibleFrame];
332   // Place the window well above the bottom of the screen and try to adjust its
333   // height. It should change appropriately (and only downwards). Then get it to
334   // shrink by the same amount; it should return to its original state.
335   NSRect initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 100,
336                                    200, 280);
337   [window setFrame:initialFrame display:YES];
338   [controller_ resetWindowGrowthState];
339   [controller_ adjustWindowHeightBy:40];
340   NSRect finalFrame = [window frame];
341   EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
342   EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
343   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
344   [controller_ adjustWindowHeightBy:-40];
345   finalFrame = [window frame];
346   EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
347   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
349   // Place the window at the bottom of the screen and try again.  Its height
350   // should still change, but it should not grow down below the work area; it
351   // should instead move upwards. Then shrink it and make sure it goes back to
352   // the way it was.
353   initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 280);
354   [window setFrame:initialFrame display:YES];
355   [controller_ resetWindowGrowthState];
356   [controller_ adjustWindowHeightBy:40];
357   finalFrame = [window frame];
358   EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
359   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
360   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
361   [controller_ adjustWindowHeightBy:-40];
362   finalFrame = [window frame];
363   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
364   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
366   // Put the window slightly offscreen and try again.  The height should not
367   // change this time.
368   initialFrame = NSMakeRect(workarea.origin.x - 10, 0, 200, 280);
369   [window setFrame:initialFrame display:YES];
370   [controller_ resetWindowGrowthState];
371   [controller_ adjustWindowHeightBy:40];
372   EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
373   [controller_ adjustWindowHeightBy:-40];
374   EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
376   // Make the window the same size as the workarea.  Resizing both larger and
377   // smaller should have no effect.
378   [window setFrame:workarea display:YES];
379   [controller_ resetWindowGrowthState];
380   [controller_ adjustWindowHeightBy:40];
381   EXPECT_TRUE(NSEqualRects([window frame], workarea));
382   [controller_ adjustWindowHeightBy:-40];
383   EXPECT_TRUE(NSEqualRects([window frame], workarea));
385   // Make the window smaller than the workarea and place it near the bottom of
386   // the workarea.  The window should grow down until it hits the bottom and
387   // then continue to grow up. Then shrink it, and it should return to where it
388   // was.
389   initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 5,
390                             200, 280);
391   [window setFrame:initialFrame display:YES];
392   [controller_ resetWindowGrowthState];
393   [controller_ adjustWindowHeightBy:40];
394   finalFrame = [window frame];
395   EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
396   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
397   [controller_ adjustWindowHeightBy:-40];
398   finalFrame = [window frame];
399   EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
400   EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
402   // Inset the window slightly from the workarea.  It should not grow to be
403   // larger than the workarea. Shrink it; it should return to where it started.
404   initialFrame = NSInsetRect(workarea, 0, 5);
405   [window setFrame:initialFrame display:YES];
406   [controller_ resetWindowGrowthState];
407   [controller_ adjustWindowHeightBy:40];
408   finalFrame = [window frame];
409   EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
410   EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
411   [controller_ adjustWindowHeightBy:-40];
412   finalFrame = [window frame];
413   EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
414   EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
416   // Place the window at the bottom of the screen and grow; it should grow
417   // upwards. Move the window off the bottom, then shrink. It should then shrink
418   // from the bottom.
419   initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 280);
420   [window setFrame:initialFrame display:YES];
421   [controller_ resetWindowGrowthState];
422   [controller_ adjustWindowHeightBy:40];
423   finalFrame = [window frame];
424   EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
425   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
426   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
427   NSPoint oldOrigin = initialFrame.origin;
428   NSPoint newOrigin = NSMakePoint(oldOrigin.x, oldOrigin.y + 10);
429   [window setFrameOrigin:newOrigin];
430   initialFrame = [window frame];
431   EXPECT_FLOAT_EQ(NSMinY(initialFrame), oldOrigin.y + 10);
432   [controller_ adjustWindowHeightBy:-40];
433   finalFrame = [window frame];
434   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame) + 40);
435   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) - 40);
437   // Do the "inset" test above, but using multiple calls to
438   // |-adjustWindowHeightBy|; the result should be the same.
439   initialFrame = NSInsetRect(workarea, 0, 5);
440   [window setFrame:initialFrame display:YES];
441   [controller_ resetWindowGrowthState];
442   for (int i = 0; i < 8; i++)
443     [controller_ adjustWindowHeightBy:5];
444   finalFrame = [window frame];
445   EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
446   EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
447   for (int i = 0; i < 8; i++)
448     [controller_ adjustWindowHeightBy:-5];
449   finalFrame = [window frame];
450   EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
451   EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
454 // Test to make sure resizing and relaying-out subviews works correctly.
455 TEST_F(BrowserWindowControllerTest, TestResizeViews) {
456   TabStripView* tabstrip = [controller_ tabStripView];
457   NSView* contentView = [[tabstrip window] contentView];
458   NSView* toolbar = [controller_ toolbarView];
459   NSView* infobar = [controller_ infoBarContainerView];
461   // We need to muck with the views a bit to put us in a consistent state before
462   // we start resizing.  In particular, we need to move the tab strip to be
463   // immediately above the content area, since we layout views to be directly
464   // under the tab strip.
465   NSRect tabstripFrame = [tabstrip frame];
466   tabstripFrame.origin.y = NSMaxY([contentView frame]);
467   [tabstrip setFrame:tabstripFrame];
469   // Make the download shelf and set its initial height to 0.
470   [controller_ createAndAddDownloadShelf];
471   NSView* download = [[controller_ downloadShelf] view];
472   NSRect downloadFrame = [download frame];
473   downloadFrame.size.height = 0;
474   [download setFrame:downloadFrame];
476   // Force a layout and check each view's frame.
477   [controller_ layoutSubviews];
478   CheckViewPositions(controller_);
480   // Expand the infobar to 60px and recheck
481   [controller_ resizeView:infobar newHeight:60];
482   CheckViewPositions(controller_);
484   // Expand the toolbar to 64px and recheck
485   [controller_ resizeView:toolbar newHeight:64];
486   CheckViewPositions(controller_);
488   // Add a 30px download shelf and recheck
489   [controller_ resizeView:download newHeight:30];
490   CheckViewPositions(controller_);
492   // Shrink the infobar to 0px and toolbar to 39px and recheck
493   [controller_ resizeView:infobar newHeight:0];
494   [controller_ resizeView:toolbar newHeight:39];
495   CheckViewPositions(controller_);
498 TEST_F(BrowserWindowControllerTest, TestResizeViewsWithBookmarkBar) {
499   // Force a display of the bookmark bar.
500   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
501   [controller_ browserWindow]->BookmarkBarStateChanged(
502       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
504   TabStripView* tabstrip = [controller_ tabStripView];
505   NSView* contentView = [[tabstrip window] contentView];
506   NSView* toolbar = [controller_ toolbarView];
507   NSView* bookmark = [controller_ bookmarkView];
508   NSView* infobar = [controller_ infoBarContainerView];
510   // We need to muck with the views a bit to put us in a consistent state before
511   // we start resizing.  In particular, we need to move the tab strip to be
512   // immediately above the content area, since we layout views to be directly
513   // under the tab strip.
514   NSRect tabstripFrame = [tabstrip frame];
515   tabstripFrame.origin.y = NSMaxY([contentView frame]);
516   [tabstrip setFrame:tabstripFrame];
518   // The download shelf is created lazily.  Force-create it and set its initial
519   // height to 0.
520   [controller_ createAndAddDownloadShelf];
521   NSView* download = [[controller_ downloadShelf] view];
522   NSRect downloadFrame = [download frame];
523   downloadFrame.size.height = 0;
524   [download setFrame:downloadFrame];
526   // Force a layout and check each view's frame.
527   [controller_ layoutSubviews];
528   CheckViewPositions(controller_);
530   // Add the bookmark bar and recheck.
531   [controller_ resizeView:bookmark newHeight:40];
532   CheckViewPositions(controller_);
534   // Expand the infobar to 60px and recheck
535   [controller_ resizeView:infobar newHeight:60];
536   CheckViewPositions(controller_);
538   // Expand the toolbar to 64px and recheck
539   [controller_ resizeView:toolbar newHeight:64];
540   CheckViewPositions(controller_);
542   // Add a 30px download shelf and recheck
543   [controller_ resizeView:download newHeight:30];
544   CheckViewPositions(controller_);
546   // Remove the bookmark bar and recheck
547   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, false);
548   [controller_ browserWindow]->BookmarkBarStateChanged(
549       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
550   [controller_ resizeView:bookmark newHeight:0];
551   CheckViewPositions(controller_);
553   // Shrink the infobar to 0px and toolbar to 39px and recheck
554   [controller_ resizeView:infobar newHeight:0];
555   [controller_ resizeView:toolbar newHeight:39];
556   CheckViewPositions(controller_);
559 // Make sure, by default, the bookmark bar and the toolbar are the same width.
560 TEST_F(BrowserWindowControllerTest, BookmarkBarIsSameWidth) {
561   // Set the pref to the bookmark bar is visible when the toolbar is
562   // first created.
563   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
565   // Make sure the bookmark bar is the same width as the toolbar
566   NSView* bookmarkBarView = [controller_ bookmarkView];
567   NSView* toolbarView = [controller_ toolbarView];
568   EXPECT_EQ([toolbarView frame].size.width,
569             [bookmarkBarView frame].size.width);
572 TEST_F(BrowserWindowControllerTest, TestTopRightForBubble) {
573   // The bookmark bubble must be attached to a lit and visible star.
574   [controller_ setStarredState:YES];
575   NSPoint p = [controller_ bookmarkBubblePoint];  // Window coordinates.
576   NSRect all = [[controller_ window] frame];      // Screen coordinates.
578   // As a sanity check make sure the point is vaguely in the top right
579   // of the window.
580   EXPECT_GT(p.y, all.size.height / 2);
581   EXPECT_GT(p.x, all.size.width / 2);
584 // By the "zoom frame", we mean what Apple calls the "standard frame".
585 TEST_F(BrowserWindowControllerTest, TestZoomFrame) {
586   NSWindow* window = [controller_ window];
587   ASSERT_TRUE(window);
588   NSRect screenFrame = [[window screen] visibleFrame];
589   ASSERT_FALSE(NSIsEmptyRect(screenFrame));
591   // Minimum zoomed width is the larger of 60% of available horizontal space or
592   // 60% of available vertical space, subject to available horizontal space.
593   CGFloat minZoomWidth =
594       std::min(std::max((CGFloat)0.6 * screenFrame.size.width,
595                         (CGFloat)0.6 * screenFrame.size.height),
596                screenFrame.size.width);
598   // |testFrame| is the size of the window we start out with, and |zoomFrame| is
599   // the one returned by |-windowWillUseStandardFrame:defaultFrame:|.
600   NSRect testFrame;
601   NSRect zoomFrame;
603   // 1. Test a case where it zooms the window both horizontally and vertically,
604   // and only moves it vertically. "+ 32", etc. are just arbitrary constants
605   // used to check that the window is moved properly and not just to the origin;
606   // they should be small enough to not shove windows off the screen.
607   testFrame.size.width = 0.5 * minZoomWidth;
608   testFrame.size.height = 0.5 * screenFrame.size.height;
609   testFrame.origin.x = screenFrame.origin.x + 32;  // See above.
610   testFrame.origin.y = screenFrame.origin.y + 23;
611   [window setFrame:testFrame display:NO];
612   zoomFrame = [controller_ windowWillUseStandardFrame:window
613                                          defaultFrame:screenFrame];
614   EXPECT_LE(minZoomWidth, zoomFrame.size.width);
615   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
616   EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
617   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
619   // 2. Test a case where it zooms the window only horizontally, and only moves
620   // it horizontally.
621   testFrame.size.width = 0.5 * minZoomWidth;
622   testFrame.size.height = screenFrame.size.height;
623   testFrame.origin.x = screenFrame.origin.x + screenFrame.size.width -
624                        testFrame.size.width;
625   testFrame.origin.y = screenFrame.origin.y;
626   [window setFrame:testFrame display:NO];
627   zoomFrame = [controller_ windowWillUseStandardFrame:window
628                                          defaultFrame:screenFrame];
629   EXPECT_LE(minZoomWidth, zoomFrame.size.width);
630   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
631   EXPECT_EQ(screenFrame.origin.x + screenFrame.size.width -
632             zoomFrame.size.width, zoomFrame.origin.x);
633   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
635   // 3. Test a case where it zooms the window only vertically, and only moves it
636   // vertically.
637   testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
638                                   screenFrame.size.width);
639   testFrame.size.height = 0.3 * screenFrame.size.height;
640   testFrame.origin.x = screenFrame.origin.x + 32;  // See above (in 1.).
641   testFrame.origin.y = screenFrame.origin.y + 123;
642   [window setFrame:testFrame display:NO];
643   zoomFrame = [controller_ windowWillUseStandardFrame:window
644                                          defaultFrame:screenFrame];
645   // Use the actual width of the window frame, since it's subject to rounding.
646   EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
647   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
648   EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
649   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
651   // 4. Test a case where zooming should do nothing (i.e., we're already at a
652   // zoomed frame).
653   testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
654                                   screenFrame.size.width);
655   testFrame.size.height = screenFrame.size.height;
656   testFrame.origin.x = screenFrame.origin.x + 32;  // See above (in 1.).
657   testFrame.origin.y = screenFrame.origin.y;
658   [window setFrame:testFrame display:NO];
659   zoomFrame = [controller_ windowWillUseStandardFrame:window
660                                          defaultFrame:screenFrame];
661   // Use the actual width of the window frame, since it's subject to rounding.
662   EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
663   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
664   EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
665   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
668 TEST_F(BrowserWindowControllerTest, TestFindBarOnTop) {
669   FindBarBridge bridge(NULL);
670   [controller_ addFindBar:bridge.find_bar_cocoa_controller()];
672   // Test that the Z-order of the find bar is on top of everything.
673   NSArray* subviews = [controller_.chromeContentView subviews];
674   NSUInteger findBar_index =
675       [subviews indexOfObject:[controller_ findBarView]];
676   EXPECT_NE(NSNotFound, findBar_index);
677   NSUInteger toolbar_index =
678       [subviews indexOfObject:[controller_ toolbarView]];
679   EXPECT_NE(NSNotFound, toolbar_index);
680   NSUInteger bookmark_index =
681       [subviews indexOfObject:[controller_ bookmarkView]];
682   EXPECT_NE(NSNotFound, bookmark_index);
684   EXPECT_GT(findBar_index, toolbar_index);
685   EXPECT_GT(findBar_index, bookmark_index);
688 // Verify that hit testing works correctly when the bookmark bar overlaps
689 // web contents.
690 TEST_F(BrowserWindowControllerTest, BookmarkBarHitTest) {
691   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
692   [controller_ browserWindow]->BookmarkBarStateChanged(
693       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
695   NSView* bookmarkView = [controller_ bookmarkView];
696   NSView* contentView = [[controller_ window] contentView];
697   NSPoint point = [bookmarkView convertPoint:NSMakePoint(1, 1)
698                                       toView:[contentView superview]];
700   EXPECT_TRUE([[contentView hitTest:point] isDescendantOf:bookmarkView]);
703 @interface BrowserWindowControllerFakeFullscreen : BrowserWindowController {
704  @private
705   // We release the window ourselves, so we don't have to rely on the unittest
706   // doing it for us.
707   base::scoped_nsobject<NSWindow> testFullscreenWindow_;
709 @end
711 class BrowserWindowFullScreenControllerTest : public CocoaProfileTest {
712  public:
713   void SetUp() override {
714     CocoaProfileTest::SetUp();
715     ASSERT_TRUE(browser());
717     controller_ =
718         [[BrowserWindowControllerFakeFullscreen alloc] initWithBrowser:browser()
719                                                          takeOwnership:NO];
720   }
722   void TearDown() override {
723     [controller_ close];
724     CocoaProfileTest::TearDown();
725   }
727  public:
728   BrowserWindowController* controller_;
731 // Check if the window is front most or if one of its child windows (such
732 // as a status bubble) is front most.
733 static bool IsFrontWindow(NSWindow* window) {
734   NSWindow* frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
735   return [frontmostWindow isEqual:window] ||
736          [[frontmostWindow parentWindow] isEqual:window];
739 void WaitForFullScreenTransition() {
740   content::WindowedNotificationObserver observer(
741       chrome::NOTIFICATION_FULLSCREEN_CHANGED,
742       content::NotificationService::AllSources());
743   observer.Wait();
746 // http://crbug.com/53586
747 TEST_F(BrowserWindowFullScreenControllerTest, DISABLED_TestFullscreen) {
748   [controller_ showWindow:nil];
749   EXPECT_FALSE([controller_ isInAnyFullscreenMode]);
751   [controller_ enterBrowserFullscreenWithToolbar:YES];
752   WaitForFullScreenTransition();
753   EXPECT_TRUE([controller_ isInAnyFullscreenMode]);
755   [controller_ exitAnyFullscreen];
756   WaitForFullScreenTransition();
757   EXPECT_FALSE([controller_ isInAnyFullscreenMode]);
760 // If this test fails, it is usually a sign that the bots have some sort of
761 // problem (such as a modal dialog up).  This tests is a very useful canary, so
762 // please do not mark it as flaky without first verifying that there are no bot
763 // problems.
764 // http://crbug.com/53586
765 TEST_F(BrowserWindowFullScreenControllerTest, DISABLED_TestActivate) {
766   [controller_ showWindow:nil];
768   EXPECT_FALSE([controller_ isInAnyFullscreenMode]);
770   [controller_ activate];
771   EXPECT_TRUE(IsFrontWindow([controller_ window]));
773   [controller_ enterBrowserFullscreenWithToolbar:YES];
774   WaitForFullScreenTransition();
775   [controller_ activate];
777   // No fullscreen window on 10.7+.
778   if (base::mac::IsOSSnowLeopard())
779     EXPECT_TRUE(IsFrontWindow([controller_ createFullscreenWindow]));
781   // We have to cleanup after ourselves by unfullscreening.
782   [controller_ exitAnyFullscreen];
783   WaitForFullScreenTransition();
786 @implementation BrowserWindowControllerFakeFullscreen
787 // Override |-createFullscreenWindow| to return a dummy window. This isn't
788 // needed to pass the test, but because the dummy window is only 100x100, it
789 // prevents the real fullscreen window from flashing up and taking over the
790 // whole screen. We have to return an actual window because |-layoutSubviews|
791 // looks at the window's frame.
792 - (NSWindow*)createFullscreenWindow {
793   if (testFullscreenWindow_.get())
794     return testFullscreenWindow_.get();
796   testFullscreenWindow_.reset(
797       [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,400,400)
798                                   styleMask:NSBorderlessWindowMask
799                                     backing:NSBackingStoreBuffered
800                                       defer:NO]);
801   [[testFullscreenWindow_ contentView] setWantsLayer:YES];
802   return testFullscreenWindow_.get();
804 @end
806 /* TODO(???): test other methods of BrowserWindowController */