Home | History | Annotate | Download | only in web_contents
      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 #include "base/logging.h"
      6 #include "base/strings/utf_string_conversions.h"
      7 #include "content/browser/frame_host/cross_site_transferring_request.h"
      8 #include "content/browser/frame_host/interstitial_page_impl.h"
      9 #include "content/browser/frame_host/navigation_entry_impl.h"
     10 #include "content/browser/renderer_host/render_view_host_impl.h"
     11 #include "content/browser/site_instance_impl.h"
     12 #include "content/browser/webui/web_ui_controller_factory_registry.h"
     13 #include "content/common/frame_messages.h"
     14 #include "content/common/input/synthetic_web_input_event_builders.h"
     15 #include "content/common/view_messages.h"
     16 #include "content/public/browser/global_request_id.h"
     17 #include "content/public/browser/interstitial_page_delegate.h"
     18 #include "content/public/browser/navigation_details.h"
     19 #include "content/public/browser/notification_details.h"
     20 #include "content/public/browser/notification_source.h"
     21 #include "content/public/browser/render_widget_host_view.h"
     22 #include "content/public/browser/web_contents_delegate.h"
     23 #include "content/public/browser/web_contents_observer.h"
     24 #include "content/public/browser/web_ui_controller.h"
     25 #include "content/public/common/bindings_policy.h"
     26 #include "content/public/common/content_constants.h"
     27 #include "content/public/common/url_constants.h"
     28 #include "content/public/common/url_utils.h"
     29 #include "content/public/test/mock_render_process_host.h"
     30 #include "content/public/test/test_utils.h"
     31 #include "content/test/test_content_browser_client.h"
     32 #include "content/test/test_content_client.h"
     33 #include "content/test/test_render_view_host.h"
     34 #include "content/test/test_web_contents.h"
     35 #include "testing/gtest/include/gtest/gtest.h"
     36 
     37 namespace content {
     38 namespace {
     39 
     40 const char kTestWebUIUrl[] = "chrome://blah";
     41 
     42 class WebContentsImplTestWebUIControllerFactory
     43     : public WebUIControllerFactory {
     44  public:
     45   virtual WebUIController* CreateWebUIControllerForURL(
     46       WebUI* web_ui, const GURL& url) const OVERRIDE {
     47     if (!UseWebUI(url))
     48       return NULL;
     49     return new WebUIController(web_ui);
     50   }
     51 
     52   virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
     53       const GURL& url) const OVERRIDE {
     54     return WebUI::kNoWebUI;
     55   }
     56 
     57   virtual bool UseWebUIForURL(BrowserContext* browser_context,
     58                               const GURL& url) const OVERRIDE {
     59     return UseWebUI(url);
     60   }
     61 
     62   virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
     63                                       const GURL& url) const OVERRIDE {
     64     return UseWebUI(url);
     65   }
     66 
     67  private:
     68   bool UseWebUI(const GURL& url) const {
     69     return url == GURL(kTestWebUIUrl);
     70   }
     71 };
     72 
     73 class TestInterstitialPage;
     74 
     75 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
     76  public:
     77   explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
     78       : interstitial_page_(interstitial_page) {}
     79   virtual void CommandReceived(const std::string& command) OVERRIDE;
     80   virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
     81   virtual void OnDontProceed() OVERRIDE;
     82   virtual void OnProceed() OVERRIDE;
     83  private:
     84   TestInterstitialPage* interstitial_page_;
     85 };
     86 
     87 class TestInterstitialPage : public InterstitialPageImpl {
     88  public:
     89   enum InterstitialState {
     90     INVALID = 0,    // Hasn't yet been initialized.
     91     UNDECIDED,      // Initialized, but no decision taken yet.
     92     OKED,           // Proceed was called.
     93     CANCELED        // DontProceed was called.
     94   };
     95 
     96   class Delegate {
     97    public:
     98     virtual void TestInterstitialPageDeleted(
     99         TestInterstitialPage* interstitial) = 0;
    100 
    101    protected:
    102     virtual ~Delegate() {}
    103   };
    104 
    105   // IMPORTANT NOTE: if you pass stack allocated values for |state| and
    106   // |deleted| (like all interstitial related tests do at this point), make sure
    107   // to create an instance of the TestInterstitialPageStateGuard class on the
    108   // stack in your test.  This will ensure that the TestInterstitialPage states
    109   // are cleared when the test finishes.
    110   // Not doing so will cause stack trashing if your test does not hide the
    111   // interstitial, as in such a case it will be destroyed in the test TearDown
    112   // method and will dereference the |deleted| local variable which by then is
    113   // out of scope.
    114   TestInterstitialPage(WebContentsImpl* contents,
    115                        bool new_navigation,
    116                        const GURL& url,
    117                        InterstitialState* state,
    118                        bool* deleted)
    119       : InterstitialPageImpl(
    120             contents,
    121             static_cast<RenderWidgetHostDelegate*>(contents),
    122             new_navigation, url, new TestInterstitialPageDelegate(this)),
    123         state_(state),
    124         deleted_(deleted),
    125         command_received_count_(0),
    126         delegate_(NULL) {
    127     *state_ = UNDECIDED;
    128     *deleted_ = false;
    129   }
    130 
    131   virtual ~TestInterstitialPage() {
    132     if (deleted_)
    133       *deleted_ = true;
    134     if (delegate_)
    135       delegate_->TestInterstitialPageDeleted(this);
    136   }
    137 
    138   void OnDontProceed() {
    139     if (state_)
    140       *state_ = CANCELED;
    141   }
    142   void OnProceed() {
    143     if (state_)
    144       *state_ = OKED;
    145   }
    146 
    147   int command_received_count() const {
    148     return command_received_count_;
    149   }
    150 
    151   void TestDomOperationResponse(const std::string& json_string) {
    152     if (enabled())
    153       CommandReceived();
    154   }
    155 
    156   void TestDidNavigate(int page_id, const GURL& url) {
    157     FrameHostMsg_DidCommitProvisionalLoad_Params params;
    158     InitNavigateParams(&params, page_id, url, PAGE_TRANSITION_TYPED);
    159     DidNavigate(GetRenderViewHostForTesting(), params);
    160   }
    161 
    162   void TestRenderViewTerminated(base::TerminationStatus status,
    163                                 int error_code) {
    164     RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
    165   }
    166 
    167   bool is_showing() const {
    168     return static_cast<TestRenderWidgetHostView*>(
    169         GetRenderViewHostForTesting()->GetView())->is_showing();
    170   }
    171 
    172   void ClearStates() {
    173     state_ = NULL;
    174     deleted_ = NULL;
    175     delegate_ = NULL;
    176   }
    177 
    178   void CommandReceived() {
    179     command_received_count_++;
    180   }
    181 
    182   void set_delegate(Delegate* delegate) {
    183     delegate_ = delegate;
    184   }
    185 
    186  protected:
    187   virtual WebContentsView* CreateWebContentsView() OVERRIDE {
    188     return NULL;
    189   }
    190 
    191  private:
    192   InterstitialState* state_;
    193   bool* deleted_;
    194   int command_received_count_;
    195   Delegate* delegate_;
    196 };
    197 
    198 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
    199   interstitial_page_->CommandReceived();
    200 }
    201 
    202 void TestInterstitialPageDelegate::OnDontProceed() {
    203   interstitial_page_->OnDontProceed();
    204 }
    205 
    206 void TestInterstitialPageDelegate::OnProceed() {
    207   interstitial_page_->OnProceed();
    208 }
    209 
    210 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
    211  public:
    212   explicit TestInterstitialPageStateGuard(
    213       TestInterstitialPage* interstitial_page)
    214       : interstitial_page_(interstitial_page) {
    215     DCHECK(interstitial_page_);
    216     interstitial_page_->set_delegate(this);
    217   }
    218   virtual ~TestInterstitialPageStateGuard() {
    219     if (interstitial_page_)
    220       interstitial_page_->ClearStates();
    221   }
    222 
    223   virtual void TestInterstitialPageDeleted(
    224       TestInterstitialPage* interstitial) OVERRIDE {
    225     DCHECK(interstitial_page_ == interstitial);
    226     interstitial_page_ = NULL;
    227   }
    228 
    229  private:
    230   TestInterstitialPage* interstitial_page_;
    231 };
    232 
    233 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
    234  public:
    235   WebContentsImplTestBrowserClient()
    236       : assign_site_for_url_(false) {}
    237 
    238   virtual ~WebContentsImplTestBrowserClient() {}
    239 
    240   virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
    241     return assign_site_for_url_;
    242   }
    243 
    244   void set_assign_site_for_url(bool assign) {
    245     assign_site_for_url_ = assign;
    246   }
    247 
    248  private:
    249   bool assign_site_for_url_;
    250 };
    251 
    252 class WebContentsImplTest : public RenderViewHostImplTestHarness {
    253  public:
    254   virtual void SetUp() {
    255     RenderViewHostImplTestHarness::SetUp();
    256     WebUIControllerFactory::RegisterFactory(&factory_);
    257   }
    258 
    259   virtual void TearDown() {
    260     WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
    261     RenderViewHostImplTestHarness::TearDown();
    262   }
    263 
    264  private:
    265   WebContentsImplTestWebUIControllerFactory factory_;
    266 };
    267 
    268 class TestWebContentsObserver : public WebContentsObserver {
    269  public:
    270   explicit TestWebContentsObserver(WebContents* contents)
    271       : WebContentsObserver(contents) {
    272   }
    273   virtual ~TestWebContentsObserver() {}
    274 
    275   virtual void DidFinishLoad(int64 frame_id,
    276                              const GURL& validated_url,
    277                              bool is_main_frame,
    278                              RenderViewHost* render_view_host) OVERRIDE {
    279     last_url_ = validated_url;
    280   }
    281   virtual void DidFailLoad(int64 frame_id,
    282                            const GURL& validated_url,
    283                            bool is_main_frame,
    284                            int error_code,
    285                            const base::string16& error_description,
    286                            RenderViewHost* render_view_host) OVERRIDE {
    287     last_url_ = validated_url;
    288   }
    289 
    290   const GURL& last_url() const { return last_url_; }
    291 
    292  private:
    293   GURL last_url_;
    294 
    295   DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
    296 };
    297 
    298 // Pretends to be a normal browser that receives toggles and transitions to/from
    299 // a fullscreened state.
    300 class FakeFullscreenDelegate : public WebContentsDelegate {
    301  public:
    302   FakeFullscreenDelegate() : fullscreened_contents_(NULL) {}
    303   virtual ~FakeFullscreenDelegate() {}
    304 
    305   virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
    306                                           bool enter_fullscreen) OVERRIDE {
    307     fullscreened_contents_ = enter_fullscreen ? web_contents : NULL;
    308   }
    309 
    310   virtual bool IsFullscreenForTabOrPending(const WebContents* web_contents)
    311       const OVERRIDE {
    312     return fullscreened_contents_ && web_contents == fullscreened_contents_;
    313   }
    314 
    315  private:
    316   WebContents* fullscreened_contents_;
    317 
    318   DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate);
    319 };
    320 
    321 class FakeValidationMessageDelegate : public WebContentsDelegate {
    322  public:
    323   FakeValidationMessageDelegate()
    324       : hide_validation_message_was_called_(false) {}
    325   virtual ~FakeValidationMessageDelegate() {}
    326 
    327   virtual void HideValidationMessage(WebContents* web_contents) OVERRIDE {
    328     hide_validation_message_was_called_ = true;
    329   }
    330 
    331   bool hide_validation_message_was_called() const {
    332     return hide_validation_message_was_called_;
    333   }
    334 
    335  private:
    336   bool hide_validation_message_was_called_;
    337 
    338   DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate);
    339 };
    340 
    341 }  // namespace
    342 
    343 // Test to make sure that title updates get stripped of whitespace.
    344 TEST_F(WebContentsImplTest, UpdateTitle) {
    345   NavigationControllerImpl& cont =
    346       static_cast<NavigationControllerImpl&>(controller());
    347   FrameHostMsg_DidCommitProvisionalLoad_Params params;
    348   InitNavigateParams(
    349       &params, 0, GURL(url::kAboutBlankURL), PAGE_TRANSITION_TYPED);
    350 
    351   LoadCommittedDetails details;
    352   cont.RendererDidNavigate(main_test_rfh(), params, &details);
    353 
    354   contents()->UpdateTitle(main_test_rfh(), 0,
    355                           base::ASCIIToUTF16("    Lots O' Whitespace\n"),
    356                           base::i18n::LEFT_TO_RIGHT);
    357   EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
    358 }
    359 
    360 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
    361   const GURL kGURL("chrome://blah");
    362   controller().LoadURL(
    363       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    364   EXPECT_EQ(base::string16(), contents()->GetTitle());
    365 }
    366 
    367 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
    368   const GURL kGURL("chrome://blah");
    369   const base::string16 title = base::ASCIIToUTF16("My Title");
    370   controller().LoadURL(
    371       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    372 
    373   NavigationEntry* entry = controller().GetVisibleEntry();
    374   ASSERT_EQ(kGURL, entry->GetURL());
    375   entry->SetTitle(title);
    376 
    377   EXPECT_EQ(title, contents()->GetTitle());
    378 }
    379 
    380 // Test view source mode for a webui page.
    381 TEST_F(WebContentsImplTest, NTPViewSource) {
    382   NavigationControllerImpl& cont =
    383       static_cast<NavigationControllerImpl&>(controller());
    384   const char kUrl[] = "view-source:chrome://blah";
    385   const GURL kGURL(kUrl);
    386 
    387   process()->sink().ClearMessages();
    388 
    389   cont.LoadURL(
    390       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    391   rvh()->GetDelegate()->RenderViewCreated(rvh());
    392   // Did we get the expected message?
    393   EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
    394       ViewMsg_EnableViewSourceMode::ID));
    395 
    396   FrameHostMsg_DidCommitProvisionalLoad_Params params;
    397   InitNavigateParams(&params, 0, kGURL, PAGE_TRANSITION_TYPED);
    398   LoadCommittedDetails details;
    399   cont.RendererDidNavigate(main_test_rfh(), params, &details);
    400   // Also check title and url.
    401   EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
    402 }
    403 
    404 // Test to ensure UpdateMaxPageID is working properly.
    405 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
    406   SiteInstance* instance1 = contents()->GetSiteInstance();
    407   scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
    408 
    409   // Starts at -1.
    410   EXPECT_EQ(-1, contents()->GetMaxPageID());
    411   EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
    412   EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
    413 
    414   // Make sure max_page_id_ is monotonically increasing per SiteInstance.
    415   contents()->UpdateMaxPageID(3);
    416   contents()->UpdateMaxPageID(1);
    417   EXPECT_EQ(3, contents()->GetMaxPageID());
    418   EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
    419   EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
    420 
    421   contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
    422   EXPECT_EQ(3, contents()->GetMaxPageID());
    423   EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
    424   EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
    425 }
    426 
    427 // Test simple same-SiteInstance navigation.
    428 TEST_F(WebContentsImplTest, SimpleNavigation) {
    429   TestRenderViewHost* orig_rvh = test_rvh();
    430   SiteInstance* instance1 = contents()->GetSiteInstance();
    431   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    432 
    433   // Navigate to URL
    434   const GURL url("http://www.google.com");
    435   controller().LoadURL(
    436       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    437   EXPECT_FALSE(contents()->cross_navigation_pending());
    438   EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
    439   // Controller's pending entry will have a NULL site instance until we assign
    440   // it in DidNavigate.
    441   EXPECT_TRUE(
    442       NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
    443           site_instance() == NULL);
    444 
    445   // DidNavigate from the page
    446   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    447   EXPECT_FALSE(contents()->cross_navigation_pending());
    448   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    449   EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
    450   // Controller's entry should now have the SiteInstance, or else we won't be
    451   // able to find it later.
    452   EXPECT_EQ(
    453       instance1,
    454       NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
    455           site_instance());
    456 }
    457 
    458 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
    459 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
    460   // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
    461   const GURL url(std::string("http://example.org/").append(
    462       GetMaxURLChars() + 1, 'a'));
    463 
    464   controller().LoadURL(
    465       url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
    466   EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
    467 }
    468 
    469 // Test that navigating across a site boundary creates a new RenderViewHost
    470 // with a new SiteInstance.  Going back should do the same.
    471 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
    472   TestRenderViewHost* orig_rvh = test_rvh();
    473   RenderFrameHostImpl* orig_rfh =
    474       contents()->GetFrameTree()->root()->current_frame_host();
    475   int orig_rvh_delete_count = 0;
    476   orig_rvh->set_delete_counter(&orig_rvh_delete_count);
    477   SiteInstance* instance1 = contents()->GetSiteInstance();
    478 
    479   // Navigate to URL.  First URL should use first RenderViewHost.
    480   const GURL url("http://www.google.com");
    481   controller().LoadURL(
    482       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    483   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    484 
    485   // Keep the number of active views in orig_rvh's SiteInstance
    486   // non-zero so that orig_rvh doesn't get deleted when it gets
    487   // swapped out.
    488   static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
    489       increment_active_view_count();
    490 
    491   EXPECT_FALSE(contents()->cross_navigation_pending());
    492   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    493   EXPECT_EQ(url, contents()->GetLastCommittedURL());
    494   EXPECT_EQ(url, contents()->GetVisibleURL());
    495 
    496   // Navigate to new site
    497   const GURL url2("http://www.yahoo.com");
    498   controller().LoadURL(
    499       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    500   EXPECT_TRUE(contents()->cross_navigation_pending());
    501   EXPECT_EQ(url, contents()->GetLastCommittedURL());
    502   EXPECT_EQ(url2, contents()->GetVisibleURL());
    503   TestRenderViewHost* pending_rvh =
    504       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    505   int pending_rvh_delete_count = 0;
    506   pending_rvh->set_delete_counter(&pending_rvh_delete_count);
    507   RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()->
    508       render_manager()->pending_frame_host();
    509 
    510   // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
    511   EXPECT_TRUE(pending_rvh->are_navigations_suspended());
    512   orig_rvh->SendBeforeUnloadACK(true);
    513   EXPECT_FALSE(pending_rvh->are_navigations_suspended());
    514 
    515   // DidNavigate from the pending page
    516   contents()->TestDidNavigate(
    517       pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    518   SiteInstance* instance2 = contents()->GetSiteInstance();
    519 
    520   // Keep the number of active views in pending_rvh's SiteInstance
    521   // non-zero so that orig_rvh doesn't get deleted when it gets
    522   // swapped out.
    523   static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
    524       increment_active_view_count();
    525 
    526   EXPECT_FALSE(contents()->cross_navigation_pending());
    527   EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
    528   EXPECT_EQ(url2, contents()->GetLastCommittedURL());
    529   EXPECT_EQ(url2, contents()->GetVisibleURL());
    530   EXPECT_NE(instance1, instance2);
    531   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    532   // We keep the original RFH around, swapped out.
    533   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
    534       orig_rfh));
    535   EXPECT_EQ(orig_rvh_delete_count, 0);
    536 
    537   // Going back should switch SiteInstances again.  The first SiteInstance is
    538   // stored in the NavigationEntry, so it should be the same as at the start.
    539   // We should use the same RVH as before, swapping it back in.
    540   controller().GoBack();
    541   TestRenderViewHost* goback_rvh =
    542       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    543   EXPECT_EQ(orig_rvh, goback_rvh);
    544   EXPECT_TRUE(contents()->cross_navigation_pending());
    545 
    546   // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
    547   EXPECT_TRUE(goback_rvh->are_navigations_suspended());
    548   pending_rvh->SendBeforeUnloadACK(true);
    549   EXPECT_FALSE(goback_rvh->are_navigations_suspended());
    550 
    551   // DidNavigate from the back action
    552   contents()->TestDidNavigate(
    553       goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    554   EXPECT_FALSE(contents()->cross_navigation_pending());
    555   EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
    556   EXPECT_EQ(instance1, contents()->GetSiteInstance());
    557   // The pending RFH should now be swapped out, not deleted.
    558   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
    559       IsOnSwappedOutList(pending_rfh));
    560   EXPECT_EQ(pending_rvh_delete_count, 0);
    561   pending_rvh->OnSwappedOut(false);
    562 
    563   // Close contents and ensure RVHs are deleted.
    564   DeleteContents();
    565   EXPECT_EQ(orig_rvh_delete_count, 1);
    566   EXPECT_EQ(pending_rvh_delete_count, 1);
    567 }
    568 
    569 // Test that navigating across a site boundary after a crash creates a new
    570 // RVH without requiring a cross-site transition (i.e., PENDING state).
    571 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
    572   TestRenderViewHost* orig_rvh = test_rvh();
    573   int orig_rvh_delete_count = 0;
    574   orig_rvh->set_delete_counter(&orig_rvh_delete_count);
    575   SiteInstance* instance1 = contents()->GetSiteInstance();
    576 
    577   // Navigate to URL.  First URL should use first RenderViewHost.
    578   const GURL url("http://www.google.com");
    579   controller().LoadURL(
    580       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    581   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    582 
    583   EXPECT_FALSE(contents()->cross_navigation_pending());
    584   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    585 
    586   // Crash the renderer.
    587   orig_rvh->set_render_view_created(false);
    588 
    589   // Navigate to new site.  We should not go into PENDING.
    590   const GURL url2("http://www.yahoo.com");
    591   controller().LoadURL(
    592       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    593   RenderViewHost* new_rvh = rvh();
    594   EXPECT_FALSE(contents()->cross_navigation_pending());
    595   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    596   EXPECT_NE(orig_rvh, new_rvh);
    597   EXPECT_EQ(orig_rvh_delete_count, 1);
    598 
    599   // DidNavigate from the new page
    600   contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    601   SiteInstance* instance2 = contents()->GetSiteInstance();
    602 
    603   EXPECT_FALSE(contents()->cross_navigation_pending());
    604   EXPECT_EQ(new_rvh, rvh());
    605   EXPECT_NE(instance1, instance2);
    606   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    607 
    608   // Close contents and ensure RVHs are deleted.
    609   DeleteContents();
    610   EXPECT_EQ(orig_rvh_delete_count, 1);
    611 }
    612 
    613 // Test that opening a new contents in the same SiteInstance and then navigating
    614 // both contentses to a new site will place both contentses in a single
    615 // SiteInstance.
    616 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
    617   TestRenderViewHost* orig_rvh = test_rvh();
    618   SiteInstance* instance1 = contents()->GetSiteInstance();
    619 
    620   // Navigate to URL.  First URL should use first RenderViewHost.
    621   const GURL url("http://www.google.com");
    622   controller().LoadURL(
    623       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    624   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    625 
    626   // Open a new contents with the same SiteInstance, navigated to the same site.
    627   scoped_ptr<TestWebContents> contents2(
    628       TestWebContents::Create(browser_context(), instance1));
    629   contents2->GetController().LoadURL(url, Referrer(),
    630                                     PAGE_TRANSITION_TYPED,
    631                                     std::string());
    632   // Need this page id to be 2 since the site instance is the same (which is the
    633   // scope of page IDs) and we want to consider this a new page.
    634   contents2->TestDidNavigate(
    635       contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
    636 
    637   // Navigate first contents to a new site.
    638   const GURL url2a("http://www.yahoo.com");
    639   controller().LoadURL(
    640       url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    641   orig_rvh->SendBeforeUnloadACK(true);
    642   TestRenderViewHost* pending_rvh_a =
    643       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    644   contents()->TestDidNavigate(
    645       pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
    646   SiteInstance* instance2a = contents()->GetSiteInstance();
    647   EXPECT_NE(instance1, instance2a);
    648 
    649   // Navigate second contents to the same site as the first tab.
    650   const GURL url2b("http://mail.yahoo.com");
    651   contents2->GetController().LoadURL(url2b, Referrer(),
    652                                     PAGE_TRANSITION_TYPED,
    653                                     std::string());
    654   TestRenderViewHost* rvh2 =
    655       static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
    656   rvh2->SendBeforeUnloadACK(true);
    657   TestRenderViewHost* pending_rvh_b =
    658       static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
    659   EXPECT_TRUE(pending_rvh_b != NULL);
    660   EXPECT_TRUE(contents2->cross_navigation_pending());
    661 
    662   // NOTE(creis): We used to be in danger of showing a crash page here if the
    663   // second contents hadn't navigated somewhere first (bug 1145430).  That case
    664   // is now covered by the CrossSiteBoundariesAfterCrash test.
    665   contents2->TestDidNavigate(
    666       pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
    667   SiteInstance* instance2b = contents2->GetSiteInstance();
    668   EXPECT_NE(instance1, instance2b);
    669 
    670   // Both contentses should now be in the same SiteInstance.
    671   EXPECT_EQ(instance2a, instance2b);
    672 }
    673 
    674 TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
    675   WebContentsImplTestBrowserClient browser_client;
    676   SetBrowserClientForTesting(&browser_client);
    677 
    678   TestRenderViewHost* orig_rvh = test_rvh();
    679   RenderFrameHostImpl* orig_rfh =
    680       contents()->GetFrameTree()->root()->current_frame_host();
    681   int orig_rvh_delete_count = 0;
    682   orig_rvh->set_delete_counter(&orig_rvh_delete_count);
    683   SiteInstanceImpl* orig_instance =
    684       static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
    685 
    686   browser_client.set_assign_site_for_url(false);
    687   // Navigate to an URL that will not assign a new SiteInstance.
    688   const GURL native_url("non-site-url://stuffandthings");
    689   controller().LoadURL(
    690       native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    691   contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
    692 
    693   EXPECT_FALSE(contents()->cross_navigation_pending());
    694   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    695   EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
    696   EXPECT_EQ(native_url, contents()->GetVisibleURL());
    697   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
    698   EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
    699   EXPECT_FALSE(orig_instance->HasSite());
    700 
    701   browser_client.set_assign_site_for_url(true);
    702   // Navigate to new site (should keep same site instance).
    703   const GURL url("http://www.google.com");
    704   controller().LoadURL(
    705       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    706   EXPECT_FALSE(contents()->cross_navigation_pending());
    707   EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
    708   EXPECT_EQ(url, contents()->GetVisibleURL());
    709   EXPECT_FALSE(contents()->GetPendingRenderViewHost());
    710   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    711 
    712   // Keep the number of active views in orig_rvh's SiteInstance
    713   // non-zero so that orig_rvh doesn't get deleted when it gets
    714   // swapped out.
    715   static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
    716       increment_active_view_count();
    717 
    718   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
    719   EXPECT_TRUE(
    720       contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
    721   EXPECT_EQ(url, contents()->GetLastCommittedURL());
    722 
    723   // Navigate to another new site (should create a new site instance).
    724   const GURL url2("http://www.yahoo.com");
    725   controller().LoadURL(
    726       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    727   EXPECT_TRUE(contents()->cross_navigation_pending());
    728   EXPECT_EQ(url, contents()->GetLastCommittedURL());
    729   EXPECT_EQ(url2, contents()->GetVisibleURL());
    730   TestRenderViewHost* pending_rvh =
    731       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    732   int pending_rvh_delete_count = 0;
    733   pending_rvh->set_delete_counter(&pending_rvh_delete_count);
    734 
    735   // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
    736   EXPECT_TRUE(pending_rvh->are_navigations_suspended());
    737   orig_rvh->SendBeforeUnloadACK(true);
    738   EXPECT_FALSE(pending_rvh->are_navigations_suspended());
    739 
    740   // DidNavigate from the pending page.
    741   contents()->TestDidNavigate(
    742       pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    743   SiteInstance* new_instance = contents()->GetSiteInstance();
    744 
    745   EXPECT_FALSE(contents()->cross_navigation_pending());
    746   EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
    747   EXPECT_EQ(url2, contents()->GetLastCommittedURL());
    748   EXPECT_EQ(url2, contents()->GetVisibleURL());
    749   EXPECT_NE(new_instance, orig_instance);
    750   EXPECT_FALSE(contents()->GetPendingRenderViewHost());
    751   // We keep the original RFH around, swapped out.
    752   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
    753       orig_rfh));
    754   EXPECT_EQ(orig_rvh_delete_count, 0);
    755   orig_rvh->OnSwappedOut(false);
    756 
    757   // Close contents and ensure RVHs are deleted.
    758   DeleteContents();
    759   EXPECT_EQ(orig_rvh_delete_count, 1);
    760   EXPECT_EQ(pending_rvh_delete_count, 1);
    761 }
    762 
    763 // Test that we can find an opener RVH even if it's pending.
    764 // http://crbug.com/176252.
    765 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
    766   TestRenderViewHost* orig_rvh = test_rvh();
    767 
    768   // Navigate to a URL.
    769   const GURL url("http://www.google.com");
    770   controller().LoadURL(
    771       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    772   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    773 
    774   // Start to navigate first tab to a new site, so that it has a pending RVH.
    775   const GURL url2("http://www.yahoo.com");
    776   controller().LoadURL(
    777       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    778   orig_rvh->SendBeforeUnloadACK(true);
    779   TestRenderViewHost* pending_rvh =
    780       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    781 
    782   // While it is still pending, simulate opening a new tab with the first tab
    783   // as its opener.  This will call WebContentsImpl::CreateOpenerRenderViews
    784   // on the opener to ensure that an RVH exists.
    785   int opener_routing_id = contents()->CreateOpenerRenderViews(
    786       pending_rvh->GetSiteInstance());
    787 
    788   // We should find the pending RVH and not create a new one.
    789   EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
    790 }
    791 
    792 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
    793 // to determine whether a navigation is cross-site.
    794 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
    795   RenderViewHost* orig_rvh = rvh();
    796   SiteInstance* instance1 = contents()->GetSiteInstance();
    797 
    798   // Navigate to URL.
    799   const GURL url("http://www.google.com");
    800   controller().LoadURL(
    801       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    802   contents()->TestDidNavigate(
    803       orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    804 
    805   // Open a related contents to a second site.
    806   scoped_ptr<TestWebContents> contents2(
    807       TestWebContents::Create(browser_context(), instance1));
    808   const GURL url2("http://www.yahoo.com");
    809   contents2->GetController().LoadURL(url2, Referrer(),
    810                                     PAGE_TRANSITION_TYPED,
    811                                     std::string());
    812   // The first RVH in contents2 isn't live yet, so we shortcut the cross site
    813   // pending.
    814   TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
    815       contents2->GetRenderViewHost());
    816   EXPECT_FALSE(contents2->cross_navigation_pending());
    817   contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
    818   SiteInstance* instance2 = contents2->GetSiteInstance();
    819   EXPECT_NE(instance1, instance2);
    820   EXPECT_FALSE(contents2->cross_navigation_pending());
    821 
    822   // Simulate a link click in first contents to second site.  Doesn't switch
    823   // SiteInstances, because we don't intercept WebKit navigations.
    824   contents()->TestDidNavigate(
    825       orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
    826   SiteInstance* instance3 = contents()->GetSiteInstance();
    827   EXPECT_EQ(instance1, instance3);
    828   EXPECT_FALSE(contents()->cross_navigation_pending());
    829 
    830   // Navigate to the new site.  Doesn't switch SiteInstancees, because we
    831   // compare against the current URL, not the SiteInstance's site.
    832   const GURL url3("http://mail.yahoo.com");
    833   controller().LoadURL(
    834       url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    835   EXPECT_FALSE(contents()->cross_navigation_pending());
    836   contents()->TestDidNavigate(
    837       orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
    838   SiteInstance* instance4 = contents()->GetSiteInstance();
    839   EXPECT_EQ(instance1, instance4);
    840 }
    841 
    842 // Test that the onbeforeunload and onunload handlers run when navigating
    843 // across site boundaries.
    844 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
    845   TestRenderViewHost* orig_rvh = test_rvh();
    846   SiteInstance* instance1 = contents()->GetSiteInstance();
    847 
    848   // Navigate to URL.  First URL should use first RenderViewHost.
    849   const GURL url("http://www.google.com");
    850   controller().LoadURL(
    851       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    852   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    853   EXPECT_FALSE(contents()->cross_navigation_pending());
    854   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    855 
    856   // Navigate to new site, but simulate an onbeforeunload denial.
    857   const GURL url2("http://www.yahoo.com");
    858   controller().LoadURL(
    859       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    860   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    861   base::TimeTicks now = base::TimeTicks::Now();
    862   orig_rvh->GetMainFrame()->OnMessageReceived(
    863       FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
    864   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    865   EXPECT_FALSE(contents()->cross_navigation_pending());
    866   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    867 
    868   // Navigate again, but simulate an onbeforeunload approval.
    869   controller().LoadURL(
    870       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    871   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    872   now = base::TimeTicks::Now();
    873   orig_rvh->GetMainFrame()->OnMessageReceived(
    874       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
    875   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    876   EXPECT_TRUE(contents()->cross_navigation_pending());
    877   TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
    878       contents()->GetPendingRenderViewHost());
    879 
    880   // We won't hear DidNavigate until the onunload handler has finished running.
    881 
    882   // DidNavigate from the pending page.
    883   contents()->TestDidNavigate(
    884       pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    885   SiteInstance* instance2 = contents()->GetSiteInstance();
    886   EXPECT_FALSE(contents()->cross_navigation_pending());
    887   EXPECT_EQ(pending_rvh, rvh());
    888   EXPECT_NE(instance1, instance2);
    889   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    890 }
    891 
    892 // Test that during a slow cross-site navigation, the original renderer can
    893 // navigate to a different URL and have it displayed, canceling the slow
    894 // navigation.
    895 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
    896   TestRenderViewHost* orig_rvh = test_rvh();
    897   SiteInstance* instance1 = contents()->GetSiteInstance();
    898 
    899   // Navigate to URL.  First URL should use first RenderViewHost.
    900   const GURL url("http://www.google.com");
    901   controller().LoadURL(
    902       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    903   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
    904   EXPECT_FALSE(contents()->cross_navigation_pending());
    905   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
    906 
    907   // Navigate to new site, simulating an onbeforeunload approval.
    908   const GURL url2("http://www.yahoo.com");
    909   controller().LoadURL(
    910       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    911   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    912   base::TimeTicks now = base::TimeTicks::Now();
    913   orig_rvh->GetMainFrame()->OnMessageReceived(
    914       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
    915   EXPECT_TRUE(contents()->cross_navigation_pending());
    916 
    917   // Suppose the original renderer navigates before the new one is ready.
    918   orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
    919 
    920   // Verify that the pending navigation is cancelled.
    921   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    922   SiteInstance* instance2 = contents()->GetSiteInstance();
    923   EXPECT_FALSE(contents()->cross_navigation_pending());
    924   EXPECT_EQ(orig_rvh, rvh());
    925   EXPECT_EQ(instance1, instance2);
    926   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
    927 }
    928 
    929 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
    930   // Start with a web ui page, which gets a new RVH with WebUI bindings.
    931   const GURL url1("chrome://blah");
    932   controller().LoadURL(
    933       url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    934   TestRenderViewHost* ntp_rvh = test_rvh();
    935   contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
    936   NavigationEntry* entry1 = controller().GetLastCommittedEntry();
    937   SiteInstance* instance1 = contents()->GetSiteInstance();
    938 
    939   EXPECT_FALSE(contents()->cross_navigation_pending());
    940   EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
    941   EXPECT_EQ(url1, entry1->GetURL());
    942   EXPECT_EQ(instance1,
    943             NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
    944   EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
    945 
    946   // Navigate to new site.
    947   const GURL url2("http://www.google.com");
    948   controller().LoadURL(
    949       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    950   EXPECT_TRUE(contents()->cross_navigation_pending());
    951   TestRenderViewHost* google_rvh =
    952       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
    953 
    954   // Simulate beforeunload approval.
    955   EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
    956   base::TimeTicks now = base::TimeTicks::Now();
    957   ntp_rvh->GetMainFrame()->OnMessageReceived(
    958       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
    959 
    960   // DidNavigate from the pending page.
    961   contents()->TestDidNavigate(
    962       google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
    963   NavigationEntry* entry2 = controller().GetLastCommittedEntry();
    964   SiteInstance* instance2 = contents()->GetSiteInstance();
    965 
    966   EXPECT_FALSE(contents()->cross_navigation_pending());
    967   EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
    968   EXPECT_NE(instance1, instance2);
    969   EXPECT_FALSE(contents()->GetPendingRenderViewHost());
    970   EXPECT_EQ(url2, entry2->GetURL());
    971   EXPECT_EQ(instance2,
    972             NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
    973   EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
    974 
    975   // Navigate to third page on same site.
    976   const GURL url3("http://news.google.com");
    977   controller().LoadURL(
    978       url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
    979   EXPECT_FALSE(contents()->cross_navigation_pending());
    980   contents()->TestDidNavigate(
    981       google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
    982   NavigationEntry* entry3 = controller().GetLastCommittedEntry();
    983   SiteInstance* instance3 = contents()->GetSiteInstance();
    984 
    985   EXPECT_FALSE(contents()->cross_navigation_pending());
    986   EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
    987   EXPECT_EQ(instance2, instance3);
    988   EXPECT_FALSE(contents()->GetPendingRenderViewHost());
    989   EXPECT_EQ(url3, entry3->GetURL());
    990   EXPECT_EQ(instance3,
    991             NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
    992 
    993   // Go back within the site.
    994   controller().GoBack();
    995   EXPECT_FALSE(contents()->cross_navigation_pending());
    996   EXPECT_EQ(entry2, controller().GetPendingEntry());
    997 
    998   // Before that commits, go back again.
    999   controller().GoBack();
   1000   EXPECT_TRUE(contents()->cross_navigation_pending());
   1001   EXPECT_TRUE(contents()->GetPendingRenderViewHost());
   1002   EXPECT_EQ(entry1, controller().GetPendingEntry());
   1003 
   1004   // Simulate beforeunload approval.
   1005   EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
   1006   now = base::TimeTicks::Now();
   1007   google_rvh->GetMainFrame()->OnMessageReceived(
   1008       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   1009 
   1010   // DidNavigate from the first back. This aborts the second back's pending RVH.
   1011   contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
   1012 
   1013   // We should commit this page and forget about the second back.
   1014   EXPECT_FALSE(contents()->cross_navigation_pending());
   1015   EXPECT_FALSE(controller().GetPendingEntry());
   1016   EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
   1017   EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
   1018 
   1019   // We should not have corrupted the NTP entry.
   1020   EXPECT_EQ(instance3,
   1021             NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
   1022   EXPECT_EQ(instance2,
   1023             NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
   1024   EXPECT_EQ(instance1,
   1025             NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
   1026   EXPECT_EQ(url1, entry1->GetURL());
   1027 }
   1028 
   1029 // Test that during a slow cross-site navigation, a sub-frame navigation in the
   1030 // original renderer will not cancel the slow navigation (bug 42029).
   1031 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
   1032   TestRenderViewHost* orig_rvh = test_rvh();
   1033 
   1034   // Navigate to URL.  First URL should use first RenderViewHost.
   1035   const GURL url("http://www.google.com");
   1036   controller().LoadURL(
   1037       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1038   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1039   EXPECT_FALSE(contents()->cross_navigation_pending());
   1040   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1041 
   1042   // Start navigating to new site.
   1043   const GURL url2("http://www.yahoo.com");
   1044   controller().LoadURL(
   1045       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1046 
   1047   // Simulate a sub-frame navigation arriving and ensure the RVH is still
   1048   // waiting for a before unload response.
   1049   orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
   1050                                        PAGE_TRANSITION_AUTO_SUBFRAME);
   1051   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
   1052 
   1053   // Now simulate the onbeforeunload approval and verify the navigation is
   1054   // not canceled.
   1055   base::TimeTicks now = base::TimeTicks::Now();
   1056   orig_rvh->GetMainFrame()->OnMessageReceived(
   1057       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   1058   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
   1059   EXPECT_TRUE(contents()->cross_navigation_pending());
   1060 }
   1061 
   1062 // Test that a cross-site navigation is not preempted if the previous
   1063 // renderer sends a FrameNavigate message just before being told to stop.
   1064 // We should only preempt the cross-site navigation if the previous renderer
   1065 // has started a new navigation.  See http://crbug.com/79176.
   1066 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
   1067   // Navigate to NTP URL.
   1068   const GURL url("chrome://blah");
   1069   controller().LoadURL(
   1070       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1071   TestRenderViewHost* orig_rvh = test_rvh();
   1072   EXPECT_FALSE(contents()->cross_navigation_pending());
   1073 
   1074   // Navigate to new site, with the beforeunload request in flight.
   1075   const GURL url2("http://www.yahoo.com");
   1076   controller().LoadURL(
   1077       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1078   TestRenderViewHost* pending_rvh =
   1079       static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
   1080   EXPECT_TRUE(contents()->cross_navigation_pending());
   1081   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
   1082 
   1083   // Suppose the first navigation tries to commit now, with a
   1084   // ViewMsg_Stop in flight.  This should not cancel the pending navigation,
   1085   // but it should act as if the beforeunload ack arrived.
   1086   orig_rvh->SendNavigate(1, GURL("chrome://blah"));
   1087   EXPECT_TRUE(contents()->cross_navigation_pending());
   1088   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1089   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
   1090 
   1091   // The pending navigation should be able to commit successfully.
   1092   contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
   1093   EXPECT_FALSE(contents()->cross_navigation_pending());
   1094   EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
   1095 }
   1096 
   1097 // Test that the original renderer cannot preempt a cross-site navigation once
   1098 // the unload request has been made.  At this point, the cross-site navigation
   1099 // is almost ready to be displayed, and the original renderer is only given a
   1100 // short chance to run an unload handler.  Prevents regression of bug 23942.
   1101 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
   1102   TestRenderViewHost* orig_rvh = test_rvh();
   1103   SiteInstance* instance1 = contents()->GetSiteInstance();
   1104 
   1105   // Navigate to URL.  First URL should use first RenderViewHost.
   1106   const GURL url("http://www.google.com");
   1107   controller().LoadURL(
   1108       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1109   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1110   EXPECT_FALSE(contents()->cross_navigation_pending());
   1111   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1112 
   1113   // Navigate to new site, simulating an onbeforeunload approval.
   1114   const GURL url2("http://www.yahoo.com");
   1115   controller().LoadURL(
   1116       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1117   base::TimeTicks now = base::TimeTicks::Now();
   1118   orig_rvh->GetMainFrame()->OnMessageReceived(
   1119       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   1120   EXPECT_TRUE(contents()->cross_navigation_pending());
   1121   TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
   1122       contents()->GetPendingRenderViewHost());
   1123 
   1124   // Simulate the pending renderer's response, which leads to an unload request
   1125   // being sent to orig_rvh.
   1126   std::vector<GURL> url_chain;
   1127   url_chain.push_back(GURL());
   1128   contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
   1129       contents()->GetRenderManagerForTesting()->pending_frame_host(),
   1130       GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
   1131       url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
   1132 
   1133   // Suppose the original renderer navigates now, while the unload request is in
   1134   // flight.  We should ignore it, wait for the unload ack, and let the pending
   1135   // request continue.  Otherwise, the contents may close spontaneously or stop
   1136   // responding to navigation requests.  (See bug 23942.)
   1137   FrameHostMsg_DidCommitProvisionalLoad_Params params1a;
   1138   InitNavigateParams(&params1a, 2, GURL("http://www.google.com/foo"),
   1139                      PAGE_TRANSITION_TYPED);
   1140   orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
   1141 
   1142   // Verify that the pending navigation is still in progress.
   1143   EXPECT_TRUE(contents()->cross_navigation_pending());
   1144   EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
   1145 
   1146   // DidNavigate from the pending page should commit it.
   1147   contents()->TestDidNavigate(
   1148       pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
   1149   SiteInstance* instance2 = contents()->GetSiteInstance();
   1150   EXPECT_FALSE(contents()->cross_navigation_pending());
   1151   EXPECT_EQ(pending_rvh, rvh());
   1152   EXPECT_NE(instance1, instance2);
   1153   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
   1154 }
   1155 
   1156 // Test that a cross-site navigation that doesn't commit after the unload
   1157 // handler doesn't leave the contents in a stuck state.  http://crbug.com/88562
   1158 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
   1159   TestRenderViewHost* orig_rvh = test_rvh();
   1160   SiteInstance* instance1 = contents()->GetSiteInstance();
   1161 
   1162   // Navigate to URL.  First URL should use first RenderViewHost.
   1163   const GURL url("http://www.google.com");
   1164   controller().LoadURL(
   1165       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1166   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1167   EXPECT_FALSE(contents()->cross_navigation_pending());
   1168   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1169 
   1170   // Navigate to new site, simulating an onbeforeunload approval.
   1171   const GURL url2("http://www.yahoo.com");
   1172   controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1173   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
   1174   base::TimeTicks now = base::TimeTicks::Now();
   1175   orig_rvh->GetMainFrame()->OnMessageReceived(
   1176       FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
   1177   EXPECT_TRUE(contents()->cross_navigation_pending());
   1178 
   1179   // Simulate swap out message when the response arrives.
   1180   orig_rvh->OnSwappedOut(false);
   1181 
   1182   // Suppose the navigation doesn't get a chance to commit, and the user
   1183   // navigates in the current RVH's SiteInstance.
   1184   controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1185 
   1186   // Verify that the pending navigation is cancelled and the renderer is no
   1187   // longer swapped out.
   1188   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
   1189   SiteInstance* instance2 = contents()->GetSiteInstance();
   1190   EXPECT_FALSE(contents()->cross_navigation_pending());
   1191   EXPECT_EQ(orig_rvh, rvh());
   1192   EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, orig_rvh->rvh_state());
   1193   EXPECT_EQ(instance1, instance2);
   1194   EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
   1195 }
   1196 
   1197 // Test that NavigationEntries have the correct page state after going
   1198 // forward and back.  Prevents regression for bug 1116137.
   1199 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
   1200   TestRenderViewHost* orig_rvh = test_rvh();
   1201 
   1202   // Navigate to URL.  There should be no committed entry yet.
   1203   const GURL url("http://www.google.com");
   1204   controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1205   NavigationEntry* entry = controller().GetLastCommittedEntry();
   1206   EXPECT_TRUE(entry == NULL);
   1207 
   1208   // Committed entry should have page state after DidNavigate.
   1209   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1210   entry = controller().GetLastCommittedEntry();
   1211   EXPECT_TRUE(entry->GetPageState().IsValid());
   1212 
   1213   // Navigate to same site.
   1214   const GURL url2("http://images.google.com");
   1215   controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1216   entry = controller().GetLastCommittedEntry();
   1217   EXPECT_TRUE(entry->GetPageState().IsValid());
   1218 
   1219   // Committed entry should have page state after DidNavigate.
   1220   contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
   1221   entry = controller().GetLastCommittedEntry();
   1222   EXPECT_TRUE(entry->GetPageState().IsValid());
   1223 
   1224   // Now go back.  Committed entry should still have page state.
   1225   controller().GoBack();
   1226   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1227   entry = controller().GetLastCommittedEntry();
   1228   EXPECT_TRUE(entry->GetPageState().IsValid());
   1229 }
   1230 
   1231 // Test that NavigationEntries have the correct page state and SiteInstance
   1232 // state after opening a new window to about:blank.  Prevents regression for
   1233 // bugs b/1116137 and http://crbug.com/111975.
   1234 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
   1235   TestRenderViewHost* orig_rvh = test_rvh();
   1236 
   1237   // When opening a new window, it is navigated to about:blank internally.
   1238   // Currently, this results in two DidNavigate events.
   1239   const GURL url(url::kAboutBlankURL);
   1240   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1241   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1242 
   1243   // Should have a page state here.
   1244   NavigationEntry* entry = controller().GetLastCommittedEntry();
   1245   EXPECT_TRUE(entry->GetPageState().IsValid());
   1246 
   1247   // The SiteInstance should be available for other navigations to use.
   1248   NavigationEntryImpl* entry_impl =
   1249       NavigationEntryImpl::FromNavigationEntry(entry);
   1250   EXPECT_FALSE(entry_impl->site_instance()->HasSite());
   1251   int32 site_instance_id = entry_impl->site_instance()->GetId();
   1252 
   1253   // Navigating to a normal page should not cause a process swap.
   1254   const GURL new_url("http://www.google.com");
   1255   controller().LoadURL(new_url, Referrer(),
   1256                        PAGE_TRANSITION_TYPED, std::string());
   1257   EXPECT_FALSE(contents()->cross_navigation_pending());
   1258   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1259   contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
   1260   NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
   1261       controller().GetLastCommittedEntry());
   1262   EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
   1263   EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
   1264 }
   1265 
   1266 // Tests that fullscreen is exited throughout the object hierarchy when
   1267 // navigating to a new page.
   1268 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
   1269   FakeFullscreenDelegate fake_delegate;
   1270   contents()->SetDelegate(&fake_delegate);
   1271   TestRenderViewHost* orig_rvh = test_rvh();
   1272 
   1273   // Navigate to a site.
   1274   const GURL url("http://www.google.com");
   1275   controller().LoadURL(
   1276       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1277   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1278   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1279 
   1280   // Toggle fullscreen mode on (as if initiated via IPC from renderer).
   1281   EXPECT_FALSE(orig_rvh->IsFullscreen());
   1282   EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
   1283   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
   1284   orig_rvh->OnMessageReceived(
   1285       ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
   1286   EXPECT_TRUE(orig_rvh->IsFullscreen());
   1287   EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
   1288   EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
   1289 
   1290   // Navigate to a new site.
   1291   const GURL url2("http://www.yahoo.com");
   1292   controller().LoadURL(
   1293       url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1294   RenderViewHost* const pending_rvh = contents()->GetPendingRenderViewHost();
   1295   contents()->TestDidNavigate(
   1296       pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
   1297 
   1298   // Confirm fullscreen has exited.
   1299   EXPECT_FALSE(orig_rvh->IsFullscreen());
   1300   EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
   1301   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
   1302 
   1303   contents()->SetDelegate(NULL);
   1304 }
   1305 
   1306 // Tests that fullscreen is exited throughout the object hierarchy when
   1307 // instructing NavigationController to GoBack() or GoForward().
   1308 TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
   1309   FakeFullscreenDelegate fake_delegate;
   1310   contents()->SetDelegate(&fake_delegate);
   1311   TestRenderViewHost* const orig_rvh = test_rvh();
   1312 
   1313   // Navigate to a site.
   1314   const GURL url("http://www.google.com");
   1315   controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1316   contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
   1317   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1318 
   1319   // Now, navigate to another page on the same site.
   1320   const GURL url2("http://www.google.com/search?q=kittens");
   1321   controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1322   EXPECT_FALSE(contents()->cross_navigation_pending());
   1323   contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
   1324   EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1325 
   1326   // Sanity-check: Confirm we're not starting out in fullscreen mode.
   1327   EXPECT_FALSE(orig_rvh->IsFullscreen());
   1328   EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
   1329   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
   1330 
   1331   for (int i = 0; i < 2; ++i) {
   1332     // Toggle fullscreen mode on (as if initiated via IPC from renderer).
   1333     orig_rvh->OnMessageReceived(
   1334         ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
   1335     EXPECT_TRUE(orig_rvh->IsFullscreen());
   1336     EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
   1337     EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
   1338 
   1339     // Navigate backward (or forward).
   1340     if (i == 0)
   1341       controller().GoBack();
   1342     else
   1343       controller().GoForward();
   1344     EXPECT_FALSE(contents()->cross_navigation_pending());
   1345     EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
   1346     contents()->TestDidNavigate(
   1347         orig_rvh, i + 1, url, PAGE_TRANSITION_FORWARD_BACK);
   1348 
   1349     // Confirm fullscreen has exited.
   1350     EXPECT_FALSE(orig_rvh->IsFullscreen());
   1351     EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
   1352     EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
   1353   }
   1354 
   1355   contents()->SetDelegate(NULL);
   1356 }
   1357 
   1358 TEST_F(WebContentsImplTest, TerminateHidesValidationMessage) {
   1359   FakeValidationMessageDelegate fake_delegate;
   1360   contents()->SetDelegate(&fake_delegate);
   1361   EXPECT_FALSE(fake_delegate.hide_validation_message_was_called());
   1362 
   1363   // Crash the renderer.
   1364   test_rvh()->OnMessageReceived(
   1365       ViewHostMsg_RenderProcessGone(
   1366           0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
   1367 
   1368   // Confirm HideValidationMessage was called.
   1369   EXPECT_TRUE(fake_delegate.hide_validation_message_was_called());
   1370 
   1371   contents()->SetDelegate(NULL);
   1372 }
   1373 
   1374 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
   1375 // crash.
   1376 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
   1377   FakeFullscreenDelegate fake_delegate;
   1378   contents()->SetDelegate(&fake_delegate);
   1379 
   1380   // Navigate to a site.
   1381   const GURL url("http://www.google.com");
   1382   controller().LoadURL(
   1383       url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   1384   contents()->TestDidNavigate(test_rvh(), 1, url, PAGE_TRANSITION_TYPED);
   1385   EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
   1386 
   1387   // Toggle fullscreen mode on (as if initiated via IPC from renderer).
   1388   EXPECT_FALSE(test_rvh()->IsFullscreen());
   1389   EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
   1390   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
   1391   test_rvh()->OnMessageReceived(
   1392       ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
   1393   EXPECT_TRUE(test_rvh()->IsFullscreen());
   1394   EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
   1395   EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
   1396 
   1397   // Crash the renderer.
   1398   test_rvh()->OnMessageReceived(
   1399       ViewHostMsg_RenderProcessGone(
   1400           0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
   1401 
   1402   // Confirm fullscreen has exited.
   1403   EXPECT_FALSE(test_rvh()->IsFullscreen());
   1404   EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
   1405   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
   1406 
   1407   contents()->SetDelegate(NULL);
   1408 }
   1409 
   1410 ////////////////////////////////////////////////////////////////////////////////
   1411 // Interstitial Tests
   1412 ////////////////////////////////////////////////////////////////////////////////
   1413 
   1414 // Test navigating to a page (with the navigation initiated from the browser,
   1415 // as when a URL is typed in the location bar) that shows an interstitial and
   1416 // creates a new navigation entry, then hiding it without proceeding.
   1417 TEST_F(WebContentsImplTest,
   1418        ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
   1419   // Navigate to a page.
   1420   GURL url1("http://www.google.com");
   1421   test_rvh()->SendNavigate(1, url1);
   1422   EXPECT_EQ(1, controller().GetEntryCount());
   1423 
   1424   // Initiate a browser navigation that will trigger the interstitial
   1425   controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
   1426                         PAGE_TRANSITION_TYPED, std::string());
   1427 
   1428   // Show an interstitial.
   1429   TestInterstitialPage::InterstitialState state =
   1430       TestInterstitialPage::INVALID;
   1431   bool deleted = false;
   1432   GURL url2("http://interstitial");
   1433   TestInterstitialPage* interstitial =
   1434       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1435   TestInterstitialPageStateGuard state_guard(interstitial);
   1436   interstitial->Show();
   1437   // The interstitial should not show until its navigation has committed.
   1438   EXPECT_FALSE(interstitial->is_showing());
   1439   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1440   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1441   // Let's commit the interstitial navigation.
   1442   interstitial->TestDidNavigate(1, url2);
   1443   EXPECT_TRUE(interstitial->is_showing());
   1444   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1445   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1446   NavigationEntry* entry = controller().GetVisibleEntry();
   1447   ASSERT_TRUE(entry != NULL);
   1448   EXPECT_TRUE(entry->GetURL() == url2);
   1449 
   1450   // Now don't proceed.
   1451   interstitial->DontProceed();
   1452   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1453   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1454   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1455   entry = controller().GetVisibleEntry();
   1456   ASSERT_TRUE(entry != NULL);
   1457   EXPECT_TRUE(entry->GetURL() == url1);
   1458   EXPECT_EQ(1, controller().GetEntryCount());
   1459 
   1460   RunAllPendingInMessageLoop();
   1461   EXPECT_TRUE(deleted);
   1462 }
   1463 
   1464 // Test navigating to a page (with the navigation initiated from the renderer,
   1465 // as when clicking on a link in the page) that shows an interstitial and
   1466 // creates a new navigation entry, then hiding it without proceeding.
   1467 TEST_F(WebContentsImplTest,
   1468        ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
   1469   // Navigate to a page.
   1470   GURL url1("http://www.google.com");
   1471   test_rvh()->SendNavigate(1, url1);
   1472   EXPECT_EQ(1, controller().GetEntryCount());
   1473 
   1474   // Show an interstitial (no pending entry, the interstitial would have been
   1475   // triggered by clicking on a link).
   1476   TestInterstitialPage::InterstitialState state =
   1477       TestInterstitialPage::INVALID;
   1478   bool deleted = false;
   1479   GURL url2("http://interstitial");
   1480   TestInterstitialPage* interstitial =
   1481       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1482   TestInterstitialPageStateGuard state_guard(interstitial);
   1483   interstitial->Show();
   1484   // The interstitial should not show until its navigation has committed.
   1485   EXPECT_FALSE(interstitial->is_showing());
   1486   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1487   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1488   // Let's commit the interstitial navigation.
   1489   interstitial->TestDidNavigate(1, url2);
   1490   EXPECT_TRUE(interstitial->is_showing());
   1491   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1492   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1493   NavigationEntry* entry = controller().GetVisibleEntry();
   1494   ASSERT_TRUE(entry != NULL);
   1495   EXPECT_TRUE(entry->GetURL() == url2);
   1496 
   1497   // Now don't proceed.
   1498   interstitial->DontProceed();
   1499   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1500   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1501   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1502   entry = controller().GetVisibleEntry();
   1503   ASSERT_TRUE(entry != NULL);
   1504   EXPECT_TRUE(entry->GetURL() == url1);
   1505   EXPECT_EQ(1, controller().GetEntryCount());
   1506 
   1507   RunAllPendingInMessageLoop();
   1508   EXPECT_TRUE(deleted);
   1509 }
   1510 
   1511 // Test navigating to a page that shows an interstitial without creating a new
   1512 // navigation entry (this happens when the interstitial is triggered by a
   1513 // sub-resource in the page), then hiding it without proceeding.
   1514 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
   1515   // Navigate to a page.
   1516   GURL url1("http://www.google.com");
   1517   test_rvh()->SendNavigate(1, url1);
   1518   EXPECT_EQ(1, controller().GetEntryCount());
   1519 
   1520   // Show an interstitial.
   1521   TestInterstitialPage::InterstitialState state =
   1522       TestInterstitialPage::INVALID;
   1523   bool deleted = false;
   1524   GURL url2("http://interstitial");
   1525   TestInterstitialPage* interstitial =
   1526       new TestInterstitialPage(contents(), false, url2, &state, &deleted);
   1527   TestInterstitialPageStateGuard state_guard(interstitial);
   1528   interstitial->Show();
   1529   // The interstitial should not show until its navigation has committed.
   1530   EXPECT_FALSE(interstitial->is_showing());
   1531   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1532   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1533   // Let's commit the interstitial navigation.
   1534   interstitial->TestDidNavigate(1, url2);
   1535   EXPECT_TRUE(interstitial->is_showing());
   1536   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1537   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1538   NavigationEntry* entry = controller().GetVisibleEntry();
   1539   ASSERT_TRUE(entry != NULL);
   1540   // The URL specified to the interstitial should have been ignored.
   1541   EXPECT_TRUE(entry->GetURL() == url1);
   1542 
   1543   // Now don't proceed.
   1544   interstitial->DontProceed();
   1545   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1546   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1547   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1548   entry = controller().GetVisibleEntry();
   1549   ASSERT_TRUE(entry != NULL);
   1550   EXPECT_TRUE(entry->GetURL() == url1);
   1551   EXPECT_EQ(1, controller().GetEntryCount());
   1552 
   1553   RunAllPendingInMessageLoop();
   1554   EXPECT_TRUE(deleted);
   1555 }
   1556 
   1557 // Test navigating to a page (with the navigation initiated from the browser,
   1558 // as when a URL is typed in the location bar) that shows an interstitial and
   1559 // creates a new navigation entry, then proceeding.
   1560 TEST_F(WebContentsImplTest,
   1561        ShowInterstitialFromBrowserNewNavigationProceed) {
   1562   // Navigate to a page.
   1563   GURL url1("http://www.google.com");
   1564   test_rvh()->SendNavigate(1, url1);
   1565   EXPECT_EQ(1, controller().GetEntryCount());
   1566 
   1567   // Initiate a browser navigation that will trigger the interstitial
   1568   controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
   1569                         PAGE_TRANSITION_TYPED, std::string());
   1570 
   1571   // Show an interstitial.
   1572   TestInterstitialPage::InterstitialState state =
   1573       TestInterstitialPage::INVALID;
   1574   bool deleted = false;
   1575   GURL url2("http://interstitial");
   1576   TestInterstitialPage* interstitial =
   1577       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1578   TestInterstitialPageStateGuard state_guard(interstitial);
   1579   interstitial->Show();
   1580   // The interstitial should not show until its navigation has committed.
   1581   EXPECT_FALSE(interstitial->is_showing());
   1582   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1583   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1584   // Let's commit the interstitial navigation.
   1585   interstitial->TestDidNavigate(1, url2);
   1586   EXPECT_TRUE(interstitial->is_showing());
   1587   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1588   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1589   NavigationEntry* entry = controller().GetVisibleEntry();
   1590   ASSERT_TRUE(entry != NULL);
   1591   EXPECT_TRUE(entry->GetURL() == url2);
   1592 
   1593   // Then proceed.
   1594   interstitial->Proceed();
   1595   // The interstitial should show until the new navigation commits.
   1596   RunAllPendingInMessageLoop();
   1597   ASSERT_FALSE(deleted);
   1598   EXPECT_EQ(TestInterstitialPage::OKED, state);
   1599   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1600   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1601 
   1602   // Simulate the navigation to the page, that's when the interstitial gets
   1603   // hidden.
   1604   GURL url3("http://www.thepage.com");
   1605   test_rvh()->SendNavigate(2, url3);
   1606 
   1607   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1608   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1609   entry = controller().GetVisibleEntry();
   1610   ASSERT_TRUE(entry != NULL);
   1611   EXPECT_TRUE(entry->GetURL() == url3);
   1612 
   1613   EXPECT_EQ(2, controller().GetEntryCount());
   1614 
   1615   RunAllPendingInMessageLoop();
   1616   EXPECT_TRUE(deleted);
   1617 }
   1618 
   1619 // Test navigating to a page (with the navigation initiated from the renderer,
   1620 // as when clicking on a link in the page) that shows an interstitial and
   1621 // creates a new navigation entry, then proceeding.
   1622 TEST_F(WebContentsImplTest,
   1623        ShowInterstitialFromRendererNewNavigationProceed) {
   1624   // Navigate to a page.
   1625   GURL url1("http://www.google.com");
   1626   test_rvh()->SendNavigate(1, url1);
   1627   EXPECT_EQ(1, controller().GetEntryCount());
   1628 
   1629   // Show an interstitial.
   1630   TestInterstitialPage::InterstitialState state =
   1631       TestInterstitialPage::INVALID;
   1632   bool deleted = false;
   1633   GURL url2("http://interstitial");
   1634   TestInterstitialPage* interstitial =
   1635       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1636   TestInterstitialPageStateGuard state_guard(interstitial);
   1637   interstitial->Show();
   1638   // The interstitial should not show until its navigation has committed.
   1639   EXPECT_FALSE(interstitial->is_showing());
   1640   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1641   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1642   // Let's commit the interstitial navigation.
   1643   interstitial->TestDidNavigate(1, url2);
   1644   EXPECT_TRUE(interstitial->is_showing());
   1645   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1646   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1647   NavigationEntry* entry = controller().GetVisibleEntry();
   1648   ASSERT_TRUE(entry != NULL);
   1649   EXPECT_TRUE(entry->GetURL() == url2);
   1650 
   1651   // Then proceed.
   1652   interstitial->Proceed();
   1653   // The interstitial should show until the new navigation commits.
   1654   RunAllPendingInMessageLoop();
   1655   ASSERT_FALSE(deleted);
   1656   EXPECT_EQ(TestInterstitialPage::OKED, state);
   1657   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1658   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1659 
   1660   // Simulate the navigation to the page, that's when the interstitial gets
   1661   // hidden.
   1662   GURL url3("http://www.thepage.com");
   1663   test_rvh()->SendNavigate(2, url3);
   1664 
   1665   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1666   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1667   entry = controller().GetVisibleEntry();
   1668   ASSERT_TRUE(entry != NULL);
   1669   EXPECT_TRUE(entry->GetURL() == url3);
   1670 
   1671   EXPECT_EQ(2, controller().GetEntryCount());
   1672 
   1673   RunAllPendingInMessageLoop();
   1674   EXPECT_TRUE(deleted);
   1675 }
   1676 
   1677 // Test navigating to a page that shows an interstitial without creating a new
   1678 // navigation entry (this happens when the interstitial is triggered by a
   1679 // sub-resource in the page), then proceeding.
   1680 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
   1681   // Navigate to a page so we have a navigation entry in the controller.
   1682   GURL url1("http://www.google.com");
   1683   test_rvh()->SendNavigate(1, url1);
   1684   EXPECT_EQ(1, controller().GetEntryCount());
   1685 
   1686   // Show an interstitial.
   1687   TestInterstitialPage::InterstitialState state =
   1688       TestInterstitialPage::INVALID;
   1689   bool deleted = false;
   1690   GURL url2("http://interstitial");
   1691   TestInterstitialPage* interstitial =
   1692       new TestInterstitialPage(contents(), false, url2, &state, &deleted);
   1693   TestInterstitialPageStateGuard state_guard(interstitial);
   1694   interstitial->Show();
   1695   // The interstitial should not show until its navigation has committed.
   1696   EXPECT_FALSE(interstitial->is_showing());
   1697   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1698   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1699   // Let's commit the interstitial navigation.
   1700   interstitial->TestDidNavigate(1, url2);
   1701   EXPECT_TRUE(interstitial->is_showing());
   1702   EXPECT_TRUE(contents()->ShowingInterstitialPage());
   1703   EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
   1704   NavigationEntry* entry = controller().GetVisibleEntry();
   1705   ASSERT_TRUE(entry != NULL);
   1706   // The URL specified to the interstitial should have been ignored.
   1707   EXPECT_TRUE(entry->GetURL() == url1);
   1708 
   1709   // Then proceed.
   1710   interstitial->Proceed();
   1711   // Since this is not a new navigation, the previous page is dismissed right
   1712   // away and shows the original page.
   1713   EXPECT_EQ(TestInterstitialPage::OKED, state);
   1714   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1715   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1716   entry = controller().GetVisibleEntry();
   1717   ASSERT_TRUE(entry != NULL);
   1718   EXPECT_TRUE(entry->GetURL() == url1);
   1719 
   1720   EXPECT_EQ(1, controller().GetEntryCount());
   1721 
   1722   RunAllPendingInMessageLoop();
   1723   EXPECT_TRUE(deleted);
   1724 }
   1725 
   1726 // Test navigating to a page that shows an interstitial, then navigating away.
   1727 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
   1728   // Show interstitial.
   1729   TestInterstitialPage::InterstitialState state =
   1730       TestInterstitialPage::INVALID;
   1731   bool deleted = false;
   1732   GURL url("http://interstitial");
   1733   TestInterstitialPage* interstitial =
   1734       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1735   TestInterstitialPageStateGuard state_guard(interstitial);
   1736   interstitial->Show();
   1737   interstitial->TestDidNavigate(1, url);
   1738 
   1739   // While interstitial showing, navigate to a new URL.
   1740   const GURL url2("http://www.yahoo.com");
   1741   test_rvh()->SendNavigate(1, url2);
   1742 
   1743   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1744 
   1745   RunAllPendingInMessageLoop();
   1746   EXPECT_TRUE(deleted);
   1747 }
   1748 
   1749 // Test navigating to a page that shows an interstitial, then going back.
   1750 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
   1751   // Navigate to a page so we have a navigation entry in the controller.
   1752   GURL url1("http://www.google.com");
   1753   test_rvh()->SendNavigate(1, url1);
   1754   EXPECT_EQ(1, controller().GetEntryCount());
   1755 
   1756   // Show interstitial.
   1757   TestInterstitialPage::InterstitialState state =
   1758       TestInterstitialPage::INVALID;
   1759   bool deleted = false;
   1760   GURL interstitial_url("http://interstitial");
   1761   TestInterstitialPage* interstitial =
   1762       new TestInterstitialPage(contents(), true, interstitial_url,
   1763                                &state, &deleted);
   1764   TestInterstitialPageStateGuard state_guard(interstitial);
   1765   interstitial->Show();
   1766   interstitial->TestDidNavigate(2, interstitial_url);
   1767 
   1768   // While the interstitial is showing, go back.
   1769   controller().GoBack();
   1770   test_rvh()->SendNavigate(1, url1);
   1771 
   1772   // Make sure we are back to the original page and that the interstitial is
   1773   // gone.
   1774   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1775   NavigationEntry* entry = controller().GetVisibleEntry();
   1776   ASSERT_TRUE(entry);
   1777   EXPECT_EQ(url1.spec(), entry->GetURL().spec());
   1778 
   1779   RunAllPendingInMessageLoop();
   1780   EXPECT_TRUE(deleted);
   1781 }
   1782 
   1783 // Test navigating to a page that shows an interstitial, has a renderer crash,
   1784 // and then goes back.
   1785 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
   1786   // Navigate to a page so we have a navigation entry in the controller.
   1787   GURL url1("http://www.google.com");
   1788   test_rvh()->SendNavigate(1, url1);
   1789   EXPECT_EQ(1, controller().GetEntryCount());
   1790 
   1791   // Show interstitial.
   1792   TestInterstitialPage::InterstitialState state =
   1793       TestInterstitialPage::INVALID;
   1794   bool deleted = false;
   1795   GURL interstitial_url("http://interstitial");
   1796   TestInterstitialPage* interstitial =
   1797       new TestInterstitialPage(contents(), true, interstitial_url,
   1798                                &state, &deleted);
   1799   TestInterstitialPageStateGuard state_guard(interstitial);
   1800   interstitial->Show();
   1801   interstitial->TestDidNavigate(2, interstitial_url);
   1802 
   1803   // Crash the renderer
   1804   test_rvh()->OnMessageReceived(
   1805       ViewHostMsg_RenderProcessGone(
   1806           0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
   1807 
   1808   // While the interstitial is showing, go back.
   1809   controller().GoBack();
   1810   test_rvh()->SendNavigate(1, url1);
   1811 
   1812   // Make sure we are back to the original page and that the interstitial is
   1813   // gone.
   1814   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1815   NavigationEntry* entry = controller().GetVisibleEntry();
   1816   ASSERT_TRUE(entry);
   1817   EXPECT_EQ(url1.spec(), entry->GetURL().spec());
   1818 
   1819   RunAllPendingInMessageLoop();
   1820   EXPECT_TRUE(deleted);
   1821 }
   1822 
   1823 // Test navigating to a page that shows an interstitial, has the renderer crash,
   1824 // and then navigates to the interstitial.
   1825 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
   1826   // Navigate to a page so we have a navigation entry in the controller.
   1827   GURL url1("http://www.google.com");
   1828   test_rvh()->SendNavigate(1, url1);
   1829   EXPECT_EQ(1, controller().GetEntryCount());
   1830 
   1831   // Show interstitial.
   1832   TestInterstitialPage::InterstitialState state =
   1833       TestInterstitialPage::INVALID;
   1834   bool deleted = false;
   1835   GURL interstitial_url("http://interstitial");
   1836   TestInterstitialPage* interstitial =
   1837       new TestInterstitialPage(contents(), true, interstitial_url,
   1838                                &state, &deleted);
   1839   TestInterstitialPageStateGuard state_guard(interstitial);
   1840   interstitial->Show();
   1841 
   1842   // Crash the renderer
   1843   test_rvh()->OnMessageReceived(
   1844       ViewHostMsg_RenderProcessGone(
   1845           0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
   1846 
   1847   interstitial->TestDidNavigate(2, interstitial_url);
   1848 }
   1849 
   1850 // Test navigating to a page that shows an interstitial, then close the
   1851 // contents.
   1852 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
   1853   // Show interstitial.
   1854   TestInterstitialPage::InterstitialState state =
   1855       TestInterstitialPage::INVALID;
   1856   bool deleted = false;
   1857   GURL url("http://interstitial");
   1858   TestInterstitialPage* interstitial =
   1859       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1860   TestInterstitialPageStateGuard state_guard(interstitial);
   1861   interstitial->Show();
   1862   interstitial->TestDidNavigate(1, url);
   1863 
   1864   // Now close the contents.
   1865   DeleteContents();
   1866   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1867 
   1868   RunAllPendingInMessageLoop();
   1869   EXPECT_TRUE(deleted);
   1870 }
   1871 
   1872 // Test navigating to a page that shows an interstitial, then close the
   1873 // contents.
   1874 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
   1875   // Show interstitial.
   1876   TestInterstitialPage::InterstitialState state =
   1877       TestInterstitialPage::INVALID;
   1878   bool deleted = false;
   1879   GURL url("http://interstitial");
   1880   TestInterstitialPage* interstitial =
   1881       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1882   TestInterstitialPageStateGuard state_guard(interstitial);
   1883   interstitial->Show();
   1884   interstitial->TestDidNavigate(1, url);
   1885   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
   1886       interstitial->GetRenderViewHostForTesting());
   1887 
   1888   // Now close the contents.
   1889   DeleteContents();
   1890   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1891 
   1892   // Before the interstitial has a chance to process its shutdown task,
   1893   // simulate quitting the browser.  This goes through all processes and
   1894   // tells them to destruct.
   1895   rvh->OnMessageReceived(
   1896         ViewHostMsg_RenderProcessGone(0, 0, 0));
   1897 
   1898   RunAllPendingInMessageLoop();
   1899   EXPECT_TRUE(deleted);
   1900 }
   1901 
   1902 // Test that after Proceed is called and an interstitial is still shown, no more
   1903 // commands get executed.
   1904 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
   1905   // Navigate to a page so we have a navigation entry in the controller.
   1906   GURL url1("http://www.google.com");
   1907   test_rvh()->SendNavigate(1, url1);
   1908   EXPECT_EQ(1, controller().GetEntryCount());
   1909 
   1910   // Show an interstitial.
   1911   TestInterstitialPage::InterstitialState state =
   1912       TestInterstitialPage::INVALID;
   1913   bool deleted = false;
   1914   GURL url2("http://interstitial");
   1915   TestInterstitialPage* interstitial =
   1916       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1917   TestInterstitialPageStateGuard state_guard(interstitial);
   1918   interstitial->Show();
   1919   interstitial->TestDidNavigate(1, url2);
   1920 
   1921   // Run a command.
   1922   EXPECT_EQ(0, interstitial->command_received_count());
   1923   interstitial->TestDomOperationResponse("toto");
   1924   EXPECT_EQ(1, interstitial->command_received_count());
   1925 
   1926   // Then proceed.
   1927   interstitial->Proceed();
   1928   RunAllPendingInMessageLoop();
   1929   ASSERT_FALSE(deleted);
   1930 
   1931   // While the navigation to the new page is pending, send other commands, they
   1932   // should be ignored.
   1933   interstitial->TestDomOperationResponse("hello");
   1934   interstitial->TestDomOperationResponse("hi");
   1935   EXPECT_EQ(1, interstitial->command_received_count());
   1936 }
   1937 
   1938 // Test showing an interstitial while another interstitial is already showing.
   1939 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
   1940   // Navigate to a page so we have a navigation entry in the controller.
   1941   GURL start_url("http://www.google.com");
   1942   test_rvh()->SendNavigate(1, start_url);
   1943   EXPECT_EQ(1, controller().GetEntryCount());
   1944 
   1945   // Show an interstitial.
   1946   TestInterstitialPage::InterstitialState state1 =
   1947       TestInterstitialPage::INVALID;
   1948   bool deleted1 = false;
   1949   GURL url1("http://interstitial1");
   1950   TestInterstitialPage* interstitial1 =
   1951       new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
   1952   TestInterstitialPageStateGuard state_guard1(interstitial1);
   1953   interstitial1->Show();
   1954   interstitial1->TestDidNavigate(1, url1);
   1955 
   1956   // Now show another interstitial.
   1957   TestInterstitialPage::InterstitialState state2 =
   1958       TestInterstitialPage::INVALID;
   1959   bool deleted2 = false;
   1960   GURL url2("http://interstitial2");
   1961   TestInterstitialPage* interstitial2 =
   1962       new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
   1963   TestInterstitialPageStateGuard state_guard2(interstitial2);
   1964   interstitial2->Show();
   1965   interstitial2->TestDidNavigate(1, url2);
   1966 
   1967   // Showing interstitial2 should have caused interstitial1 to go away.
   1968   EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
   1969   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   1970 
   1971   RunAllPendingInMessageLoop();
   1972   EXPECT_TRUE(deleted1);
   1973   ASSERT_FALSE(deleted2);
   1974 
   1975   // Let's make sure interstitial2 is working as intended.
   1976   interstitial2->Proceed();
   1977   GURL landing_url("http://www.thepage.com");
   1978   test_rvh()->SendNavigate(2, landing_url);
   1979 
   1980   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   1981   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   1982   NavigationEntry* entry = controller().GetVisibleEntry();
   1983   ASSERT_TRUE(entry != NULL);
   1984   EXPECT_TRUE(entry->GetURL() == landing_url);
   1985   EXPECT_EQ(2, controller().GetEntryCount());
   1986   RunAllPendingInMessageLoop();
   1987   EXPECT_TRUE(deleted2);
   1988 }
   1989 
   1990 // Test showing an interstitial, proceeding and then navigating to another
   1991 // interstitial.
   1992 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
   1993   // Navigate to a page so we have a navigation entry in the controller.
   1994   GURL start_url("http://www.google.com");
   1995   test_rvh()->SendNavigate(1, start_url);
   1996   EXPECT_EQ(1, controller().GetEntryCount());
   1997 
   1998   // Show an interstitial.
   1999   TestInterstitialPage::InterstitialState state1 =
   2000       TestInterstitialPage::INVALID;
   2001   bool deleted1 = false;
   2002   GURL url1("http://interstitial1");
   2003   TestInterstitialPage* interstitial1 =
   2004       new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
   2005   TestInterstitialPageStateGuard state_guard1(interstitial1);
   2006   interstitial1->Show();
   2007   interstitial1->TestDidNavigate(1, url1);
   2008 
   2009   // Take action.  The interstitial won't be hidden until the navigation is
   2010   // committed.
   2011   interstitial1->Proceed();
   2012   EXPECT_EQ(TestInterstitialPage::OKED, state1);
   2013 
   2014   // Now show another interstitial (simulating the navigation causing another
   2015   // interstitial).
   2016   TestInterstitialPage::InterstitialState state2 =
   2017       TestInterstitialPage::INVALID;
   2018   bool deleted2 = false;
   2019   GURL url2("http://interstitial2");
   2020   TestInterstitialPage* interstitial2 =
   2021       new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
   2022   TestInterstitialPageStateGuard state_guard2(interstitial2);
   2023   interstitial2->Show();
   2024   interstitial2->TestDidNavigate(1, url2);
   2025 
   2026   // Showing interstitial2 should have caused interstitial1 to go away.
   2027   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   2028   RunAllPendingInMessageLoop();
   2029   EXPECT_TRUE(deleted1);
   2030   ASSERT_FALSE(deleted2);
   2031 
   2032   // Let's make sure interstitial2 is working as intended.
   2033   interstitial2->Proceed();
   2034   GURL landing_url("http://www.thepage.com");
   2035   test_rvh()->SendNavigate(2, landing_url);
   2036 
   2037   RunAllPendingInMessageLoop();
   2038   EXPECT_TRUE(deleted2);
   2039   EXPECT_FALSE(contents()->ShowingInterstitialPage());
   2040   EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
   2041   NavigationEntry* entry = controller().GetVisibleEntry();
   2042   ASSERT_TRUE(entry != NULL);
   2043   EXPECT_TRUE(entry->GetURL() == landing_url);
   2044   EXPECT_EQ(2, controller().GetEntryCount());
   2045 }
   2046 
   2047 // Test that navigating away from an interstitial while it's loading cause it
   2048 // not to show.
   2049 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
   2050   // Show an interstitial.
   2051   TestInterstitialPage::InterstitialState state =
   2052       TestInterstitialPage::INVALID;
   2053   bool deleted = false;
   2054   GURL interstitial_url("http://interstitial");
   2055   TestInterstitialPage* interstitial =
   2056       new TestInterstitialPage(contents(), true, interstitial_url,
   2057                                &state, &deleted);
   2058   TestInterstitialPageStateGuard state_guard(interstitial);
   2059   interstitial->Show();
   2060 
   2061   // Let's simulate a navigation initiated from the browser before the
   2062   // interstitial finishes loading.
   2063   const GURL url("http://www.google.com");
   2064   controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   2065   EXPECT_FALSE(interstitial->is_showing());
   2066   RunAllPendingInMessageLoop();
   2067   ASSERT_FALSE(deleted);
   2068 
   2069   // Now let's make the interstitial navigation commit.
   2070   interstitial->TestDidNavigate(1, interstitial_url);
   2071 
   2072   // After it loaded the interstitial should be gone.
   2073   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   2074 
   2075   RunAllPendingInMessageLoop();
   2076   EXPECT_TRUE(deleted);
   2077 }
   2078 
   2079 // Test that a new request to show an interstitial while an interstitial is
   2080 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
   2081 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
   2082   GURL interstitial_url("http://interstitial");
   2083 
   2084   // Show a first interstitial.
   2085   TestInterstitialPage::InterstitialState state1 =
   2086       TestInterstitialPage::INVALID;
   2087   bool deleted1 = false;
   2088   TestInterstitialPage* interstitial1 =
   2089       new TestInterstitialPage(contents(), true, interstitial_url,
   2090                                &state1, &deleted1);
   2091   TestInterstitialPageStateGuard state_guard1(interstitial1);
   2092   interstitial1->Show();
   2093 
   2094   // Show another interstitial on that same contents before the first one had
   2095   // time to load.
   2096   TestInterstitialPage::InterstitialState state2 =
   2097       TestInterstitialPage::INVALID;
   2098   bool deleted2 = false;
   2099   TestInterstitialPage* interstitial2 =
   2100       new TestInterstitialPage(contents(), true, interstitial_url,
   2101                                &state2, &deleted2);
   2102   TestInterstitialPageStateGuard state_guard2(interstitial2);
   2103   interstitial2->Show();
   2104 
   2105   // The first interstitial should have been closed and deleted.
   2106   EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
   2107   // The 2nd one should still be OK.
   2108   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   2109 
   2110   RunAllPendingInMessageLoop();
   2111   EXPECT_TRUE(deleted1);
   2112   ASSERT_FALSE(deleted2);
   2113 
   2114   // Make the interstitial navigation commit it should be showing.
   2115   interstitial2->TestDidNavigate(1, interstitial_url);
   2116   EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
   2117 }
   2118 
   2119 // Test showing an interstitial and have its renderer crash.
   2120 TEST_F(WebContentsImplTest, InterstitialCrasher) {
   2121   // Show an interstitial.
   2122   TestInterstitialPage::InterstitialState state =
   2123       TestInterstitialPage::INVALID;
   2124   bool deleted = false;
   2125   GURL url("http://interstitial");
   2126   TestInterstitialPage* interstitial =
   2127       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   2128   TestInterstitialPageStateGuard state_guard(interstitial);
   2129   interstitial->Show();
   2130   // Simulate a renderer crash before the interstitial is shown.
   2131   interstitial->TestRenderViewTerminated(
   2132       base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
   2133   // The interstitial should have been dismissed.
   2134   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   2135   RunAllPendingInMessageLoop();
   2136   EXPECT_TRUE(deleted);
   2137 
   2138   // Now try again but this time crash the intersitial after it was shown.
   2139   interstitial =
   2140       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   2141   interstitial->Show();
   2142   interstitial->TestDidNavigate(1, url);
   2143   // Simulate a renderer crash.
   2144   interstitial->TestRenderViewTerminated(
   2145       base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
   2146   // The interstitial should have been dismissed.
   2147   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   2148   RunAllPendingInMessageLoop();
   2149   EXPECT_TRUE(deleted);
   2150 }
   2151 
   2152 // Tests that showing an interstitial as a result of a browser initiated
   2153 // navigation while an interstitial is showing does not remove the pending
   2154 // entry (see http://crbug.com/9791).
   2155 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
   2156   const char kUrl[] = "http://www.badguys.com/";
   2157   const GURL kGURL(kUrl);
   2158 
   2159   // Start a navigation to a page
   2160   contents()->GetController().LoadURL(
   2161       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   2162 
   2163   // Simulate that navigation triggering an interstitial.
   2164   TestInterstitialPage::InterstitialState state =
   2165       TestInterstitialPage::INVALID;
   2166   bool deleted = false;
   2167   TestInterstitialPage* interstitial =
   2168       new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
   2169   TestInterstitialPageStateGuard state_guard(interstitial);
   2170   interstitial->Show();
   2171   interstitial->TestDidNavigate(1, kGURL);
   2172 
   2173   // Initiate a new navigation from the browser that also triggers an
   2174   // interstitial.
   2175   contents()->GetController().LoadURL(
   2176       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   2177   TestInterstitialPage::InterstitialState state2 =
   2178       TestInterstitialPage::INVALID;
   2179   bool deleted2 = false;
   2180   TestInterstitialPage* interstitial2 =
   2181       new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
   2182   TestInterstitialPageStateGuard state_guard2(interstitial2);
   2183   interstitial2->Show();
   2184   interstitial2->TestDidNavigate(1, kGURL);
   2185 
   2186   // Make sure we still have an entry.
   2187   NavigationEntry* entry = contents()->GetController().GetPendingEntry();
   2188   ASSERT_TRUE(entry);
   2189   EXPECT_EQ(kUrl, entry->GetURL().spec());
   2190 
   2191   // And that the first interstitial is gone, but not the second.
   2192   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   2193   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   2194   RunAllPendingInMessageLoop();
   2195   EXPECT_TRUE(deleted);
   2196   EXPECT_FALSE(deleted2);
   2197 }
   2198 
   2199 // Tests that Javascript messages are not shown while an interstitial is
   2200 // showing.
   2201 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
   2202   const char kUrl[] = "http://www.badguys.com/";
   2203   const GURL kGURL(kUrl);
   2204 
   2205   // Start a navigation to a page
   2206   contents()->GetController().LoadURL(
   2207       kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
   2208   // DidNavigate from the page
   2209   contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
   2210 
   2211   // Simulate showing an interstitial while the page is showing.
   2212   TestInterstitialPage::InterstitialState state =
   2213       TestInterstitialPage::INVALID;
   2214   bool deleted = false;
   2215   TestInterstitialPage* interstitial =
   2216       new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
   2217   TestInterstitialPageStateGuard state_guard(interstitial);
   2218   interstitial->Show();
   2219   interstitial->TestDidNavigate(1, kGURL);
   2220 
   2221   // While the interstitial is showing, let's simulate the hidden page
   2222   // attempting to show a JS message.
   2223   IPC::Message* dummy_message = new IPC::Message;
   2224   contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
   2225       base::ASCIIToUTF16("This is an informative message"),
   2226       base::ASCIIToUTF16("OK"),
   2227       kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message);
   2228   EXPECT_TRUE(contents()->last_dialog_suppressed_);
   2229 }
   2230 
   2231 // Makes sure that if the source passed to CopyStateFromAndPrune has an
   2232 // interstitial it isn't copied over to the destination.
   2233 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
   2234   // Navigate to a page.
   2235   GURL url1("http://www.google.com");
   2236   test_rvh()->SendNavigate(1, url1);
   2237   EXPECT_EQ(1, controller().GetEntryCount());
   2238 
   2239   // Initiate a browser navigation that will trigger the interstitial
   2240   controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
   2241                         PAGE_TRANSITION_TYPED, std::string());
   2242 
   2243   // Show an interstitial.
   2244   TestInterstitialPage::InterstitialState state =
   2245       TestInterstitialPage::INVALID;
   2246   bool deleted = false;
   2247   GURL url2("http://interstitial");
   2248   TestInterstitialPage* interstitial =
   2249       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   2250   TestInterstitialPageStateGuard state_guard(interstitial);
   2251   interstitial->Show();
   2252   interstitial->TestDidNavigate(1, url2);
   2253   EXPECT_TRUE(interstitial->is_showing());
   2254   EXPECT_EQ(2, controller().GetEntryCount());
   2255 
   2256   // Create another NavigationController.
   2257   GURL url3("http://foo2");
   2258   scoped_ptr<TestWebContents> other_contents(
   2259       static_cast<TestWebContents*>(CreateTestWebContents()));
   2260   NavigationControllerImpl& other_controller = other_contents->GetController();
   2261   other_contents->NavigateAndCommit(url3);
   2262   other_contents->ExpectSetHistoryLengthAndPrune(
   2263       NavigationEntryImpl::FromNavigationEntry(
   2264           other_controller.GetEntryAtIndex(0))->site_instance(), 1,
   2265       other_controller.GetEntryAtIndex(0)->GetPageID());
   2266   other_controller.CopyStateFromAndPrune(&controller(), false);
   2267 
   2268   // The merged controller should only have two entries: url1 and url2.
   2269   ASSERT_EQ(2, other_controller.GetEntryCount());
   2270   EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
   2271   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   2272   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
   2273 
   2274   // And the merged controller shouldn't be showing an interstitial.
   2275   EXPECT_FALSE(other_contents->ShowingInterstitialPage());
   2276 }
   2277 
   2278 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
   2279 // showing an interstitial.
   2280 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
   2281   // Navigate to a page.
   2282   GURL url1("http://www.google.com");
   2283   contents()->NavigateAndCommit(url1);
   2284 
   2285   // Create another NavigationController.
   2286   scoped_ptr<TestWebContents> other_contents(
   2287       static_cast<TestWebContents*>(CreateTestWebContents()));
   2288   NavigationControllerImpl& other_controller = other_contents->GetController();
   2289 
   2290   // Navigate it to url2.
   2291   GURL url2("http://foo2");
   2292   other_contents->NavigateAndCommit(url2);
   2293 
   2294   // Show an interstitial.
   2295   TestInterstitialPage::InterstitialState state =
   2296       TestInterstitialPage::INVALID;
   2297   bool deleted = false;
   2298   GURL url3("http://interstitial");
   2299   TestInterstitialPage* interstitial =
   2300       new TestInterstitialPage(other_contents.get(), true, url3, &state,
   2301                                &deleted);
   2302   TestInterstitialPageStateGuard state_guard(interstitial);
   2303   interstitial->Show();
   2304   interstitial->TestDidNavigate(1, url3);
   2305   EXPECT_TRUE(interstitial->is_showing());
   2306   EXPECT_EQ(2, other_controller.GetEntryCount());
   2307 
   2308   // Ensure that we do not allow calling CopyStateFromAndPrune when an
   2309   // interstitial is showing in the target.
   2310   EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
   2311 }
   2312 
   2313 // Regression test for http://crbug.com/168611 - the URLs passed by the
   2314 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
   2315 TEST_F(WebContentsImplTest, FilterURLs) {
   2316   TestWebContentsObserver observer(contents());
   2317 
   2318   // A navigation to about:whatever should always look like a navigation to
   2319   // about:blank
   2320   GURL url_normalized(url::kAboutBlankURL);
   2321   GURL url_from_ipc("about:whatever");
   2322 
   2323   // We navigate the test WebContents to about:blank, since NavigateAndCommit
   2324   // will use the given URL to create the NavigationEntry as well, and that
   2325   // entry should contain the filtered URL.
   2326   contents()->NavigateAndCommit(url_normalized);
   2327 
   2328   // Check that an IPC with about:whatever is correctly normalized.
   2329   contents()->TestDidFinishLoad(url_from_ipc);
   2330 
   2331   EXPECT_EQ(url_normalized, observer.last_url());
   2332 
   2333   // Create and navigate another WebContents.
   2334   scoped_ptr<TestWebContents> other_contents(
   2335       static_cast<TestWebContents*>(CreateTestWebContents()));
   2336   TestWebContentsObserver other_observer(other_contents.get());
   2337   other_contents->NavigateAndCommit(url_normalized);
   2338 
   2339   // Check that an IPC with about:whatever is correctly normalized.
   2340   other_contents->TestDidFailLoadWithError(
   2341       url_from_ipc, 1, base::string16());
   2342   EXPECT_EQ(url_normalized, other_observer.last_url());
   2343 }
   2344 
   2345 // Test that if a pending contents is deleted before it is shown, we don't
   2346 // crash.
   2347 TEST_F(WebContentsImplTest, PendingContents) {
   2348   scoped_ptr<TestWebContents> other_contents(
   2349       static_cast<TestWebContents*>(CreateTestWebContents()));
   2350   contents()->AddPendingContents(other_contents.get());
   2351   int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
   2352   other_contents.reset();
   2353   EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
   2354 }
   2355 
   2356 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
   2357   const gfx::Size original_preferred_size(1024, 768);
   2358   contents()->UpdatePreferredSize(original_preferred_size);
   2359 
   2360   // With no capturers, expect the preferred size to be the one propagated into
   2361   // WebContentsImpl via the RenderViewHostDelegate interface.
   2362   EXPECT_EQ(contents()->GetCapturerCount(), 0);
   2363   EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
   2364 
   2365   // Increment capturer count, but without specifying a capture size.  Expect
   2366   // a "not set" preferred size.
   2367   contents()->IncrementCapturerCount(gfx::Size());
   2368   EXPECT_EQ(1, contents()->GetCapturerCount());
   2369   EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
   2370 
   2371   // Increment capturer count again, but with an overriding capture size.
   2372   // Expect preferred size to now be overridden to the capture size.
   2373   const gfx::Size capture_size(1280, 720);
   2374   contents()->IncrementCapturerCount(capture_size);
   2375   EXPECT_EQ(2, contents()->GetCapturerCount());
   2376   EXPECT_EQ(capture_size, contents()->GetPreferredSize());
   2377 
   2378   // Increment capturer count a third time, but the expect that the preferred
   2379   // size is still the first capture size.
   2380   const gfx::Size another_capture_size(720, 480);
   2381   contents()->IncrementCapturerCount(another_capture_size);
   2382   EXPECT_EQ(3, contents()->GetCapturerCount());
   2383   EXPECT_EQ(capture_size, contents()->GetPreferredSize());
   2384 
   2385   // Decrement capturer count twice, but expect the preferred size to still be
   2386   // overridden.
   2387   contents()->DecrementCapturerCount();
   2388   contents()->DecrementCapturerCount();
   2389   EXPECT_EQ(1, contents()->GetCapturerCount());
   2390   EXPECT_EQ(capture_size, contents()->GetPreferredSize());
   2391 
   2392   // Decrement capturer count, and since the count has dropped to zero, the
   2393   // original preferred size should be restored.
   2394   contents()->DecrementCapturerCount();
   2395   EXPECT_EQ(0, contents()->GetCapturerCount());
   2396   EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
   2397 }
   2398 
   2399 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
   2400 // on activity.
   2401 TEST_F(WebContentsImplTest, GetLastActiveTime) {
   2402   // The WebContents starts with a valid creation time.
   2403   EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
   2404 
   2405   // Reset the last active time to a known-bad value.
   2406   contents()->last_active_time_ = base::TimeTicks();
   2407   ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
   2408 
   2409   // Simulate activating the WebContents. The active time should update.
   2410   contents()->WasShown();
   2411   EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
   2412 }
   2413 
   2414 class ContentsZoomChangedDelegate : public WebContentsDelegate {
   2415  public:
   2416   ContentsZoomChangedDelegate() :
   2417     contents_zoom_changed_call_count_(0),
   2418     last_zoom_in_(false) {
   2419   }
   2420 
   2421   int GetAndResetContentsZoomChangedCallCount() {
   2422     int count = contents_zoom_changed_call_count_;
   2423     contents_zoom_changed_call_count_ = 0;
   2424     return count;
   2425   }
   2426 
   2427   bool last_zoom_in() const {
   2428     return last_zoom_in_;
   2429   }
   2430 
   2431   // WebContentsDelegate:
   2432   virtual void ContentsZoomChange(bool zoom_in) OVERRIDE {
   2433     contents_zoom_changed_call_count_++;
   2434     last_zoom_in_ = zoom_in;
   2435   }
   2436 
   2437  private:
   2438   int contents_zoom_changed_call_count_;
   2439   bool last_zoom_in_;
   2440 
   2441   DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
   2442 };
   2443 
   2444 // Tests that some mouseehweel events get turned into browser zoom requests.
   2445 TEST_F(WebContentsImplTest, HandleWheelEvent) {
   2446   using blink::WebInputEvent;
   2447 
   2448   scoped_ptr<ContentsZoomChangedDelegate> delegate(
   2449       new ContentsZoomChangedDelegate());
   2450   contents()->SetDelegate(delegate.get());
   2451 
   2452   int modifiers = 0;
   2453   // Verify that normal mouse wheel events do nothing to change the zoom level.
   2454   blink::WebMouseWheelEvent event =
   2455       SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
   2456   EXPECT_FALSE(contents()->HandleWheelEvent(event));
   2457   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
   2458 
   2459   modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey;
   2460   event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
   2461   EXPECT_FALSE(contents()->HandleWheelEvent(event));
   2462   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
   2463 
   2464   // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
   2465   // Except on MacOS where we never want to adjust zoom with mousewheel.
   2466   modifiers = WebInputEvent::ControlKey;
   2467   event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
   2468   bool handled = contents()->HandleWheelEvent(event);
   2469 #if defined(OS_MACOSX)
   2470   EXPECT_FALSE(handled);
   2471   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
   2472 #else
   2473   EXPECT_TRUE(handled);
   2474   EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
   2475   EXPECT_TRUE(delegate->last_zoom_in());
   2476 #endif
   2477 
   2478   modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
   2479       WebInputEvent::AltKey;
   2480   event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false);
   2481   handled = contents()->HandleWheelEvent(event);
   2482 #if defined(OS_MACOSX)
   2483   EXPECT_FALSE(handled);
   2484   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
   2485 #else
   2486   EXPECT_TRUE(handled);
   2487   EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
   2488   EXPECT_FALSE(delegate->last_zoom_in());
   2489 #endif
   2490 
   2491   // Unless there is no vertical movement.
   2492   event = SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers, false);
   2493   EXPECT_FALSE(contents()->HandleWheelEvent(event));
   2494   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
   2495 
   2496   // Events containing precise scrolling deltas also shouldn't result in the
   2497   // zoom being adjusted, to avoid accidental adjustments caused by
   2498   // two-finger-scrolling on a touchpad.
   2499   modifiers = WebInputEvent::ControlKey;
   2500   event = SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers, true);
   2501   EXPECT_FALSE(contents()->HandleWheelEvent(event));
   2502   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
   2503 
   2504   // Ensure pointers to the delegate aren't kept beyond its lifetime.
   2505   contents()->SetDelegate(NULL);
   2506 }
   2507 
   2508 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
   2509 TEST_F(WebContentsImplTest, HandleGestureEvent) {
   2510   using blink::WebGestureEvent;
   2511   using blink::WebInputEvent;
   2512 
   2513   scoped_ptr<ContentsZoomChangedDelegate> delegate(
   2514       new ContentsZoomChangedDelegate());
   2515   contents()->SetDelegate(delegate.get());
   2516 
   2517   const float kZoomStepValue = 0.6f;
   2518   blink::WebGestureEvent event = SyntheticWebGestureEventBuilder::Build(
   2519       WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchpad);
   2520 
   2521   // A pinch less than the step value doesn't change the zoom level.
   2522   event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 0.8f;
   2523   EXPECT_TRUE(contents()->HandleGestureEvent(event));
   2524   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
   2525 
   2526   // But repeating the event so the combined scale is greater does.
   2527   EXPECT_TRUE(contents()->HandleGestureEvent(event));
   2528   EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
   2529   EXPECT_TRUE(delegate->last_zoom_in());
   2530 
   2531   // Pinching back out one step goes back to 100%.
   2532   event.data.pinchUpdate.scale = 1.0f - kZoomStepValue;
   2533   EXPECT_TRUE(contents()->HandleGestureEvent(event));
   2534   EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
   2535   EXPECT_FALSE(delegate->last_zoom_in());
   2536 
   2537   // Pinching out again doesn't zoom (step is twice as large around 100%).
   2538   EXPECT_TRUE(contents()->HandleGestureEvent(event));
   2539   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
   2540 
   2541   // And again now it zooms once per step.
   2542   EXPECT_TRUE(contents()->HandleGestureEvent(event));
   2543   EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
   2544   EXPECT_FALSE(delegate->last_zoom_in());
   2545 
   2546   // No other type of gesture event is handled by WebContentsImpl (for example
   2547   // a touchscreen pinch gesture).
   2548   event = SyntheticWebGestureEventBuilder::Build(
   2549       WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchscreen);
   2550   event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 3;
   2551   EXPECT_FALSE(contents()->HandleGestureEvent(event));
   2552   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
   2553 
   2554   // Ensure pointers to the delegate aren't kept beyond it's lifetime.
   2555   contents()->SetDelegate(NULL);
   2556 }
   2557 
   2558 // Tests that GetRelatedActiveContentsCount is shared between related
   2559 // SiteInstances and includes WebContents that have not navigated yet.
   2560 TEST_F(WebContentsImplTest, ActiveContentsCountBasic) {
   2561   scoped_refptr<SiteInstance> instance1(
   2562       SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
   2563   scoped_refptr<SiteInstance> instance2(
   2564       instance1->GetRelatedSiteInstance(GURL("http://b.com")));
   2565 
   2566   EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
   2567   EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
   2568 
   2569   scoped_ptr<TestWebContents> contents1(
   2570       TestWebContents::Create(browser_context(), instance1));
   2571   EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
   2572   EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
   2573 
   2574   scoped_ptr<TestWebContents> contents2(
   2575       TestWebContents::Create(browser_context(), instance1));
   2576   EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount());
   2577   EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount());
   2578 
   2579   contents1.reset();
   2580   EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
   2581   EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
   2582 
   2583   contents2.reset();
   2584   EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
   2585   EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
   2586 }
   2587 
   2588 // Tests that GetRelatedActiveContentsCount is preserved correctly across
   2589 // same-site and cross-site navigations.
   2590 TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
   2591   scoped_refptr<SiteInstance> instance(
   2592       SiteInstance::Create(browser_context()));
   2593 
   2594   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
   2595 
   2596   scoped_ptr<TestWebContents> contents(
   2597       TestWebContents::Create(browser_context(), instance));
   2598   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2599 
   2600   // Navigate to a URL.
   2601   contents->GetController().LoadURL(
   2602       GURL("http://a.com/1"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
   2603   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2604   contents->CommitPendingNavigation();
   2605   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2606 
   2607   // Navigate to a URL in the same site.
   2608   contents->GetController().LoadURL(
   2609       GURL("http://a.com/2"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
   2610   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2611   contents->CommitPendingNavigation();
   2612   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2613 
   2614   // Navigate to a URL in a different site.
   2615   contents->GetController().LoadURL(
   2616       GURL("http://b.com"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
   2617   EXPECT_TRUE(contents->cross_navigation_pending());
   2618   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2619   contents->CommitPendingNavigation();
   2620   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2621 
   2622   contents.reset();
   2623   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
   2624 }
   2625 
   2626 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
   2627 // from WebUI.
   2628 TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
   2629   scoped_refptr<SiteInstance> instance(
   2630       SiteInstance::Create(browser_context()));
   2631 
   2632   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
   2633 
   2634   scoped_ptr<TestWebContents> contents(
   2635       TestWebContents::Create(browser_context(), instance));
   2636   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2637 
   2638   // Navigate to a URL.
   2639   contents->NavigateAndCommit(GURL("http://a.com"));
   2640   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2641 
   2642   // Navigate to a URL with WebUI. This will change BrowsingInstances.
   2643   contents->GetController().LoadURL(
   2644       GURL(kTestWebUIUrl), Referrer(), PAGE_TRANSITION_TYPED, std::string());
   2645   EXPECT_TRUE(contents->cross_navigation_pending());
   2646   scoped_refptr<SiteInstance> instance_webui(
   2647       contents->GetPendingRenderViewHost()->GetSiteInstance());
   2648   EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
   2649 
   2650   // At this point, contents still counts for the old BrowsingInstance.
   2651   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
   2652   EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
   2653 
   2654   // Commit and contents counts for the new one.
   2655   contents->CommitPendingNavigation();
   2656   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
   2657   EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount());
   2658 
   2659   contents.reset();
   2660   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
   2661   EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
   2662 }
   2663 
   2664 }  // namespace content
   2665