browser_view_unittest.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1// Copyright 2013 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#include "chrome/browser/ui/views/frame/browser_view.h" 6 7#include "base/memory/scoped_ptr.h" 8 9#include "chrome/app/chrome_command_ids.h" 10#include "chrome/browser/autocomplete/autocomplete_classifier.h" 11#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" 12#include "chrome/browser/search_engines/template_url_service.h" 13#include "chrome/browser/search_engines/template_url_service_factory.h" 14#include "chrome/browser/ui/browser_commands.h" 15#include "chrome/browser/ui/tabs/tab_strip_model.h" 16#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" 17#include "chrome/browser/ui/views/frame/browser_view_layout.h" 18#include "chrome/browser/ui/views/frame/overlay_container.h" 19#include "chrome/browser/ui/views/frame/top_container_view.h" 20#include "chrome/browser/ui/views/infobars/infobar_container_view.h" 21#include "chrome/browser/ui/views/tabs/tab_strip.h" 22#include "chrome/browser/ui/views/toolbar_view.h" 23#include "chrome/common/url_constants.h" 24#include "chrome/test/base/browser_with_test_window_test.h" 25#include "chrome/test/base/scoped_testing_local_state.h" 26#include "chrome/test/base/testing_browser_process.h" 27#include "grit/theme_resources.h" 28#include "testing/gtest/include/gtest/gtest.h" 29#include "ui/views/controls/single_split_view.h" 30#include "ui/views/controls/webview/webview.h" 31 32#if defined(OS_CHROMEOS) 33#include "chrome/browser/chromeos/input_method/input_method_configuration.h" 34#include "chrome/browser/chromeos/input_method/mock_input_method_manager.h" 35#endif 36 37#if defined(OS_WIN) 38#include "chrome/browser/ui/views/frame/browser_frame_win.h" 39#endif 40 41namespace { 42 43// Tab strip bounds depend on the window frame sizes. 44gfx::Point ExpectedTabStripOrigin(BrowserView* browser_view) { 45 gfx::Rect tabstrip_bounds( 46 browser_view->frame()->GetBoundsForTabStrip(browser_view->tabstrip())); 47 gfx::Point tabstrip_origin(tabstrip_bounds.origin()); 48 views::View::ConvertPointToTarget(browser_view->parent(), 49 browser_view, 50 &tabstrip_origin); 51 return tabstrip_origin; 52} 53 54// Caller owns the returned service. 55BrowserContextKeyedService* CreateTemplateURLService( 56 content::BrowserContext* profile) { 57 return new TemplateURLService(static_cast<Profile*>(profile)); 58} 59 60BrowserContextKeyedService* CreateAutocompleteClassifier( 61 content::BrowserContext* profile) { 62 return new AutocompleteClassifier(static_cast<Profile*>(profile)); 63} 64 65} // namespace 66 67class BrowserViewTest : public BrowserWithTestWindowTest { 68 public: 69 BrowserViewTest(); 70 virtual ~BrowserViewTest() {} 71 72 // BrowserWithTestWindowTest overrides: 73 virtual void SetUp() OVERRIDE; 74 virtual void TearDown() OVERRIDE; 75 virtual TestingProfile* CreateProfile() OVERRIDE; 76 virtual BrowserWindow* CreateBrowserWindow() OVERRIDE; 77 78 void Init(); 79 BrowserView* browser_view() { return browser_view_; } 80 81 private: 82 BrowserView* browser_view_; // Not owned. 83 scoped_ptr<ScopedTestingLocalState> local_state_; 84 DISALLOW_COPY_AND_ASSIGN(BrowserViewTest); 85}; 86 87BrowserViewTest::BrowserViewTest() 88 : browser_view_(NULL) { 89} 90 91void BrowserViewTest::SetUp() { 92 Init(); 93 // Memory ownership is tricky here. BrowserView has taken ownership of 94 // |browser|, so BrowserWithTestWindowTest cannot continue to own it. 95 ASSERT_TRUE(release_browser()); 96} 97 98void BrowserViewTest::TearDown() { 99 // Clean up any tabs we opened, otherwise Browser crashes in destruction. 100 browser_view_->browser()->tab_strip_model()->CloseAllTabs(); 101 // Ensure the Browser is reset before BrowserWithTestWindowTest cleans up 102 // the Profile. 103 browser_view_->GetWidget()->CloseNow(); 104 browser_view_ = NULL; 105 BrowserWithTestWindowTest::TearDown(); 106#if defined(OS_CHROMEOS) 107 chromeos::input_method::Shutdown(); 108#endif 109 local_state_.reset(NULL); 110} 111 112TestingProfile* BrowserViewTest::CreateProfile() { 113 TestingProfile* profile = BrowserWithTestWindowTest::CreateProfile(); 114 // TemplateURLService is normally NULL during testing. Instant extended 115 // needs this service so set a custom factory function. 116 TemplateURLServiceFactory::GetInstance()->SetTestingFactory( 117 profile, &CreateTemplateURLService); 118 // TODO(jamescook): Eliminate this by introducing a mock toolbar or mock 119 // location bar. 120 AutocompleteClassifierFactory::GetInstance()->SetTestingFactory( 121 profile, &CreateAutocompleteClassifier); 122 return profile; 123} 124 125BrowserWindow* BrowserViewTest::CreateBrowserWindow() { 126 // Allow BrowserWithTestWindowTest to use Browser to create the default 127 // BrowserView and BrowserFrame. 128 return NULL; 129} 130 131void BrowserViewTest::Init() { 132 local_state_.reset( 133 new ScopedTestingLocalState(TestingBrowserProcess::GetGlobal())); 134#if defined(OS_CHROMEOS) 135 chromeos::input_method::InitializeForTesting( 136 new chromeos::input_method::MockInputMethodManager); 137#endif 138 BrowserWithTestWindowTest::SetUp(); 139 browser_view_ = static_cast<BrowserView*>(browser()->window()); 140} 141 142// Test basic construction and initialization. 143TEST_F(BrowserViewTest, BrowserView) { 144 // The window is owned by the native widget, not the test class. 145 EXPECT_FALSE(window()); 146 // |browser_view_| owns the Browser, not the test class. 147 EXPECT_FALSE(browser()); 148 EXPECT_TRUE(browser_view()->browser()); 149 150 // Test initial state. 151 EXPECT_TRUE(browser_view()->IsTabStripVisible()); 152 EXPECT_FALSE(browser_view()->IsOffTheRecord()); 153 EXPECT_EQ(IDR_OTR_ICON, browser_view()->GetOTRIconResourceID()); 154 EXPECT_FALSE(browser_view()->IsGuestSession()); 155 EXPECT_FALSE(browser_view()->ShouldShowAvatar()); 156 EXPECT_TRUE(browser_view()->IsBrowserTypeNormal()); 157 EXPECT_FALSE(browser_view()->IsFullscreen()); 158 EXPECT_FALSE(browser_view()->IsBookmarkBarVisible()); 159 EXPECT_FALSE(browser_view()->IsBookmarkBarAnimating()); 160} 161 162// Test layout of the top-of-window UI. 163TEST_F(BrowserViewTest, BrowserViewLayout) { 164 BookmarkBarView::DisableAnimationsForTesting(true); 165 166 // |browser_view_| owns the Browser, not the test class. 167 Browser* browser = browser_view()->browser(); 168 TopContainerView* top_container = browser_view()->top_container(); 169 TabStrip* tabstrip = browser_view()->tabstrip(); 170 ToolbarView* toolbar = browser_view()->toolbar(); 171 views::SingleSplitView* contents_split = 172 browser_view()->GetContentsSplitForTest(); 173 views::WebView* contents_web_view = 174 browser_view()->GetContentsWebViewForTest(); 175 OverlayContainer* overlay_container = 176 browser_view()->GetOverlayContainerForTest(); 177 178 // Start with a single tab open to a normal page. 179 AddTab(browser, GURL("about:blank")); 180 181 // Verify the view hierarchy. 182 EXPECT_EQ(top_container, browser_view()->tabstrip()->parent()); 183 EXPECT_EQ(top_container, browser_view()->toolbar()->parent()); 184 EXPECT_EQ(top_container, browser_view()->GetBookmarkBarView()->parent()); 185 EXPECT_EQ(browser_view(), browser_view()->infobar_container()->parent()); 186 EXPECT_EQ(browser_view(), overlay_container->parent()); 187 188 // Overlay container is at the front of the view hierarchy, followed by the 189 // find bar host and the top container. 190 EXPECT_EQ(browser_view()->child_count() - 1, 191 browser_view()->GetIndexOf(overlay_container)); 192 EXPECT_EQ(browser_view()->child_count() - 2, 193 browser_view()->GetIndexOf(browser_view()->find_bar_host_view())); 194 EXPECT_EQ(browser_view()->child_count() - 3, 195 browser_view()->GetIndexOf(top_container)); 196 197 // Verify basic layout. 198 EXPECT_EQ(0, top_container->x()); 199 EXPECT_EQ(0, top_container->y()); 200 EXPECT_EQ(browser_view()->width(), top_container->width()); 201 // Tabstrip layout varies based on window frame sizes. 202 gfx::Point expected_tabstrip_origin = ExpectedTabStripOrigin(browser_view()); 203 EXPECT_EQ(expected_tabstrip_origin.x(), tabstrip->x()); 204 EXPECT_EQ(expected_tabstrip_origin.y(), tabstrip->y()); 205 EXPECT_EQ(0, toolbar->x()); 206 EXPECT_EQ( 207 tabstrip->bounds().bottom() - 208 BrowserViewLayout::kToolbarTabStripVerticalOverlap, 209 toolbar->y()); 210 EXPECT_EQ(0, contents_split->x()); 211 EXPECT_EQ(toolbar->bounds().bottom(), contents_split->y()); 212 EXPECT_EQ(0, contents_web_view->x()); 213 EXPECT_EQ(0, contents_web_view->y()); 214 215 // Verify bookmark bar visibility. 216 BookmarkBarView* bookmark_bar = browser_view()->GetBookmarkBarView(); 217 EXPECT_FALSE(bookmark_bar->visible()); 218 EXPECT_FALSE(bookmark_bar->IsDetached()); 219 chrome::ExecuteCommand(browser, IDC_SHOW_BOOKMARK_BAR); 220 EXPECT_TRUE(bookmark_bar->visible()); 221 EXPECT_FALSE(bookmark_bar->IsDetached()); 222 chrome::ExecuteCommand(browser, IDC_SHOW_BOOKMARK_BAR); 223 EXPECT_FALSE(bookmark_bar->visible()); 224 EXPECT_FALSE(bookmark_bar->IsDetached()); 225 226 // Bookmark bar is reparented to BrowserView on NTP. 227 NavigateAndCommitActiveTabWithTitle(browser, 228 GURL(chrome::kChromeUINewTabURL), 229 string16()); 230 EXPECT_TRUE(bookmark_bar->visible()); 231 EXPECT_TRUE(bookmark_bar->IsDetached()); 232 EXPECT_EQ(browser_view(), bookmark_bar->parent()); 233 // Overlay container is still at the front of the view hierarchy, followed by 234 // the find bar host and the top container. 235 EXPECT_EQ(browser_view()->child_count() - 1, 236 browser_view()->GetIndexOf(overlay_container)); 237 EXPECT_EQ(browser_view()->child_count() - 2, 238 browser_view()->GetIndexOf(browser_view()->find_bar_host_view())); 239 EXPECT_EQ(browser_view()->child_count() - 3, 240 browser_view()->GetIndexOf(top_container)); 241 242 // Bookmark bar layout on NTP. 243 EXPECT_EQ(0, bookmark_bar->x()); 244 EXPECT_EQ( 245 tabstrip->bounds().bottom() + 246 toolbar->height() - 247 BrowserViewLayout::kToolbarTabStripVerticalOverlap - 248 views::NonClientFrameView::kClientEdgeThickness, 249 bookmark_bar->y()); 250 EXPECT_EQ(toolbar->bounds().bottom(), contents_split->y()); 251 // Contents view has a "top margin" pushing it below the bookmark bar. 252 EXPECT_EQ(bookmark_bar->height() - 253 views::NonClientFrameView::kClientEdgeThickness, 254 contents_web_view->y()); 255 256 // Bookmark bar is parented back to top container on normal page. 257 NavigateAndCommitActiveTabWithTitle(browser, 258 GURL("about:blank"), 259 string16()); 260 EXPECT_FALSE(bookmark_bar->visible()); 261 EXPECT_FALSE(bookmark_bar->IsDetached()); 262 EXPECT_EQ(top_container, bookmark_bar->parent()); 263 // Top container is still third from front. 264 EXPECT_EQ(browser_view()->child_count() - 3, 265 browser_view()->GetIndexOf(top_container)); 266 267 BookmarkBarView::DisableAnimationsForTesting(false); 268} 269 270#if defined(OS_WIN) && !defined(USE_AURA) 271 272// This class provides functionality to test the incognito window/normal window 273// switcher button which is added to Windows 8 metro Chrome. 274// We create the BrowserView ourselves in the 275// BrowserWithTestWindowTest::CreateBrowserWindow function override and add the 276// switcher button to the view. We also provide an incognito profile to ensure 277// that the switcher button is visible. 278class BrowserViewIncognitoSwitcherTest : public BrowserViewTest { 279 public: 280 // Subclass of BrowserView, which overrides the GetRestoreBounds/IsMaximized 281 // functions to return dummy values. This is needed because we create the 282 // BrowserView instance ourselves and initialize it with the created Browser 283 // instance. These functions get called before the underlying Widget is 284 // initialized which causes a crash while dereferencing a null native_widget_ 285 // pointer in the Widget class. 286 class TestBrowserView : public BrowserView { 287 public: 288 virtual ~TestBrowserView() {} 289 290 virtual gfx::Rect GetRestoredBounds() const OVERRIDE { 291 return gfx::Rect(); 292 } 293 virtual bool IsMaximized() const OVERRIDE { 294 return false; 295 } 296 }; 297 298 BrowserViewIncognitoSwitcherTest() 299 : browser_view_(NULL) {} 300 virtual ~BrowserViewIncognitoSwitcherTest() {} 301 302 virtual void SetUp() OVERRIDE { 303 Init(); 304 browser_view_->Init(browser()); 305 (new BrowserFrame(browser_view_))->InitBrowserFrame(); 306 browser_view_->SetBounds(gfx::Rect(10, 10, 500, 500)); 307 browser_view_->Show(); 308 // Memory ownership is tricky here. BrowserView has taken ownership of 309 // |browser|, so BrowserWithTestWindowTest cannot continue to own it. 310 ASSERT_TRUE(release_browser()); 311 } 312 313 virtual void TearDown() OVERRIDE { 314 // ok to release the window_ pointer because BrowserViewTest::TearDown 315 // deletes the BrowserView instance created. 316 release_browser_window(); 317 BrowserViewTest::TearDown(); 318 browser_view_ = NULL; 319 } 320 321 virtual BrowserWindow* CreateBrowserWindow() OVERRIDE { 322 // We need an incognito profile for the window switcher button to be 323 // visible. 324 // This profile instance is owned by the TestingProfile instance within the 325 // BrowserWithTestWindowTest class. 326 TestingProfile* incognito_profile = new TestingProfile(); 327 incognito_profile->set_incognito(true); 328 GetProfile()->SetOffTheRecordProfile(incognito_profile); 329 330 browser_view_ = new TestBrowserView(); 331 browser_view_->SetWindowSwitcherButton( 332 MakeWindowSwitcherButton(NULL, false)); 333 return browser_view_; 334 } 335 336 private: 337 BrowserView* browser_view_; 338 339 DISALLOW_COPY_AND_ASSIGN(BrowserViewIncognitoSwitcherTest); 340}; 341 342// Test whether the windows incognito/normal browser window switcher button 343// is the event handler for a point within its bounds. The event handler for 344// a point in the View class is dependent on the order in which children are 345// added to it. This test ensures that we don't regress in the window switcher 346// functionality when additional children are added to the BrowserView class. 347TEST_F(BrowserViewIncognitoSwitcherTest, 348 BrowserViewIncognitoSwitcherEventHandlerTest) { 349 // |browser_view_| owns the Browser, not the test class. 350 EXPECT_FALSE(browser()); 351 EXPECT_TRUE(browser_view()->browser()); 352 // Test initial state. 353 EXPECT_TRUE(browser_view()->IsTabStripVisible()); 354 // Validate whether the window switcher button is the target for the position 355 // passed in. 356 gfx::Point switcher_point(browser_view()->window_switcher_button()->x() + 2, 357 browser_view()->window_switcher_button()->y()); 358 EXPECT_EQ(browser_view()->GetEventHandlerForPoint(switcher_point), 359 browser_view()->window_switcher_button()); 360} 361#endif 362