|  | // Copyright 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "chrome/browser/ui/browser.h" | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "chrome/app/chrome_command_ids.h" | 
|  | #include "chrome/browser/ui/browser_command_controller.h" | 
|  | #include "chrome/browser/ui/browser_commands.h" | 
|  | #include "chrome/browser/ui/tabs/tab_strip_model.h" | 
|  | #include "chrome/test/base/browser_with_test_window_test.h" | 
|  | #include "components/zoom/zoom_controller.h" | 
|  | #include "content/public/browser/render_widget_host_view.h" | 
|  | #include "content/public/browser/site_instance.h" | 
|  | #include "content/public/browser/web_contents.h" | 
|  | #include "content/public/test/web_contents_tester.h" | 
|  | #include "third_party/skia/include/core/SkColor.h" | 
|  |  | 
|  | using content::SiteInstance; | 
|  | using content::WebContents; | 
|  | using content::WebContentsTester; | 
|  |  | 
|  | class BrowserUnitTest : public BrowserWithTestWindowTest { | 
|  | public: | 
|  | BrowserUnitTest() {} | 
|  | ~BrowserUnitTest() override {} | 
|  |  | 
|  | // Caller owns the memory. | 
|  | std::unique_ptr<WebContents> CreateTestWebContents() { | 
|  | return WebContentsTester::CreateTestWebContents( | 
|  | profile(), SiteInstance::Create(profile())); | 
|  | } | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(BrowserUnitTest); | 
|  | }; | 
|  |  | 
|  | // Ensure crashed tabs are not reloaded when selected. crbug.com/232323 | 
|  | TEST_F(BrowserUnitTest, ReloadCrashedTab) { | 
|  | TabStripModel* tab_strip_model = browser()->tab_strip_model(); | 
|  |  | 
|  | // Start with a single foreground tab. |tab_strip_model| owns the memory. | 
|  | std::unique_ptr<WebContents> contents1 = CreateTestWebContents(); | 
|  | content::WebContents* raw_contents1 = contents1.get(); | 
|  | tab_strip_model->AppendWebContents(std::move(contents1), true); | 
|  | WebContentsTester::For(raw_contents1)->NavigateAndCommit(GURL("about:blank")); | 
|  | WebContentsTester::For(raw_contents1)->TestSetIsLoading(false); | 
|  | EXPECT_TRUE(tab_strip_model->IsTabSelected(0)); | 
|  | EXPECT_FALSE(raw_contents1->IsLoading()); | 
|  |  | 
|  | // Add a second tab in the background. | 
|  | std::unique_ptr<WebContents> contents2 = CreateTestWebContents(); | 
|  | content::WebContents* raw_contents2 = contents2.get(); | 
|  | tab_strip_model->AppendWebContents(std::move(contents2), false); | 
|  | WebContentsTester::For(raw_contents2)->NavigateAndCommit(GURL("about:blank")); | 
|  | WebContentsTester::For(raw_contents2)->TestSetIsLoading(false); | 
|  | EXPECT_EQ(2, browser()->tab_strip_model()->count()); | 
|  | EXPECT_TRUE(tab_strip_model->IsTabSelected(0)); | 
|  | EXPECT_FALSE(raw_contents2->IsLoading()); | 
|  |  | 
|  | // Simulate the second tab crashing. | 
|  | raw_contents2->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); | 
|  | EXPECT_TRUE(raw_contents2->IsCrashed()); | 
|  |  | 
|  | // Selecting the second tab does not cause a load or clear the crash. | 
|  | tab_strip_model->ActivateTabAt(1, true); | 
|  | EXPECT_TRUE(tab_strip_model->IsTabSelected(1)); | 
|  | EXPECT_FALSE(raw_contents2->IsLoading()); | 
|  | EXPECT_TRUE(raw_contents2->IsCrashed()); | 
|  | } | 
|  |  | 
|  | // This tests a workaround which is not necessary on Mac. | 
|  | // https://crbug.com/719230 | 
|  | #if defined(OS_MACOSX) | 
|  | #define MAYBE_SetBackgroundColorForNewTab DISABLED_SetBackgroundColorForNewTab | 
|  | #else | 
|  | #define MAYBE_SetBackgroundColorForNewTab SetBackgroundColorForNewTab | 
|  | #endif | 
|  | TEST_F(BrowserUnitTest, MAYBE_SetBackgroundColorForNewTab) { | 
|  | TabStripModel* tab_strip_model = browser()->tab_strip_model(); | 
|  |  | 
|  | std::unique_ptr<WebContents> contents1 = CreateTestWebContents(); | 
|  | content::WebContents* raw_contents1 = contents1.get(); | 
|  | tab_strip_model->AppendWebContents(std::move(contents1), true); | 
|  | WebContentsTester::For(raw_contents1)->NavigateAndCommit(GURL("about:blank")); | 
|  | WebContentsTester::For(raw_contents1)->TestSetIsLoading(false); | 
|  |  | 
|  | raw_contents1->GetMainFrame()->GetView()->SetBackgroundColor(SK_ColorRED); | 
|  |  | 
|  | // Add a second tab in the background. | 
|  | std::unique_ptr<WebContents> contents2 = CreateTestWebContents(); | 
|  | content::WebContents* raw_contents2 = contents2.get(); | 
|  | tab_strip_model->AppendWebContents(std::move(contents2), false); | 
|  | WebContentsTester::For(raw_contents2)->NavigateAndCommit(GURL("about:blank")); | 
|  | WebContentsTester::For(raw_contents2)->TestSetIsLoading(false); | 
|  |  | 
|  | tab_strip_model->ActivateTabAt(1, true); | 
|  | ASSERT_TRUE(raw_contents2->GetMainFrame()->GetView()->GetBackgroundColor()); | 
|  | EXPECT_EQ(SK_ColorRED, | 
|  | *raw_contents2->GetMainFrame()->GetView()->GetBackgroundColor()); | 
|  | } | 
|  |  | 
|  | // Ensure the print command gets disabled when a tab crashes. | 
|  | TEST_F(BrowserUnitTest, DisablePrintOnCrashedTab) { | 
|  | TabStripModel* tab_strip_model = browser()->tab_strip_model(); | 
|  |  | 
|  | std::unique_ptr<WebContents> contents = CreateTestWebContents(); | 
|  | content::WebContents* raw_contents = contents.get(); | 
|  | tab_strip_model->AppendWebContents(std::move(contents), true); | 
|  | WebContentsTester::For(raw_contents)->NavigateAndCommit(GURL("about:blank")); | 
|  |  | 
|  | CommandUpdater* command_updater = browser()->command_controller(); | 
|  |  | 
|  | EXPECT_FALSE(raw_contents->IsCrashed()); | 
|  | EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_PRINT)); | 
|  | EXPECT_TRUE(chrome::CanPrint(browser())); | 
|  |  | 
|  | raw_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); | 
|  |  | 
|  | EXPECT_TRUE(raw_contents->IsCrashed()); | 
|  | EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_PRINT)); | 
|  | EXPECT_FALSE(chrome::CanPrint(browser())); | 
|  | } | 
|  |  | 
|  | // Ensure the zoom-in and zoom-out commands get disabled when a tab crashes. | 
|  | TEST_F(BrowserUnitTest, DisableZoomOnCrashedTab) { | 
|  | TabStripModel* tab_strip_model = browser()->tab_strip_model(); | 
|  |  | 
|  | std::unique_ptr<WebContents> contents = CreateTestWebContents(); | 
|  | content::WebContents* raw_contents = contents.get(); | 
|  | tab_strip_model->AppendWebContents(std::move(contents), true); | 
|  | WebContentsTester::For(raw_contents)->NavigateAndCommit(GURL("about:blank")); | 
|  | zoom::ZoomController* zoom_controller = | 
|  | zoom::ZoomController::FromWebContents(raw_contents); | 
|  | EXPECT_TRUE(zoom_controller->SetZoomLevel(zoom_controller-> | 
|  | GetDefaultZoomLevel())); | 
|  |  | 
|  | CommandUpdater* command_updater = browser()->command_controller(); | 
|  |  | 
|  | EXPECT_TRUE(zoom_controller->IsAtDefaultZoom()); | 
|  | EXPECT_FALSE(raw_contents->IsCrashed()); | 
|  | EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_ZOOM_PLUS)); | 
|  | EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_ZOOM_MINUS)); | 
|  | EXPECT_TRUE(chrome::CanZoomIn(raw_contents)); | 
|  | EXPECT_TRUE(chrome::CanZoomOut(raw_contents)); | 
|  |  | 
|  | raw_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); | 
|  |  | 
|  | EXPECT_TRUE(raw_contents->IsCrashed()); | 
|  | EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_ZOOM_PLUS)); | 
|  | EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_ZOOM_MINUS)); | 
|  | EXPECT_FALSE(chrome::CanZoomIn(raw_contents)); | 
|  | EXPECT_FALSE(chrome::CanZoomOut(raw_contents)); | 
|  | } | 
|  |  | 
|  | class BrowserBookmarkBarTest : public BrowserWithTestWindowTest { | 
|  | public: | 
|  | BrowserBookmarkBarTest() {} | 
|  | ~BrowserBookmarkBarTest() override {} | 
|  |  | 
|  | protected: | 
|  | BookmarkBar::State window_bookmark_bar_state() const { | 
|  | return static_cast<BookmarkBarStateTestBrowserWindow*>( | 
|  | browser()->window())->bookmark_bar_state(); | 
|  | } | 
|  |  | 
|  | // BrowserWithTestWindowTest: | 
|  | void SetUp() override { | 
|  | BrowserWithTestWindowTest::SetUp(); | 
|  | static_cast<BookmarkBarStateTestBrowserWindow*>( | 
|  | browser()->window())->set_browser(browser()); | 
|  | } | 
|  |  | 
|  | BrowserWindow* CreateBrowserWindow() override { | 
|  | return new BookmarkBarStateTestBrowserWindow(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | class BookmarkBarStateTestBrowserWindow : public TestBrowserWindow { | 
|  | public: | 
|  | BookmarkBarStateTestBrowserWindow() | 
|  | : browser_(NULL), | 
|  | bookmark_bar_state_(BookmarkBar::HIDDEN) {} | 
|  | ~BookmarkBarStateTestBrowserWindow() override {} | 
|  |  | 
|  | void set_browser(Browser* browser) { browser_ = browser; } | 
|  |  | 
|  | BookmarkBar::State bookmark_bar_state() const { | 
|  | return bookmark_bar_state_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | // TestBrowserWindow: | 
|  | void BookmarkBarStateChanged( | 
|  | BookmarkBar::AnimateChangeType change_type) override { | 
|  | bookmark_bar_state_ = browser_->bookmark_bar_state(); | 
|  | TestBrowserWindow::BookmarkBarStateChanged(change_type); | 
|  | } | 
|  |  | 
|  | void OnActiveTabChanged(content::WebContents* old_contents, | 
|  | content::WebContents* new_contents, | 
|  | int index, | 
|  | int reason) override { | 
|  | bookmark_bar_state_ = browser_->bookmark_bar_state(); | 
|  | TestBrowserWindow::OnActiveTabChanged(old_contents, new_contents, index, | 
|  | reason); | 
|  | } | 
|  |  | 
|  | Browser* browser_;  // Weak ptr. | 
|  | BookmarkBar::State bookmark_bar_state_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(BookmarkBarStateTestBrowserWindow); | 
|  | }; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(BrowserBookmarkBarTest); | 
|  | }; | 
|  |  | 
|  | // Ensure bookmark bar states in Browser and BrowserWindow are in sync after | 
|  | // Browser::ActiveTabChanged() calls BrowserWindow::OnActiveTabChanged(). | 
|  | TEST_F(BrowserBookmarkBarTest, StateOnActiveTabChanged) { | 
|  | ASSERT_EQ(BookmarkBar::HIDDEN, browser()->bookmark_bar_state()); | 
|  | ASSERT_EQ(BookmarkBar::HIDDEN, window_bookmark_bar_state()); | 
|  |  | 
|  | GURL ntp_url("chrome://newtab"); | 
|  | GURL non_ntp_url("http://foo"); | 
|  |  | 
|  | // Open a tab to NTP. | 
|  | AddTab(browser(), ntp_url); | 
|  | EXPECT_EQ(BookmarkBar::DETACHED, browser()->bookmark_bar_state()); | 
|  | EXPECT_EQ(BookmarkBar::DETACHED, window_bookmark_bar_state()); | 
|  |  | 
|  | // Navigate 1st tab to a non-NTP URL. | 
|  | NavigateAndCommitActiveTab(non_ntp_url); | 
|  | EXPECT_EQ(BookmarkBar::HIDDEN, browser()->bookmark_bar_state()); | 
|  | EXPECT_EQ(BookmarkBar::HIDDEN, window_bookmark_bar_state()); | 
|  |  | 
|  | // Open a tab to NTP at index 0. | 
|  | AddTab(browser(), ntp_url); | 
|  | EXPECT_EQ(BookmarkBar::DETACHED, browser()->bookmark_bar_state()); | 
|  | EXPECT_EQ(BookmarkBar::DETACHED, window_bookmark_bar_state()); | 
|  |  | 
|  | // Activate the 2nd tab which is non-NTP. | 
|  | browser()->tab_strip_model()->ActivateTabAt(1, true); | 
|  | EXPECT_EQ(BookmarkBar::HIDDEN, browser()->bookmark_bar_state()); | 
|  | EXPECT_EQ(BookmarkBar::HIDDEN, window_bookmark_bar_state()); | 
|  |  | 
|  | // Toggle bookmark bar while 2nd tab (non-NTP) is active. | 
|  | chrome::ToggleBookmarkBar(browser()); | 
|  | EXPECT_EQ(BookmarkBar::SHOW, browser()->bookmark_bar_state()); | 
|  | EXPECT_EQ(BookmarkBar::SHOW, window_bookmark_bar_state()); | 
|  |  | 
|  | // Activate the 1st tab which is NTP. | 
|  | browser()->tab_strip_model()->ActivateTabAt(0, true); | 
|  | EXPECT_EQ(BookmarkBar::SHOW, browser()->bookmark_bar_state()); | 
|  | EXPECT_EQ(BookmarkBar::SHOW, window_bookmark_bar_state()); | 
|  |  | 
|  | // Activate the 2nd tab which is non-NTP. | 
|  | browser()->tab_strip_model()->ActivateTabAt(1, true); | 
|  | EXPECT_EQ(BookmarkBar::SHOW, browser()->bookmark_bar_state()); | 
|  | EXPECT_EQ(BookmarkBar::SHOW, window_bookmark_bar_state()); | 
|  | } |