[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / browser_window_controller_unittest.mm
blob0823f2ddd77c243196336cae988566f0b029797f
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 "base/strings/utf_string_conversions.h"
12 #include "chrome/app/chrome_command_ids.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/signin/fake_signin_manager.h"
15 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
16 #include "chrome/browser/signin/signin_manager_factory.h"
17 #include "chrome/browser/sync/profile_sync_service.h"
18 #include "chrome/browser/sync/profile_sync_service_factory.h"
19 #include "chrome/browser/sync/profile_sync_service_mock.h"
20 #include "chrome/browser/ui/browser_list.h"
21 #include "chrome/browser/ui/browser_window.h"
22 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
23 #include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h"
24 #include "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
25 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
26 #include "chrome/browser/ui/host_desktop.h"
27 #include "chrome/common/pref_names.h"
28 #include "chrome/test/base/testing_profile.h"
29 #include "components/signin/core/browser/fake_auth_status_provider.h"
30 #include "components/signin/core/browser/profile_oauth2_token_service.h"
31 #include "components/signin/core/browser/signin_error_controller.h"
32 #include "components/signin/core/browser/signin_manager.h"
33 #include "content/public/browser/notification_service.h"
34 #include "content/public/test/test_utils.h"
35 #include "grit/chromium_strings.h"
36 #include "grit/generated_resources.h"
37 #include "testing/gmock/include/gmock/gmock.h"
38 #include "ui/base/l10n/l10n_util.h"
39 #include "ui/base/l10n/l10n_util_mac.h"
41 using ::testing::Return;
43 @interface BrowserWindowController (JustForTesting)
44 // Already defined in BWC.
45 - (void)saveWindowPositionIfNeeded;
46 - (void)layoutSubviews;
47 @end
49 @interface BrowserWindowController (ExposedForTesting)
50 // Implementations are below.
51 - (NSView*)infoBarContainerView;
52 - (NSView*)toolbarView;
53 - (NSView*)bookmarkView;
54 - (BOOL)bookmarkBarVisible;
55 @end
57 @implementation BrowserWindowController (ExposedForTesting)
58 - (NSView*)infoBarContainerView {
59   return [infoBarContainerController_ view];
62 - (NSView*)toolbarView {
63   return [toolbarController_ view];
66 - (NSView*)bookmarkView {
67   return [bookmarkBarController_ view];
70 - (NSView*)findBarView {
71   return [findBarCocoaController_ view];
74 - (BOOL)bookmarkBarVisible {
75   return [bookmarkBarController_ isVisible];
77 @end
79 class BrowserWindowControllerTest : public CocoaProfileTest {
80  public:
81   virtual void SetUp() {
82     CocoaProfileTest::SetUp();
83     ASSERT_TRUE(browser());
85     controller_ = [[BrowserWindowController alloc] initWithBrowser:browser()
86                                                      takeOwnership:NO];
87   }
89   virtual void TearDown() {
90     [controller_ close];
91     CocoaProfileTest::TearDown();
92   }
94  public:
95   BrowserWindowController* controller_;
98 TEST_F(BrowserWindowControllerTest, TestSaveWindowPosition) {
99   PrefService* prefs = profile()->GetPrefs();
100   ASSERT_TRUE(prefs != NULL);
102   // Check to make sure there is no existing pref for window placement.
103   const base::DictionaryValue* browser_window_placement =
104       prefs->GetDictionary(prefs::kBrowserWindowPlacement);
105   ASSERT_TRUE(browser_window_placement);
106   EXPECT_TRUE(browser_window_placement->empty());
108   // Ask the window to save its position, then check that a preference
109   // exists.
110   BrowserList::SetLastActive(browser());
111   [controller_ saveWindowPositionIfNeeded];
112   browser_window_placement =
113       prefs->GetDictionary(prefs::kBrowserWindowPlacement);
114   ASSERT_TRUE(browser_window_placement);
115   EXPECT_FALSE(browser_window_placement->empty());
118 TEST_F(BrowserWindowControllerTest, TestFullScreenWindow) {
119   // Confirm that |-createFullscreenWindow| doesn't return nil.
120   // See BrowserWindowFullScreenControllerTest for more fullscreen tests.
121   EXPECT_TRUE([controller_ createFullscreenWindow]);
124 TEST_F(BrowserWindowControllerTest, TestNormal) {
125   // Force the bookmark bar to be shown.
126   profile()->GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true);
127   [controller_ browserWindow]->BookmarkBarStateChanged(
128       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
130   // Make sure a normal BrowserWindowController is, uh, normal.
131   EXPECT_TRUE([controller_ isTabbedWindow]);
132   EXPECT_TRUE([controller_ hasTabStrip]);
133   EXPECT_FALSE([controller_ hasTitleBar]);
134   EXPECT_TRUE([controller_ isBookmarkBarVisible]);
136   // And make sure a controller for a pop-up window is not normal.
137   // popup_browser will be owned by its window.
138   Browser* popup_browser(new Browser(
139       Browser::CreateParams(Browser::TYPE_POPUP, profile(),
140                             chrome::GetActiveDesktop())));
141   NSWindow *cocoaWindow = popup_browser->window()->GetNativeWindow();
142   BrowserWindowController* controller =
143       static_cast<BrowserWindowController*>([cocoaWindow windowController]);
144   ASSERT_TRUE([controller isKindOfClass:[BrowserWindowController class]]);
145   EXPECT_FALSE([controller isTabbedWindow]);
146   EXPECT_FALSE([controller hasTabStrip]);
147   EXPECT_TRUE([controller hasTitleBar]);
148   EXPECT_FALSE([controller isBookmarkBarVisible]);
149   [controller close];
152 TEST_F(BrowserWindowControllerTest, TestSetBounds) {
153   // Create a normal browser with bounds smaller than the minimum.
154   Browser::CreateParams params(Browser::TYPE_TABBED, profile(),
155                                chrome::GetActiveDesktop());
156   params.initial_bounds = gfx::Rect(0, 0, 50, 50);
157   Browser* browser = new Browser(params);
158   NSWindow *cocoaWindow = browser->window()->GetNativeWindow();
159   BrowserWindowController* controller =
160     static_cast<BrowserWindowController*>([cocoaWindow windowController]);
162   ASSERT_TRUE([controller isTabbedWindow]);
163   BrowserWindow* browser_window = [controller browserWindow];
164   EXPECT_EQ(browser_window, browser->window());
165   gfx::Rect bounds = browser_window->GetBounds();
166   EXPECT_EQ(400, bounds.width());
167   EXPECT_EQ(272, bounds.height());
169   // Try to set the bounds smaller than the minimum.
170   browser_window->SetBounds(gfx::Rect(0, 0, 50, 50));
171   bounds = browser_window->GetBounds();
172   EXPECT_EQ(400, bounds.width());
173   EXPECT_EQ(272, bounds.height());
175   [controller close];
178 TEST_F(BrowserWindowControllerTest, TestSetBoundsPopup) {
179   // Create a popup with bounds smaller than the minimum.
180   Browser::CreateParams params(Browser::TYPE_POPUP, profile(),
181                                chrome::GetActiveDesktop());
182   params.initial_bounds = gfx::Rect(0, 0, 50, 50);
183   Browser* browser = new Browser(params);
184   NSWindow *cocoaWindow = browser->window()->GetNativeWindow();
185   BrowserWindowController* controller =
186     static_cast<BrowserWindowController*>([cocoaWindow windowController]);
188   ASSERT_FALSE([controller isTabbedWindow]);
189   BrowserWindow* browser_window = [controller browserWindow];
190   EXPECT_EQ(browser_window, browser->window());
191   gfx::Rect bounds = browser_window->GetBounds();
192   EXPECT_EQ(100, bounds.width());
193   EXPECT_EQ(122, bounds.height());
195   // Try to set the bounds smaller than the minimum.
196   browser_window->SetBounds(gfx::Rect(0, 0, 50, 50));
197   bounds = browser_window->GetBounds();
198   EXPECT_EQ(100, bounds.width());
199   EXPECT_EQ(122, bounds.height());
201   [controller close];
204 TEST_F(BrowserWindowControllerTest, TestTheme) {
205   [controller_ userChangedTheme];
208 TEST_F(BrowserWindowControllerTest, BookmarkBarControllerIndirection) {
209   EXPECT_FALSE([controller_ isBookmarkBarVisible]);
211   // Explicitly show the bar. Can't use chrome::ToggleBookmarkBarWhenVisible()
212   // because of the notification issues.
213   profile()->GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true);
215   [controller_ browserWindow]->BookmarkBarStateChanged(
216       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
217   EXPECT_TRUE([controller_ isBookmarkBarVisible]);
220 #if 0
221 // TODO(jrg): This crashes trying to create the BookmarkBarController, adding
222 // an observer to the BookmarkModel.
223 TEST_F(BrowserWindowControllerTest, TestIncognitoWidthSpace) {
224   scoped_ptr<TestingProfile> incognito_profile(new TestingProfile());
225   incognito_profile->set_off_the_record(true);
226   scoped_ptr<Browser> browser(
227       new Browser(Browser::CreateParams(incognito_profile.get(),
228                                         chrome::GetActiveDesktop()));
229   controller_.reset([[BrowserWindowController alloc]
230                               initWithBrowser:browser.get()
231                                 takeOwnership:NO]);
233   NSRect tabFrame = [[controller_ tabStripView] frame];
234   [controller_ installIncognitoBadge];
235   NSRect newTabFrame = [[controller_ tabStripView] frame];
236   EXPECT_GT(tabFrame.size.width, newTabFrame.size.width);
238   controller_.release();
240 #endif
242 namespace {
244 // Verifies that the toolbar, infobar, tab content area, and download shelf
245 // completely fill the area under the tabstrip.
246 void CheckViewPositions(BrowserWindowController* controller) {
247   NSRect contentView = [[[controller window] contentView] bounds];
248   NSRect tabstrip = [[controller tabStripView] frame];
249   NSRect toolbar = [[controller toolbarView] frame];
250   NSRect infobar = [[controller infoBarContainerView] frame];
251   NSRect contentArea = [[controller tabContentArea] frame];
252   NSRect download = [[[controller downloadShelf] view] frame];
254   EXPECT_EQ(NSMinY(contentView), NSMinY(download));
255   EXPECT_EQ(NSMaxY(download), NSMinY(contentArea));
256   EXPECT_EQ(NSMaxY(contentArea), NSMinY(infobar));
258   // Bookmark bar frame is random memory when hidden.
259   if ([controller bookmarkBarVisible]) {
260     NSRect bookmark = [[controller bookmarkView] frame];
261     EXPECT_EQ(NSMaxY(infobar), NSMinY(bookmark));
262     EXPECT_EQ(NSMaxY(bookmark), NSMinY(toolbar));
263     EXPECT_FALSE([[controller bookmarkView] isHidden]);
264   } else {
265     EXPECT_EQ(NSMaxY(infobar), NSMinY(toolbar));
266     EXPECT_TRUE([[controller bookmarkView] isHidden]);
267   }
269   // Toolbar should start immediately under the tabstrip, but the tabstrip is
270   // not necessarily fixed with respect to the content view.
271   EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar));
274 }  // end namespace
276 TEST_F(BrowserWindowControllerTest, TestAdjustWindowHeight) {
277   NSWindow* window = [controller_ window];
278   NSRect workarea = [[window screen] visibleFrame];
280   // Place the window well above the bottom of the screen and try to adjust its
281   // height. It should change appropriately (and only downwards). Then get it to
282   // shrink by the same amount; it should return to its original state.
283   NSRect initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 100,
284                                    200, 200);
285   [window setFrame:initialFrame display:YES];
286   [controller_ resetWindowGrowthState];
287   [controller_ adjustWindowHeightBy:40];
288   NSRect finalFrame = [window frame];
289   EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
290   EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
291   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
292   [controller_ adjustWindowHeightBy:-40];
293   finalFrame = [window frame];
294   EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
295   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
297   // Place the window at the bottom of the screen and try again.  Its height
298   // should still change, but it should not grow down below the work area; it
299   // should instead move upwards. Then shrink it and make sure it goes back to
300   // the way it was.
301   initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
302   [window setFrame:initialFrame display:YES];
303   [controller_ resetWindowGrowthState];
304   [controller_ adjustWindowHeightBy:40];
305   finalFrame = [window frame];
306   EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
307   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
308   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
309   [controller_ adjustWindowHeightBy:-40];
310   finalFrame = [window frame];
311   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
312   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
314   // Put the window slightly offscreen and try again.  The height should not
315   // change this time.
316   initialFrame = NSMakeRect(workarea.origin.x - 10, 0, 200, 200);
317   [window setFrame:initialFrame display:YES];
318   [controller_ resetWindowGrowthState];
319   [controller_ adjustWindowHeightBy:40];
320   EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
321   [controller_ adjustWindowHeightBy:-40];
322   EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
324   // Make the window the same size as the workarea.  Resizing both larger and
325   // smaller should have no effect.
326   [window setFrame:workarea display:YES];
327   [controller_ resetWindowGrowthState];
328   [controller_ adjustWindowHeightBy:40];
329   EXPECT_TRUE(NSEqualRects([window frame], workarea));
330   [controller_ adjustWindowHeightBy:-40];
331   EXPECT_TRUE(NSEqualRects([window frame], workarea));
333   // Make the window smaller than the workarea and place it near the bottom of
334   // the workarea.  The window should grow down until it hits the bottom and
335   // then continue to grow up. Then shrink it, and it should return to where it
336   // was.
337   initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 5,
338                             200, 200);
339   [window setFrame:initialFrame display:YES];
340   [controller_ resetWindowGrowthState];
341   [controller_ adjustWindowHeightBy:40];
342   finalFrame = [window frame];
343   EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
344   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
345   [controller_ adjustWindowHeightBy:-40];
346   finalFrame = [window frame];
347   EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
348   EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
350   // Inset the window slightly from the workarea.  It should not grow to be
351   // larger than the workarea. Shrink it; it should return to where it started.
352   initialFrame = NSInsetRect(workarea, 0, 5);
353   [window setFrame:initialFrame display:YES];
354   [controller_ resetWindowGrowthState];
355   [controller_ adjustWindowHeightBy:40];
356   finalFrame = [window frame];
357   EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
358   EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
359   [controller_ adjustWindowHeightBy:-40];
360   finalFrame = [window frame];
361   EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
362   EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
364   // Place the window at the bottom of the screen and grow; it should grow
365   // upwards. Move the window off the bottom, then shrink. It should then shrink
366   // from the bottom.
367   initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
368   [window setFrame:initialFrame display:YES];
369   [controller_ resetWindowGrowthState];
370   [controller_ adjustWindowHeightBy:40];
371   finalFrame = [window frame];
372   EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
373   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
374   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
375   NSPoint oldOrigin = initialFrame.origin;
376   NSPoint newOrigin = NSMakePoint(oldOrigin.x, oldOrigin.y + 10);
377   [window setFrameOrigin:newOrigin];
378   initialFrame = [window frame];
379   EXPECT_FLOAT_EQ(NSMinY(initialFrame), oldOrigin.y + 10);
380   [controller_ adjustWindowHeightBy:-40];
381   finalFrame = [window frame];
382   EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame) + 40);
383   EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) - 40);
385   // Do the "inset" test above, but using multiple calls to
386   // |-adjustWindowHeightBy|; the result should be the same.
387   initialFrame = NSInsetRect(workarea, 0, 5);
388   [window setFrame:initialFrame display:YES];
389   [controller_ resetWindowGrowthState];
390   for (int i = 0; i < 8; i++)
391     [controller_ adjustWindowHeightBy:5];
392   finalFrame = [window frame];
393   EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
394   EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
395   for (int i = 0; i < 8; i++)
396     [controller_ adjustWindowHeightBy:-5];
397   finalFrame = [window frame];
398   EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
399   EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
402 // Test to make sure resizing and relaying-out subviews works correctly.
403 TEST_F(BrowserWindowControllerTest, TestResizeViews) {
404   TabStripView* tabstrip = [controller_ tabStripView];
405   NSView* contentView = [[tabstrip window] contentView];
406   NSView* toolbar = [controller_ toolbarView];
407   NSView* infobar = [controller_ infoBarContainerView];
409   // We need to muck with the views a bit to put us in a consistent state before
410   // we start resizing.  In particular, we need to move the tab strip to be
411   // immediately above the content area, since we layout views to be directly
412   // under the tab strip.
413   NSRect tabstripFrame = [tabstrip frame];
414   tabstripFrame.origin.y = NSMaxY([contentView frame]);
415   [tabstrip setFrame:tabstripFrame];
417   // The download shelf is created lazily.  Force-create it and set its initial
418   // height to 0.
419   NSView* download = [[controller_ downloadShelf] view];
420   NSRect downloadFrame = [download frame];
421   downloadFrame.size.height = 0;
422   [download setFrame:downloadFrame];
424   // Force a layout and check each view's frame.
425   [controller_ layoutSubviews];
426   CheckViewPositions(controller_);
428   // Expand the infobar to 60px and recheck
429   [controller_ resizeView:infobar newHeight:60];
430   CheckViewPositions(controller_);
432   // Expand the toolbar to 64px and recheck
433   [controller_ resizeView:toolbar newHeight:64];
434   CheckViewPositions(controller_);
436   // Add a 30px download shelf and recheck
437   [controller_ resizeView:download newHeight:30];
438   CheckViewPositions(controller_);
440   // Shrink the infobar to 0px and toolbar to 39px and recheck
441   [controller_ resizeView:infobar newHeight:0];
442   [controller_ resizeView:toolbar newHeight:39];
443   CheckViewPositions(controller_);
446 TEST_F(BrowserWindowControllerTest, TestResizeViewsWithBookmarkBar) {
447   // Force a display of the bookmark bar.
448   profile()->GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true);
449   [controller_ browserWindow]->BookmarkBarStateChanged(
450       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
452   TabStripView* tabstrip = [controller_ tabStripView];
453   NSView* contentView = [[tabstrip window] contentView];
454   NSView* toolbar = [controller_ toolbarView];
455   NSView* bookmark = [controller_ bookmarkView];
456   NSView* infobar = [controller_ infoBarContainerView];
458   // We need to muck with the views a bit to put us in a consistent state before
459   // we start resizing.  In particular, we need to move the tab strip to be
460   // immediately above the content area, since we layout views to be directly
461   // under the tab strip.
462   NSRect tabstripFrame = [tabstrip frame];
463   tabstripFrame.origin.y = NSMaxY([contentView frame]);
464   [tabstrip setFrame:tabstripFrame];
466   // The download shelf is created lazily.  Force-create it and set its initial
467   // height to 0.
468   NSView* download = [[controller_ downloadShelf] view];
469   NSRect downloadFrame = [download frame];
470   downloadFrame.size.height = 0;
471   [download setFrame:downloadFrame];
473   // Force a layout and check each view's frame.
474   [controller_ layoutSubviews];
475   CheckViewPositions(controller_);
477   // Add the bookmark bar and recheck.
478   [controller_ resizeView:bookmark newHeight:40];
479   CheckViewPositions(controller_);
481   // Expand the infobar to 60px and recheck
482   [controller_ resizeView:infobar newHeight:60];
483   CheckViewPositions(controller_);
485   // Expand the toolbar to 64px and recheck
486   [controller_ resizeView:toolbar newHeight:64];
487   CheckViewPositions(controller_);
489   // Add a 30px download shelf and recheck
490   [controller_ resizeView:download newHeight:30];
491   CheckViewPositions(controller_);
493   // Remove the bookmark bar and recheck
494   profile()->GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, false);
495   [controller_ resizeView:bookmark newHeight:0];
496   CheckViewPositions(controller_);
498   // Shrink the infobar to 0px and toolbar to 39px and recheck
499   [controller_ resizeView:infobar newHeight:0];
500   [controller_ resizeView:toolbar newHeight:39];
501   CheckViewPositions(controller_);
504 // Make sure, by default, the bookmark bar and the toolbar are the same width.
505 TEST_F(BrowserWindowControllerTest, BookmarkBarIsSameWidth) {
506   // Set the pref to the bookmark bar is visible when the toolbar is
507   // first created.
508   profile()->GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true);
510   // Make sure the bookmark bar is the same width as the toolbar
511   NSView* bookmarkBarView = [controller_ bookmarkView];
512   NSView* toolbarView = [controller_ toolbarView];
513   EXPECT_EQ([toolbarView frame].size.width,
514             [bookmarkBarView frame].size.width);
517 TEST_F(BrowserWindowControllerTest, TestTopRightForBubble) {
518   // The bookmark bubble must be attached to a lit and visible star.
519   [controller_ setStarredState:YES];
520   NSPoint p = [controller_ bookmarkBubblePoint];
521   NSRect all = [[controller_ window] frame];
523   // As a sanity check make sure the point is vaguely in the top right
524   // of the window.
525   EXPECT_GT(p.y, all.origin.y + (all.size.height/2));
526   EXPECT_GT(p.x, all.origin.x + (all.size.width/2));
529 // By the "zoom frame", we mean what Apple calls the "standard frame".
530 TEST_F(BrowserWindowControllerTest, TestZoomFrame) {
531   NSWindow* window = [controller_ window];
532   ASSERT_TRUE(window);
533   NSRect screenFrame = [[window screen] visibleFrame];
534   ASSERT_FALSE(NSIsEmptyRect(screenFrame));
536   // Minimum zoomed width is the larger of 60% of available horizontal space or
537   // 60% of available vertical space, subject to available horizontal space.
538   CGFloat minZoomWidth =
539       std::min(std::max((CGFloat)0.6 * screenFrame.size.width,
540                         (CGFloat)0.6 * screenFrame.size.height),
541                screenFrame.size.width);
543   // |testFrame| is the size of the window we start out with, and |zoomFrame| is
544   // the one returned by |-windowWillUseStandardFrame:defaultFrame:|.
545   NSRect testFrame;
546   NSRect zoomFrame;
548   // 1. Test a case where it zooms the window both horizontally and vertically,
549   // and only moves it vertically. "+ 32", etc. are just arbitrary constants
550   // used to check that the window is moved properly and not just to the origin;
551   // they should be small enough to not shove windows off the screen.
552   testFrame.size.width = 0.5 * minZoomWidth;
553   testFrame.size.height = 0.5 * screenFrame.size.height;
554   testFrame.origin.x = screenFrame.origin.x + 32;  // See above.
555   testFrame.origin.y = screenFrame.origin.y + 23;
556   [window setFrame:testFrame display:NO];
557   zoomFrame = [controller_ windowWillUseStandardFrame:window
558                                          defaultFrame:screenFrame];
559   EXPECT_LE(minZoomWidth, zoomFrame.size.width);
560   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
561   EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
562   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
564   // 2. Test a case where it zooms the window only horizontally, and only moves
565   // it horizontally.
566   testFrame.size.width = 0.5 * minZoomWidth;
567   testFrame.size.height = screenFrame.size.height;
568   testFrame.origin.x = screenFrame.origin.x + screenFrame.size.width -
569                        testFrame.size.width;
570   testFrame.origin.y = screenFrame.origin.y;
571   [window setFrame:testFrame display:NO];
572   zoomFrame = [controller_ windowWillUseStandardFrame:window
573                                          defaultFrame:screenFrame];
574   EXPECT_LE(minZoomWidth, zoomFrame.size.width);
575   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
576   EXPECT_EQ(screenFrame.origin.x + screenFrame.size.width -
577             zoomFrame.size.width, zoomFrame.origin.x);
578   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
580   // 3. Test a case where it zooms the window only vertically, and only moves it
581   // vertically.
582   testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
583                                   screenFrame.size.width);
584   testFrame.size.height = 0.3 * screenFrame.size.height;
585   testFrame.origin.x = screenFrame.origin.x + 32;  // See above (in 1.).
586   testFrame.origin.y = screenFrame.origin.y + 123;
587   [window setFrame:testFrame display:NO];
588   zoomFrame = [controller_ windowWillUseStandardFrame:window
589                                          defaultFrame:screenFrame];
590   // Use the actual width of the window frame, since it's subject to rounding.
591   EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
592   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
593   EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
594   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
596   // 4. Test a case where zooming should do nothing (i.e., we're already at a
597   // zoomed frame).
598   testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
599                                   screenFrame.size.width);
600   testFrame.size.height = screenFrame.size.height;
601   testFrame.origin.x = screenFrame.origin.x + 32;  // See above (in 1.).
602   testFrame.origin.y = screenFrame.origin.y;
603   [window setFrame:testFrame display:NO];
604   zoomFrame = [controller_ windowWillUseStandardFrame:window
605                                          defaultFrame:screenFrame];
606   // Use the actual width of the window frame, since it's subject to rounding.
607   EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
608   EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
609   EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
610   EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
613 TEST_F(BrowserWindowControllerTest, TestFindBarOnTop) {
614   FindBarBridge bridge(NULL);
615   [controller_ addFindBar:bridge.find_bar_cocoa_controller()];
617   // Test that the Z-order of the find bar is on top of everything.
618   NSArray* subviews = [[[controller_ window] contentView] subviews];
619   NSUInteger findBar_index =
620       [subviews indexOfObject:[controller_ findBarView]];
621   EXPECT_NE(NSNotFound, findBar_index);
622   NSUInteger toolbar_index =
623       [subviews indexOfObject:[controller_ toolbarView]];
624   EXPECT_NE(NSNotFound, toolbar_index);
625   NSUInteger bookmark_index =
626       [subviews indexOfObject:[controller_ bookmarkView]];
627   EXPECT_NE(NSNotFound, bookmark_index);
629   EXPECT_GT(findBar_index, toolbar_index);
630   EXPECT_GT(findBar_index, bookmark_index);
633 TEST_F(BrowserWindowControllerTest, TestSigninMenuItemNoErrors) {
634   base::scoped_nsobject<NSMenuItem> syncMenuItem(
635       [[NSMenuItem alloc] initWithTitle:@""
636                                  action:@selector(commandDispatch)
637                           keyEquivalent:@""]);
638   [syncMenuItem setTag:IDC_SHOW_SYNC_SETUP];
640   NSString* startSignin =
641     l10n_util::GetNSStringFWithFixup(
642         IDS_SYNC_MENU_PRE_SYNCED_LABEL,
643         l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
645   // Make sure shouldShow parameter is obeyed, and we get the default
646   // label if not signed in.
647   [BrowserWindowController updateSigninItem:syncMenuItem
648                                  shouldShow:YES
649                              currentProfile:profile()];
651   EXPECT_TRUE([[syncMenuItem title] isEqualTo:startSignin]);
652   EXPECT_FALSE([syncMenuItem isHidden]);
654   [BrowserWindowController updateSigninItem:syncMenuItem
655                                  shouldShow:NO
656                              currentProfile:profile()];
657   EXPECT_TRUE([[syncMenuItem title] isEqualTo:startSignin]);
658   EXPECT_TRUE([syncMenuItem isHidden]);
660   // Now sign in.
661   std::string username = "foo@example.com";
662   NSString* alreadySignedIn =
663     l10n_util::GetNSStringFWithFixup(IDS_SYNC_MENU_SYNCED_LABEL,
664                                      base::UTF8ToUTF16(username));
665   SigninManager* signin = SigninManagerFactory::GetForProfile(profile());
666   signin->SetAuthenticatedUsername(username);
667   ProfileSyncService* sync =
668     ProfileSyncServiceFactory::GetForProfile(profile());
669   sync->SetSyncSetupCompleted();
670   [BrowserWindowController updateSigninItem:syncMenuItem
671                                  shouldShow:YES
672                              currentProfile:profile()];
673   EXPECT_TRUE([[syncMenuItem title] isEqualTo:alreadySignedIn]);
674   EXPECT_FALSE([syncMenuItem isHidden]);
677 TEST_F(BrowserWindowControllerTest, TestSigninMenuItemAuthError) {
678   base::scoped_nsobject<NSMenuItem> syncMenuItem(
679       [[NSMenuItem alloc] initWithTitle:@""
680                                  action:@selector(commandDispatch)
681                           keyEquivalent:@""]);
682   [syncMenuItem setTag:IDC_SHOW_SYNC_SETUP];
684   // Now sign in.
685   std::string username = "foo@example.com";
686   SigninManager* signin = SigninManagerFactory::GetForProfile(profile());
687   signin->SetAuthenticatedUsername(username);
688   ProfileSyncService* sync =
689       ProfileSyncServiceFactory::GetForProfile(profile());
690   sync->SetSyncSetupCompleted();
691   // Force an auth error.
692   FakeAuthStatusProvider provider(
693       ProfileOAuth2TokenServiceFactory::GetForProfile(profile())->
694           signin_error_controller());
695   GoogleServiceAuthError error(
696       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
697   provider.SetAuthError("user@gmail.com", "user@gmail.com", error);
698   [BrowserWindowController updateSigninItem:syncMenuItem
699                                  shouldShow:YES
700                              currentProfile:profile()];
701   NSString* authError =
702     l10n_util::GetNSStringWithFixup(IDS_SYNC_SIGN_IN_ERROR_WRENCH_MENU_ITEM);
703   EXPECT_TRUE([[syncMenuItem title] isEqualTo:authError]);
704   EXPECT_FALSE([syncMenuItem isHidden]);
708 // If there's a separator after the signin menu item, make sure it is hidden/
709 // shown when the signin menu item is.
710 TEST_F(BrowserWindowControllerTest, TestSigninMenuItemWithSeparator) {
711   base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
712   NSMenuItem* signinMenuItem =
713       [menu addItemWithTitle:@""
714                       action:@selector(commandDispatch)
715                keyEquivalent:@""];
716   [signinMenuItem setTag:IDC_SHOW_SYNC_SETUP];
717   NSMenuItem* followingSeparator = [NSMenuItem separatorItem];
718   [menu addItem:followingSeparator];
719   [signinMenuItem setHidden:NO];
720   [followingSeparator setHidden:NO];
722   [BrowserWindowController updateSigninItem:signinMenuItem
723                                  shouldShow:NO
724                              currentProfile:profile()];
726   EXPECT_FALSE([followingSeparator isEnabled]);
727   EXPECT_TRUE([signinMenuItem isHidden]);
728   EXPECT_TRUE([followingSeparator isHidden]);
730   [BrowserWindowController updateSigninItem:signinMenuItem
731                                  shouldShow:YES
732                              currentProfile:profile()];
734   EXPECT_FALSE([followingSeparator isEnabled]);
735   EXPECT_FALSE([signinMenuItem isHidden]);
736   EXPECT_FALSE([followingSeparator isHidden]);
739 // If there's a non-separator item after the signin menu item, it should not
740 // change state when the signin menu item is hidden/shown.
741 TEST_F(BrowserWindowControllerTest, TestSigninMenuItemWithNonSeparator) {
742   base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
743   NSMenuItem* signinMenuItem =
744       [menu addItemWithTitle:@""
745                       action:@selector(commandDispatch)
746                keyEquivalent:@""];
747   [signinMenuItem setTag:IDC_SHOW_SYNC_SETUP];
748   NSMenuItem* followingNonSeparator =
749       [menu addItemWithTitle:@""
750                       action:@selector(commandDispatch)
751                keyEquivalent:@""];
752   [signinMenuItem setHidden:NO];
753   [followingNonSeparator setHidden:NO];
755   [BrowserWindowController updateSigninItem:signinMenuItem
756                                  shouldShow:NO
757                              currentProfile:profile()];
759   EXPECT_TRUE([followingNonSeparator isEnabled]);
760   EXPECT_TRUE([signinMenuItem isHidden]);
761   EXPECT_FALSE([followingNonSeparator isHidden]);
763   [followingNonSeparator setHidden:YES];
764   [BrowserWindowController updateSigninItem:signinMenuItem
765                                  shouldShow:YES
766                              currentProfile:profile()];
768   EXPECT_TRUE([followingNonSeparator isEnabled]);
769   EXPECT_FALSE([signinMenuItem isHidden]);
770   EXPECT_TRUE([followingNonSeparator isHidden]);
773 // Verify that hit testing works correctly when the bookmark bar overlaps
774 // web contents.
775 TEST_F(BrowserWindowControllerTest, BookmarkBarHitTest) {
776   profile()->GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, true);
777   [controller_ browserWindow]->BookmarkBarStateChanged(
778       BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
780   NSView* bookmarkView = [controller_ bookmarkView];
781   NSView* contentView = [[controller_ window] contentView];
782   NSPoint point = [bookmarkView convertPoint:NSMakePoint(1, 1)
783                                       toView:[contentView superview]];
785   EXPECT_TRUE([[contentView hitTest:point] isDescendantOf:bookmarkView]);
788 @interface BrowserWindowControllerFakeFullscreen : BrowserWindowController {
789  @private
790   // We release the window ourselves, so we don't have to rely on the unittest
791   // doing it for us.
792   base::scoped_nsobject<NSWindow> testFullscreenWindow_;
794 @end
796 class BrowserWindowFullScreenControllerTest : public CocoaProfileTest {
797  public:
798   virtual void SetUp() {
799     CocoaProfileTest::SetUp();
800     ASSERT_TRUE(browser());
802     controller_ =
803         [[BrowserWindowControllerFakeFullscreen alloc] initWithBrowser:browser()
804                                                          takeOwnership:NO];
805   }
807   virtual void TearDown() {
808     [controller_ close];
809     CocoaProfileTest::TearDown();
810   }
812  public:
813   BrowserWindowController* controller_;
816 // Check if the window is front most or if one of its child windows (such
817 // as a status bubble) is front most.
818 static bool IsFrontWindow(NSWindow *window) {
819   NSWindow* frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
820   return [frontmostWindow isEqual:window] ||
821          [[frontmostWindow parentWindow] isEqual:window];
824 void WaitForFullScreenTransition() {
825   content::WindowedNotificationObserver observer(
826       chrome::NOTIFICATION_FULLSCREEN_CHANGED,
827       content::NotificationService::AllSources());
828   observer.Wait();
831 TEST_F(BrowserWindowFullScreenControllerTest, TestFullscreen) {
832   [controller_ showWindow:nil];
833   EXPECT_FALSE([controller_ isFullscreen]);
835   [controller_ enterFullscreen];
836   WaitForFullScreenTransition();
837   EXPECT_TRUE([controller_ isFullscreen]);
839   [controller_ exitFullscreen];
840   WaitForFullScreenTransition();
841   EXPECT_FALSE([controller_ isFullscreen]);
844 // If this test fails, it is usually a sign that the bots have some sort of
845 // problem (such as a modal dialog up).  This tests is a very useful canary, so
846 // please do not mark it as flaky without first verifying that there are no bot
847 // problems.
848 TEST_F(BrowserWindowFullScreenControllerTest, TestActivate) {
849   [controller_ showWindow:nil];
851   EXPECT_FALSE([controller_ isFullscreen]);
853   [controller_ activate];
854   EXPECT_TRUE(IsFrontWindow([controller_ window]));
856   [controller_ enterFullscreen];
857   WaitForFullScreenTransition();
858   [controller_ activate];
860   // No fullscreen window on 10.7+.
861   if (base::mac::IsOSSnowLeopard())
862     EXPECT_TRUE(IsFrontWindow([controller_ createFullscreenWindow]));
864   // We have to cleanup after ourselves by unfullscreening.
865   [controller_ exitFullscreen];
866   WaitForFullScreenTransition();
869 @implementation BrowserWindowControllerFakeFullscreen
870 // Override |-createFullscreenWindow| to return a dummy window. This isn't
871 // needed to pass the test, but because the dummy window is only 100x100, it
872 // prevents the real fullscreen window from flashing up and taking over the
873 // whole screen. We have to return an actual window because |-layoutSubviews|
874 // looks at the window's frame.
875 - (NSWindow*)createFullscreenWindow {
876   if (testFullscreenWindow_.get())
877     return testFullscreenWindow_.get();
879   testFullscreenWindow_.reset(
880       [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,400,400)
881                                   styleMask:NSBorderlessWindowMask
882                                     backing:NSBackingStoreBuffered
883                                       defer:NO]);
884   return testFullscreenWindow_.get();
886 @end
888 /* TODO(???): test other methods of BrowserWindowController */