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