Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / browser_window_controller_browsertest.mm
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.
4
5 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
6
7 #import "base/mac/mac_util.h"
8 #include "base/mac/sdk_forward_declarations.h"
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/devtools/devtools_window_testing.h"
14 #include "chrome/browser/infobars/infobar_service.h"
15 #include "chrome/browser/infobars/simple_alert_infobar_delegate.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_commands.h"
21 #include "chrome/browser/ui/browser_list.h"
22 #include "chrome/browser/ui/browser_window.h"
23 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
24 #import "chrome/browser/ui/cocoa/browser_window_controller_private.h"
25 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
26 #import "chrome/browser/ui/cocoa/history_overlay_controller.h"
27 #import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h"
28 #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
29 #import "chrome/browser/ui/cocoa/infobars/infobar_controller.h"
30 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
31 #import "chrome/browser/ui/cocoa/profiles/avatar_base_controller.h"
32 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
33 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
34 #include "chrome/browser/ui/extensions/application_launch.h"
35 #include "chrome/browser/ui/find_bar/find_bar.h"
36 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
37 #include "chrome/browser/ui/tabs/tab_strip_model.h"
38 #include "chrome/test/base/in_process_browser_test.h"
39 #include "chrome/test/base/testing_profile.h"
40 #include "content/public/browser/web_contents.h"
41 #include "content/public/test/test_utils.h"
42 #import "testing/gtest_mac.h"
43 #import "third_party/ocmock/OCMock/OCMock.h"
44 #import "ui/base/cocoa/nsview_additions.h"
45 #include "ui/gfx/animation/slide_animation.h"
46
47 namespace {
48
49 // Creates a mock of an NSWindow that has the given |frame|.
50 id MockWindowWithFrame(NSRect frame) {
51   id window = [OCMockObject mockForClass:[NSWindow class]];
52   NSValue* window_frame =
53       [NSValue valueWithBytes:&frame objCType:@encode(NSRect)];
54   [[[window stub] andReturnValue:window_frame] frame];
55   return window;
56 }
57
58 void CreateProfileCallback(const base::Closure& quit_closure,
59                            Profile* profile,
60                            Profile::CreateStatus status) {
61   EXPECT_TRUE(profile);
62   EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status);
63   EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status);
64   // This will be called multiple times. Wait until the profile is initialized
65   // fully to quit the loop.
66   if (status == Profile::CREATE_STATUS_INITIALIZED)
67     quit_closure.Run();
68 }
69
70 enum ViewID {
71   VIEW_ID_TOOLBAR,
72   VIEW_ID_BOOKMARK_BAR,
73   VIEW_ID_INFO_BAR,
74   VIEW_ID_FIND_BAR,
75   VIEW_ID_DOWNLOAD_SHELF,
76   VIEW_ID_TAB_CONTENT_AREA,
77   VIEW_ID_FULLSCREEN_FLOATING_BAR,
78   VIEW_ID_COUNT,
79 };
80
81 // Checks that no views draw on top of the supposedly exposed view.
82 class ViewExposedChecker {
83  public:
84   ViewExposedChecker() : below_exposed_view_(YES) {}
85   ~ViewExposedChecker() {}
86
87   void SetExceptions(NSArray* exceptions) {
88     exceptions_.reset([exceptions retain]);
89   }
90
91   // Checks that no views draw in front of |view|, with the exception of
92   // |exceptions|.
93   void CheckViewExposed(NSView* view) {
94     below_exposed_view_ = YES;
95     exposed_view_.reset([view retain]);
96     CheckViewsDoNotObscure([[[view window] contentView] superview]);
97   }
98
99  private:
100   // Checks that |view| does not draw on top of |exposed_view_|.
101   void CheckViewDoesNotObscure(NSView* view) {
102     NSRect viewWindowFrame = [view convertRect:[view bounds] toView:nil];
103     NSRect viewBeingVerifiedWindowFrame =
104         [exposed_view_ convertRect:[exposed_view_ bounds] toView:nil];
105
106     // The views do not intersect.
107     if (!NSIntersectsRect(viewBeingVerifiedWindowFrame, viewWindowFrame))
108       return;
109
110     // No view can be above the view being checked.
111     EXPECT_TRUE(below_exposed_view_);
112
113     // If |view| is a parent of |exposed_view_|, then there's nothing else
114     // to check.
115     NSView* parent = exposed_view_;
116     while (parent != nil) {
117       parent = [parent superview];
118       if (parent == view)
119         return;
120     }
121
122     if ([exposed_view_ layer])
123       return;
124
125     // If the view being verified doesn't have a layer, then no views that
126     // intersect it can have a layer.
127     if ([exceptions_ containsObject:view]) {
128       EXPECT_FALSE([view isOpaque]);
129       return;
130     }
131
132     EXPECT_TRUE(![view layer]) << [[view description] UTF8String] << " " <<
133         [NSStringFromRect(viewWindowFrame) UTF8String];
134   }
135
136   // Recursively checks that |view| and its subviews do not draw on top of
137   // |exposed_view_|. The recursion passes through all views in order of
138   // back-most in Z-order to front-most in Z-order.
139   void CheckViewsDoNotObscure(NSView* view) {
140     // If this is the view being checked, don't recurse into its subviews. All
141     // future views encountered in the recursion are in front of the view being
142     // checked.
143     if (view == exposed_view_) {
144       below_exposed_view_ = NO;
145       return;
146     }
147
148     CheckViewDoesNotObscure(view);
149
150     // Perform the recursion.
151     for (NSView* subview in [view subviews])
152       CheckViewsDoNotObscure(subview);
153   }
154
155   // The method CheckViewExposed() recurses through the views in the view
156   // hierarchy and checks that none of the views obscure |exposed_view_|.
157   base::scoped_nsobject<NSView> exposed_view_;
158
159   // While this flag is true, the views being recursed through are below
160   // |exposed_view_| in Z-order. After the recursion passes |exposed_view_|,
161   // this flag is set to false.
162   BOOL below_exposed_view_;
163
164   // Exceptions are allowed to overlap |exposed_view_|. Exceptions must still
165   // be Z-order behind |exposed_view_|.
166   base::scoped_nsobject<NSArray> exceptions_;
167
168   DISALLOW_COPY_AND_ASSIGN(ViewExposedChecker);
169 };
170
171 }  // namespace
172
173 @interface InfoBarContainerController(TestingAPI)
174 - (BOOL)isTopInfoBarAnimationRunning;
175 @end
176
177 @implementation InfoBarContainerController(TestingAPI)
178 - (BOOL)isTopInfoBarAnimationRunning {
179   InfoBarController* infoBarController = [infobarControllers_ objectAtIndex:0];
180   if (infoBarController) {
181     const gfx::SlideAnimation& infobarAnimation =
182         static_cast<const InfoBarCocoa*>(
183             infoBarController.infobar)->animation();
184     return infobarAnimation.is_animating();
185   }
186   return NO;
187 }
188 @end
189
190 class BrowserWindowControllerTest : public InProcessBrowserTest {
191  public:
192   BrowserWindowControllerTest() : InProcessBrowserTest() {
193   }
194
195   void SetUpOnMainThread() override {
196     [[controller() bookmarkBarController] setStateAnimationsEnabled:NO];
197     [[controller() bookmarkBarController] setInnerContentAnimationsEnabled:NO];
198   }
199
200   BrowserWindowController* controller() const {
201     return [BrowserWindowController browserWindowControllerForWindow:
202         browser()->window()->GetNativeWindow()];
203   }
204
205   static void ShowInfoBar(Browser* browser) {
206     SimpleAlertInfoBarDelegate::Create(
207         InfoBarService::FromWebContents(
208             browser->tab_strip_model()->GetActiveWebContents()),
209         0, base::string16(), false);
210   }
211
212   NSView* GetViewWithID(ViewID view_id) const {
213     switch (view_id) {
214       case VIEW_ID_FULLSCREEN_FLOATING_BAR:
215         return [controller() floatingBarBackingView];
216       case VIEW_ID_TOOLBAR:
217         return [[controller() toolbarController] view];
218       case VIEW_ID_BOOKMARK_BAR:
219         return [[controller() bookmarkBarController] view];
220       case VIEW_ID_INFO_BAR:
221         return [[controller() infoBarContainerController] view];
222       case VIEW_ID_FIND_BAR:
223         return [[controller() findBarCocoaController] view];
224       case VIEW_ID_DOWNLOAD_SHELF:
225         return [[controller() downloadShelf] view];
226       case VIEW_ID_TAB_CONTENT_AREA:
227         return [controller() tabContentArea];
228       default:
229         NOTREACHED();
230         return nil;
231     }
232   }
233
234   void VerifyZOrder(const std::vector<ViewID>& view_list) const {
235     std::vector<NSView*> visible_views;
236     for (size_t i = 0; i < view_list.size(); ++i) {
237       NSView* view = GetViewWithID(view_list[i]);
238       if ([view superview])
239         visible_views.push_back(view);
240     }
241
242     for (size_t i = 0; i < visible_views.size() - 1; ++i) {
243       NSView* bottom_view = visible_views[i];
244       NSView* top_view = visible_views[i + 1];
245
246       EXPECT_NSEQ([bottom_view superview], [top_view superview]);
247       EXPECT_TRUE([bottom_view cr_isBelowView:top_view]);
248     }
249
250     // Views not in |view_list| must either be nil or not parented.
251     for (size_t i = 0; i < VIEW_ID_COUNT; ++i) {
252       if (std::find(view_list.begin(), view_list.end(), i) == view_list.end()) {
253         NSView* view = GetViewWithID(static_cast<ViewID>(i));
254         EXPECT_TRUE(!view || ![view superview]);
255       }
256     }
257   }
258
259   CGFloat GetViewHeight(ViewID viewID) const {
260     CGFloat height = NSHeight([GetViewWithID(viewID) frame]);
261     if (viewID == VIEW_ID_INFO_BAR) {
262       height -= [[controller() infoBarContainerController]
263           overlappingTipHeight];
264     }
265     return height;
266   }
267
268   static void CheckTopInfoBarAnimation(
269       InfoBarContainerController* info_bar_container_controller,
270       const base::Closure& quit_task) {
271     if (![info_bar_container_controller isTopInfoBarAnimationRunning])
272       quit_task.Run();
273   }
274
275   static void CheckBookmarkBarAnimation(
276       BookmarkBarController* bookmark_bar_controller,
277       const base::Closure& quit_task) {
278     if (![bookmark_bar_controller isAnimationRunning])
279       quit_task.Run();
280   }
281
282   void WaitForTopInfoBarAnimationToFinish() {
283     scoped_refptr<content::MessageLoopRunner> runner =
284         new content::MessageLoopRunner;
285
286     base::Timer timer(false, true);
287     timer.Start(
288         FROM_HERE,
289         base::TimeDelta::FromMilliseconds(15),
290         base::Bind(&CheckTopInfoBarAnimation,
291                    [controller() infoBarContainerController],
292                    runner->QuitClosure()));
293     runner->Run();
294   }
295
296   void WaitForBookmarkBarAnimationToFinish() {
297     scoped_refptr<content::MessageLoopRunner> runner =
298         new content::MessageLoopRunner;
299
300     base::Timer timer(false, true);
301     timer.Start(
302         FROM_HERE,
303         base::TimeDelta::FromMilliseconds(15),
304         base::Bind(&CheckBookmarkBarAnimation,
305                    [controller() bookmarkBarController],
306                    runner->QuitClosure()));
307     runner->Run();
308   }
309
310   NSInteger GetExpectedTopInfoBarTipHeight() {
311     InfoBarContainerController* info_bar_container_controller =
312         [controller() infoBarContainerController];
313     CGFloat overlapping_tip_height =
314         [info_bar_container_controller overlappingTipHeight];
315     LocationBarViewMac* location_bar_view = [controller() locationBarBridge];
316     NSPoint icon_bottom = location_bar_view->GetPageInfoBubblePoint();
317
318     NSPoint info_bar_top = NSMakePoint(0,
319         NSHeight([info_bar_container_controller view].frame) -
320         overlapping_tip_height);
321     info_bar_top = [[info_bar_container_controller view]
322         convertPoint:info_bar_top toView:nil];
323     return icon_bottom.y - info_bar_top.y;
324   }
325
326   // Nothing should draw on top of the window controls.
327   void VerifyWindowControlsZOrder() {
328     NSWindow* window = [controller() window];
329     ViewExposedChecker checker;
330
331     // The exceptions are the contentView, chromeContentView and tabStripView,
332     // which are layer backed but transparent.
333     NSArray* exceptions = @[
334       [window contentView],
335       controller().chromeContentView,
336       controller().tabStripView
337     ];
338     checker.SetExceptions(exceptions);
339
340     checker.CheckViewExposed([window standardWindowButton:NSWindowCloseButton]);
341     checker.CheckViewExposed(
342         [window standardWindowButton:NSWindowMiniaturizeButton]);
343     checker.CheckViewExposed([window standardWindowButton:NSWindowZoomButton]);
344
345     // There is no fullscreen button on OSX 10.6 or OSX 10.10+.
346     NSView* view = [window standardWindowButton:NSWindowFullScreenButton];
347     if (view)
348       checker.CheckViewExposed(view);
349   }
350
351  private:
352   DISALLOW_COPY_AND_ASSIGN(BrowserWindowControllerTest);
353 };
354
355 // Tests that adding the first profile moves the Lion fullscreen button over
356 // correctly.
357 // DISABLED_ because it regularly times out: http://crbug.com/159002.
358 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
359                        DISABLED_ProfileAvatarFullscreenButton) {
360   if (base::mac::IsOSSnowLeopard())
361     return;
362
363   // Initialize the locals.
364   ProfileManager* profile_manager = g_browser_process->profile_manager();
365   ASSERT_TRUE(profile_manager);
366
367   NSWindow* window = browser()->window()->GetNativeWindow();
368   ASSERT_TRUE(window);
369
370   // With only one profile, the fullscreen button should be visible, but the
371   // avatar button should not.
372   EXPECT_EQ(1u, profile_manager->GetNumberOfProfiles());
373
374   NSButton* fullscreen_button =
375       [window standardWindowButton:NSWindowFullScreenButton];
376   EXPECT_TRUE(fullscreen_button);
377   EXPECT_FALSE([fullscreen_button isHidden]);
378
379   AvatarBaseController* avatar_controller =
380       [controller() avatarButtonController];
381   NSView* avatar = [avatar_controller view];
382   EXPECT_TRUE(avatar);
383   EXPECT_TRUE([avatar isHidden]);
384
385   // Create a profile asynchronously and run the loop until its creation
386   // is complete.
387   base::RunLoop run_loop;
388
389   ProfileManager::CreateCallback create_callback =
390       base::Bind(&CreateProfileCallback, run_loop.QuitClosure());
391   profile_manager->CreateProfileAsync(
392       profile_manager->user_data_dir().Append("test"),
393       create_callback,
394       base::ASCIIToUTF16("avatar_test"),
395       base::string16(),
396       std::string());
397
398   run_loop.Run();
399
400   // There should now be two profiles, and the avatar button and fullscreen
401   // button are both visible.
402   EXPECT_EQ(2u, profile_manager->GetNumberOfProfiles());
403   EXPECT_FALSE([avatar isHidden]);
404   EXPECT_FALSE([fullscreen_button isHidden]);
405   EXPECT_EQ([avatar window], [fullscreen_button window]);
406
407   // Make sure the visual order of the buttons is correct and that they don't
408   // overlap.
409   NSRect avatar_frame = [avatar frame];
410   NSRect fullscreen_frame = [fullscreen_button frame];
411
412   EXPECT_LT(NSMinX(fullscreen_frame), NSMinX(avatar_frame));
413   EXPECT_LT(NSMaxX(fullscreen_frame), NSMinX(avatar_frame));
414 }
415
416 // Verify that in non-Instant normal mode that the find bar and download shelf
417 // are above the content area. Everything else should be below it.
418 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, ZOrderNormal) {
419   browser()->GetFindBarController();  // add find bar
420
421   std::vector<ViewID> view_list;
422   view_list.push_back(VIEW_ID_DOWNLOAD_SHELF);
423   view_list.push_back(VIEW_ID_BOOKMARK_BAR);
424   view_list.push_back(VIEW_ID_TOOLBAR);
425   view_list.push_back(VIEW_ID_INFO_BAR);
426   view_list.push_back(VIEW_ID_TAB_CONTENT_AREA);
427   view_list.push_back(VIEW_ID_FIND_BAR);
428   VerifyZOrder(view_list);
429
430   [controller() showOverlay];
431   [controller() removeOverlay];
432   VerifyZOrder(view_list);
433
434   [controller() enterImmersiveFullscreen];
435   [controller() exitImmersiveFullscreen];
436   VerifyZOrder(view_list);
437 }
438
439 // Verify that in non-Instant presentation mode that the info bar is below the
440 // content are and everything else is above it.
441 // DISABLED due to flaky failures on trybots. http://crbug.com/178778
442 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
443                        DISABLED_ZOrderPresentationMode) {
444   chrome::ToggleFullscreenMode(browser());
445   browser()->GetFindBarController();  // add find bar
446
447   std::vector<ViewID> view_list;
448   view_list.push_back(VIEW_ID_INFO_BAR);
449   view_list.push_back(VIEW_ID_TAB_CONTENT_AREA);
450   view_list.push_back(VIEW_ID_FULLSCREEN_FLOATING_BAR);
451   view_list.push_back(VIEW_ID_BOOKMARK_BAR);
452   view_list.push_back(VIEW_ID_TOOLBAR);
453   view_list.push_back(VIEW_ID_FIND_BAR);
454   view_list.push_back(VIEW_ID_DOWNLOAD_SHELF);
455   VerifyZOrder(view_list);
456 }
457
458 // Verify that if the fullscreen floating bar view is below the tab content area
459 // then calling |updateSubviewZOrder:| will correctly move back above.
460 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
461                        DISABLED_FloatingBarBelowContentView) {
462   // TODO(kbr): re-enable: http://crbug.com/222296
463   if (base::mac::IsOSMountainLionOrLater())
464     return;
465
466   chrome::ToggleFullscreenMode(browser());
467
468   NSView* fullscreen_floating_bar =
469       GetViewWithID(VIEW_ID_FULLSCREEN_FLOATING_BAR);
470   [fullscreen_floating_bar removeFromSuperview];
471   [[[controller() window] contentView] addSubview:fullscreen_floating_bar
472                                        positioned:NSWindowBelow
473                                        relativeTo:nil];
474   [controller() updateSubviewZOrder];
475
476   std::vector<ViewID> view_list;
477   view_list.push_back(VIEW_ID_INFO_BAR);
478   view_list.push_back(VIEW_ID_TAB_CONTENT_AREA);
479   view_list.push_back(VIEW_ID_FULLSCREEN_FLOATING_BAR);
480   view_list.push_back(VIEW_ID_BOOKMARK_BAR);
481   view_list.push_back(VIEW_ID_TOOLBAR);
482   view_list.push_back(VIEW_ID_DOWNLOAD_SHELF);
483   VerifyZOrder(view_list);
484 }
485
486 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, SheetPosition) {
487   ASSERT_TRUE([controller() isKindOfClass:[BrowserWindowController class]]);
488   EXPECT_TRUE([controller() isTabbedWindow]);
489   EXPECT_TRUE([controller() hasTabStrip]);
490   EXPECT_FALSE([controller() hasTitleBar]);
491   EXPECT_TRUE([controller() hasToolbar]);
492   EXPECT_FALSE([controller() isBookmarkBarVisible]);
493
494   NSRect defaultAlertFrame = NSMakeRect(0, 0, 300, 200);
495   id sheet = MockWindowWithFrame(defaultAlertFrame);
496   NSWindow* window = browser()->window()->GetNativeWindow();
497   NSRect alertFrame = [controller() window:window
498                          willPositionSheet:nil
499                                  usingRect:defaultAlertFrame];
500   NSRect toolbarFrame = [[[controller() toolbarController] view] frame];
501   EXPECT_EQ(NSMinY(alertFrame), NSMinY(toolbarFrame));
502
503   // Open sheet with normal browser window, persistent bookmark bar.
504   chrome::ToggleBookmarkBarWhenVisible(browser()->profile());
505   EXPECT_TRUE([controller() isBookmarkBarVisible]);
506   alertFrame = [controller() window:window
507                   willPositionSheet:sheet
508                           usingRect:defaultAlertFrame];
509   NSRect bookmarkBarFrame = [[[controller() bookmarkBarController] view] frame];
510   EXPECT_EQ(NSMinY(alertFrame), NSMinY(bookmarkBarFrame));
511
512   // If the sheet is too large, it should be positioned at the top of the
513   // window.
514   defaultAlertFrame = NSMakeRect(0, 0, 300, 2000);
515   sheet = MockWindowWithFrame(defaultAlertFrame);
516   alertFrame = [controller() window:window
517                   willPositionSheet:sheet
518                           usingRect:defaultAlertFrame];
519   EXPECT_EQ(NSMinY(alertFrame), NSHeight([window frame]));
520
521   // Reset the sheet's size.
522   defaultAlertFrame = NSMakeRect(0, 0, 300, 200);
523   sheet = MockWindowWithFrame(defaultAlertFrame);
524
525   // Make sure the profile does not have the bookmark visible so that
526   // we'll create the shortcut window without the bookmark bar.
527   chrome::ToggleBookmarkBarWhenVisible(browser()->profile());
528   // Open application mode window.
529   OpenAppShortcutWindow(browser()->profile(), GURL("about:blank"));
530   Browser* popup_browser = BrowserList::GetInstance(
531       chrome::GetActiveDesktop())->GetLastActive();
532   NSWindow* popupWindow = popup_browser->window()->GetNativeWindow();
533   BrowserWindowController* popupController =
534       [BrowserWindowController browserWindowControllerForWindow:popupWindow];
535   ASSERT_TRUE([popupController isKindOfClass:[BrowserWindowController class]]);
536   EXPECT_FALSE([popupController isTabbedWindow]);
537   EXPECT_FALSE([popupController hasTabStrip]);
538   EXPECT_TRUE([popupController hasTitleBar]);
539   EXPECT_FALSE([popupController isBookmarkBarVisible]);
540   EXPECT_FALSE([popupController hasToolbar]);
541
542   // Open sheet in an application window.
543   [popupController showWindow:nil];
544   alertFrame = [popupController window:popupWindow
545                      willPositionSheet:sheet
546                              usingRect:defaultAlertFrame];
547   EXPECT_EQ(NSMinY(alertFrame),
548             NSHeight([[popupWindow contentView] frame]) -
549             defaultAlertFrame.size.height);
550
551   // Close the application window.
552   popup_browser->tab_strip_model()->CloseSelectedTabs();
553   [popupController close];
554 }
555
556 // Verify that the info bar tip is hidden when the toolbar is not visible.
557 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
558                        InfoBarTipHiddenForWindowWithoutToolbar) {
559   ShowInfoBar(browser());
560   EXPECT_FALSE(
561       [[controller() infoBarContainerController] shouldSuppressTopInfoBarTip]);
562
563   OpenAppShortcutWindow(browser()->profile(), GURL("about:blank"));
564   Browser* popup_browser = BrowserList::GetInstance(
565       chrome::HOST_DESKTOP_TYPE_NATIVE)->GetLastActive();
566   NSWindow* popupWindow = popup_browser->window()->GetNativeWindow();
567   BrowserWindowController* popupController =
568       [BrowserWindowController browserWindowControllerForWindow:popupWindow];
569   EXPECT_FALSE([popupController hasToolbar]);
570
571   // Show infobar for controller.
572   ShowInfoBar(popup_browser);
573   EXPECT_TRUE(
574       [[popupController infoBarContainerController]
575           shouldSuppressTopInfoBarTip]);
576 }
577
578 // Tests that status bubble's base frame does move when devTools are docked.
579 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
580                        StatusBubblePositioning) {
581   NSPoint origin = [controller() statusBubbleBaseFrame].origin;
582
583   DevToolsWindow* devtools_window =
584       DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true);
585   DevToolsWindowTesting::Get(devtools_window)->SetInspectedPageBounds(
586       gfx::Rect(10, 10, 100, 100));
587
588   NSPoint originWithDevTools = [controller() statusBubbleBaseFrame].origin;
589   EXPECT_FALSE(NSEqualPoints(origin, originWithDevTools));
590
591   DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window);
592 }
593
594 // Tests that top infobar tip is streched when bookmark bar becomes SHOWN/HIDDEN
595 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest,
596                        InfoBarTipStretchedWhenBookmarkBarStatusChanged) {
597   EXPECT_FALSE([controller() isBookmarkBarVisible]);
598   ShowInfoBar(browser());
599   // The infobar tip is animated during the infobar is being added, wait until
600   // it completes.
601   WaitForTopInfoBarAnimationToFinish();
602
603   EXPECT_FALSE([[controller() infoBarContainerController]
604       shouldSuppressTopInfoBarTip]);
605
606   NSInteger max_tip_height = infobars::InfoBar::kMaximumArrowTargetHeight +
607       infobars::InfoBar::kSeparatorLineHeight;
608
609   chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR);
610   WaitForBookmarkBarAnimationToFinish();
611   EXPECT_TRUE([controller() isBookmarkBarVisible]);
612   EXPECT_EQ(std::min(GetExpectedTopInfoBarTipHeight(), max_tip_height),
613             [[controller() infoBarContainerController] overlappingTipHeight]);
614
615   chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR);
616   WaitForBookmarkBarAnimationToFinish();
617   EXPECT_FALSE([controller() isBookmarkBarVisible]);
618   EXPECT_EQ(std::min(GetExpectedTopInfoBarTipHeight(), max_tip_height),
619             [[controller() infoBarContainerController] overlappingTipHeight]);
620 }
621
622 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, TrafficLightZOrder) {
623   // Verify z order immediately after creation.
624   VerifyWindowControlsZOrder();
625
626   // Verify z order in and out of overlay.
627   [controller() showOverlay];
628   VerifyWindowControlsZOrder();
629   [controller() removeOverlay];
630   VerifyWindowControlsZOrder();
631
632   // Toggle immersive fullscreen, then verify z order. In immersive fullscreen,
633   // there are no window controls.
634   [controller() enterImmersiveFullscreen];
635   [controller() exitImmersiveFullscreen];
636   VerifyWindowControlsZOrder();
637 }