Home | History | Annotate | Download | only in tab_contents
      1 // Copyright (c) 2011 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 <vector>
      6 
      7 #include "base/logging.h"
      8 #include "base/utf_string_conversions.h"
      9 #include "chrome/browser/prefs/pref_service.h"
     10 #include "chrome/browser/prefs/pref_value_store.h"
     11 #include "chrome/common/chrome_paths.h"
     12 #include "chrome/common/pref_names.h"
     13 #include "chrome/common/render_messages.h"
     14 #include "chrome/common/url_constants.h"
     15 #include "chrome/test/testing_pref_service.h"
     16 #include "chrome/test/testing_profile.h"
     17 #include "content/browser/browser_thread.h"
     18 #include "content/browser/renderer_host/render_view_host.h"
     19 #include "content/browser/renderer_host/render_widget_host_view.h"
     20 #include "content/browser/renderer_host/test_render_view_host.h"
     21 #include "content/browser/site_instance.h"
     22 #include "content/browser/tab_contents/constrained_window.h"
     23 #include "content/browser/tab_contents/interstitial_page.h"
     24 #include "content/browser/tab_contents/navigation_controller.h"
     25 #include "content/browser/tab_contents/navigation_entry.h"
     26 #include "content/browser/tab_contents/test_tab_contents.h"
     27 #include "content/common/bindings_policy.h"
     28 #include "content/common/view_messages.h"
     29 #include "ipc/ipc_channel.h"
     30 #include "testing/gtest/include/gtest/gtest.h"
     31 #include "ui/base/message_box_flags.h"
     32 #include "webkit/glue/webkit_glue.h"
     33 
     34 using webkit_glue::PasswordForm;
     35 
     36 static void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params,
     37                                int page_id,
     38                                const GURL& url) {
     39   params->page_id = page_id;
     40   params->url = url;
     41   params->referrer = GURL();
     42   params->transition = PageTransition::TYPED;
     43   params->redirects = std::vector<GURL>();
     44   params->should_update_history = false;
     45   params->searchable_form_url = GURL();
     46   params->searchable_form_encoding = std::string();
     47   params->password_form = PasswordForm();
     48   params->security_info = std::string();
     49   params->gesture = NavigationGestureUser;
     50   params->was_within_same_page = false;
     51   params->is_post = false;
     52   params->content_state = webkit_glue::CreateHistoryStateForURL(GURL(url));
     53 }
     54 
     55 class TestInterstitialPage : public InterstitialPage {
     56  public:
     57   enum InterstitialState {
     58     UNDECIDED = 0, // No decision taken yet.
     59     OKED,          // Proceed was called.
     60     CANCELED       // DontProceed was called.
     61   };
     62 
     63   class Delegate {
     64    public:
     65     virtual void TestInterstitialPageDeleted(
     66         TestInterstitialPage* interstitial) = 0;
     67 
     68    protected:
     69     virtual ~Delegate() {}
     70   };
     71 
     72   // IMPORTANT NOTE: if you pass stack allocated values for |state| and
     73   // |deleted| (like all interstitial related tests do at this point), make sure
     74   // to create an instance of the TestInterstitialPageStateGuard class on the
     75   // stack in your test.  This will ensure that the TestInterstitialPage states
     76   // are cleared when the test finishes.
     77   // Not doing so will cause stack trashing if your test does not hide the
     78   // interstitial, as in such a case it will be destroyed in the test TearDown
     79   // method and will dereference the |deleted| local variable which by then is
     80   // out of scope.
     81   TestInterstitialPage(TabContents* tab,
     82                        bool new_navigation,
     83                        const GURL& url,
     84                        InterstitialState* state,
     85                        bool* deleted)
     86       : InterstitialPage(tab, new_navigation, url),
     87         state_(state),
     88         deleted_(deleted),
     89         command_received_count_(0),
     90         delegate_(NULL) {
     91     *state_ = UNDECIDED;
     92     *deleted_ = false;
     93   }
     94 
     95   virtual ~TestInterstitialPage() {
     96     if (deleted_)
     97       *deleted_ = true;
     98     if (delegate_)
     99       delegate_->TestInterstitialPageDeleted(this);
    100   }
    101 
    102   virtual void DontProceed() {
    103     if (state_)
    104       *state_ = CANCELED;
    105     InterstitialPage::DontProceed();
    106   }
    107   virtual void Proceed() {
    108     if (state_)
    109       *state_ = OKED;
    110     InterstitialPage::Proceed();
    111   }
    112 
    113   int command_received_count() const {
    114     return command_received_count_;
    115   }
    116 
    117   void TestDomOperationResponse(const std::string& json_string) {
    118     DomOperationResponse(json_string, 1);
    119   }
    120 
    121   void TestDidNavigate(int page_id, const GURL& url) {
    122     ViewHostMsg_FrameNavigate_Params params;
    123     InitNavigateParams(&params, page_id, url);
    124     DidNavigate(render_view_host(), params);
    125   }
    126 
    127   void TestRenderViewGone(base::TerminationStatus status, int error_code) {
    128     RenderViewGone(render_view_host(), status, error_code);
    129   }
    130 
    131   bool is_showing() const {
    132     return static_cast<TestRenderWidgetHostView*>(render_view_host()->view())->
    133         is_showing();
    134   }
    135 
    136   void ClearStates() {
    137     state_ = NULL;
    138     deleted_ = NULL;
    139     delegate_ = NULL;
    140   }
    141 
    142   void set_delegate(Delegate* delegate) {
    143     delegate_ = delegate;
    144   }
    145 
    146  protected:
    147   virtual RenderViewHost* CreateRenderViewHost() {
    148     return new TestRenderViewHost(
    149         SiteInstance::CreateSiteInstance(tab()->profile()),
    150         this, MSG_ROUTING_NONE);
    151   }
    152 
    153   virtual TabContentsView* CreateTabContentsView() { return NULL; }
    154 
    155 
    156   virtual void CommandReceived(const std::string& command) {
    157     command_received_count_++;
    158   }
    159 
    160  private:
    161   InterstitialState* state_;
    162   bool* deleted_;
    163   int command_received_count_;
    164   Delegate* delegate_;
    165 };
    166 
    167 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
    168  public:
    169   explicit TestInterstitialPageStateGuard(
    170       TestInterstitialPage* interstitial_page)
    171       : interstitial_page_(interstitial_page) {
    172     DCHECK(interstitial_page_);
    173     interstitial_page_->set_delegate(this);
    174   }
    175   ~TestInterstitialPageStateGuard() {
    176     if (interstitial_page_)
    177       interstitial_page_->ClearStates();
    178   }
    179 
    180   virtual void TestInterstitialPageDeleted(TestInterstitialPage* interstitial) {
    181     DCHECK(interstitial_page_ == interstitial);
    182     interstitial_page_ = NULL;
    183   }
    184 
    185  private:
    186   TestInterstitialPage* interstitial_page_;
    187 };
    188 
    189 class TabContentsTest : public RenderViewHostTestHarness {
    190  public:
    191   TabContentsTest()
    192       : RenderViewHostTestHarness(),
    193         ui_thread_(BrowserThread::UI, &message_loop_) {
    194   }
    195 
    196  private:
    197   // Supply our own profile so we use the correct profile data. The test harness
    198   // is not supposed to overwrite a profile if it's already created.
    199   virtual void SetUp() {
    200     TestingProfile* profile = new TestingProfile();
    201     profile_.reset(profile);
    202 
    203     // Set some (WebKit) user preferences.
    204     TestingPrefService* pref_services = profile->GetTestingPrefService();
    205 #if defined(TOOLKIT_USES_GTK)
    206     pref_services->SetUserPref(prefs::kUsesSystemTheme,
    207                                Value::CreateBooleanValue(false));
    208 #endif
    209     pref_services->SetUserPref(prefs::kDefaultCharset,
    210                                Value::CreateStringValue("utf8"));
    211     pref_services->SetUserPref(prefs::kWebKitDefaultFontSize,
    212                                Value::CreateIntegerValue(20));
    213     pref_services->SetUserPref(prefs::kWebKitTextAreasAreResizable,
    214                                Value::CreateBooleanValue(false));
    215     pref_services->SetUserPref(prefs::kWebKitUsesUniversalDetector,
    216                                Value::CreateBooleanValue(true));
    217     pref_services->SetUserPref("webkit.webprefs.foo",
    218                                Value::CreateStringValue("bar"));
    219 
    220     RenderViewHostTestHarness::SetUp();
    221   }
    222 
    223   virtual void TearDown() {
    224     RenderViewHostTestHarness::TearDown();
    225 
    226     profile_.reset(NULL);
    227   }
    228 
    229   BrowserThread ui_thread_;
    230 };
    231 
    232 // Test to make sure that title updates get stripped of whitespace.
    233 TEST_F(TabContentsTest, UpdateTitle) {
    234   ViewHostMsg_FrameNavigate_Params params;
    235   InitNavigateParams(&params, 0, GURL(chrome::kAboutBlankURL));
    236 
    237   NavigationController::LoadCommittedDetails details;
    238   controller().RendererDidNavigate(params, 0, &details);
    239 
    240   contents()->UpdateTitle(rvh(), 0, L"    Lots O' Whitespace\n");
    241   EXPECT_EQ(ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
    242 }
    243 
    244 // Test view source mode for the new tabs page.
    245 TEST_F(TabContentsTest, NTPViewSource) {
    246   const char kUrl[] = "view-source:chrome://newtab";
    247   const GURL kGURL(kUrl);
    248 
    249   process()->sink().ClearMessages();
    250 
    251   controller().LoadURL(kGURL, GURL(), PageTransition::TYPED);
    252   rvh()->delegate()->RenderViewCreated(rvh());
    253   // Did we get the expected message?
    254   EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
    255       ViewMsg_EnableViewSourceMode::ID));
    256 
    257   ViewHostMsg_FrameNavigate_Params params;
    258   InitNavigateParams(&params, 0, kGURL);
    259   NavigationController::LoadCommittedDetails details;
    260   controller().RendererDidNavigate(params, 0, &details);
    261   // Also check title and url.
    262   EXPECT_EQ(ASCIIToUTF16(kUrl), contents()->GetTitle());
    263   EXPECT_TRUE(contents()->ShouldDisplayURL());
    264 }
    265 
    266 // Test simple same-SiteInstance navigation.
    267 TEST_F(TabContentsTest, SimpleNavigation) {
    268   TestRenderViewHost* orig_rvh = rvh();
    269   SiteInstance* instance1 = contents()->GetSiteInstance();
    270   EXPECT_TRUE(contents()->pending_rvh() == NULL);
    271 
    272   // Navigate to URL
    273   const GURL url("http://www.google.com");
    274   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    275   EXPECT_FALSE(contents()->cross_navigation_pending());
    276   EXPECT_EQ(instance1, orig_rvh->site_instance());
    277   // Controller's pending entry will have a NULL site instance until we assign
    278   // it in DidNavigate.
    279   EXPECT_TRUE(controller().GetActiveEntry()->site_instance() == NULL);
    280 
    281   // DidNavigate from the page
    282   ViewHostMsg_FrameNavigate_Params params;
    283   InitNavigateParams(&params, 1, url);
    284   contents()->TestDidNavigate(orig_rvh, params);
    285   EXPECT_FALSE(contents()->cross_navigation_pending());
    286   EXPECT_EQ(orig_rvh, contents()->render_view_host());
    287   EXPECT_EQ(instance1, orig_rvh->site_instance());
    288   // Controller's entry should now have the SiteInstance, or else we won't be
    289   // able to find it later.
    290   EXPECT_EQ(instance1, controller().GetActiveEntry()->site_instance());
    291 }
    292 
    293 // Test that navigating across a site boundary creates a new RenderViewHost
    294 // with a new SiteInstance.  Going back should do the same.
    295 TEST_F(TabContentsTest, CrossSiteBoundaries) {
    296   contents()->transition_cross_site = true;
    297   TestRenderViewHost* orig_rvh = rvh();
    298   int orig_rvh_delete_count = 0;
    299   orig_rvh->set_delete_counter(&orig_rvh_delete_count);
    300   SiteInstance* instance1 = contents()->GetSiteInstance();
    301 
    302   // Navigate to URL.  First URL should use first RenderViewHost.
    303   const GURL url("http://www.google.com");
    304   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    305   ViewHostMsg_FrameNavigate_Params params1;
    306   InitNavigateParams(&params1, 1, url);
    307   contents()->TestDidNavigate(orig_rvh, params1);
    308 
    309   EXPECT_FALSE(contents()->cross_navigation_pending());
    310   EXPECT_EQ(orig_rvh, contents()->render_view_host());
    311 
    312   // Navigate to new site
    313   const GURL url2("http://www.yahoo.com");
    314   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    315   EXPECT_TRUE(contents()->cross_navigation_pending());
    316   TestRenderViewHost* pending_rvh = contents()->pending_rvh();
    317   int pending_rvh_delete_count = 0;
    318   pending_rvh->set_delete_counter(&pending_rvh_delete_count);
    319 
    320   // DidNavigate from the pending page
    321   ViewHostMsg_FrameNavigate_Params params2;
    322   InitNavigateParams(&params2, 1, url2);
    323   contents()->TestDidNavigate(pending_rvh, params2);
    324   SiteInstance* instance2 = contents()->GetSiteInstance();
    325 
    326   EXPECT_FALSE(contents()->cross_navigation_pending());
    327   EXPECT_EQ(pending_rvh, contents()->render_view_host());
    328   EXPECT_NE(instance1, instance2);
    329   EXPECT_TRUE(contents()->pending_rvh() == NULL);
    330   EXPECT_EQ(orig_rvh_delete_count, 1);
    331 
    332   // Going back should switch SiteInstances again.  The first SiteInstance is
    333   // stored in the NavigationEntry, so it should be the same as at the start.
    334   controller().GoBack();
    335   TestRenderViewHost* goback_rvh = contents()->pending_rvh();
    336   EXPECT_TRUE(contents()->cross_navigation_pending());
    337 
    338   // DidNavigate from the back action
    339   contents()->TestDidNavigate(goback_rvh, params1);
    340   EXPECT_FALSE(contents()->cross_navigation_pending());
    341   EXPECT_EQ(goback_rvh, contents()->render_view_host());
    342   EXPECT_EQ(pending_rvh_delete_count, 1);
    343   EXPECT_EQ(instance1, contents()->GetSiteInstance());
    344 }
    345 
    346 // Test that navigating across a site boundary after a crash creates a new
    347 // RVH without requiring a cross-site transition (i.e., PENDING state).
    348 TEST_F(TabContentsTest, CrossSiteBoundariesAfterCrash) {
    349   contents()->transition_cross_site = true;
    350   TestRenderViewHost* orig_rvh = rvh();
    351   int orig_rvh_delete_count = 0;
    352   orig_rvh->set_delete_counter(&orig_rvh_delete_count);
    353   SiteInstance* instance1 = contents()->GetSiteInstance();
    354 
    355   // Navigate to URL.  First URL should use first RenderViewHost.
    356   const GURL url("http://www.google.com");
    357   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    358   ViewHostMsg_FrameNavigate_Params params1;
    359   InitNavigateParams(&params1, 1, url);
    360   contents()->TestDidNavigate(orig_rvh, params1);
    361 
    362   EXPECT_FALSE(contents()->cross_navigation_pending());
    363   EXPECT_EQ(orig_rvh, contents()->render_view_host());
    364 
    365   // Crash the renderer.
    366   orig_rvh->set_render_view_created(false);
    367 
    368   // Navigate to new site.  We should not go into PENDING.
    369   const GURL url2("http://www.yahoo.com");
    370   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    371   TestRenderViewHost* new_rvh = rvh();
    372   EXPECT_FALSE(contents()->cross_navigation_pending());
    373   EXPECT_TRUE(contents()->pending_rvh() == NULL);
    374   EXPECT_NE(orig_rvh, new_rvh);
    375   EXPECT_EQ(orig_rvh_delete_count, 1);
    376 
    377   // DidNavigate from the new page
    378   ViewHostMsg_FrameNavigate_Params params2;
    379   InitNavigateParams(&params2, 1, url2);
    380   contents()->TestDidNavigate(new_rvh, params2);
    381   SiteInstance* instance2 = contents()->GetSiteInstance();
    382 
    383   EXPECT_FALSE(contents()->cross_navigation_pending());
    384   EXPECT_EQ(new_rvh, rvh());
    385   EXPECT_NE(instance1, instance2);
    386   EXPECT_TRUE(contents()->pending_rvh() == NULL);
    387 }
    388 
    389 // Test that opening a new tab in the same SiteInstance and then navigating
    390 // both tabs to a new site will place both tabs in a single SiteInstance.
    391 TEST_F(TabContentsTest, NavigateTwoTabsCrossSite) {
    392   contents()->transition_cross_site = true;
    393   TestRenderViewHost* orig_rvh = rvh();
    394   SiteInstance* instance1 = contents()->GetSiteInstance();
    395 
    396   // Navigate to URL.  First URL should use first RenderViewHost.
    397   const GURL url("http://www.google.com");
    398   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    399   ViewHostMsg_FrameNavigate_Params params1;
    400   InitNavigateParams(&params1, 1, url);
    401   contents()->TestDidNavigate(orig_rvh, params1);
    402 
    403   // Open a new tab with the same SiteInstance, navigated to the same site.
    404   TestTabContents contents2(profile(), instance1);
    405   params1.page_id = 2;  // Need this since the site instance is the same (which
    406                         // is the scope of page IDs) and we want to consider
    407                         // this a new page.
    408   contents2.transition_cross_site = true;
    409   contents2.controller().LoadURL(url, GURL(), PageTransition::TYPED);
    410   contents2.TestDidNavigate(contents2.render_view_host(), params1);
    411 
    412   // Navigate first tab to a new site
    413   const GURL url2a("http://www.yahoo.com");
    414   controller().LoadURL(url2a, GURL(), PageTransition::TYPED);
    415   TestRenderViewHost* pending_rvh_a = contents()->pending_rvh();
    416   ViewHostMsg_FrameNavigate_Params params2a;
    417   InitNavigateParams(&params2a, 1, url2a);
    418   contents()->TestDidNavigate(pending_rvh_a, params2a);
    419   SiteInstance* instance2a = contents()->GetSiteInstance();
    420   EXPECT_NE(instance1, instance2a);
    421 
    422   // Navigate second tab to the same site as the first tab
    423   const GURL url2b("http://mail.yahoo.com");
    424   contents2.controller().LoadURL(url2b, GURL(), PageTransition::TYPED);
    425   TestRenderViewHost* pending_rvh_b = contents2.pending_rvh();
    426   EXPECT_TRUE(pending_rvh_b != NULL);
    427   EXPECT_TRUE(contents2.cross_navigation_pending());
    428 
    429   // NOTE(creis): We used to be in danger of showing a sad tab page here if the
    430   // second tab hadn't navigated somewhere first (bug 1145430).  That case is
    431   // now covered by the CrossSiteBoundariesAfterCrash test.
    432 
    433   ViewHostMsg_FrameNavigate_Params params2b;
    434   InitNavigateParams(&params2b, 2, url2b);
    435   contents2.TestDidNavigate(pending_rvh_b, params2b);
    436   SiteInstance* instance2b = contents2.GetSiteInstance();
    437   EXPECT_NE(instance1, instance2b);
    438 
    439   // Both tabs should now be in the same SiteInstance.
    440   EXPECT_EQ(instance2a, instance2b);
    441 }
    442 
    443 // Tests that TabContents uses the current URL, not the SiteInstance's site, to
    444 // determine whether a navigation is cross-site.
    445 TEST_F(TabContentsTest, CrossSiteComparesAgainstCurrentPage) {
    446   contents()->transition_cross_site = true;
    447   TestRenderViewHost* orig_rvh = rvh();
    448   SiteInstance* instance1 = contents()->GetSiteInstance();
    449 
    450   // Navigate to URL.
    451   const GURL url("http://www.google.com");
    452   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    453   ViewHostMsg_FrameNavigate_Params params1;
    454   InitNavigateParams(&params1, 1, url);
    455   contents()->TestDidNavigate(orig_rvh, params1);
    456 
    457   // Open a related tab to a second site.
    458   TestTabContents contents2(profile(), instance1);
    459   contents2.transition_cross_site = true;
    460   const GURL url2("http://www.yahoo.com");
    461   contents2.controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    462   // The first RVH in contents2 isn't live yet, so we shortcut the cross site
    463   // pending.
    464   TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
    465       contents2.render_view_host());
    466   EXPECT_FALSE(contents2.cross_navigation_pending());
    467   ViewHostMsg_FrameNavigate_Params params2;
    468   InitNavigateParams(&params2, 2, url2);
    469   contents2.TestDidNavigate(rvh2, params2);
    470   SiteInstance* instance2 = contents2.GetSiteInstance();
    471   EXPECT_NE(instance1, instance2);
    472   EXPECT_FALSE(contents2.cross_navigation_pending());
    473 
    474   // Simulate a link click in first tab to second site.  Doesn't switch
    475   // SiteInstances, because we don't intercept WebKit navigations.
    476   ViewHostMsg_FrameNavigate_Params params3;
    477   InitNavigateParams(&params3, 2, url2);
    478   contents()->TestDidNavigate(orig_rvh, params3);
    479   SiteInstance* instance3 = contents()->GetSiteInstance();
    480   EXPECT_EQ(instance1, instance3);
    481   EXPECT_FALSE(contents()->cross_navigation_pending());
    482 
    483   // Navigate to the new site.  Doesn't switch SiteInstancees, because we
    484   // compare against the current URL, not the SiteInstance's site.
    485   const GURL url3("http://mail.yahoo.com");
    486   controller().LoadURL(url3, GURL(), PageTransition::TYPED);
    487   EXPECT_FALSE(contents()->cross_navigation_pending());
    488   ViewHostMsg_FrameNavigate_Params params4;
    489   InitNavigateParams(&params4, 3, url3);
    490   contents()->TestDidNavigate(orig_rvh, params4);
    491   SiteInstance* instance4 = contents()->GetSiteInstance();
    492   EXPECT_EQ(instance1, instance4);
    493 }
    494 
    495 // Test that the onbeforeunload and onunload handlers run when navigating
    496 // across site boundaries.
    497 TEST_F(TabContentsTest, CrossSiteUnloadHandlers) {
    498   contents()->transition_cross_site = true;
    499   TestRenderViewHost* orig_rvh = rvh();
    500   SiteInstance* instance1 = contents()->GetSiteInstance();
    501 
    502   // Navigate to URL.  First URL should use first RenderViewHost.
    503   const GURL url("http://www.google.com");
    504   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    505   ViewHostMsg_FrameNavigate_Params params1;
    506   InitNavigateParams(&params1, 1, url);
    507   contents()->TestDidNavigate(orig_rvh, params1);
    508   EXPECT_FALSE(contents()->cross_navigation_pending());
    509   EXPECT_EQ(orig_rvh, contents()->render_view_host());
    510 
    511   // Navigate to new site, but simulate an onbeforeunload denial.
    512   const GURL url2("http://www.yahoo.com");
    513   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    514   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    515   orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, false));
    516   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    517   EXPECT_FALSE(contents()->cross_navigation_pending());
    518   EXPECT_EQ(orig_rvh, contents()->render_view_host());
    519 
    520   // Navigate again, but simulate an onbeforeunload approval.
    521   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    522   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    523   orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true));
    524   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    525   EXPECT_TRUE(contents()->cross_navigation_pending());
    526   TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
    527       contents()->pending_rvh());
    528 
    529   // We won't hear DidNavigate until the onunload handler has finished running.
    530   // (No way to simulate that here, but it involves a call from RDH to
    531   // TabContents::OnCrossSiteResponse.)
    532 
    533   // DidNavigate from the pending page
    534   ViewHostMsg_FrameNavigate_Params params2;
    535   InitNavigateParams(&params2, 1, url2);
    536   contents()->TestDidNavigate(pending_rvh, params2);
    537   SiteInstance* instance2 = contents()->GetSiteInstance();
    538   EXPECT_FALSE(contents()->cross_navigation_pending());
    539   EXPECT_EQ(pending_rvh, rvh());
    540   EXPECT_NE(instance1, instance2);
    541   EXPECT_TRUE(contents()->pending_rvh() == NULL);
    542 }
    543 
    544 // Test that during a slow cross-site navigation, the original renderer can
    545 // navigate to a different URL and have it displayed, canceling the slow
    546 // navigation.
    547 TEST_F(TabContentsTest, CrossSiteNavigationPreempted) {
    548   contents()->transition_cross_site = true;
    549   TestRenderViewHost* orig_rvh = rvh();
    550   SiteInstance* instance1 = contents()->GetSiteInstance();
    551 
    552   // Navigate to URL.  First URL should use first RenderViewHost.
    553   const GURL url("http://www.google.com");
    554   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    555   ViewHostMsg_FrameNavigate_Params params1;
    556   InitNavigateParams(&params1, 1, url);
    557   contents()->TestDidNavigate(orig_rvh, params1);
    558   EXPECT_FALSE(contents()->cross_navigation_pending());
    559   EXPECT_EQ(orig_rvh, contents()->render_view_host());
    560 
    561   // Navigate to new site, simulating an onbeforeunload approval.
    562   const GURL url2("http://www.yahoo.com");
    563   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    564   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    565   orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true));
    566   EXPECT_TRUE(contents()->cross_navigation_pending());
    567 
    568   // Suppose the original renderer navigates before the new one is ready.
    569   orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
    570 
    571   // Verify that the pending navigation is cancelled.
    572   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    573   SiteInstance* instance2 = contents()->GetSiteInstance();
    574   EXPECT_FALSE(contents()->cross_navigation_pending());
    575   EXPECT_EQ(orig_rvh, rvh());
    576   EXPECT_EQ(instance1, instance2);
    577   EXPECT_TRUE(contents()->pending_rvh() == NULL);
    578 }
    579 
    580 TEST_F(TabContentsTest, CrossSiteNavigationBackPreempted) {
    581   contents()->transition_cross_site = true;
    582 
    583   // Start with NTP, which gets a new RVH with WebUI bindings.
    584   const GURL url1("chrome://newtab");
    585   controller().LoadURL(url1, GURL(), PageTransition::TYPED);
    586   TestRenderViewHost* ntp_rvh = rvh();
    587   ViewHostMsg_FrameNavigate_Params params1;
    588   InitNavigateParams(&params1, 1, url1);
    589   contents()->TestDidNavigate(ntp_rvh, params1);
    590   NavigationEntry* entry1 = controller().GetLastCommittedEntry();
    591   SiteInstance* instance1 = contents()->GetSiteInstance();
    592 
    593   EXPECT_FALSE(contents()->cross_navigation_pending());
    594   EXPECT_EQ(ntp_rvh, contents()->render_view_host());
    595   EXPECT_EQ(url1, entry1->url());
    596   EXPECT_EQ(instance1, entry1->site_instance());
    597   EXPECT_TRUE(BindingsPolicy::is_web_ui_enabled(ntp_rvh->enabled_bindings()));
    598 
    599   // Navigate to new site.
    600   const GURL url2("http://www.google.com");
    601   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    602   EXPECT_TRUE(contents()->cross_navigation_pending());
    603   TestRenderViewHost* google_rvh = contents()->pending_rvh();
    604 
    605   // Simulate beforeunload approval.
    606   EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
    607   ntp_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true));
    608 
    609   // DidNavigate from the pending page.
    610   ViewHostMsg_FrameNavigate_Params params2;
    611   InitNavigateParams(&params2, 1, url2);
    612   contents()->TestDidNavigate(google_rvh, params2);
    613   NavigationEntry* entry2 = controller().GetLastCommittedEntry();
    614   SiteInstance* instance2 = contents()->GetSiteInstance();
    615 
    616   EXPECT_FALSE(contents()->cross_navigation_pending());
    617   EXPECT_EQ(google_rvh, contents()->render_view_host());
    618   EXPECT_NE(instance1, instance2);
    619   EXPECT_FALSE(contents()->pending_rvh());
    620   EXPECT_EQ(url2, entry2->url());
    621   EXPECT_EQ(instance2, entry2->site_instance());
    622   EXPECT_FALSE(BindingsPolicy::is_web_ui_enabled(
    623       google_rvh->enabled_bindings()));
    624 
    625   // Navigate to third page on same site.
    626   const GURL url3("http://news.google.com");
    627   controller().LoadURL(url3, GURL(), PageTransition::TYPED);
    628   EXPECT_FALSE(contents()->cross_navigation_pending());
    629   ViewHostMsg_FrameNavigate_Params params3;
    630   InitNavigateParams(&params3, 2, url3);
    631   contents()->TestDidNavigate(google_rvh, params3);
    632   NavigationEntry* entry3 = controller().GetLastCommittedEntry();
    633   SiteInstance* instance3 = contents()->GetSiteInstance();
    634 
    635   EXPECT_FALSE(contents()->cross_navigation_pending());
    636   EXPECT_EQ(google_rvh, contents()->render_view_host());
    637   EXPECT_EQ(instance2, instance3);
    638   EXPECT_FALSE(contents()->pending_rvh());
    639   EXPECT_EQ(url3, entry3->url());
    640   EXPECT_EQ(instance3, entry3->site_instance());
    641 
    642   // Go back within the site.
    643   controller().GoBack();
    644   EXPECT_FALSE(contents()->cross_navigation_pending());
    645   EXPECT_EQ(entry2, controller().pending_entry());
    646 
    647   // Before that commits, go back again.
    648   controller().GoBack();
    649   EXPECT_TRUE(contents()->cross_navigation_pending());
    650   EXPECT_TRUE(contents()->pending_rvh());
    651   EXPECT_EQ(entry1, controller().pending_entry());
    652 
    653   // Simulate beforeunload approval.
    654   EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
    655   google_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true));
    656 
    657   // DidNavigate from the first back. This aborts the second back's pending RVH.
    658   contents()->TestDidNavigate(google_rvh, params2);
    659 
    660   // We should commit this page and forget about the second back.
    661   EXPECT_FALSE(contents()->cross_navigation_pending());
    662   EXPECT_FALSE(controller().pending_entry());
    663   EXPECT_EQ(google_rvh, contents()->render_view_host());
    664   EXPECT_EQ(url2, controller().GetLastCommittedEntry()->url());
    665 
    666   // We should not have corrupted the NTP entry.
    667   EXPECT_EQ(instance3, entry3->site_instance());
    668   EXPECT_EQ(instance2, entry2->site_instance());
    669   EXPECT_EQ(instance1, entry1->site_instance());
    670   EXPECT_EQ(url1, entry1->url());
    671 }
    672 
    673 // Test that during a slow cross-site navigation, a sub-frame navigation in the
    674 // original renderer will not cancel the slow navigation (bug 42029).
    675 TEST_F(TabContentsTest, CrossSiteNavigationNotPreemptedByFrame) {
    676   contents()->transition_cross_site = true;
    677   TestRenderViewHost* orig_rvh = rvh();
    678 
    679   // Navigate to URL.  First URL should use first RenderViewHost.
    680   const GURL url("http://www.google.com");
    681   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    682   ViewHostMsg_FrameNavigate_Params params1;
    683   InitNavigateParams(&params1, 1, url);
    684   contents()->TestDidNavigate(orig_rvh, params1);
    685   EXPECT_FALSE(contents()->cross_navigation_pending());
    686   EXPECT_EQ(orig_rvh, contents()->render_view_host());
    687 
    688   // Start navigating to new site.
    689   const GURL url2("http://www.yahoo.com");
    690   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    691 
    692   // Simulate a sub-frame navigation arriving and ensure the RVH is still
    693   // waiting for a before unload response.
    694   orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
    695                                        PageTransition::AUTO_SUBFRAME);
    696   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    697 
    698   // Now simulate the onbeforeunload approval and verify the navigation is
    699   // not canceled.
    700   orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true));
    701   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    702   EXPECT_TRUE(contents()->cross_navigation_pending());
    703 }
    704 
    705 // Test that a cross-site navigation is not preempted if the previous
    706 // renderer sends a FrameNavigate message just before being told to stop.
    707 // We should only preempt the cross-site navigation if the previous renderer
    708 // has started a new navigation.  See http://crbug.com/79176.
    709 TEST_F(TabContentsTest, CrossSiteNotPreemptedDuringBeforeUnload) {
    710   contents()->transition_cross_site = true;
    711 
    712   // Navigate to NTP URL.
    713   const GURL url("chrome://newtab");
    714   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    715   TestRenderViewHost* orig_rvh = rvh();
    716   EXPECT_FALSE(contents()->cross_navigation_pending());
    717 
    718   // Navigate to new site, with the beforeunload request in flight.
    719   const GURL url2("http://www.yahoo.com");
    720   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    721   TestRenderViewHost* pending_rvh = contents()->pending_rvh();
    722   EXPECT_TRUE(contents()->cross_navigation_pending());
    723   EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
    724 
    725   // Suppose the first navigation tries to commit now, with a
    726   // ViewMsg_Stop in flight.  This should not cancel the pending navigation,
    727   // but it should act as if the beforeunload ack arrived.
    728   orig_rvh->SendNavigate(1, GURL("chrome://newtab"));
    729   EXPECT_TRUE(contents()->cross_navigation_pending());
    730   EXPECT_EQ(orig_rvh, contents()->render_view_host());
    731   EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
    732 
    733   // The pending navigation should be able to commit successfully.
    734   ViewHostMsg_FrameNavigate_Params params2;
    735   InitNavigateParams(&params2, 1, url2, PageTransition::TYPED);
    736   contents()->TestDidNavigate(pending_rvh, params2);
    737   EXPECT_FALSE(contents()->cross_navigation_pending());
    738   EXPECT_EQ(pending_rvh, contents()->render_view_host());
    739 }
    740 
    741 // Test that the original renderer cannot preempt a cross-site navigation once
    742 // the unload request has been made.  At this point, the cross-site navigation
    743 // is almost ready to be displayed, and the original renderer is only given a
    744 // short chance to run an unload handler.  Prevents regression of bug 23942.
    745 TEST_F(TabContentsTest, CrossSiteCantPreemptAfterUnload) {
    746   contents()->transition_cross_site = true;
    747   TestRenderViewHost* orig_rvh = rvh();
    748   SiteInstance* instance1 = contents()->GetSiteInstance();
    749 
    750   // Navigate to URL.  First URL should use first RenderViewHost.
    751   const GURL url("http://www.google.com");
    752   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    753   ViewHostMsg_FrameNavigate_Params params1;
    754   InitNavigateParams(&params1, 1, url);
    755   contents()->TestDidNavigate(orig_rvh, params1);
    756   EXPECT_FALSE(contents()->cross_navigation_pending());
    757   EXPECT_EQ(orig_rvh, contents()->render_view_host());
    758 
    759   // Navigate to new site, simulating an onbeforeunload approval.
    760   const GURL url2("http://www.yahoo.com");
    761   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    762   orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true));
    763   EXPECT_TRUE(contents()->cross_navigation_pending());
    764   TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
    765       contents()->pending_rvh());
    766 
    767   // Simulate the pending renderer's response, which leads to an unload request
    768   // being sent to orig_rvh.
    769   contents()->OnCrossSiteResponse(0, 0);
    770 
    771   // Suppose the original renderer navigates now, while the unload request is in
    772   // flight.  We should ignore it, wait for the unload ack, and let the pending
    773   // request continue.  Otherwise, the tab may close spontaneously or stop
    774   // responding to navigation requests.  (See bug 23942.)
    775   ViewHostMsg_FrameNavigate_Params params1a;
    776   InitNavigateParams(&params1a, 2, GURL("http://www.google.com/foo"));
    777   orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
    778 
    779   // Verify that the pending navigation is still in progress.
    780   EXPECT_TRUE(contents()->cross_navigation_pending());
    781   EXPECT_TRUE(contents()->pending_rvh() != NULL);
    782 
    783   // DidNavigate from the pending page should commit it.
    784   ViewHostMsg_FrameNavigate_Params params2;
    785   InitNavigateParams(&params2, 1, url2);
    786   contents()->TestDidNavigate(pending_rvh, params2);
    787   SiteInstance* instance2 = contents()->GetSiteInstance();
    788   EXPECT_FALSE(contents()->cross_navigation_pending());
    789   EXPECT_EQ(pending_rvh, rvh());
    790   EXPECT_NE(instance1, instance2);
    791   EXPECT_TRUE(contents()->pending_rvh() == NULL);
    792 }
    793 
    794 // Test that NavigationEntries have the correct content state after going
    795 // forward and back.  Prevents regression for bug 1116137.
    796 TEST_F(TabContentsTest, NavigationEntryContentState) {
    797   TestRenderViewHost* orig_rvh = rvh();
    798 
    799   // Navigate to URL.  There should be no committed entry yet.
    800   const GURL url("http://www.google.com");
    801   controller().LoadURL(url, GURL(), PageTransition::TYPED);
    802   NavigationEntry* entry = controller().GetLastCommittedEntry();
    803   EXPECT_TRUE(entry == NULL);
    804 
    805   // Committed entry should have content state after DidNavigate.
    806   ViewHostMsg_FrameNavigate_Params params1;
    807   InitNavigateParams(&params1, 1, url);
    808   contents()->TestDidNavigate(orig_rvh, params1);
    809   entry = controller().GetLastCommittedEntry();
    810   EXPECT_FALSE(entry->content_state().empty());
    811 
    812   // Navigate to same site.
    813   const GURL url2("http://images.google.com");
    814   controller().LoadURL(url2, GURL(), PageTransition::TYPED);
    815   entry = controller().GetLastCommittedEntry();
    816   EXPECT_FALSE(entry->content_state().empty());
    817 
    818   // Committed entry should have content state after DidNavigate.
    819   ViewHostMsg_FrameNavigate_Params params2;
    820   InitNavigateParams(&params2, 2, url2);
    821   contents()->TestDidNavigate(orig_rvh, params2);
    822   entry = controller().GetLastCommittedEntry();
    823   EXPECT_FALSE(entry->content_state().empty());
    824 
    825   // Now go back.  Committed entry should still have content state.
    826   controller().GoBack();
    827   contents()->TestDidNavigate(orig_rvh, params1);
    828   entry = controller().GetLastCommittedEntry();
    829   EXPECT_FALSE(entry->content_state().empty());
    830 }
    831 
    832 // Test that NavigationEntries have the correct content state after opening
    833 // a new window to about:blank.  Prevents regression for bug 1116137.
    834 TEST_F(TabContentsTest, NavigationEntryContentStateNewWindow) {
    835   TestRenderViewHost* orig_rvh = rvh();
    836 
    837   // When opening a new window, it is navigated to about:blank internally.
    838   // Currently, this results in two DidNavigate events.
    839   const GURL url(chrome::kAboutBlankURL);
    840   ViewHostMsg_FrameNavigate_Params params1;
    841   InitNavigateParams(&params1, 1, url);
    842   contents()->TestDidNavigate(orig_rvh, params1);
    843   contents()->TestDidNavigate(orig_rvh, params1);
    844 
    845   // Should have a content state here.
    846   NavigationEntry* entry = controller().GetLastCommittedEntry();
    847   EXPECT_FALSE(entry->content_state().empty());
    848 }
    849 
    850 // Tests to see that webkit preferences are properly loaded and copied over
    851 // to a WebPreferences object.
    852 TEST_F(TabContentsTest, WebKitPrefs) {
    853   WebPreferences webkit_prefs = contents()->TestGetWebkitPrefs();
    854 
    855   // These values have been overridden by the profile preferences.
    856   EXPECT_EQ("UTF-8", webkit_prefs.default_encoding);
    857   EXPECT_EQ(20, webkit_prefs.default_font_size);
    858   EXPECT_FALSE(webkit_prefs.text_areas_are_resizable);
    859   EXPECT_TRUE(webkit_prefs.uses_universal_detector);
    860 
    861   // These should still be the default values.
    862 #if defined(OS_MACOSX)
    863   const char kDefaultFont[] = "Times";
    864 #elif defined(OS_CHROMEOS)
    865   const char kDefaultFont[] = "Tinos";
    866 #else
    867   const char kDefaultFont[] = "Times New Roman";
    868 #endif
    869   EXPECT_EQ(ASCIIToUTF16(kDefaultFont), webkit_prefs.standard_font_family);
    870   EXPECT_TRUE(webkit_prefs.javascript_enabled);
    871 }
    872 
    873 ////////////////////////////////////////////////////////////////////////////////
    874 // Interstitial Tests
    875 ////////////////////////////////////////////////////////////////////////////////
    876 
    877 // Test navigating to a page (with the navigation initiated from the browser,
    878 // as when a URL is typed in the location bar) that shows an interstitial and
    879 // creates a new navigation entry, then hiding it without proceeding.
    880 TEST_F(TabContentsTest,
    881        ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
    882   // Navigate to a page.
    883   GURL url1("http://www.google.com");
    884   rvh()->SendNavigate(1, url1);
    885   EXPECT_EQ(1, controller().entry_count());
    886 
    887   // Initiate a browser navigation that will trigger the interstitial
    888   controller().LoadURL(GURL("http://www.evil.com"), GURL(),
    889                         PageTransition::TYPED);
    890 
    891   // Show an interstitial.
    892   TestInterstitialPage::InterstitialState state =
    893       TestInterstitialPage::UNDECIDED;
    894   bool deleted = false;
    895   GURL url2("http://interstitial");
    896   TestInterstitialPage* interstitial =
    897       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
    898   TestInterstitialPageStateGuard state_guard(interstitial);
    899   interstitial->Show();
    900   // The interstitial should not show until its navigation has committed.
    901   EXPECT_FALSE(interstitial->is_showing());
    902   EXPECT_FALSE(contents()->showing_interstitial_page());
    903   EXPECT_TRUE(contents()->interstitial_page() == NULL);
    904   // Let's commit the interstitial navigation.
    905   interstitial->TestDidNavigate(1, url2);
    906   EXPECT_TRUE(interstitial->is_showing());
    907   EXPECT_TRUE(contents()->showing_interstitial_page());
    908   EXPECT_TRUE(contents()->interstitial_page() == interstitial);
    909   NavigationEntry* entry = controller().GetActiveEntry();
    910   ASSERT_TRUE(entry != NULL);
    911   EXPECT_TRUE(entry->url() == url2);
    912 
    913   // Now don't proceed.
    914   interstitial->DontProceed();
    915   EXPECT_TRUE(deleted);
    916   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
    917   EXPECT_FALSE(contents()->showing_interstitial_page());
    918   EXPECT_TRUE(contents()->interstitial_page() == NULL);
    919   entry = controller().GetActiveEntry();
    920   ASSERT_TRUE(entry != NULL);
    921   EXPECT_TRUE(entry->url() == url1);
    922   EXPECT_EQ(1, controller().entry_count());
    923 }
    924 
    925 // Test navigating to a page (with the navigation initiated from the renderer,
    926 // as when clicking on a link in the page) that shows an interstitial and
    927 // creates a new navigation entry, then hiding it without proceeding.
    928 TEST_F(TabContentsTest,
    929        ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
    930   // Navigate to a page.
    931   GURL url1("http://www.google.com");
    932   rvh()->SendNavigate(1, url1);
    933   EXPECT_EQ(1, controller().entry_count());
    934 
    935   // Show an interstitial (no pending entry, the interstitial would have been
    936   // triggered by clicking on a link).
    937   TestInterstitialPage::InterstitialState state =
    938       TestInterstitialPage::UNDECIDED;
    939   bool deleted = false;
    940   GURL url2("http://interstitial");
    941   TestInterstitialPage* interstitial =
    942       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
    943   TestInterstitialPageStateGuard state_guard(interstitial);
    944   interstitial->Show();
    945   // The interstitial should not show until its navigation has committed.
    946   EXPECT_FALSE(interstitial->is_showing());
    947   EXPECT_FALSE(contents()->showing_interstitial_page());
    948   EXPECT_TRUE(contents()->interstitial_page() == NULL);
    949   // Let's commit the interstitial navigation.
    950   interstitial->TestDidNavigate(1, url2);
    951   EXPECT_TRUE(interstitial->is_showing());
    952   EXPECT_TRUE(contents()->showing_interstitial_page());
    953   EXPECT_TRUE(contents()->interstitial_page() == interstitial);
    954   NavigationEntry* entry = controller().GetActiveEntry();
    955   ASSERT_TRUE(entry != NULL);
    956   EXPECT_TRUE(entry->url() == url2);
    957 
    958   // Now don't proceed.
    959   interstitial->DontProceed();
    960   EXPECT_TRUE(deleted);
    961   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
    962   EXPECT_FALSE(contents()->showing_interstitial_page());
    963   EXPECT_TRUE(contents()->interstitial_page() == NULL);
    964   entry = controller().GetActiveEntry();
    965   ASSERT_TRUE(entry != NULL);
    966   EXPECT_TRUE(entry->url() == url1);
    967   EXPECT_EQ(1, controller().entry_count());
    968 }
    969 
    970 // Test navigating to a page that shows an interstitial without creating a new
    971 // navigation entry (this happens when the interstitial is triggered by a
    972 // sub-resource in the page), then hiding it without proceeding.
    973 TEST_F(TabContentsTest, ShowInterstitialNoNewNavigationDontProceed) {
    974   // Navigate to a page.
    975   GURL url1("http://www.google.com");
    976   rvh()->SendNavigate(1, url1);
    977   EXPECT_EQ(1, controller().entry_count());
    978 
    979   // Show an interstitial.
    980   TestInterstitialPage::InterstitialState state =
    981       TestInterstitialPage::UNDECIDED;
    982   bool deleted = false;
    983   GURL url2("http://interstitial");
    984   TestInterstitialPage* interstitial =
    985       new TestInterstitialPage(contents(), false, url2, &state, &deleted);
    986   TestInterstitialPageStateGuard state_guard(interstitial);
    987   interstitial->Show();
    988   // The interstitial should not show until its navigation has committed.
    989   EXPECT_FALSE(interstitial->is_showing());
    990   EXPECT_FALSE(contents()->showing_interstitial_page());
    991   EXPECT_TRUE(contents()->interstitial_page() == NULL);
    992   // Let's commit the interstitial navigation.
    993   interstitial->TestDidNavigate(1, url2);
    994   EXPECT_TRUE(interstitial->is_showing());
    995   EXPECT_TRUE(contents()->showing_interstitial_page());
    996   EXPECT_TRUE(contents()->interstitial_page() == interstitial);
    997   NavigationEntry* entry = controller().GetActiveEntry();
    998   ASSERT_TRUE(entry != NULL);
    999   // The URL specified to the interstitial should have been ignored.
   1000   EXPECT_TRUE(entry->url() == url1);
   1001 
   1002   // Now don't proceed.
   1003   interstitial->DontProceed();
   1004   EXPECT_TRUE(deleted);
   1005   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1006   EXPECT_FALSE(contents()->showing_interstitial_page());
   1007   EXPECT_TRUE(contents()->interstitial_page() == NULL);
   1008   entry = controller().GetActiveEntry();
   1009   ASSERT_TRUE(entry != NULL);
   1010   EXPECT_TRUE(entry->url() == url1);
   1011   EXPECT_EQ(1, controller().entry_count());
   1012 }
   1013 
   1014 // Test navigating to a page (with the navigation initiated from the browser,
   1015 // as when a URL is typed in the location bar) that shows an interstitial and
   1016 // creates a new navigation entry, then proceeding.
   1017 TEST_F(TabContentsTest,
   1018        ShowInterstitialFromBrowserNewNavigationProceed) {
   1019   // Navigate to a page.
   1020   GURL url1("http://www.google.com");
   1021   rvh()->SendNavigate(1, url1);
   1022   EXPECT_EQ(1, controller().entry_count());
   1023 
   1024   // Initiate a browser navigation that will trigger the interstitial
   1025   controller().LoadURL(GURL("http://www.evil.com"), GURL(),
   1026                         PageTransition::TYPED);
   1027 
   1028   // Show an interstitial.
   1029   TestInterstitialPage::InterstitialState state =
   1030       TestInterstitialPage::UNDECIDED;
   1031   bool deleted = false;
   1032   GURL url2("http://interstitial");
   1033   TestInterstitialPage* interstitial =
   1034       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1035   TestInterstitialPageStateGuard state_guard(interstitial);
   1036   interstitial->Show();
   1037   // The interstitial should not show until its navigation has committed.
   1038   EXPECT_FALSE(interstitial->is_showing());
   1039   EXPECT_FALSE(contents()->showing_interstitial_page());
   1040   EXPECT_TRUE(contents()->interstitial_page() == NULL);
   1041   // Let's commit the interstitial navigation.
   1042   interstitial->TestDidNavigate(1, url2);
   1043   EXPECT_TRUE(interstitial->is_showing());
   1044   EXPECT_TRUE(contents()->showing_interstitial_page());
   1045   EXPECT_TRUE(contents()->interstitial_page() == interstitial);
   1046   NavigationEntry* entry = controller().GetActiveEntry();
   1047   ASSERT_TRUE(entry != NULL);
   1048   EXPECT_TRUE(entry->url() == url2);
   1049 
   1050   // Then proceed.
   1051   interstitial->Proceed();
   1052   // The interstitial should show until the new navigation commits.
   1053   ASSERT_FALSE(deleted);
   1054   EXPECT_EQ(TestInterstitialPage::OKED, state);
   1055   EXPECT_TRUE(contents()->showing_interstitial_page());
   1056   EXPECT_TRUE(contents()->interstitial_page() == interstitial);
   1057 
   1058   // Simulate the navigation to the page, that's when the interstitial gets
   1059   // hidden.
   1060   GURL url3("http://www.thepage.com");
   1061   rvh()->SendNavigate(2, url3);
   1062 
   1063   EXPECT_TRUE(deleted);
   1064   EXPECT_FALSE(contents()->showing_interstitial_page());
   1065   EXPECT_TRUE(contents()->interstitial_page() == NULL);
   1066   entry = controller().GetActiveEntry();
   1067   ASSERT_TRUE(entry != NULL);
   1068   EXPECT_TRUE(entry->url() == url3);
   1069 
   1070   EXPECT_EQ(2, controller().entry_count());
   1071 }
   1072 
   1073 // Test navigating to a page (with the navigation initiated from the renderer,
   1074 // as when clicking on a link in the page) that shows an interstitial and
   1075 // creates a new navigation entry, then proceeding.
   1076 TEST_F(TabContentsTest,
   1077        ShowInterstitialFromRendererNewNavigationProceed) {
   1078   // Navigate to a page.
   1079   GURL url1("http://www.google.com");
   1080   rvh()->SendNavigate(1, url1);
   1081   EXPECT_EQ(1, controller().entry_count());
   1082 
   1083   // Show an interstitial.
   1084   TestInterstitialPage::InterstitialState state =
   1085       TestInterstitialPage::UNDECIDED;
   1086   bool deleted = false;
   1087   GURL url2("http://interstitial");
   1088   TestInterstitialPage* interstitial =
   1089       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1090   TestInterstitialPageStateGuard state_guard(interstitial);
   1091   interstitial->Show();
   1092   // The interstitial should not show until its navigation has committed.
   1093   EXPECT_FALSE(interstitial->is_showing());
   1094   EXPECT_FALSE(contents()->showing_interstitial_page());
   1095   EXPECT_TRUE(contents()->interstitial_page() == NULL);
   1096   // Let's commit the interstitial navigation.
   1097   interstitial->TestDidNavigate(1, url2);
   1098   EXPECT_TRUE(interstitial->is_showing());
   1099   EXPECT_TRUE(contents()->showing_interstitial_page());
   1100   EXPECT_TRUE(contents()->interstitial_page() == interstitial);
   1101   NavigationEntry* entry = controller().GetActiveEntry();
   1102   ASSERT_TRUE(entry != NULL);
   1103   EXPECT_TRUE(entry->url() == url2);
   1104 
   1105   // Then proceed.
   1106   interstitial->Proceed();
   1107   // The interstitial should show until the new navigation commits.
   1108   ASSERT_FALSE(deleted);
   1109   EXPECT_EQ(TestInterstitialPage::OKED, state);
   1110   EXPECT_TRUE(contents()->showing_interstitial_page());
   1111   EXPECT_TRUE(contents()->interstitial_page() == interstitial);
   1112 
   1113   // Simulate the navigation to the page, that's when the interstitial gets
   1114   // hidden.
   1115   GURL url3("http://www.thepage.com");
   1116   rvh()->SendNavigate(2, url3);
   1117 
   1118   EXPECT_TRUE(deleted);
   1119   EXPECT_FALSE(contents()->showing_interstitial_page());
   1120   EXPECT_TRUE(contents()->interstitial_page() == NULL);
   1121   entry = controller().GetActiveEntry();
   1122   ASSERT_TRUE(entry != NULL);
   1123   EXPECT_TRUE(entry->url() == url3);
   1124 
   1125   EXPECT_EQ(2, controller().entry_count());
   1126 }
   1127 
   1128 // Test navigating to a page that shows an interstitial without creating a new
   1129 // navigation entry (this happens when the interstitial is triggered by a
   1130 // sub-resource in the page), then proceeding.
   1131 TEST_F(TabContentsTest, ShowInterstitialNoNewNavigationProceed) {
   1132   // Navigate to a page so we have a navigation entry in the controller.
   1133   GURL url1("http://www.google.com");
   1134   rvh()->SendNavigate(1, url1);
   1135   EXPECT_EQ(1, controller().entry_count());
   1136 
   1137   // Show an interstitial.
   1138   TestInterstitialPage::InterstitialState state =
   1139       TestInterstitialPage::UNDECIDED;
   1140   bool deleted = false;
   1141   GURL url2("http://interstitial");
   1142   TestInterstitialPage* interstitial =
   1143       new TestInterstitialPage(contents(), false, url2, &state, &deleted);
   1144   TestInterstitialPageStateGuard state_guard(interstitial);
   1145   interstitial->Show();
   1146   // The interstitial should not show until its navigation has committed.
   1147   EXPECT_FALSE(interstitial->is_showing());
   1148   EXPECT_FALSE(contents()->showing_interstitial_page());
   1149   EXPECT_TRUE(contents()->interstitial_page() == NULL);
   1150   // Let's commit the interstitial navigation.
   1151   interstitial->TestDidNavigate(1, url2);
   1152   EXPECT_TRUE(interstitial->is_showing());
   1153   EXPECT_TRUE(contents()->showing_interstitial_page());
   1154   EXPECT_TRUE(contents()->interstitial_page() == interstitial);
   1155   NavigationEntry* entry = controller().GetActiveEntry();
   1156   ASSERT_TRUE(entry != NULL);
   1157   // The URL specified to the interstitial should have been ignored.
   1158   EXPECT_TRUE(entry->url() == url1);
   1159 
   1160   // Then proceed.
   1161   interstitial->Proceed();
   1162   // Since this is not a new navigation, the previous page is dismissed right
   1163   // away and shows the original page.
   1164   EXPECT_TRUE(deleted);
   1165   EXPECT_EQ(TestInterstitialPage::OKED, state);
   1166   EXPECT_FALSE(contents()->showing_interstitial_page());
   1167   EXPECT_TRUE(contents()->interstitial_page() == NULL);
   1168   entry = controller().GetActiveEntry();
   1169   ASSERT_TRUE(entry != NULL);
   1170   EXPECT_TRUE(entry->url() == url1);
   1171 
   1172   EXPECT_EQ(1, controller().entry_count());
   1173 }
   1174 
   1175 // Test navigating to a page that shows an interstitial, then navigating away.
   1176 TEST_F(TabContentsTest, ShowInterstitialThenNavigate) {
   1177   // Show interstitial.
   1178   TestInterstitialPage::InterstitialState state =
   1179       TestInterstitialPage::UNDECIDED;
   1180   bool deleted = false;
   1181   GURL url("http://interstitial");
   1182   TestInterstitialPage* interstitial =
   1183       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1184   TestInterstitialPageStateGuard state_guard(interstitial);
   1185   interstitial->Show();
   1186   interstitial->TestDidNavigate(1, url);
   1187 
   1188   // While interstitial showing, navigate to a new URL.
   1189   const GURL url2("http://www.yahoo.com");
   1190   rvh()->SendNavigate(1, url2);
   1191 
   1192   EXPECT_TRUE(deleted);
   1193   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1194 }
   1195 
   1196 // Test navigating to a page that shows an interstitial, then going back.
   1197 TEST_F(TabContentsTest, ShowInterstitialThenGoBack) {
   1198   // Navigate to a page so we have a navigation entry in the controller.
   1199   GURL url1("http://www.google.com");
   1200   rvh()->SendNavigate(1, url1);
   1201   EXPECT_EQ(1, controller().entry_count());
   1202 
   1203   // Show interstitial.
   1204   TestInterstitialPage::InterstitialState state =
   1205       TestInterstitialPage::UNDECIDED;
   1206   bool deleted = false;
   1207   GURL interstitial_url("http://interstitial");
   1208   TestInterstitialPage* interstitial =
   1209       new TestInterstitialPage(contents(), true, interstitial_url,
   1210                                &state, &deleted);
   1211   TestInterstitialPageStateGuard state_guard(interstitial);
   1212   interstitial->Show();
   1213   interstitial->TestDidNavigate(2, interstitial_url);
   1214 
   1215   // While the interstitial is showing, go back.
   1216   controller().GoBack();
   1217   rvh()->SendNavigate(1, url1);
   1218 
   1219   // Make sure we are back to the original page and that the interstitial is
   1220   // gone.
   1221   EXPECT_TRUE(deleted);
   1222   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1223   NavigationEntry* entry = controller().GetActiveEntry();
   1224   ASSERT_TRUE(entry);
   1225   EXPECT_EQ(url1.spec(), entry->url().spec());
   1226 }
   1227 
   1228 // Test navigating to a page that shows an interstitial, has a renderer crash,
   1229 // and then goes back.
   1230 TEST_F(TabContentsTest, ShowInterstitialCrashRendererThenGoBack) {
   1231   // Navigate to a page so we have a navigation entry in the controller.
   1232   GURL url1("http://www.google.com");
   1233   rvh()->SendNavigate(1, url1);
   1234   EXPECT_EQ(1, controller().entry_count());
   1235 
   1236   // Show interstitial.
   1237   TestInterstitialPage::InterstitialState state =
   1238       TestInterstitialPage::UNDECIDED;
   1239   bool deleted = false;
   1240   GURL interstitial_url("http://interstitial");
   1241   TestInterstitialPage* interstitial =
   1242       new TestInterstitialPage(contents(), true, interstitial_url,
   1243                                &state, &deleted);
   1244   TestInterstitialPageStateGuard state_guard(interstitial);
   1245   interstitial->Show();
   1246   interstitial->TestDidNavigate(2, interstitial_url);
   1247 
   1248   // Crash the renderer
   1249   rvh()->TestOnMessageReceived(
   1250       ViewHostMsg_RenderViewGone(
   1251           0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
   1252 
   1253   // While the interstitial is showing, go back.
   1254   controller().GoBack();
   1255   rvh()->SendNavigate(1, url1);
   1256 
   1257   // Make sure we are back to the original page and that the interstitial is
   1258   // gone.
   1259   EXPECT_TRUE(deleted);
   1260   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1261   NavigationEntry* entry = controller().GetActiveEntry();
   1262   ASSERT_TRUE(entry);
   1263   EXPECT_EQ(url1.spec(), entry->url().spec());
   1264 }
   1265 
   1266 // Test navigating to a page that shows an interstitial, has the renderer crash,
   1267 // and then navigates to the interstitial.
   1268 TEST_F(TabContentsTest, ShowInterstitialCrashRendererThenNavigate) {
   1269   // Navigate to a page so we have a navigation entry in the controller.
   1270   GURL url1("http://www.google.com");
   1271   rvh()->SendNavigate(1, url1);
   1272   EXPECT_EQ(1, controller().entry_count());
   1273 
   1274   // Show interstitial.
   1275   TestInterstitialPage::InterstitialState state =
   1276       TestInterstitialPage::UNDECIDED;
   1277   bool deleted = false;
   1278   GURL interstitial_url("http://interstitial");
   1279   TestInterstitialPage* interstitial =
   1280       new TestInterstitialPage(contents(), true, interstitial_url,
   1281                                &state, &deleted);
   1282   TestInterstitialPageStateGuard state_guard(interstitial);
   1283   interstitial->Show();
   1284 
   1285   // Crash the renderer
   1286   rvh()->TestOnMessageReceived(
   1287       ViewHostMsg_RenderViewGone(
   1288           0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
   1289 
   1290   interstitial->TestDidNavigate(2, interstitial_url);
   1291 }
   1292 
   1293 // Test navigating to a page that shows an interstitial, then close the tab.
   1294 TEST_F(TabContentsTest, ShowInterstitialThenCloseTab) {
   1295   // Show interstitial.
   1296   TestInterstitialPage::InterstitialState state =
   1297       TestInterstitialPage::UNDECIDED;
   1298   bool deleted = false;
   1299   GURL url("http://interstitial");
   1300   TestInterstitialPage* interstitial =
   1301       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1302   TestInterstitialPageStateGuard state_guard(interstitial);
   1303   interstitial->Show();
   1304   interstitial->TestDidNavigate(1, url);
   1305 
   1306   // Now close the tab.
   1307   DeleteContents();
   1308   EXPECT_TRUE(deleted);
   1309   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1310 }
   1311 
   1312 // Test that after Proceed is called and an interstitial is still shown, no more
   1313 // commands get executed.
   1314 TEST_F(TabContentsTest, ShowInterstitialProceedMultipleCommands) {
   1315   // Navigate to a page so we have a navigation entry in the controller.
   1316   GURL url1("http://www.google.com");
   1317   rvh()->SendNavigate(1, url1);
   1318   EXPECT_EQ(1, controller().entry_count());
   1319 
   1320   // Show an interstitial.
   1321   TestInterstitialPage::InterstitialState state =
   1322       TestInterstitialPage::UNDECIDED;
   1323   bool deleted = false;
   1324   GURL url2("http://interstitial");
   1325   TestInterstitialPage* interstitial =
   1326       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1327   TestInterstitialPageStateGuard state_guard(interstitial);
   1328   interstitial->Show();
   1329   interstitial->TestDidNavigate(1, url2);
   1330 
   1331   // Run a command.
   1332   EXPECT_EQ(0, interstitial->command_received_count());
   1333   interstitial->TestDomOperationResponse("toto");
   1334   EXPECT_EQ(1, interstitial->command_received_count());
   1335 
   1336   // Then proceed.
   1337   interstitial->Proceed();
   1338   ASSERT_FALSE(deleted);
   1339 
   1340   // While the navigation to the new page is pending, send other commands, they
   1341   // should be ignored.
   1342   interstitial->TestDomOperationResponse("hello");
   1343   interstitial->TestDomOperationResponse("hi");
   1344   EXPECT_EQ(1, interstitial->command_received_count());
   1345 }
   1346 
   1347 // Test showing an interstitial while another interstitial is already showing.
   1348 TEST_F(TabContentsTest, ShowInterstitialOnInterstitial) {
   1349   // Navigate to a page so we have a navigation entry in the controller.
   1350   GURL start_url("http://www.google.com");
   1351   rvh()->SendNavigate(1, start_url);
   1352   EXPECT_EQ(1, controller().entry_count());
   1353 
   1354   // Show an interstitial.
   1355   TestInterstitialPage::InterstitialState state1 =
   1356       TestInterstitialPage::UNDECIDED;
   1357   bool deleted1 = false;
   1358   GURL url1("http://interstitial1");
   1359   TestInterstitialPage* interstitial1 =
   1360       new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
   1361   TestInterstitialPageStateGuard state_guard1(interstitial1);
   1362   interstitial1->Show();
   1363   interstitial1->TestDidNavigate(1, url1);
   1364 
   1365   // Now show another interstitial.
   1366   TestInterstitialPage::InterstitialState state2 =
   1367       TestInterstitialPage::UNDECIDED;
   1368   bool deleted2 = false;
   1369   GURL url2("http://interstitial2");
   1370   TestInterstitialPage* interstitial2 =
   1371       new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
   1372   TestInterstitialPageStateGuard state_guard2(interstitial2);
   1373   interstitial2->Show();
   1374   interstitial2->TestDidNavigate(1, url2);
   1375 
   1376   // Showing interstitial2 should have caused interstitial1 to go away.
   1377   EXPECT_TRUE(deleted1);
   1378   EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
   1379 
   1380   // Let's make sure interstitial2 is working as intended.
   1381   ASSERT_FALSE(deleted2);
   1382   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   1383   interstitial2->Proceed();
   1384   GURL landing_url("http://www.thepage.com");
   1385   rvh()->SendNavigate(2, landing_url);
   1386 
   1387   EXPECT_TRUE(deleted2);
   1388   EXPECT_FALSE(contents()->showing_interstitial_page());
   1389   EXPECT_TRUE(contents()->interstitial_page() == NULL);
   1390   NavigationEntry* entry = controller().GetActiveEntry();
   1391   ASSERT_TRUE(entry != NULL);
   1392   EXPECT_TRUE(entry->url() == landing_url);
   1393   EXPECT_EQ(2, controller().entry_count());
   1394 }
   1395 
   1396 // Test showing an interstitial, proceeding and then navigating to another
   1397 // interstitial.
   1398 TEST_F(TabContentsTest, ShowInterstitialProceedShowInterstitial) {
   1399   // Navigate to a page so we have a navigation entry in the controller.
   1400   GURL start_url("http://www.google.com");
   1401   rvh()->SendNavigate(1, start_url);
   1402   EXPECT_EQ(1, controller().entry_count());
   1403 
   1404   // Show an interstitial.
   1405   TestInterstitialPage::InterstitialState state1 =
   1406       TestInterstitialPage::UNDECIDED;
   1407   bool deleted1 = false;
   1408   GURL url1("http://interstitial1");
   1409   TestInterstitialPage* interstitial1 =
   1410       new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
   1411   TestInterstitialPageStateGuard state_guard1(interstitial1);
   1412   interstitial1->Show();
   1413   interstitial1->TestDidNavigate(1, url1);
   1414 
   1415   // Take action.  The interstitial won't be hidden until the navigation is
   1416   // committed.
   1417   interstitial1->Proceed();
   1418   EXPECT_EQ(TestInterstitialPage::OKED, state1);
   1419 
   1420   // Now show another interstitial (simulating the navigation causing another
   1421   // interstitial).
   1422   TestInterstitialPage::InterstitialState state2 =
   1423       TestInterstitialPage::UNDECIDED;
   1424   bool deleted2 = false;
   1425   GURL url2("http://interstitial2");
   1426   TestInterstitialPage* interstitial2 =
   1427       new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
   1428   TestInterstitialPageStateGuard state_guard2(interstitial2);
   1429   interstitial2->Show();
   1430   interstitial2->TestDidNavigate(1, url2);
   1431 
   1432   // Showing interstitial2 should have caused interstitial1 to go away.
   1433   EXPECT_TRUE(deleted1);
   1434 
   1435   // Let's make sure interstitial2 is working as intended.
   1436   ASSERT_FALSE(deleted2);
   1437   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   1438   interstitial2->Proceed();
   1439   GURL landing_url("http://www.thepage.com");
   1440   rvh()->SendNavigate(2, landing_url);
   1441 
   1442   EXPECT_TRUE(deleted2);
   1443   EXPECT_FALSE(contents()->showing_interstitial_page());
   1444   EXPECT_TRUE(contents()->interstitial_page() == NULL);
   1445   NavigationEntry* entry = controller().GetActiveEntry();
   1446   ASSERT_TRUE(entry != NULL);
   1447   EXPECT_TRUE(entry->url() == landing_url);
   1448   EXPECT_EQ(2, controller().entry_count());
   1449 }
   1450 
   1451 // Test that navigating away from an interstitial while it's loading cause it
   1452 // not to show.
   1453 TEST_F(TabContentsTest, NavigateBeforeInterstitialShows) {
   1454   // Show an interstitial.
   1455   TestInterstitialPage::InterstitialState state =
   1456       TestInterstitialPage::UNDECIDED;
   1457   bool deleted = false;
   1458   GURL interstitial_url("http://interstitial");
   1459   TestInterstitialPage* interstitial =
   1460       new TestInterstitialPage(contents(), true, interstitial_url,
   1461                                &state, &deleted);
   1462   TestInterstitialPageStateGuard state_guard(interstitial);
   1463   interstitial->Show();
   1464 
   1465   // Let's simulate a navigation initiated from the browser before the
   1466   // interstitial finishes loading.
   1467   const GURL url("http://www.google.com");
   1468   controller().LoadURL(url, GURL(), PageTransition::TYPED);
   1469   ASSERT_FALSE(deleted);
   1470   EXPECT_FALSE(interstitial->is_showing());
   1471 
   1472   // Now let's make the interstitial navigation commit.
   1473   interstitial->TestDidNavigate(1, interstitial_url);
   1474 
   1475   // After it loaded the interstitial should be gone.
   1476   EXPECT_TRUE(deleted);
   1477   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1478 }
   1479 
   1480 // Test that a new request to show an interstitial while an interstitial is
   1481 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
   1482 TEST_F(TabContentsTest, TwoQuickInterstitials) {
   1483   GURL interstitial_url("http://interstitial");
   1484 
   1485   // Show a first interstitial.
   1486   TestInterstitialPage::InterstitialState state1 =
   1487       TestInterstitialPage::UNDECIDED;
   1488   bool deleted1 = false;
   1489   TestInterstitialPage* interstitial1 =
   1490       new TestInterstitialPage(contents(), true, interstitial_url,
   1491                                &state1, &deleted1);
   1492   TestInterstitialPageStateGuard state_guard1(interstitial1);
   1493   interstitial1->Show();
   1494 
   1495   // Show another interstitial on that same tab before the first one had time
   1496   // to load.
   1497   TestInterstitialPage::InterstitialState state2 =
   1498       TestInterstitialPage::UNDECIDED;
   1499   bool deleted2 = false;
   1500   TestInterstitialPage* interstitial2 =
   1501       new TestInterstitialPage(contents(), true, interstitial_url,
   1502                                &state2, &deleted2);
   1503   TestInterstitialPageStateGuard state_guard2(interstitial2);
   1504   interstitial2->Show();
   1505 
   1506   // The first interstitial should have been closed and deleted.
   1507   EXPECT_TRUE(deleted1);
   1508   EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
   1509 
   1510   // The 2nd one should still be OK.
   1511   ASSERT_FALSE(deleted2);
   1512   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   1513 
   1514   // Make the interstitial navigation commit it should be showing.
   1515   interstitial2->TestDidNavigate(1, interstitial_url);
   1516   EXPECT_EQ(interstitial2, contents()->interstitial_page());
   1517 }
   1518 
   1519 // Test showing an interstitial and have its renderer crash.
   1520 TEST_F(TabContentsTest, InterstitialCrasher) {
   1521   // Show an interstitial.
   1522   TestInterstitialPage::InterstitialState state =
   1523       TestInterstitialPage::UNDECIDED;
   1524   bool deleted = false;
   1525   GURL url("http://interstitial");
   1526   TestInterstitialPage* interstitial =
   1527       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1528   TestInterstitialPageStateGuard state_guard(interstitial);
   1529   interstitial->Show();
   1530   // Simulate a renderer crash before the interstitial is shown.
   1531   interstitial->TestRenderViewGone(
   1532       base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
   1533   // The interstitial should have been dismissed.
   1534   EXPECT_TRUE(deleted);
   1535   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1536 
   1537   // Now try again but this time crash the intersitial after it was shown.
   1538   interstitial =
   1539       new TestInterstitialPage(contents(), true, url, &state, &deleted);
   1540   interstitial->Show();
   1541   interstitial->TestDidNavigate(1, url);
   1542   // Simulate a renderer crash.
   1543   interstitial->TestRenderViewGone(
   1544       base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
   1545   // The interstitial should have been dismissed.
   1546   EXPECT_TRUE(deleted);
   1547   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1548 }
   1549 
   1550 // Tests that showing an interstitial as a result of a browser initiated
   1551 // navigation while an interstitial is showing does not remove the pending
   1552 // entry (see http://crbug.com/9791).
   1553 TEST_F(TabContentsTest, NewInterstitialDoesNotCancelPendingEntry) {
   1554   const char kUrl[] = "http://www.badguys.com/";
   1555   const GURL kGURL(kUrl);
   1556 
   1557   // Start a navigation to a page
   1558   contents()->controller().LoadURL(kGURL, GURL(), PageTransition::TYPED);
   1559 
   1560   // Simulate that navigation triggering an interstitial.
   1561   TestInterstitialPage::InterstitialState state =
   1562       TestInterstitialPage::UNDECIDED;
   1563   bool deleted = false;
   1564   TestInterstitialPage* interstitial =
   1565       new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
   1566   TestInterstitialPageStateGuard state_guard(interstitial);
   1567   interstitial->Show();
   1568   interstitial->TestDidNavigate(1, kGURL);
   1569 
   1570   // Initiate a new navigation from the browser that also triggers an
   1571   // interstitial.
   1572   contents()->controller().LoadURL(kGURL, GURL(), PageTransition::TYPED);
   1573   TestInterstitialPage::InterstitialState state2 =
   1574       TestInterstitialPage::UNDECIDED;
   1575   bool deleted2 = false;
   1576   TestInterstitialPage* interstitial2 =
   1577       new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
   1578   TestInterstitialPageStateGuard state_guard2(interstitial2);
   1579   interstitial2->Show();
   1580   interstitial2->TestDidNavigate(1, kGURL);
   1581 
   1582   // Make sure we still have an entry.
   1583   NavigationEntry* entry = contents()->controller().pending_entry();
   1584   ASSERT_TRUE(entry);
   1585   EXPECT_EQ(kUrl, entry->url().spec());
   1586 
   1587   // And that the first interstitial is gone, but not the second.
   1588   EXPECT_TRUE(deleted);
   1589   EXPECT_EQ(TestInterstitialPage::CANCELED, state);
   1590   EXPECT_FALSE(deleted2);
   1591   EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
   1592 }
   1593 
   1594 // Tests that Javascript messages are not shown while an interstitial is
   1595 // showing.
   1596 TEST_F(TabContentsTest, NoJSMessageOnInterstitials) {
   1597   const char kUrl[] = "http://www.badguys.com/";
   1598   const GURL kGURL(kUrl);
   1599 
   1600   // Start a navigation to a page
   1601   contents()->controller().LoadURL(kGURL, GURL(), PageTransition::TYPED);
   1602   // DidNavigate from the page
   1603   ViewHostMsg_FrameNavigate_Params params;
   1604   InitNavigateParams(&params, 1, kGURL);
   1605   contents()->TestDidNavigate(rvh(), params);
   1606 
   1607   // Simulate showing an interstitial while the page is showing.
   1608   TestInterstitialPage::InterstitialState state =
   1609       TestInterstitialPage::UNDECIDED;
   1610   bool deleted = false;
   1611   TestInterstitialPage* interstitial =
   1612       new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
   1613   TestInterstitialPageStateGuard state_guard(interstitial);
   1614   interstitial->Show();
   1615   interstitial->TestDidNavigate(1, kGURL);
   1616 
   1617   // While the interstitial is showing, let's simulate the hidden page
   1618   // attempting to show a JS message.
   1619   IPC::Message* dummy_message = new IPC::Message;
   1620   bool did_suppress_message = false;
   1621   contents()->RunJavaScriptMessage(L"This is an informative message", L"OK",
   1622       kGURL, ui::MessageBoxFlags::kIsJavascriptAlert, dummy_message,
   1623       &did_suppress_message);
   1624   EXPECT_TRUE(did_suppress_message);
   1625 }
   1626 
   1627 // Makes sure that if the source passed to CopyStateFromAndPrune has an
   1628 // interstitial it isn't copied over to the destination.
   1629 TEST_F(TabContentsTest, CopyStateFromAndPruneSourceInterstitial) {
   1630   // Navigate to a page.
   1631   GURL url1("http://www.google.com");
   1632   rvh()->SendNavigate(1, url1);
   1633   EXPECT_EQ(1, controller().entry_count());
   1634 
   1635   // Initiate a browser navigation that will trigger the interstitial
   1636   controller().LoadURL(GURL("http://www.evil.com"), GURL(),
   1637                         PageTransition::TYPED);
   1638 
   1639   // Show an interstitial.
   1640   TestInterstitialPage::InterstitialState state =
   1641       TestInterstitialPage::UNDECIDED;
   1642   bool deleted = false;
   1643   GURL url2("http://interstitial");
   1644   TestInterstitialPage* interstitial =
   1645       new TestInterstitialPage(contents(), true, url2, &state, &deleted);
   1646   TestInterstitialPageStateGuard state_guard(interstitial);
   1647   interstitial->Show();
   1648   interstitial->TestDidNavigate(1, url2);
   1649   EXPECT_TRUE(interstitial->is_showing());
   1650   EXPECT_EQ(2, controller().entry_count());
   1651 
   1652   // Create another NavigationController.
   1653   GURL url3("http://foo2");
   1654   scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
   1655   NavigationController& other_controller = other_contents->controller();
   1656   other_contents->NavigateAndCommit(url3);
   1657   other_controller.CopyStateFromAndPrune(&controller(), false);
   1658 
   1659   // The merged controller should only have two entries: url1 and url2.
   1660   ASSERT_EQ(2, other_controller.entry_count());
   1661   EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
   1662   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
   1663   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->url());
   1664 
   1665   // And the merged controller shouldn't be showing an interstitial.
   1666   EXPECT_FALSE(other_contents->showing_interstitial_page());
   1667 }
   1668 
   1669 // Makes sure that CopyStateFromAndPrune does the right thing if the object
   1670 // CopyStateFromAndPrune is invoked on is showing an interstitial.
   1671 TEST_F(TabContentsTest, CopyStateFromAndPruneTargetInterstitial) {
   1672   // Navigate to a page.
   1673   GURL url1("http://www.google.com");
   1674   contents()->NavigateAndCommit(url1);
   1675 
   1676   // Create another NavigationController.
   1677   scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
   1678   NavigationController& other_controller = other_contents->controller();
   1679 
   1680   // Navigate it to url2.
   1681   GURL url2("http://foo2");
   1682   other_contents->NavigateAndCommit(url2);
   1683 
   1684   // Show an interstitial.
   1685   TestInterstitialPage::InterstitialState state =
   1686       TestInterstitialPage::UNDECIDED;
   1687   bool deleted = false;
   1688   GURL url3("http://interstitial");
   1689   TestInterstitialPage* interstitial =
   1690       new TestInterstitialPage(other_contents.get(), true, url3, &state,
   1691                                &deleted);
   1692   TestInterstitialPageStateGuard state_guard(interstitial);
   1693   interstitial->Show();
   1694   interstitial->TestDidNavigate(1, url3);
   1695   EXPECT_TRUE(interstitial->is_showing());
   1696   EXPECT_EQ(2, other_controller.entry_count());
   1697 
   1698   other_controller.CopyStateFromAndPrune(&controller(), false);
   1699 
   1700   // The merged controller should only have two entries: url1 and url2.
   1701   ASSERT_EQ(2, other_controller.entry_count());
   1702   EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
   1703   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
   1704   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->url());
   1705 
   1706   // It should have a transient entry.
   1707   EXPECT_TRUE(other_controller.GetTransientEntry());
   1708 
   1709   // And the interstitial should be showing.
   1710   EXPECT_TRUE(other_contents->showing_interstitial_page());
   1711 
   1712   // And the interstitial should do a reload on don't proceed.
   1713   EXPECT_TRUE(other_contents->interstitial_page()->reload_on_dont_proceed());
   1714 }
   1715 
   1716 class ConstrainedWindowCloseTest : public ConstrainedWindow {
   1717  public:
   1718   explicit ConstrainedWindowCloseTest(TabContents* tab_contents)
   1719       : tab_contents_(tab_contents) {
   1720   }
   1721 
   1722   virtual void ShowConstrainedWindow() {}
   1723   virtual void FocusConstrainedWindow() {}
   1724   virtual ~ConstrainedWindowCloseTest() {}
   1725 
   1726   virtual void CloseConstrainedWindow() {
   1727     tab_contents_->WillClose(this);
   1728     close_count++;
   1729   }
   1730 
   1731   int close_count;
   1732   TabContents* tab_contents_;
   1733 };
   1734 
   1735 TEST_F(TabContentsTest, ConstrainedWindows) {
   1736   TabContents* tab_contents = CreateTestTabContents();
   1737   ConstrainedWindowCloseTest window(tab_contents);
   1738   window.close_count = 0;
   1739 
   1740   const int kWindowCount = 4;
   1741   for (int i = 0; i < kWindowCount; i++) {
   1742     tab_contents->AddConstrainedDialog(&window);
   1743   }
   1744   EXPECT_EQ(window.close_count, 0);
   1745   delete tab_contents;
   1746   EXPECT_EQ(window.close_count, kWindowCount);
   1747 }
   1748