summaryrefslogtreecommitdiffstats
path: root/chrome/browser/web_contents_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/web_contents_unittest.cc')
-rw-r--r--chrome/browser/web_contents_unittest.cc1242
1 files changed, 1242 insertions, 0 deletions
diff --git a/chrome/browser/web_contents_unittest.cc b/chrome/browser/web_contents_unittest.cc
new file mode 100644
index 0000000..728b82e
--- /dev/null
+++ b/chrome/browser/web_contents_unittest.cc
@@ -0,0 +1,1242 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/logging.h"
+#include "chrome/browser/navigation_controller.h"
+#include "chrome/browser/navigation_entry.h"
+#include "chrome/browser/render_view_host.h"
+#include "chrome/browser/render_widget_host_view.h"
+#include "chrome/browser/web_contents.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/ipc_channel.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Subclass the RenderViewHost's view so that we can call Show(), etc.,
+// without having side-effects.
+class TestRenderWidgetHostView : public RenderWidgetHostView {
+ public:
+ TestRenderWidgetHostView() {}
+ void DidBecomeSelected() {}
+ void WasHidden() {}
+ void SetSize(const gfx::Size& size) {}
+ HWND GetPluginHWND() { return NULL; }
+ HANDLE ModalDialogEvent() { return NULL; }
+ void ForwardMouseEventToRenderer(UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {}
+ void Focus() {}
+ void Blur() {}
+ bool HasFocus() { return true; }
+ void AdvanceFocus(bool reverse) {}
+ void Show() {}
+ void Hide() {}
+ gfx::Rect GetViewBounds() const { return gfx::Rect(); }
+ void UpdateCursor(const WebCursor& cursor) {}
+ void UpdateCursorIfOverSelf() {}
+ // Indicates if the page has finished loading.
+ virtual void SetIsLoading(bool is_loading) {}
+ void IMEUpdateStatus(ViewHostMsg_ImeControl control, int x, int y) {}
+ void DidPaintRect(const gfx::Rect& rect) {}
+ void DidScrollRect(const gfx::Rect& rect, int dx, int dy) {}
+ void RendererGone() {}
+ void Destroy() {}
+ void PrepareToDestroy() {}
+ void SetTooltipText(const std::wstring& tooltip_text) {}
+};
+
+// Subclass RenderViewHost so that it does not create a process.
+class TestRenderViewHost : public RenderViewHost {
+ public:
+ TestRenderViewHost(
+ SiteInstance* instance,
+ RenderViewHostDelegate* delegate,
+ int routing_id,
+ HANDLE modal_dialog_event)
+ : RenderViewHost(instance, delegate, routing_id, modal_dialog_event),
+ is_loading(false),
+ is_created(false),
+ immediate_before_unload(true),
+ delete_counter_(NULL) {
+ set_view(new TestRenderWidgetHostView());
+ }
+ ~TestRenderViewHost() {
+ // Track the delete if we've been asked to.
+ if (delete_counter_)
+ ++*delete_counter_;
+
+ // Since this isn't a traditional view, we have to delete it.
+ delete view_;
+ }
+
+ // If set, *delete_counter is incremented when this object destructs.
+ void set_delete_counter(int* delete_counter) {
+ delete_counter_ = delete_counter;
+ }
+
+ bool CreateRenderView() {
+ is_created = true;
+ return true;
+ }
+
+ bool IsRenderViewLive() const { return is_created; }
+
+ bool IsNavigationSuspended() { return navigations_suspended_; }
+
+ void NavigateToEntry(const NavigationEntry& entry, bool is_reload) {
+ is_loading = true;
+ }
+
+ void LoadAlternateHTMLString(const std::string& html_text,
+ bool new_navigation,
+ const GURL& display_url,
+ const std::string& security_info) {
+ is_loading = true;
+ }
+
+ // Support for onbeforeunload, onunload
+ void AttemptToClosePage(bool is_closing_browser) {
+ // TODO(ojan): Add tests for the case where is_closing_browser is true.
+ DCHECK(!is_closing_browser);
+ if (immediate_before_unload)
+ delegate()->ShouldClosePage(true);
+ }
+ void ClosePage(int new_render_process_host_id, int new_request_id) {
+ // Nothing to do here... This would cause a ClosePage_ACK to be sent to
+ // ResourceDispatcherHost, so we can simulate that manually.
+ }
+ void TestOnMsgShouldClose(bool proceed) {
+ OnMsgShouldCloseACK(proceed, false);
+ }
+
+ bool is_loading;
+ bool is_created;
+ bool immediate_before_unload;
+ int* delete_counter_;
+};
+
+// Factory to create TestRenderViewHosts.
+class TestRenderViewHostFactory : public RenderViewHostFactory {
+ public:
+ static TestRenderViewHostFactory* GetInstance() {
+ static TestRenderViewHostFactory instance;
+ return &instance;
+ }
+
+ virtual RenderViewHost* CreateRenderViewHost(
+ SiteInstance* instance,
+ RenderViewHostDelegate* delegate,
+ int routing_id,
+ HANDLE modal_dialog_event) {
+ return new TestRenderViewHost(
+ instance, delegate, routing_id, modal_dialog_event);
+ }
+
+ private:
+ TestRenderViewHostFactory() {}
+};
+
+// Subclass the TestingProfile so that it can return certain services we need.
+class WebContentsTestingProfile : public TestingProfile {
+ public:
+ WebContentsTestingProfile() : TestingProfile() { }
+
+ virtual PrefService* GetPrefs() {
+ if (!prefs_.get()) {
+ std::wstring source_path;
+ PathService::Get(chrome::DIR_TEST_DATA, &source_path);
+ file_util::AppendToPath(&source_path, L"profiles");
+ file_util::AppendToPath(&source_path, L"chrome_prefs");
+ file_util::AppendToPath(&source_path, L"Preferences");
+
+ prefs_.reset(new PrefService(source_path));
+ Profile::RegisterUserPrefs(prefs_.get());
+ browser::RegisterAllPrefs(prefs_.get(), prefs_.get());
+ }
+ return prefs_.get();
+ }
+};
+
+// Subclass WebContents to ensure it creates TestRenderViewHosts and does
+// not do anything involving views.
+class TestWebContents : public WebContents {
+ public:
+ TestWebContents(Profile* profile, SiteInstance* instance)
+ : WebContents(profile,
+ instance,
+ TestRenderViewHostFactory::GetInstance(),
+ MSG_ROUTING_NONE,
+ NULL),
+ transition_cross_site(false) {}
+
+ // Accessors for interesting fields
+ RendererState renderer_state() { return renderer_state_; }
+ TestRenderViewHost* rvh() {
+ return static_cast<TestRenderViewHost*>(render_view_host_);
+ }
+ TestRenderViewHost* pending_rvh() {
+ return static_cast<TestRenderViewHost*>(pending_render_view_host_);
+ }
+ TestRenderViewHost* interstitial_rvh() {
+ return static_cast<TestRenderViewHost*>(interstitial_render_view_host_);
+ }
+ TestRenderViewHost* original_rvh() {
+ return static_cast<TestRenderViewHost*>(original_render_view_host_);
+ }
+
+ // Ensure we create TestRenderViewHosts that don't spawn processes.
+ RenderViewHost* CreateRenderViewHost(SiteInstance* instance,
+ RenderViewHostDelegate* delegate,
+ int routing_id,
+ HANDLE modal_dialog_event) {
+ return new TestRenderViewHost(
+ instance, delegate, routing_id, modal_dialog_event);
+ }
+
+ // Overrides WebContents::ShouldTransitionCrossSite so that we can test both
+ // alternatives without using command-line switches.
+ bool ShouldTransitionCrossSite() { return transition_cross_site; }
+
+ // Promote DidNavigate to public.
+ void TestDidNavigate(TestRenderViewHost* render_view_host,
+ const ViewHostMsg_FrameNavigate_Params& params) {
+ DidNavigate(render_view_host, params);
+ render_view_host->is_loading = false;
+ }
+
+ // Promote IsInPageNavigation to public.
+ bool TestIsInPageNavigation(const GURL& url) {
+ return IsInPageNavigation(url);
+ }
+
+ // Promote GetWebkitPrefs to public.
+ WebPreferences TestGetWebkitPrefs() {
+ return GetWebkitPrefs();
+ }
+
+ // Prevent interaction with views.
+ bool CreateRenderView(RenderViewHost* render_view_host) {
+ // This will go to a TestRenderViewHost.
+ render_view_host->CreateRenderView();
+ return true;
+ }
+ void UpdateRenderViewSize() {}
+
+ // Set by individual tests.
+ bool transition_cross_site;
+};
+
+class WebContentsTest : public testing::Test {
+ public:
+ WebContentsTest() : contents(NULL) {}
+
+ void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params,
+ int pageID,
+ const GURL& url) {
+ params->page_id = pageID;
+ params->url = url;
+ params->referrer = GURL::EmptyGURL();
+ params->transition = PageTransition::TYPED;
+ params->redirects = std::vector<GURL>();
+ params->should_update_history = false;
+ params->searchable_form_url = GURL::EmptyGURL();
+ params->searchable_form_element_name = std::wstring();
+ params->searchable_form_encoding = std::string();
+ params->password_form = PasswordForm();
+ params->security_info = std::string();
+ params->gesture = NavigationGestureUser;
+ params->is_post = false;
+ }
+
+ // testing::Test methods:
+
+ virtual void SetUp() {
+ profile.reset(new WebContentsTestingProfile());
+
+ // This will be deleted when the WebContents goes away
+ SiteInstance* instance = SiteInstance::CreateSiteInstance(profile.get());
+
+ contents = new TestWebContents(profile.get(), instance);
+ contents->SetupController(profile.get());
+ }
+
+ virtual void TearDown() {
+ // This will delete the contents.
+ contents->CloseContents();
+
+ // Make sure that we flush any messages related to WebContents destruction
+ // before we destroy the profile.
+ MessageLoop::current()->Quit();
+ MessageLoop::current()->Run();
+ }
+
+ scoped_ptr<WebContentsTestingProfile> profile;
+ TestWebContents* contents;
+};
+
+// Test to make sure that title updates get stripped of whitespace
+TEST_F(WebContentsTest, OnMessageReceived) {
+ contents->controller()->DidNavigateToEntry(new NavigationEntry(
+ contents->type(), contents->site_instance(), 0, GURL("about:blank"),
+ std::wstring(), PageTransition::TYPED));
+
+ contents->UpdateTitle(NULL, 0, L" Lots O' Whitespace\n");
+ EXPECT_EQ(std::wstring(L"Lots O' Whitespace"), contents->GetTitle());
+}
+
+// Test simple same-SiteInstance navigation.
+TEST_F(WebContentsTest, SimpleNavigation) {
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ SiteInstance* instance1 = contents->site_instance();
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+ EXPECT_FALSE(orig_rvh->is_loading);
+
+ // Navigate to URL
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_TRUE(orig_rvh->is_loading);
+ EXPECT_EQ(instance1, orig_rvh->site_instance());
+ // Controller's pending entry will have a NULL site instance until we assign
+ // it in DidNavigate.
+ EXPECT_TRUE(
+ contents->controller()->GetActiveEntry()->site_instance() == NULL);
+
+ // DidNavigate from the page
+ ViewHostMsg_FrameNavigate_Params params;
+ InitNavigateParams(&params, 1, url);
+ contents->TestDidNavigate(orig_rvh, params);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_EQ(instance1, orig_rvh->site_instance());
+ // Controller's entry should now have the SiteInstance, or else we won't be
+ // able to find it later.
+ EXPECT_EQ(instance1,
+ contents->controller()->GetActiveEntry()->site_instance());
+}
+
+// Test navigating to a page that shows an interstitial, then hiding it
+// without proceeding.
+TEST_F(WebContentsTest, ShowInterstitialDontProceed) {
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+ EXPECT_FALSE(orig_rvh->is_loading);
+
+ // Navigate to URL
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_TRUE(orig_rvh->is_loading);
+
+ // Show interstitial
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ EXPECT_EQ(WebContents::ENTERING_INTERSTITIAL, contents->renderer_state());
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+ EXPECT_TRUE(orig_rvh->is_loading); // Still loading in the background
+ EXPECT_TRUE(interstitial_rvh->is_loading);
+
+ // DidNavigate from the interstitial
+ ViewHostMsg_FrameNavigate_Params params;
+ InitNavigateParams(&params, 1, url);
+ contents->TestDidNavigate(interstitial_rvh, params);
+ EXPECT_EQ(WebContents::INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_EQ(orig_rvh, contents->original_rvh());
+ EXPECT_FALSE(interstitial_rvh->is_loading);
+
+ // Hide interstitial (don't proceed)
+ contents->HideInterstitialPage(false, false);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+}
+
+// Test navigating to a page that shows an interstitial, then proceeding.
+TEST_F(WebContentsTest, ShowInterstitialProceed) {
+ TestRenderViewHost* orig_rvh = contents->rvh();
+
+ // The RenderViewHost's SiteInstance should not yet have a site.
+ EXPECT_EQ(GURL(""), contents->rvh()->site_instance()->site());
+
+ // Navigate to URL
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+
+ // Show interstitial
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+
+ // DidNavigate from the interstitial
+ ViewHostMsg_FrameNavigate_Params params;
+ InitNavigateParams(&params, 1, url);
+ contents->TestDidNavigate(interstitial_rvh, params);
+
+ // Ensure this DidNavigate hasn't changed the SiteInstance's site.
+ // Prevents regression for bug 1163298.
+ EXPECT_EQ(GURL(""), contents->rvh()->site_instance()->site());
+
+ // Hide interstitial (proceed and wait)
+ contents->HideInterstitialPage(true, true);
+ EXPECT_EQ(WebContents::LEAVING_INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_EQ(orig_rvh, contents->original_rvh());
+
+ // DidNavigate from the destination page
+ contents->TestDidNavigate(orig_rvh, params);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // The SiteInstance's site should now be updated.
+ EXPECT_EQ(GURL("http://google.com"),
+ contents->rvh()->site_instance()->site());
+
+ // Since we weren't viewing a page before, we shouldn't be able to go back.
+ EXPECT_FALSE(contents->controller()->CanGoBack());
+}
+
+// Test navigating to a page that shows an interstitial, then navigating away.
+TEST_F(WebContentsTest, ShowInterstitialThenNavigate) {
+ TestRenderViewHost* orig_rvh = contents->rvh();
+
+ // Navigate to URL
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+
+ // Show interstitial
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+
+ // DidNavigate from the interstitial
+ ViewHostMsg_FrameNavigate_Params params;
+ InitNavigateParams(&params, 1, url);
+ contents->TestDidNavigate(interstitial_rvh, params);
+
+ // While interstitial showing, navigate to a new URL.
+ const GURL url2("http://www.yahoo.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ EXPECT_EQ(WebContents::LEAVING_INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_TRUE(orig_rvh->is_loading);
+ EXPECT_FALSE(interstitial_rvh->is_loading);
+
+ // DidNavigate from the new URL. In the old process model, we'll still have
+ // the same RenderViewHost.
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 2, url2);
+ contents->TestDidNavigate(orig_rvh, params2);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_FALSE(orig_rvh->is_loading);
+}
+
+// Ensures that an interstitial cannot be cancelled if a notification for a
+// navigation from an IFrame from the previous page is received while the
+// interstitial is being shown (bug #1182394).
+TEST_F(WebContentsTest, ShowInterstitialIFrameNavigate) {
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+ EXPECT_FALSE(orig_rvh->is_loading);
+
+ // Navigate to URL.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_TRUE(orig_rvh->is_loading);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ // Show interstitial (in real world would probably be triggered by a resource
+ // in the page).
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ EXPECT_EQ(WebContents::ENTERING_INTERSTITIAL, contents->renderer_state());
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+ EXPECT_TRUE(interstitial_rvh->is_loading);
+
+ // DidNavigate from an IFrame in the initial page.
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 1, GURL("http://www.iframe.com"));
+ params2.transition = PageTransition::AUTO_SUBFRAME;
+ contents->TestDidNavigate(orig_rvh, params2);
+
+ // Now we get the DidNavigate from the interstitial.
+ ViewHostMsg_FrameNavigate_Params params3;
+ InitNavigateParams(&params3, 1, url);
+ contents->TestDidNavigate(interstitial_rvh, params3);
+ EXPECT_EQ(WebContents::INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_EQ(orig_rvh, contents->original_rvh());
+ EXPECT_FALSE(interstitial_rvh->is_loading);
+}
+
+// Test navigating to an interstitial page from a normal page. Also test
+// visiting the interstitial-inducing URL twice (bug 1079784), and test
+// that going back shows the first page and not the interstitial.
+TEST_F(WebContentsTest, VisitInterstitialURLTwice) {
+ TestRenderViewHost* orig_rvh = contents->rvh();
+
+ // Navigate to URL
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ // Now navigate to an interstitial-inducing URL
+ const GURL url2("https://www.google.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ EXPECT_EQ(WebContents::ENTERING_INTERSTITIAL, contents->renderer_state());
+ int interstitial_delete_counter = 0;
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+ interstitial_rvh->set_delete_counter(&interstitial_delete_counter);
+
+ // DidNavigate from the interstitial
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 2, url2);
+ contents->TestDidNavigate(interstitial_rvh, params2);
+ EXPECT_EQ(WebContents::INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+
+ // While interstitial showing, navigate to the same URL.
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ EXPECT_EQ(WebContents::LEAVING_INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+
+ // Interstitial shown a second time in a different RenderViewHost.
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ EXPECT_EQ(WebContents::ENTERING_INTERSTITIAL, contents->renderer_state());
+ // We expect the original interstitial has been deleted.
+ EXPECT_EQ(interstitial_delete_counter, 1);
+ TestRenderViewHost* interstitial_rvh2 = contents->interstitial_rvh();
+ interstitial_rvh2->set_delete_counter(&interstitial_delete_counter);
+
+ // DidNavigate from the interstitial.
+ ViewHostMsg_FrameNavigate_Params params3;
+ InitNavigateParams(&params3, 3, url2);
+ contents->TestDidNavigate(interstitial_rvh2, params3);
+ EXPECT_EQ(WebContents::INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh2, contents->render_view_host());
+
+ // Proceed. In the old process model, we'll still have the same
+ // RenderViewHost.
+ contents->HideInterstitialPage(true, true);
+ EXPECT_EQ(WebContents::LEAVING_INTERSTITIAL, contents->renderer_state());
+ ViewHostMsg_FrameNavigate_Params params4;
+ InitNavigateParams(&params4, 3, url2);
+ contents->TestDidNavigate(orig_rvh, params4);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ // We expect the second interstitial has been deleted.
+ EXPECT_EQ(interstitial_delete_counter, 2);
+
+ // Now go back. Should take us back to the original page.
+ contents->controller()->GoBack();
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+
+ // DidNavigate from going back.
+ contents->TestDidNavigate(orig_rvh, params1);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+}
+
+// Test that navigating across a site boundary creates a new RenderViewHost
+// with a new SiteInstance. Going back should do the same.
+TEST_F(WebContentsTest, CrossSiteBoundaries) {
+ contents->transition_cross_site = true;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ int orig_rvh_delete_count = 0;
+ orig_rvh->set_delete_counter(&orig_rvh_delete_count);
+ SiteInstance* instance1 = contents->site_instance();
+
+ // Navigate to URL. First URL should use first RenderViewHost.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // Navigate to new site
+ const GURL url2("http://www.yahoo.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ EXPECT_EQ(WebContents::PENDING, contents->renderer_state());
+ TestRenderViewHost* pending_rvh = contents->pending_rvh();
+ int pending_rvh_delete_count = 0;
+ pending_rvh->set_delete_counter(&pending_rvh_delete_count);
+
+ // DidNavigate from the pending page
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 1, url2);
+ contents->TestDidNavigate(pending_rvh, params2);
+ SiteInstance* instance2 = contents->site_instance();
+
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(pending_rvh, contents->render_view_host());
+ EXPECT_NE(instance1, instance2);
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+ EXPECT_EQ(orig_rvh_delete_count, 1);
+
+ // Going back should switch SiteInstances again. The first SiteInstance is
+ // stored in the NavigationEntry, so it should be the same as at the start.
+ contents->controller()->GoBack();
+ TestRenderViewHost* goback_rvh = contents->pending_rvh();
+ EXPECT_EQ(WebContents::PENDING, contents->renderer_state());
+
+ // DidNavigate from the back action
+ contents->TestDidNavigate(goback_rvh, params1);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(goback_rvh, contents->render_view_host());
+ EXPECT_EQ(pending_rvh_delete_count, 1);
+ EXPECT_EQ(instance1, contents->site_instance());
+}
+
+// Test that navigating across a site boundary after a crash creates a new
+// RVH without requiring a cross-site transition (i.e., PENDING state).
+TEST_F(WebContentsTest, CrossSiteBoundariesAfterCrash) {
+ contents->transition_cross_site = true;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ int orig_rvh_delete_count = 0;
+ orig_rvh->set_delete_counter(&orig_rvh_delete_count);
+ SiteInstance* instance1 = contents->site_instance();
+
+ // Navigate to URL. First URL should use first RenderViewHost.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // Crash the renderer.
+ orig_rvh->is_created = false;
+
+ // Navigate to new site. We should not go into PENDING.
+ const GURL url2("http://www.yahoo.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ TestRenderViewHost* new_rvh = contents->rvh();
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+ EXPECT_NE(orig_rvh, new_rvh);
+ EXPECT_EQ(orig_rvh_delete_count, 1);
+
+ // DidNavigate from the new page
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 1, url2);
+ contents->TestDidNavigate(new_rvh, params2);
+ SiteInstance* instance2 = contents->site_instance();
+
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(new_rvh, contents->render_view_host());
+ EXPECT_NE(instance1, instance2);
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+}
+
+// Test state transitions when showing an interstitial in the new process
+// model, and then choosing DontProceed.
+TEST_F(WebContentsTest, CrossSiteInterstitialDontProceed) {
+ contents->transition_cross_site = true;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ SiteInstance* instance1 = contents->site_instance();
+
+ // Navigate to URL. First URL should use first RenderViewHost.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+
+ // Navigate to new site
+ const GURL url2("https://www.google.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ EXPECT_EQ(WebContents::PENDING, contents->renderer_state());
+ TestRenderViewHost* pending_rvh = contents->pending_rvh();
+
+ // Show an interstitial
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ EXPECT_EQ(WebContents::ENTERING_INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_EQ(pending_rvh, contents->pending_rvh());
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+
+ // DidNavigate from the interstitial
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 2, url2);
+ contents->TestDidNavigate(interstitial_rvh, params2);
+ EXPECT_EQ(WebContents::INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_EQ(orig_rvh, contents->original_rvh());
+ EXPECT_EQ(pending_rvh, contents->pending_rvh());
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // Hide interstitial (don't proceed)
+ contents->HideInterstitialPage(false, false);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+}
+
+// Test state transitions when showing an interstitial in the new process
+// model, and then choosing Proceed.
+TEST_F(WebContentsTest, CrossSiteInterstitialProceed) {
+ contents->transition_cross_site = true;
+ int orig_rvh_delete_count = 0;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ orig_rvh->set_delete_counter(&orig_rvh_delete_count);
+ SiteInstance* instance1 = contents->site_instance();
+
+ // Navigate to URL. First URL should use first RenderViewHost.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ // Navigate to new site
+ const GURL url2("https://www.google.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ TestRenderViewHost* pending_rvh = contents->pending_rvh();
+ int pending_rvh_delete_count = 0;
+ pending_rvh->set_delete_counter(&pending_rvh_delete_count);
+
+ // Show an interstitial
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+
+ // DidNavigate from the interstitial
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 1, url2);
+ contents->TestDidNavigate(interstitial_rvh, params2);
+ EXPECT_EQ(WebContents::INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_EQ(orig_rvh, contents->original_rvh());
+ EXPECT_EQ(pending_rvh, contents->pending_rvh());
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // Hide interstitial (proceed and wait)
+ contents->HideInterstitialPage(true, true);
+ EXPECT_EQ(WebContents::LEAVING_INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_EQ(orig_rvh, contents->original_rvh());
+ EXPECT_EQ(pending_rvh, contents->pending_rvh());
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // DidNavigate from the destination page should transition to new renderer
+ ViewHostMsg_FrameNavigate_Params params3;
+ InitNavigateParams(&params3, 2, url2);
+ contents->TestDidNavigate(pending_rvh, params3);
+ SiteInstance* instance2 = contents->site_instance();
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(pending_rvh, contents->render_view_host());
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+ EXPECT_NE(instance1, instance2);
+ EXPECT_EQ(orig_rvh_delete_count, 1); // The original should be gone.
+
+ // Since we were viewing a page before, we should be able to go back.
+ EXPECT_TRUE(contents->controller()->CanGoBack());
+
+ // Going back should switch SiteInstances again. The first SiteInstance is
+ // stored in the NavigationEntry, so it should be the same as at the start.
+ contents->controller()->GoBack();
+ TestRenderViewHost* goback_rvh = contents->pending_rvh();
+ EXPECT_EQ(WebContents::PENDING, contents->renderer_state());
+
+ // DidNavigate from the back action
+ contents->TestDidNavigate(goback_rvh, params1);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(goback_rvh, contents->render_view_host());
+ EXPECT_EQ(instance1, contents->site_instance());
+ EXPECT_EQ(pending_rvh_delete_count, 1); // The second page's rvh should die.
+}
+
+// Tests that we can transition away from an interstitial page.
+TEST_F(WebContentsTest, CrossSiteInterstitialThenNavigate) {
+ contents->transition_cross_site = true;
+ int orig_rvh_delete_count = 0;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ orig_rvh->set_delete_counter(&orig_rvh_delete_count);
+
+ // Navigate to URL. First URL should use first RenderViewHost.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ // Show an interstitial
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+
+ // DidNavigate from the interstitial
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 1, url);
+ contents->TestDidNavigate(interstitial_rvh, params2);
+ EXPECT_EQ(WebContents::INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_EQ(orig_rvh, contents->original_rvh());
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // Navigate to a new page.
+ const GURL url2("http://www.yahoo.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+
+ TestRenderViewHost* new_rvh = contents->pending_rvh();
+ ASSERT_TRUE(new_rvh != NULL);
+ // Make sure the RVH is not suspended (bug #1236441).
+ EXPECT_FALSE(new_rvh->IsNavigationSuspended());
+ EXPECT_EQ(WebContents::LEAVING_INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+
+ // DidNavigate from the new page
+ ViewHostMsg_FrameNavigate_Params params3;
+ InitNavigateParams(&params3, 1, url2);
+ contents->TestDidNavigate(new_rvh, params3);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(new_rvh, contents->render_view_host());
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_EQ(orig_rvh_delete_count, 1);
+}
+
+// Tests that we can transition away from an interstitial page even if the
+// interstitial renderer has crashed.
+TEST_F(WebContentsTest, CrossSiteInterstitialCrashThenNavigate) {
+ contents->transition_cross_site = true;
+ int orig_rvh_delete_count = 0;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ orig_rvh->set_delete_counter(&orig_rvh_delete_count);
+
+ // Navigate to URL. First URL should use first RenderViewHost.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ // Navigate to new site
+ const GURL url2("https://www.google.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ TestRenderViewHost* pending_rvh = contents->pending_rvh();
+ int pending_rvh_delete_count = 0;
+ pending_rvh->set_delete_counter(&pending_rvh_delete_count);
+
+ // Show an interstitial
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+
+ // DidNavigate from the interstitial
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 1, url2);
+ contents->TestDidNavigate(interstitial_rvh, params2);
+ EXPECT_EQ(WebContents::INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_EQ(orig_rvh, contents->original_rvh());
+ EXPECT_EQ(pending_rvh, contents->pending_rvh());
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // Crash the interstitial RVH
+ // (by making IsRenderViewLive() == false)
+ interstitial_rvh->is_created = false;
+
+ // Navigate to a new page. Since interstitial RVH is dead, we should clean
+ // it up and go to a new PENDING state, showing the orig_rvh.
+ const GURL url3("http://www.yahoo.com");
+ contents->controller()->LoadURL(url3, PageTransition::TYPED);
+ TestRenderViewHost* new_rvh = contents->pending_rvh();
+ ASSERT_TRUE(new_rvh != NULL);
+ EXPECT_EQ(WebContents::PENDING, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+ EXPECT_EQ(pending_rvh_delete_count, 1);
+ EXPECT_NE(interstitial_rvh, new_rvh);
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // DidNavigate from the new page
+ ViewHostMsg_FrameNavigate_Params params3;
+ InitNavigateParams(&params3, 1, url3);
+ contents->TestDidNavigate(new_rvh, params3);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(new_rvh, contents->render_view_host());
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_EQ(orig_rvh_delete_count, 1);
+}
+
+// Tests that we can transition away from an interstitial page even if both the
+// original and interstitial renderers have crashed.
+TEST_F(WebContentsTest, CrossSiteInterstitialCrashesThenNavigate) {
+ contents->transition_cross_site = true;
+ int orig_rvh_delete_count = 0;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ orig_rvh->set_delete_counter(&orig_rvh_delete_count);
+
+ // Navigate to URL. First URL should use first RenderViewHost.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ // Navigate to new site
+ const GURL url2("https://www.google.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ TestRenderViewHost* pending_rvh = contents->pending_rvh();
+ int pending_rvh_delete_count = 0;
+ pending_rvh->set_delete_counter(&pending_rvh_delete_count);
+
+ // Show an interstitial
+ contents->ShowInterstitialPage(std::string("Blocked"), NULL);
+ TestRenderViewHost* interstitial_rvh = contents->interstitial_rvh();
+
+ // DidNavigate from the interstitial
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 1, url2);
+ contents->TestDidNavigate(interstitial_rvh, params2);
+ EXPECT_EQ(WebContents::INTERSTITIAL, contents->renderer_state());
+ EXPECT_EQ(interstitial_rvh, contents->render_view_host());
+ EXPECT_EQ(orig_rvh, contents->original_rvh());
+ EXPECT_EQ(pending_rvh, contents->pending_rvh());
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // Crash both the original and interstitial RVHs
+ // (by making IsRenderViewLive() == false)
+ orig_rvh->is_created = false;
+ interstitial_rvh->is_created = false;
+
+ // Navigate to a new page. Since both the interstitial and original RVHs are
+ // dead, we should create a new RVH, jump back to NORMAL, and navigate.
+ const GURL url3("http://www.yahoo.com");
+ contents->controller()->LoadURL(url3, PageTransition::TYPED);
+ TestRenderViewHost* new_rvh = contents->rvh();
+ ASSERT_TRUE(new_rvh != NULL);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh_delete_count, 1);
+ EXPECT_EQ(pending_rvh_delete_count, 1);
+ EXPECT_NE(interstitial_rvh, new_rvh);
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+
+ // DidNavigate from the new page
+ ViewHostMsg_FrameNavigate_Params params3;
+ InitNavigateParams(&params3, 1, url3);
+ contents->TestDidNavigate(new_rvh, params3);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(new_rvh, contents->render_view_host());
+}
+
+// Test that opening a new tab in the same SiteInstance and then navigating
+// both tabs to a new site will place both tabs in a single SiteInstance.
+TEST_F(WebContentsTest, NavigateTwoTabsCrossSite) {
+ contents->transition_cross_site = true;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ SiteInstance* instance1 = contents->site_instance();
+
+ // Navigate to URL. First URL should use first RenderViewHost.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ // Open a new tab with the same SiteInstance, navigated to the same site.
+ TestWebContents* contents2 = new TestWebContents(profile.get(), instance1);
+ contents2->transition_cross_site = true;
+ contents2->SetupController(profile.get());
+ contents2->controller()->LoadURL(url, PageTransition::TYPED);
+ contents2->TestDidNavigate(contents2->rvh(), params1);
+
+ // Navigate first tab to a new site
+ const GURL url2a("http://www.yahoo.com");
+ contents->controller()->LoadURL(url2a, PageTransition::TYPED);
+ TestRenderViewHost* pending_rvh_a = contents->pending_rvh();
+ ViewHostMsg_FrameNavigate_Params params2a;
+ InitNavigateParams(&params2a, 1, url2a);
+ contents->TestDidNavigate(pending_rvh_a, params2a);
+ SiteInstance* instance2a = contents->site_instance();
+ EXPECT_NE(instance1, instance2a);
+
+ // Navigate second tab to the same site as the first tab
+ const GURL url2b("http://mail.yahoo.com");
+ contents2->controller()->LoadURL(url2b, PageTransition::TYPED);
+ TestRenderViewHost* pending_rvh_b = contents2->pending_rvh();
+ EXPECT_TRUE(pending_rvh_b != NULL);
+ EXPECT_EQ(WebContents::PENDING, contents2->renderer_state());
+
+ // NOTE(creis): We used to be in danger of showing a sad tab page here if the
+ // second tab hadn't navigated somewhere first (bug 1145430). That case is
+ // now covered by the CrossSiteBoundariesAfterCrash test.
+
+ ViewHostMsg_FrameNavigate_Params params2b;
+ InitNavigateParams(&params2b, 2, url2b);
+ contents2->TestDidNavigate(pending_rvh_b, params2b);
+ SiteInstance* instance2b = contents2->site_instance();
+ EXPECT_NE(instance1, instance2b);
+
+ // Both tabs should now be in the same SiteInstance.
+ EXPECT_EQ(instance2a, instance2b);
+
+ contents2->CloseContents();
+}
+
+// Tests that WebContents uses the current URL, not the SiteInstance's site, to
+// determine whether a navigation is cross-site.
+TEST_F(WebContentsTest, CrossSiteComparesAgainstCurrentPage) {
+ contents->transition_cross_site = true;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ SiteInstance* instance1 = contents->site_instance();
+
+ // Navigate to URL.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ // Open a related tab to a second site.
+ TestWebContents* contents2 = new TestWebContents(profile.get(), instance1);
+ contents2->transition_cross_site = true;
+ contents2->SetupController(profile.get());
+ const GURL url2("http://www.yahoo.com");
+ contents2->controller()->LoadURL(url2, PageTransition::TYPED);
+ // The first RVH in contents2 isn't live yet, so we shortcut the PENDING
+ // state and go straight to NORMAL.
+ TestRenderViewHost* rvh2 = contents2->rvh();
+ EXPECT_EQ(WebContents::NORMAL, contents2->renderer_state());
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 2, url2);
+ contents2->TestDidNavigate(rvh2, params2);
+ SiteInstance* instance2 = contents2->site_instance();
+ EXPECT_NE(instance1, instance2);
+ EXPECT_EQ(WebContents::NORMAL, contents2->renderer_state());
+
+ // Simulate a link click in first tab to second site. Doesn't switch
+ // SiteInstances, because we don't intercept WebKit navigations.
+ ViewHostMsg_FrameNavigate_Params params3;
+ InitNavigateParams(&params3, 2, url2);
+ contents->TestDidNavigate(orig_rvh, params3);
+ SiteInstance* instance3 = contents->site_instance();
+ EXPECT_EQ(instance1, instance3);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+
+ // Navigate to the new site. Doesn't switch SiteInstancees, because we
+ // compare against the current URL, not the SiteInstance's site.
+ const GURL url3("http://mail.yahoo.com");
+ contents->controller()->LoadURL(url3, PageTransition::TYPED);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ ViewHostMsg_FrameNavigate_Params params4;
+ InitNavigateParams(&params4, 3, url3);
+ contents->TestDidNavigate(orig_rvh, params4);
+ SiteInstance* instance4 = contents->site_instance();
+ EXPECT_EQ(instance1, instance4);
+
+ contents2->CloseContents();
+}
+
+// Test that the onbeforeunload and onunload handlers run when navigating
+// across site boundaries.
+TEST_F(WebContentsTest, CrossSiteUnloadHandlers) {
+ contents->transition_cross_site = true;
+ TestRenderViewHost* orig_rvh = contents->rvh();
+ SiteInstance* instance1 = contents->site_instance();
+
+ // Navigate to URL. First URL should use first RenderViewHost.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+
+ // Navigate to new site, but simulate an onbeforeunload denial.
+ const GURL url2("http://www.yahoo.com");
+ orig_rvh->immediate_before_unload = false;
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ orig_rvh->TestOnMsgShouldClose(false);
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(orig_rvh, contents->render_view_host());
+
+ // Navigate again, but simulate an onbeforeunload approval.
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ orig_rvh->TestOnMsgShouldClose(true);
+ EXPECT_EQ(WebContents::PENDING, contents->renderer_state());
+ TestRenderViewHost* pending_rvh = contents->pending_rvh();
+
+ // We won't hear DidNavigate until the onunload handler has finished running.
+ // (No way to simulate that here, but it involves a call from RDH to
+ // WebContents::OnCrossSiteResponse.)
+
+ // DidNavigate from the pending page
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 1, url2);
+ contents->TestDidNavigate(pending_rvh, params2);
+ SiteInstance* instance2 = contents->site_instance();
+ EXPECT_EQ(WebContents::NORMAL, contents->renderer_state());
+ EXPECT_EQ(pending_rvh, contents->render_view_host());
+ EXPECT_NE(instance1, instance2);
+ EXPECT_TRUE(contents->pending_rvh() == NULL);
+ EXPECT_TRUE(contents->original_rvh() == NULL);
+ EXPECT_TRUE(contents->interstitial_rvh() == NULL);
+}
+
+// Test that NavigationEntries have the correct content state after going
+// forward and back. Prevents regression for bug 1116137.
+TEST_F(WebContentsTest, NavigationEntryContentState) {
+ TestRenderViewHost* orig_rvh = contents->rvh();
+
+ // Navigate to URL. There should be no committed entry yet.
+ const GURL url("http://www.google.com");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ NavigationEntry* entry = contents->controller()->GetLastCommittedEntry();
+ EXPECT_TRUE(entry == NULL);
+
+ // Committed entry should have content state after DidNavigate.
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+ entry = contents->controller()->GetLastCommittedEntry();
+ EXPECT_FALSE(entry->GetContentState().empty());
+
+ // Navigate to same site.
+ const GURL url2("http://images.google.com");
+ contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ entry = contents->controller()->GetLastCommittedEntry();
+ EXPECT_FALSE(entry->GetContentState().empty());
+
+ // Committed entry should have content state after DidNavigate.
+ ViewHostMsg_FrameNavigate_Params params2;
+ InitNavigateParams(&params2, 2, url2);
+ contents->TestDidNavigate(orig_rvh, params2);
+ entry = contents->controller()->GetLastCommittedEntry();
+ EXPECT_FALSE(entry->GetContentState().empty());
+
+ // Now go back. Committed entry should still have content state.
+ contents->controller()->GoBack();
+ contents->TestDidNavigate(orig_rvh, params1);
+ entry = contents->controller()->GetLastCommittedEntry();
+ EXPECT_FALSE(entry->GetContentState().empty());
+}
+
+// Test that NavigationEntries have the correct content state after opening
+// a new window to about:blank. Prevents regression for bug 1116137.
+TEST_F(WebContentsTest, NavigationEntryContentStateNewWindow) {
+ TestRenderViewHost* orig_rvh = contents->rvh();
+
+ // When opening a new window, it is navigated to about:blank internally.
+ // Currently, this results in two DidNavigate events.
+ const GURL url("about:blank");
+ ViewHostMsg_FrameNavigate_Params params1;
+ InitNavigateParams(&params1, 1, url);
+ contents->TestDidNavigate(orig_rvh, params1);
+ contents->TestDidNavigate(orig_rvh, params1);
+
+ // Should have a content state here.
+ NavigationEntry* entry = contents->controller()->GetLastCommittedEntry();
+ EXPECT_FALSE(entry->GetContentState().empty());
+}
+
+// Tests that IsInPageNavigation returns appropriate results. Prevents
+// regression for bug 1126349.
+TEST_F(WebContentsTest, IsInPageNavigation) {
+ TestRenderViewHost* rvh = contents->rvh();
+
+ // Navigate to URL with no refs.
+ const GURL url("http://www.google.com/home.html");
+ contents->controller()->LoadURL(url, PageTransition::TYPED);
+ ViewHostMsg_FrameNavigate_Params params;
+ InitNavigateParams(&params, 1, url);
+ contents->TestDidNavigate(rvh, params);
+
+ // Reloading the page is not an in-page navigation.
+ EXPECT_FALSE(contents->TestIsInPageNavigation(url));
+ const GURL other_url("http://www.google.com/add.html");
+ EXPECT_FALSE(contents->TestIsInPageNavigation(other_url));
+ const GURL url_with_ref("http://www.google.com/home.html#my_ref");
+ EXPECT_TRUE(contents->TestIsInPageNavigation(url_with_ref));
+
+ // Navigate to URL with refs.
+ contents->controller()->LoadURL(url_with_ref, PageTransition::TYPED);
+ InitNavigateParams(&params, 2, url_with_ref);
+ contents->TestDidNavigate(rvh, params);
+
+ // Reloading the page is not an in-page navigation.
+ EXPECT_FALSE(contents->TestIsInPageNavigation(url_with_ref));
+ EXPECT_FALSE(contents->TestIsInPageNavigation(url));
+ EXPECT_FALSE(contents->TestIsInPageNavigation(other_url));
+ const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
+ EXPECT_TRUE(contents->TestIsInPageNavigation(other_url_with_ref));
+}
+
+// Tests to see that webkit preferences are properly loaded and copied over
+// to a WebPreferences object.
+TEST_F(WebContentsTest, WebKitPrefs) {
+ WebPreferences webkit_prefs = contents->TestGetWebkitPrefs();
+
+ // These values have been overridden by the profile preferences.
+ EXPECT_EQ(L"UTF-8", webkit_prefs.default_encoding);
+ EXPECT_EQ(20, webkit_prefs.default_font_size);
+ EXPECT_EQ(false, webkit_prefs.text_areas_are_resizable);
+ EXPECT_EQ(true, webkit_prefs.uses_universal_detector);
+
+ // These should still be the default values.
+ EXPECT_EQ(L"Times New Roman", webkit_prefs.standard_font_family);
+ EXPECT_EQ(true, webkit_prefs.javascript_enabled);
+}