Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / browser_window_controller_unittest.mm
blobe1a1cbf6be7de337b73a268f33f4f38f2ade326e
1 // Copyright (c) 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 #if 0
207 // TODO(jrg): This crashes trying to create the BookmarkBarController, adding
208 // an observer to the BookmarkModel.
209 TEST_F(BrowserWindowControllerTest, TestIncognitoWidthSpace) {
210   scoped_ptr<TestingProfile> incognito_profile(new TestingProfile());
211   incognito_profile->set_off_the_record(true);
212   scoped_ptr<Browser> browser(
213       new Browser(Browser::CreateParams(incognito_profile.get(),
214                                         chrome::GetActiveDesktop()));
215   controller_.reset([[BrowserWindowController alloc]
216                               initWithBrowser:browser.get()
217                                 takeOwnership:NO]);
219   NSRect tabFrame = [[controller_ tabStripView] frame];
220   [controller_ installIncognitoBadge];
221   NSRect newTabFrame = [[controller_ tabStripView] frame];
222   EXPECT_GT(tabFrame.size.width, newTabFrame.size.width);
224   controller_.release();
226 #endif
228 namespace {
230 // Returns the frame of the view in window coordinates.
231 NSRect FrameInWindowForView(NSView* view) {
232   return [[view superview] convertRect:[view frame] toView:nil];
235 // Whether the view's frame is within the bounds of the superview.
236 BOOL ViewContainmentValid(NSView* view) {
237   if (NSIsEmptyRect([view frame]))
238     return YES;
240   return NSContainsRect([[view superview] bounds], [view frame]);
243 // Checks the view hierarchy rooted at |view| to ensure that each view is
244 // properly contained.
245 BOOL ViewHierarchyContainmentValid(NSView* view) {
246   // TODO(erikchen): Fix these views to have correct containment.
247   // http://crbug.com/397665.
248   if ([view isKindOfClass:NSClassFromString(@"DownloadShelfView")])
249     return YES;
250   if ([view isKindOfClass:NSClassFromString(@"BookmarkBarToolbarView")])
251     return YES;
252   if ([view isKindOfClass:NSClassFromString(@"BrowserActionsContainerView")])
253     return YES;
255   if (!ViewContainmentValid(view)) {
256     LOG(ERROR) << "View violates containment: " <<
257         [[view description] UTF8String];
258     return NO;
259   }
261   for (NSView* subview in [view subviews]) {
262     BOOL result = ViewHierarchyContainmentValid(subview);
263     if (!result)
264       return NO;
265   }
267   return YES;
270 // Verifies that the toolbar, infobar, tab content area, and download shelf
271 // completely fill the area under the tabstrip.
272 void CheckViewPositions(BrowserWindowController* controller) {
273   EXPECT_TRUE(ViewHierarchyContainmentValid([[controller window] contentView]));
275   NSRect contentView = FrameInWindowForView([[controller window] contentView]);
276   NSRect tabstrip = FrameInWindowForView([controller tabStripView]);
277   NSRect toolbar = FrameInWindowForView([controller toolbarView]);
278   NSRect infobar = FrameInWindowForView([controller infoBarContainerView]);
279   NSRect tabContent = FrameInWindowForView([controller tabContentArea]);
280   NSRect download = NSZeroRect;
281   if ([[[controller downloadShelf] view] superview])
282     download = [[[controller downloadShelf] view] frame];
284   EXPECT_EQ(NSMinY(contentView), NSMinY(download));
285   EXPECT_EQ(NSMaxY(download), NSMinY(tabContent));
286   EXPECT_EQ(NSMaxY(tabContent), NSMinY(infobar));
288   // Bookmark bar frame is random memory when hidden.
289   if ([controller bookmarkBarVisible]) {
290     NSRect bookmark = [[controller bookmarkView] frame];
291     EXPECT_EQ(NSMaxY(infobar), NSMinY(bookmark));
292     EXPECT_EQ(NSMaxY(bookmark), NSMinY(toolbar));
293     EXPECT_FALSE([[controller bookmarkView] isHidden]);
294   } else {
295     EXPECT_EQ(NSMaxY(infobar), NSMinY(toolbar));
296     EXPECT_TRUE([[controller bookmarkView] isHidden]);
297   }
299   // Toolbar should start immediately under the tabstrip, but the tabstrip is
300   // not necessarily fixed with respect to the content view.
301   EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar));
304 }  // end namespace
306 TEST_F(BrowserWindowControllerTest, TestAdjustWindowHeight) {
307   NSWindow* window = [controller_ window];
308   NSRect workarea = [[window screen] visibleFrame];
310   // Place the window well above the bottom of the screen and try to adjust its
311   // height. It should change appropriately (and only downwards). Then get it to
312   // shrink by the same amount; it should return to its original state.
313   NSRect initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 100,
314                                    200, 200);
315   [window setFrame:initialFrame display:YES];
316   [controller_ resetWindowGrowthState];
317   [controller_ adjustWindowHeightBy:40];
318   NSRect finalFrame = [window frame];
319   EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
320   EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
321   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
322   [controller_ adjustWindowHeightBy:-40];
323   finalFrame = [window frame];
324   EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
325   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
327   // Place the window at the bottom of the screen and try again.  Its height
328   // should still change, but it should not grow down below the work area; it
329   // should instead move upwards. Then shrink it and make sure it goes back to
330   // the way it was.
331   initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
332   [window setFrame:initialFrame display:YES];
333   [controller_ resetWindowGrowthState];
334   [controller_ adjustWindowHeightBy:40];
335   finalFrame = [window frame];
336   EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
337   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
338   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
339   [controller_ adjustWindowHeightBy:-40];
340   finalFrame = [window frame];
341   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
342   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
344   // Put the window slightly offscreen and try again.  The height should not
345   // change this time.
346   initialFrame = NSMakeRect(workarea.origin.x - 10, 0, 200, 200);
347   [window setFrame:initialFrame display:YES];
348   [controller_ resetWindowGrowthState];
349   [controller_ adjustWindowHeightBy:40];
350   EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
351   [controller_ adjustWindowHeightBy:-40];
352   EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
354   // Make the window the same size as the workarea.  Resizing both larger and
355   // smaller should have no effect.
356   [window setFrame:workarea display:YES];
357   [controller_ resetWindowGrowthState];
358   [controller_ adjustWindowHeightBy:40];
359   EXPECT_TRUE(NSEqualRects([window frame], workarea));
360   [controller_ adjustWindowHeightBy:-40];
361   EXPECT_TRUE(NSEqualRects([window frame], workarea));
363   // Make the window smaller than the workarea and place it near the bottom of
364   // the workarea.  The window should grow down until it hits the bottom and
365   // then continue to grow up. Then shrink it, and it should return to where it
366   // was.
367   initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 5,
368                             200, 200);
369   [window setFrame:initialFrame display:YES];
370   [controller_ resetWindowGrowthState];
371   [controller_ adjustWindowHeightBy:40];
372   finalFrame = [window frame];
373   EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
374   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
375   [controller_ adjustWindowHeightBy:-40];
376   finalFrame = [window frame];
377   EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
378   EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
380   // Inset the window slightly from the workarea.  It should not grow to be
381   // larger than the workarea. Shrink it; it should return to where it started.
382   initialFrame = NSInsetRect(workarea, 0, 5);
383   [window setFrame:initialFrame display:YES];
384   [controller_ resetWindowGrowthState];
385   [controller_ adjustWindowHeightBy:40];
386   finalFrame = [window frame];
387   EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
388   EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
389   [controller_ adjustWindowHeightBy:-40];
390   finalFrame = [window frame];
391   EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
392   EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
394   // Place the window at the bottom of the screen and grow; it should grow
395   // upwards. Move the window off the bottom, then shrink. It should then shrink
396   // from the bottom.
397   initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
398   [window setFrame:initialFrame display:YES];
399   [controller_ resetWindowGrowthState];
400   [controller_ adjustWindowHeightBy:40];
401   finalFrame = [window frame];
402   EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
403   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
404   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
405   NSPoint oldOrigin = initialFrame.origin;
406   NSPoint newOrigin = NSMakePoint(oldOrigin.x, oldOrigin.y + 10);
407   [window setFrameOrigin:newOrigin];
408   initialFrame = [window frame];
409   EXPECT_FLOAT_EQ(NSMinY(initialFrame), oldOrigin.y + 10);
410   [controller_ adjustWindowHeightBy:-40];
411   finalFrame = [window frame];
412   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame) + 40);
413   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) - 40);
415   // Do the "inset" test above, but using multiple calls to
416   // |-adjustWindowHeightBy|; the result should be the same.
417   initialFrame = NSInsetRect(workarea, 0, 5);
418   [window setFrame:initialFrame display:YES];
419   [controller_ resetWindowGrowthState];
420   for (int i = 0; i < 8; i++)
421     [controller_ adjustWindowHeightBy:5];
422   finalFrame = [window frame];
423   EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
424   EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
425   for (int i = 0; i < 8; i++)
426     [controller_ adjustWindowHeightBy:-5];
427   finalFrame = [window frame];
428   EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
429   EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
432 // Test to make sure resizing and relaying-out subviews works correctly.
433 TEST_F(BrowserWindowControllerTest, TestResizeViews) {
434   TabStripView* tabstrip = [controller_ tabStripView];
435   NSView* contentView = [[tabstrip window] contentView];
436   NSView* toolbar = [controller_ toolbarView];
437   NSView* infobar = [controller_ infoBarContainerView];
439   // We need to muck with the views a bit to put us in a consistent state before
440   // we start resizing.  In particular, we need to move the tab strip to be
441   // immediately above the content area, since we layout views to be directly
442   // under the tab strip.
443   NSRect tabstripFrame = [tabstrip frame];
444   tabstripFrame.origin.y = NSMaxY([contentView frame]);
445   [tabstrip setFrame:tabstripFrame];
447   // Make the download shelf and set its initial height to 0.
448   [controller_ createAndAddDownloadShelf];
449   NSView* download = [[controller_ downloadShelf] view];
450   NSRect downloadFrame = [download frame];
451   downloadFrame.size.height = 0;
452   [download setFrame:downloadFrame];
454   // Force a layout and check each view's frame.
455   [controller_ layoutSubviews];
456   CheckViewPositions(controller_);
458   // Expand the infobar to 60px and recheck
459   [controller_ resizeView:infobar newHeight:60];
460   CheckViewPositions(controller_);
462   // Expand the toolbar to 64px and recheck
463   [controller_ resizeView:toolbar newHeight:64];
464   CheckViewPositions(controller_);
466   // Add a 30px download shelf and recheck
467   [controller_ resizeView:download newHeight:30];
468   CheckViewPositions(controller_);
470   // Shrink the infobar to 0px and toolbar to 39px and recheck
471   [controller_ resizeView:infobar newHeight:0];
472   [controller_ resizeView:toolbar newHeight:39];
473   CheckViewPositions(controller_);
476 TEST_F(BrowserWindowControllerTest, TestResizeViewsWithBookmarkBar) {
477   // Force a display of the bookmark bar.
478   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
479   [controller_ browserWindow]->BookmarkBarStateChanged(
480       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
482   TabStripView* tabstrip = [controller_ tabStripView];
483   NSView* contentView = [[tabstrip window] contentView];
484   NSView* toolbar = [controller_ toolbarView];
485   NSView* bookmark = [controller_ bookmarkView];
486   NSView* infobar = [controller_ infoBarContainerView];
488   // We need to muck with the views a bit to put us in a consistent state before
489   // we start resizing.  In particular, we need to move the tab strip to be
490   // immediately above the content area, since we layout views to be directly
491   // under the tab strip.
492   NSRect tabstripFrame = [tabstrip frame];
493   tabstripFrame.origin.y = NSMaxY([contentView frame]);
494   [tabstrip setFrame:tabstripFrame];
496   // The download shelf is created lazily.  Force-create it and set its initial
497   // height to 0.
498   [controller_ createAndAddDownloadShelf];
499   NSView* download = [[controller_ downloadShelf] view];
500   NSRect downloadFrame = [download frame];
501   downloadFrame.size.height = 0;
502   [download setFrame:downloadFrame];
504   // Force a layout and check each view's frame.
505   [controller_ layoutSubviews];
506   CheckViewPositions(controller_);
508   // Add the bookmark bar and recheck.
509   [controller_ resizeView:bookmark newHeight:40];
510   CheckViewPositions(controller_);
512   // Expand the infobar to 60px and recheck
513   [controller_ resizeView:infobar newHeight:60];
514   CheckViewPositions(controller_);
516   // Expand the toolbar to 64px and recheck
517   [controller_ resizeView:toolbar newHeight:64];
518   CheckViewPositions(controller_);
520   // Add a 30px download shelf and recheck
521   [controller_ resizeView:download newHeight:30];
522   CheckViewPositions(controller_);
524   // Remove the bookmark bar and recheck
525   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, false);
526   [controller_ browserWindow]->BookmarkBarStateChanged(
527       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
528   [controller_ resizeView:bookmark newHeight:0];
529   CheckViewPositions(controller_);
531   // Shrink the infobar to 0px and toolbar to 39px and recheck
532   [controller_ resizeView:infobar newHeight:0];
533   [controller_ resizeView:toolbar newHeight:39];
534   CheckViewPositions(controller_);
537 // Make sure, by default, the bookmark bar and the toolbar are the same width.
538 TEST_F(BrowserWindowControllerTest, BookmarkBarIsSameWidth) {
539   // Set the pref to the bookmark bar is visible when the toolbar is
540   // first created.
541   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
543   // Make sure the bookmark bar is the same width as the toolbar
544   NSView* bookmarkBarView = [controller_ bookmarkView];
545   NSView* toolbarView = [controller_ toolbarView];
546   EXPECT_EQ([toolbarView frame].size.width,
547             [bookmarkBarView frame].size.width);
550 TEST_F(BrowserWindowControllerTest, TestTopRightForBubble) {
551   // The bookmark bubble must be attached to a lit and visible star.
552   [controller_ setStarredState:YES];
553   NSPoint p = [controller_ bookmarkBubblePoint];  // Window coordinates.
554   NSRect all = [[controller_ window] frame];      // Screen coordinates.
556   // As a sanity check make sure the point is vaguely in the top right
557   // of the window.
558   EXPECT_GT(p.y, all.size.height / 2);
559   EXPECT_GT(p.x, all.size.width / 2);
562 // By the "zoom frame", we mean what Apple calls the "standard frame".
563 TEST_F(BrowserWindowControllerTest, TestZoomFrame) {
564   NSWindow* window = [controller_ window];
565   ASSERT_TRUE(window);
566   NSRect screenFrame = [[window screen] visibleFrame];
567   ASSERT_FALSE(NSIsEmptyRect(screenFrame));
569   // Minimum zoomed width is the larger of 60% of available horizontal space or
570   // 60% of available vertical space, subject to available horizontal space.
571   CGFloat minZoomWidth =
572       std::min(std::max((CGFloat)0.6 * screenFrame.size.width,
573                         (CGFloat)0.6 * screenFrame.size.height),
574                screenFrame.size.width);
576   // |testFrame| is the size of the window we start out with, and |zoomFrame| is
577   // the one returned by |-windowWillUseStandardFrame:defaultFrame:|.
578   NSRect testFrame;
579   NSRect zoomFrame;
581   // 1. Test a case where it zooms the window both horizontally and vertically,
582   // and only moves it vertically. "+ 32", etc. are just arbitrary constants
583   // used to check that the window is moved properly and not just to the origin;
584   // they should be small enough to not shove windows off the screen.
585   testFrame.size.width = 0.5 * minZoomWidth;
586   testFrame.size.height = 0.5 * screenFrame.size.height;
587   testFrame.origin.x = screenFrame.origin.x + 32;  // See above.
588   testFrame.origin.y = screenFrame.origin.y + 23;
589   [window setFrame:testFrame display:NO];
590   zoomFrame = [controller_ windowWillUseStandardFrame:window
591                                          defaultFrame:screenFrame];
592   EXPECT_LE(minZoomWidth, zoomFrame.size.width);
593   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
594   EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
595   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
597   // 2. Test a case where it zooms the window only horizontally, and only moves
598   // it horizontally.
599   testFrame.size.width = 0.5 * minZoomWidth;
600   testFrame.size.height = screenFrame.size.height;
601   testFrame.origin.x = screenFrame.origin.x + screenFrame.size.width -
602                        testFrame.size.width;
603   testFrame.origin.y = screenFrame.origin.y;
604   [window setFrame:testFrame display:NO];
605   zoomFrame = [controller_ windowWillUseStandardFrame:window
606                                          defaultFrame:screenFrame];
607   EXPECT_LE(minZoomWidth, zoomFrame.size.width);
608   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
609   EXPECT_EQ(screenFrame.origin.x + screenFrame.size.width -
610             zoomFrame.size.width, zoomFrame.origin.x);
611   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
613   // 3. Test a case where it zooms the window only vertically, and only moves it
614   // vertically.
615   testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
616                                   screenFrame.size.width);
617   testFrame.size.height = 0.3 * screenFrame.size.height;
618   testFrame.origin.x = screenFrame.origin.x + 32;  // See above (in 1.).
619   testFrame.origin.y = screenFrame.origin.y + 123;
620   [window setFrame:testFrame display:NO];
621   zoomFrame = [controller_ windowWillUseStandardFrame:window
622                                          defaultFrame:screenFrame];
623   // Use the actual width of the window frame, since it's subject to rounding.
624   EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
625   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
626   EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
627   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
629   // 4. Test a case where zooming should do nothing (i.e., we're already at a
630   // zoomed frame).
631   testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
632                                   screenFrame.size.width);
633   testFrame.size.height = screenFrame.size.height;
634   testFrame.origin.x = screenFrame.origin.x + 32;  // See above (in 1.).
635   testFrame.origin.y = screenFrame.origin.y;
636   [window setFrame:testFrame display:NO];
637   zoomFrame = [controller_ windowWillUseStandardFrame:window
638                                          defaultFrame:screenFrame];
639   // Use the actual width of the window frame, since it's subject to rounding.
640   EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
641   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
642   EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
643   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
646 TEST_F(BrowserWindowControllerTest, TestFindBarOnTop) {
647   FindBarBridge bridge(NULL);
648   [controller_ addFindBar:bridge.find_bar_cocoa_controller()];
650   // Test that the Z-order of the find bar is on top of everything.
651   NSArray* subviews = [controller_.chromeContentView subviews];
652   NSUInteger findBar_index =
653       [subviews indexOfObject:[controller_ findBarView]];
654   EXPECT_NE(NSNotFound, findBar_index);
655   NSUInteger toolbar_index =
656       [subviews indexOfObject:[controller_ toolbarView]];
657   EXPECT_NE(NSNotFound, toolbar_index);
658   NSUInteger bookmark_index =
659       [subviews indexOfObject:[controller_ bookmarkView]];
660   EXPECT_NE(NSNotFound, bookmark_index);
662   EXPECT_GT(findBar_index, toolbar_index);
663   EXPECT_GT(findBar_index, bookmark_index);
666 // Verify that hit testing works correctly when the bookmark bar overlaps
667 // web contents.
668 TEST_F(BrowserWindowControllerTest, BookmarkBarHitTest) {
669   profile()->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
670   [controller_ browserWindow]->BookmarkBarStateChanged(
671       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
673   NSView* bookmarkView = [controller_ bookmarkView];
674   NSView* contentView = [[controller_ window] contentView];
675   NSPoint point = [bookmarkView convertPoint:NSMakePoint(1, 1)
676                                       toView:[contentView superview]];
678   EXPECT_TRUE([[contentView hitTest:point] isDescendantOf:bookmarkView]);
681 @interface BrowserWindowControllerFakeFullscreen : BrowserWindowController {
682  @private
683   // We release the window ourselves, so we don't have to rely on the unittest
684   // doing it for us.
685   base::scoped_nsobject<NSWindow> testFullscreenWindow_;
687 @end
689 class BrowserWindowFullScreenControllerTest : public CocoaProfileTest {
690  public:
691   void SetUp() override {
692     CocoaProfileTest::SetUp();
693     ASSERT_TRUE(browser());
695     controller_ =
696         [[BrowserWindowControllerFakeFullscreen alloc] initWithBrowser:browser()
697                                                          takeOwnership:NO];
698   }
700   void TearDown() override {
701     [controller_ close];
702     CocoaProfileTest::TearDown();
703   }
705  public:
706   BrowserWindowController* controller_;
709 // Check if the window is front most or if one of its child windows (such
710 // as a status bubble) is front most.
711 static bool IsFrontWindow(NSWindow *window) {
712   NSWindow* frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
713   return [frontmostWindow isEqual:window] ||
714          [[frontmostWindow parentWindow] isEqual:window];
717 void WaitForFullScreenTransition() {
718   content::WindowedNotificationObserver observer(
719       chrome::NOTIFICATION_FULLSCREEN_CHANGED,
720       content::NotificationService::AllSources());
721   observer.Wait();
724 // http://crbug.com/53586
725 TEST_F(BrowserWindowFullScreenControllerTest, DISABLED_TestFullscreen) {
726   [controller_ showWindow:nil];
727   EXPECT_FALSE([controller_ isInAnyFullscreenMode]);
729   [controller_ enterBrowserFullscreenWithToolbar:YES];
730   WaitForFullScreenTransition();
731   EXPECT_TRUE([controller_ isInAnyFullscreenMode]);
733   [controller_ exitAnyFullscreen];
734   WaitForFullScreenTransition();
735   EXPECT_FALSE([controller_ isInAnyFullscreenMode]);
738 // If this test fails, it is usually a sign that the bots have some sort of
739 // problem (such as a modal dialog up).  This tests is a very useful canary, so
740 // please do not mark it as flaky without first verifying that there are no bot
741 // problems.
742 // http://crbug.com/53586
743 TEST_F(BrowserWindowFullScreenControllerTest, DISABLED_TestActivate) {
744   [controller_ showWindow:nil];
746   EXPECT_FALSE([controller_ isInAnyFullscreenMode]);
748   [controller_ activate];
749   EXPECT_TRUE(IsFrontWindow([controller_ window]));
751   [controller_ enterBrowserFullscreenWithToolbar:YES];
752   WaitForFullScreenTransition();
753   [controller_ activate];
755   // No fullscreen window on 10.7+.
756   if (base::mac::IsOSSnowLeopard())
757     EXPECT_TRUE(IsFrontWindow([controller_ createFullscreenWindow]));
759   // We have to cleanup after ourselves by unfullscreening.
760   [controller_ exitAnyFullscreen];
761   WaitForFullScreenTransition();
764 @implementation BrowserWindowControllerFakeFullscreen
765 // Override |-createFullscreenWindow| to return a dummy window. This isn't
766 // needed to pass the test, but because the dummy window is only 100x100, it
767 // prevents the real fullscreen window from flashing up and taking over the
768 // whole screen. We have to return an actual window because |-layoutSubviews|
769 // looks at the window's frame.
770 - (NSWindow*)createFullscreenWindow {
771   if (testFullscreenWindow_.get())
772     return testFullscreenWindow_.get();
774   testFullscreenWindow_.reset(
775       [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,400,400)
776                                   styleMask:NSBorderlessWindowMask
777                                     backing:NSBackingStoreBuffered
778                                       defer:NO]);
779   [[testFullscreenWindow_ contentView] setWantsLayer:YES];
780   return testFullscreenWindow_.get();
782 @end
784 /* TODO(???): test other methods of BrowserWindowController */