Home | History | Annotate | Download | only in frame_host
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/basictypes.h"
      6 #include "base/bind.h"
      7 #include "base/files/file_util.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/path_service.h"
     10 #include "base/stl_util.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/time/time.h"
     14 #include "content/browser/frame_host/cross_site_transferring_request.h"
     15 #include "content/browser/frame_host/navigation_controller_impl.h"
     16 #include "content/browser/frame_host/navigation_entry_impl.h"
     17 #include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
     18 #include "content/browser/frame_host/navigator.h"
     19 #include "content/browser/site_instance_impl.h"
     20 #include "content/browser/web_contents/web_contents_impl.h"
     21 #include "content/common/frame_messages.h"
     22 #include "content/common/view_messages.h"
     23 #include "content/public/browser/navigation_details.h"
     24 #include "content/public/browser/notification_registrar.h"
     25 #include "content/public/browser/notification_types.h"
     26 #include "content/public/browser/render_view_host.h"
     27 #include "content/public/browser/web_contents_delegate.h"
     28 #include "content/public/browser/web_contents_observer.h"
     29 #include "content/public/common/page_state.h"
     30 #include "content/public/common/url_constants.h"
     31 #include "content/public/test/mock_render_process_host.h"
     32 #include "content/public/test/test_notification_tracker.h"
     33 #include "content/public/test/test_utils.h"
     34 #include "content/test/test_render_frame_host.h"
     35 #include "content/test/test_render_view_host.h"
     36 #include "content/test/test_web_contents.h"
     37 #include "net/base/net_util.h"
     38 #include "skia/ext/platform_canvas.h"
     39 #include "testing/gtest/include/gtest/gtest.h"
     40 
     41 using base::Time;
     42 
     43 namespace {
     44 
     45 // Creates an image with a 1x1 SkBitmap of the specified |color|.
     46 gfx::Image CreateImage(SkColor color) {
     47   SkBitmap bitmap;
     48   bitmap.allocN32Pixels(1, 1);
     49   bitmap.eraseColor(color);
     50   return gfx::Image::CreateFrom1xBitmap(bitmap);
     51 }
     52 
     53 // Returns true if images |a| and |b| have the same pixel data.
     54 bool DoImagesMatch(const gfx::Image& a, const gfx::Image& b) {
     55   // Assume that if the 1x bitmaps match, the images match.
     56   SkBitmap a_bitmap = a.AsBitmap();
     57   SkBitmap b_bitmap = b.AsBitmap();
     58 
     59   if (a_bitmap.width() != b_bitmap.width() ||
     60       a_bitmap.height() != b_bitmap.height()) {
     61     return false;
     62   }
     63   SkAutoLockPixels a_bitmap_lock(a_bitmap);
     64   SkAutoLockPixels b_bitmap_lock(b_bitmap);
     65   return memcmp(a_bitmap.getPixels(),
     66                 b_bitmap.getPixels(),
     67                 a_bitmap.getSize()) == 0;
     68 }
     69 
     70 class MockScreenshotManager : public content::NavigationEntryScreenshotManager {
     71  public:
     72   explicit MockScreenshotManager(content::NavigationControllerImpl* owner)
     73       : content::NavigationEntryScreenshotManager(owner),
     74         encoding_screenshot_in_progress_(false) {
     75   }
     76 
     77   virtual ~MockScreenshotManager() {
     78   }
     79 
     80   void TakeScreenshotFor(content::NavigationEntryImpl* entry) {
     81     SkBitmap bitmap;
     82     bitmap.allocPixels(SkImageInfo::Make(
     83         1, 1, kAlpha_8_SkColorType, kPremul_SkAlphaType));
     84     bitmap.eraseARGB(0, 0, 0, 0);
     85     encoding_screenshot_in_progress_ = true;
     86     OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
     87     WaitUntilScreenshotIsReady();
     88   }
     89 
     90   int GetScreenshotCount() {
     91     return content::NavigationEntryScreenshotManager::GetScreenshotCount();
     92   }
     93 
     94   void WaitUntilScreenshotIsReady() {
     95     if (!encoding_screenshot_in_progress_)
     96       return;
     97     message_loop_runner_ = new content::MessageLoopRunner;
     98     message_loop_runner_->Run();
     99   }
    100 
    101  private:
    102   // Overridden from content::NavigationEntryScreenshotManager:
    103   virtual void TakeScreenshotImpl(
    104       content::RenderViewHost* host,
    105       content::NavigationEntryImpl* entry) OVERRIDE {
    106   }
    107 
    108   virtual void OnScreenshotSet(content::NavigationEntryImpl* entry) OVERRIDE {
    109     encoding_screenshot_in_progress_ = false;
    110     NavigationEntryScreenshotManager::OnScreenshotSet(entry);
    111     if (message_loop_runner_.get())
    112       message_loop_runner_->Quit();
    113   }
    114 
    115   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
    116   bool encoding_screenshot_in_progress_;
    117 
    118   DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager);
    119 };
    120 
    121 }  // namespace
    122 
    123 namespace content {
    124 
    125 // TimeSmoother tests ----------------------------------------------------------
    126 
    127 // With no duplicates, GetSmoothedTime should be the identity
    128 // function.
    129 TEST(TimeSmoother, Basic) {
    130   NavigationControllerImpl::TimeSmoother smoother;
    131   for (int64 i = 1; i < 1000; ++i) {
    132     base::Time t = base::Time::FromInternalValue(i);
    133     EXPECT_EQ(t, smoother.GetSmoothedTime(t));
    134   }
    135 }
    136 
    137 // With a single duplicate and timestamps thereafter increasing by one
    138 // microsecond, the smoothed time should always be one behind.
    139 TEST(TimeSmoother, SingleDuplicate) {
    140   NavigationControllerImpl::TimeSmoother smoother;
    141   base::Time t = base::Time::FromInternalValue(1);
    142   EXPECT_EQ(t, smoother.GetSmoothedTime(t));
    143   for (int64 i = 1; i < 1000; ++i) {
    144     base::Time expected_t = base::Time::FromInternalValue(i + 1);
    145     t = base::Time::FromInternalValue(i);
    146     EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
    147   }
    148 }
    149 
    150 // With k duplicates and timestamps thereafter increasing by one
    151 // microsecond, the smoothed time should always be k behind.
    152 TEST(TimeSmoother, ManyDuplicates) {
    153   const int64 kNumDuplicates = 100;
    154   NavigationControllerImpl::TimeSmoother smoother;
    155   base::Time t = base::Time::FromInternalValue(1);
    156   for (int64 i = 0; i < kNumDuplicates; ++i) {
    157     base::Time expected_t = base::Time::FromInternalValue(i + 1);
    158     EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
    159   }
    160   for (int64 i = 1; i < 1000; ++i) {
    161     base::Time expected_t =
    162         base::Time::FromInternalValue(i + kNumDuplicates);
    163     t = base::Time::FromInternalValue(i);
    164     EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
    165   }
    166 }
    167 
    168 // If the clock jumps far back enough after a run of duplicates, it
    169 // should immediately jump to that value.
    170 TEST(TimeSmoother, ClockBackwardsJump) {
    171   const int64 kNumDuplicates = 100;
    172   NavigationControllerImpl::TimeSmoother smoother;
    173   base::Time t = base::Time::FromInternalValue(1000);
    174   for (int64 i = 0; i < kNumDuplicates; ++i) {
    175     base::Time expected_t = base::Time::FromInternalValue(i + 1000);
    176     EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
    177   }
    178   t = base::Time::FromInternalValue(500);
    179   EXPECT_EQ(t, smoother.GetSmoothedTime(t));
    180 }
    181 
    182 // NavigationControllerTest ----------------------------------------------------
    183 
    184 class NavigationControllerTest
    185     : public RenderViewHostImplTestHarness,
    186       public WebContentsObserver {
    187  public:
    188   NavigationControllerTest() : navigation_entry_committed_counter_(0) {
    189   }
    190 
    191   virtual void SetUp() OVERRIDE {
    192     RenderViewHostImplTestHarness::SetUp();
    193     WebContents* web_contents = RenderViewHostImplTestHarness::web_contents();
    194     ASSERT_TRUE(web_contents);  // The WebContents should be created by now.
    195     WebContentsObserver::Observe(web_contents);
    196   }
    197 
    198   // WebContentsObserver:
    199   virtual void DidStartNavigationToPendingEntry(
    200       const GURL& url,
    201       NavigationController::ReloadType reload_type) OVERRIDE {
    202     navigated_url_ = url;
    203   }
    204 
    205   virtual void NavigationEntryCommitted(
    206       const LoadCommittedDetails& load_details) OVERRIDE {
    207     navigation_entry_committed_counter_++;
    208   }
    209 
    210   const GURL& navigated_url() const {
    211     return navigated_url_;
    212   }
    213 
    214   NavigationControllerImpl& controller_impl() {
    215     return static_cast<NavigationControllerImpl&>(controller());
    216   }
    217 
    218  protected:
    219   GURL navigated_url_;
    220   size_t navigation_entry_committed_counter_;
    221 };
    222 
    223 void RegisterForAllNavNotifications(TestNotificationTracker* tracker,
    224                                     NavigationController* controller) {
    225   tracker->ListenFor(NOTIFICATION_NAV_LIST_PRUNED,
    226                      Source<NavigationController>(controller));
    227   tracker->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED,
    228                      Source<NavigationController>(controller));
    229 }
    230 
    231 SiteInstance* GetSiteInstanceFromEntry(NavigationEntry* entry) {
    232   return NavigationEntryImpl::FromNavigationEntry(entry)->site_instance();
    233 }
    234 
    235 class TestWebContentsDelegate : public WebContentsDelegate {
    236  public:
    237   explicit TestWebContentsDelegate() :
    238       navigation_state_change_count_(0),
    239       repost_form_warning_count_(0) {}
    240 
    241   int navigation_state_change_count() {
    242     return navigation_state_change_count_;
    243   }
    244 
    245   int repost_form_warning_count() {
    246     return repost_form_warning_count_;
    247   }
    248 
    249   // Keep track of whether the tab has notified us of a navigation state change.
    250   virtual void NavigationStateChanged(const WebContents* source,
    251                                       InvalidateTypes changed_flags) OVERRIDE {
    252     navigation_state_change_count_++;
    253   }
    254 
    255   virtual void ShowRepostFormWarningDialog(WebContents* source) OVERRIDE {
    256     repost_form_warning_count_++;
    257   }
    258 
    259  private:
    260   // The number of times NavigationStateChanged has been called.
    261   int navigation_state_change_count_;
    262 
    263   // The number of times ShowRepostFormWarningDialog() was called.
    264   int repost_form_warning_count_;
    265 };
    266 
    267 // -----------------------------------------------------------------------------
    268 
    269 TEST_F(NavigationControllerTest, Defaults) {
    270   NavigationControllerImpl& controller = controller_impl();
    271 
    272   EXPECT_FALSE(controller.GetPendingEntry());
    273   EXPECT_FALSE(controller.GetVisibleEntry());
    274   EXPECT_FALSE(controller.GetLastCommittedEntry());
    275   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
    276   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
    277   EXPECT_EQ(controller.GetEntryCount(), 0);
    278   EXPECT_FALSE(controller.CanGoBack());
    279   EXPECT_FALSE(controller.CanGoForward());
    280 }
    281 
    282 TEST_F(NavigationControllerTest, GoToOffset) {
    283   NavigationControllerImpl& controller = controller_impl();
    284   TestNotificationTracker notifications;
    285   RegisterForAllNavNotifications(&notifications, &controller);
    286 
    287   const int kNumUrls = 5;
    288   std::vector<GURL> urls(kNumUrls);
    289   for (int i = 0; i < kNumUrls; ++i) {
    290     urls[i] = GURL(base::StringPrintf("http://www.a.com/%d", i));
    291   }
    292 
    293   main_test_rfh()->SendNavigate(0, urls[0]);
    294   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    295   navigation_entry_committed_counter_ = 0;
    296   EXPECT_EQ(urls[0], controller.GetVisibleEntry()->GetVirtualURL());
    297   EXPECT_FALSE(controller.CanGoBack());
    298   EXPECT_FALSE(controller.CanGoForward());
    299   EXPECT_FALSE(controller.CanGoToOffset(1));
    300 
    301   for (int i = 1; i <= 4; ++i) {
    302     main_test_rfh()->SendNavigate(i, urls[i]);
    303     EXPECT_EQ(1U, navigation_entry_committed_counter_);
    304     navigation_entry_committed_counter_ = 0;
    305     EXPECT_EQ(urls[i], controller.GetVisibleEntry()->GetVirtualURL());
    306     EXPECT_TRUE(controller.CanGoToOffset(-i));
    307     EXPECT_FALSE(controller.CanGoToOffset(-(i + 1)));
    308     EXPECT_FALSE(controller.CanGoToOffset(1));
    309   }
    310 
    311   // We have loaded 5 pages, and are currently at the last-loaded page.
    312   int url_index = 4;
    313 
    314   enum Tests {
    315     GO_TO_MIDDLE_PAGE = -2,
    316     GO_FORWARDS = 1,
    317     GO_BACKWARDS = -1,
    318     GO_TO_BEGINNING = -2,
    319     GO_TO_END = 4,
    320     NUM_TESTS = 5,
    321   };
    322 
    323   const int test_offsets[NUM_TESTS] = {
    324     GO_TO_MIDDLE_PAGE,
    325     GO_FORWARDS,
    326     GO_BACKWARDS,
    327     GO_TO_BEGINNING,
    328     GO_TO_END
    329   };
    330 
    331   for (int test = 0; test < NUM_TESTS; ++test) {
    332     int offset = test_offsets[test];
    333     controller.GoToOffset(offset);
    334     url_index += offset;
    335     // Check that the GoToOffset will land on the expected page.
    336     EXPECT_EQ(urls[url_index], controller.GetPendingEntry()->GetVirtualURL());
    337     main_test_rfh()->SendNavigate(url_index, urls[url_index]);
    338     EXPECT_EQ(1U, navigation_entry_committed_counter_);
    339     navigation_entry_committed_counter_ = 0;
    340     // Check that we can go to any valid offset into the history.
    341     for (size_t j = 0; j < urls.size(); ++j)
    342       EXPECT_TRUE(controller.CanGoToOffset(j - url_index));
    343     // Check that we can't go beyond the beginning or end of the history.
    344     EXPECT_FALSE(controller.CanGoToOffset(-(url_index + 1)));
    345     EXPECT_FALSE(controller.CanGoToOffset(urls.size() - url_index));
    346   }
    347 }
    348 
    349 TEST_F(NavigationControllerTest, LoadURL) {
    350   NavigationControllerImpl& controller = controller_impl();
    351   TestNotificationTracker notifications;
    352   RegisterForAllNavNotifications(&notifications, &controller);
    353 
    354   const GURL url1("http://foo1");
    355   const GURL url2("http://foo2");
    356 
    357   controller.LoadURL(
    358       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    359   // Creating a pending notification should not have issued any of the
    360   // notifications we're listening for.
    361   EXPECT_EQ(0U, notifications.size());
    362 
    363   // The load should now be pending.
    364   EXPECT_EQ(controller.GetEntryCount(), 0);
    365   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
    366   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
    367   EXPECT_FALSE(controller.GetLastCommittedEntry());
    368   ASSERT_TRUE(controller.GetPendingEntry());
    369   EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
    370   EXPECT_FALSE(controller.CanGoBack());
    371   EXPECT_FALSE(controller.CanGoForward());
    372   EXPECT_EQ(contents()->GetMaxPageID(), -1);
    373 
    374   // Neither the timestamp nor the status code should have been set yet.
    375   EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
    376   EXPECT_EQ(0, controller.GetPendingEntry()->GetHttpStatusCode());
    377 
    378   // We should have gotten no notifications from the preceeding checks.
    379   EXPECT_EQ(0U, notifications.size());
    380 
    381   main_test_rfh()->SendNavigate(0, url1);
    382   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    383   navigation_entry_committed_counter_ = 0;
    384 
    385   // The load should now be committed.
    386   EXPECT_EQ(controller.GetEntryCount(), 1);
    387   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
    388   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
    389   EXPECT_TRUE(controller.GetLastCommittedEntry());
    390   EXPECT_FALSE(controller.GetPendingEntry());
    391   ASSERT_TRUE(controller.GetVisibleEntry());
    392   EXPECT_FALSE(controller.CanGoBack());
    393   EXPECT_FALSE(controller.CanGoForward());
    394   EXPECT_EQ(contents()->GetMaxPageID(), 0);
    395   EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
    396       controller.GetLastCommittedEntry())->bindings());
    397 
    398   // The timestamp should have been set.
    399   EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
    400 
    401   // Load another...
    402   controller.LoadURL(
    403       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    404 
    405   // The load should now be pending.
    406   EXPECT_EQ(controller.GetEntryCount(), 1);
    407   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
    408   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
    409   EXPECT_TRUE(controller.GetLastCommittedEntry());
    410   ASSERT_TRUE(controller.GetPendingEntry());
    411   EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
    412   // TODO(darin): maybe this should really be true?
    413   EXPECT_FALSE(controller.CanGoBack());
    414   EXPECT_FALSE(controller.CanGoForward());
    415   EXPECT_EQ(contents()->GetMaxPageID(), 0);
    416 
    417   EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
    418 
    419   // Simulate the beforeunload ack for the cross-site transition, and then the
    420   // commit.
    421   test_rvh()->SendBeforeUnloadACK(true);
    422   contents()->GetPendingMainFrame()->SendNavigate(1, url2);
    423   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    424   navigation_entry_committed_counter_ = 0;
    425 
    426   // The load should now be committed.
    427   EXPECT_EQ(controller.GetEntryCount(), 2);
    428   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
    429   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
    430   EXPECT_TRUE(controller.GetLastCommittedEntry());
    431   EXPECT_FALSE(controller.GetPendingEntry());
    432   ASSERT_TRUE(controller.GetVisibleEntry());
    433   EXPECT_TRUE(controller.CanGoBack());
    434   EXPECT_FALSE(controller.CanGoForward());
    435   EXPECT_EQ(contents()->GetMaxPageID(), 1);
    436 
    437   EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
    438 }
    439 
    440 namespace {
    441 
    442 base::Time GetFixedTime(base::Time time) {
    443   return time;
    444 }
    445 
    446 }  // namespace
    447 
    448 TEST_F(NavigationControllerTest, LoadURLSameTime) {
    449   NavigationControllerImpl& controller = controller_impl();
    450   TestNotificationTracker notifications;
    451   RegisterForAllNavNotifications(&notifications, &controller);
    452 
    453   // Set the clock to always return a timestamp of 1.
    454   controller.SetGetTimestampCallbackForTest(
    455       base::Bind(&GetFixedTime, base::Time::FromInternalValue(1)));
    456 
    457   const GURL url1("http://foo1");
    458   const GURL url2("http://foo2");
    459 
    460   controller.LoadURL(
    461       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    462 
    463   main_test_rfh()->SendNavigate(0, url1);
    464   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    465   navigation_entry_committed_counter_ = 0;
    466 
    467   // Load another...
    468   controller.LoadURL(
    469       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    470 
    471   // Simulate the beforeunload ack for the cross-site transition, and then the
    472   // commit.
    473   test_rvh()->SendBeforeUnloadACK(true);
    474   main_test_rfh()->SendNavigate(1, url2);
    475   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    476   navigation_entry_committed_counter_ = 0;
    477 
    478   // The two loads should now be committed.
    479   ASSERT_EQ(controller.GetEntryCount(), 2);
    480 
    481   // Timestamps should be distinct despite the clock returning the
    482   // same value.
    483   EXPECT_EQ(1u,
    484             controller.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
    485   EXPECT_EQ(2u,
    486             controller.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
    487 }
    488 
    489 void CheckNavigationEntryMatchLoadParams(
    490     NavigationController::LoadURLParams& load_params,
    491     NavigationEntryImpl* entry) {
    492   EXPECT_EQ(load_params.url, entry->GetURL());
    493   EXPECT_EQ(load_params.referrer.url, entry->GetReferrer().url);
    494   EXPECT_EQ(load_params.referrer.policy, entry->GetReferrer().policy);
    495   EXPECT_EQ(load_params.transition_type, entry->GetTransitionType());
    496   EXPECT_EQ(load_params.extra_headers, entry->extra_headers());
    497 
    498   EXPECT_EQ(load_params.is_renderer_initiated, entry->is_renderer_initiated());
    499   EXPECT_EQ(load_params.base_url_for_data_url, entry->GetBaseURLForDataURL());
    500   if (!load_params.virtual_url_for_data_url.is_empty()) {
    501     EXPECT_EQ(load_params.virtual_url_for_data_url, entry->GetVirtualURL());
    502   }
    503   if (NavigationController::UA_OVERRIDE_INHERIT !=
    504       load_params.override_user_agent) {
    505     bool should_override = (NavigationController::UA_OVERRIDE_TRUE ==
    506         load_params.override_user_agent);
    507     EXPECT_EQ(should_override, entry->GetIsOverridingUserAgent());
    508   }
    509   EXPECT_EQ(load_params.browser_initiated_post_data.get(),
    510             entry->GetBrowserInitiatedPostData());
    511   EXPECT_EQ(load_params.transferred_global_request_id,
    512       entry->transferred_global_request_id());
    513 }
    514 
    515 TEST_F(NavigationControllerTest, LoadURLWithParams) {
    516   NavigationControllerImpl& controller = controller_impl();
    517 
    518   NavigationController::LoadURLParams load_params(GURL("http://foo"));
    519   load_params.referrer =
    520       Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault);
    521   load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
    522   load_params.extra_headers = "content-type: text/plain";
    523   load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT;
    524   load_params.is_renderer_initiated = true;
    525   load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
    526   load_params.transferred_global_request_id = GlobalRequestID(2, 3);
    527 
    528   controller.LoadURLWithParams(load_params);
    529   NavigationEntryImpl* entry =
    530       NavigationEntryImpl::FromNavigationEntry(
    531           controller.GetPendingEntry());
    532 
    533   // The timestamp should not have been set yet.
    534   ASSERT_TRUE(entry);
    535   EXPECT_TRUE(entry->GetTimestamp().is_null());
    536 
    537   CheckNavigationEntryMatchLoadParams(load_params, entry);
    538 }
    539 
    540 TEST_F(NavigationControllerTest, LoadURLWithExtraParams_Data) {
    541   NavigationControllerImpl& controller = controller_impl();
    542 
    543   NavigationController::LoadURLParams load_params(
    544       GURL("data:text/html,dataurl"));
    545   load_params.load_type = NavigationController::LOAD_TYPE_DATA;
    546   load_params.base_url_for_data_url = GURL("http://foo");
    547   load_params.virtual_url_for_data_url = GURL(url::kAboutBlankURL);
    548   load_params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
    549 
    550   controller.LoadURLWithParams(load_params);
    551   NavigationEntryImpl* entry =
    552       NavigationEntryImpl::FromNavigationEntry(
    553           controller.GetPendingEntry());
    554 
    555   CheckNavigationEntryMatchLoadParams(load_params, entry);
    556 }
    557 
    558 TEST_F(NavigationControllerTest, LoadURLWithExtraParams_HttpPost) {
    559   NavigationControllerImpl& controller = controller_impl();
    560 
    561   NavigationController::LoadURLParams load_params(GURL("https://posturl"));
    562   load_params.transition_type = ui::PAGE_TRANSITION_TYPED;
    563   load_params.load_type =
    564       NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
    565   load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
    566 
    567 
    568   const unsigned char* raw_data =
    569       reinterpret_cast<const unsigned char*>("d\n\0a2");
    570   const int length = 5;
    571   std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
    572   scoped_refptr<base::RefCountedBytes> data =
    573       base::RefCountedBytes::TakeVector(&post_data_vector);
    574   load_params.browser_initiated_post_data = data.get();
    575 
    576   controller.LoadURLWithParams(load_params);
    577   NavigationEntryImpl* entry =
    578       NavigationEntryImpl::FromNavigationEntry(
    579           controller.GetPendingEntry());
    580 
    581   CheckNavigationEntryMatchLoadParams(load_params, entry);
    582 }
    583 
    584 // Tests what happens when the same page is loaded again.  Should not create a
    585 // new session history entry. This is what happens when you press enter in the
    586 // URL bar to reload: a pending entry is created and then it is discarded when
    587 // the load commits (because WebCore didn't actually make a new entry).
    588 TEST_F(NavigationControllerTest, LoadURL_SamePage) {
    589   NavigationControllerImpl& controller = controller_impl();
    590   TestNotificationTracker notifications;
    591   RegisterForAllNavNotifications(&notifications, &controller);
    592 
    593   const GURL url1("http://foo1");
    594 
    595   controller.LoadURL(
    596       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    597   EXPECT_EQ(0U, notifications.size());
    598   main_test_rfh()->SendNavigate(0, url1);
    599   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    600   navigation_entry_committed_counter_ = 0;
    601 
    602   ASSERT_TRUE(controller.GetVisibleEntry());
    603   const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
    604   EXPECT_FALSE(timestamp.is_null());
    605 
    606   controller.LoadURL(
    607       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    608   EXPECT_EQ(0U, notifications.size());
    609   main_test_rfh()->SendNavigate(0, url1);
    610   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    611   navigation_entry_committed_counter_ = 0;
    612 
    613   // We should not have produced a new session history entry.
    614   EXPECT_EQ(controller.GetEntryCount(), 1);
    615   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
    616   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
    617   EXPECT_TRUE(controller.GetLastCommittedEntry());
    618   EXPECT_FALSE(controller.GetPendingEntry());
    619   ASSERT_TRUE(controller.GetVisibleEntry());
    620   EXPECT_FALSE(controller.CanGoBack());
    621   EXPECT_FALSE(controller.CanGoForward());
    622 
    623   // The timestamp should have been updated.
    624   //
    625   // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
    626   // EXPECT_GT once we guarantee that timestamps are unique.
    627   EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp);
    628 }
    629 
    630 // Load the same page twice, once as a GET and once as a POST.
    631 // We should update the post state on the NavigationEntry.
    632 TEST_F(NavigationControllerTest, LoadURL_SamePage_DifferentMethod) {
    633   NavigationControllerImpl& controller = controller_impl();
    634   TestNotificationTracker notifications;
    635   RegisterForAllNavNotifications(&notifications, &controller);
    636 
    637   const GURL url1("http://foo1");
    638 
    639   controller.LoadURL(
    640       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    641   FrameHostMsg_DidCommitProvisionalLoad_Params params;
    642   params.page_id = 0;
    643   params.url = url1;
    644   params.transition = ui::PAGE_TRANSITION_TYPED;
    645   params.is_post = true;
    646   params.post_id = 123;
    647   params.page_state = PageState::CreateForTesting(url1, false, 0, 0);
    648   main_test_rfh()->SendNavigateWithParams(&params);
    649 
    650   // The post data should be visible.
    651   NavigationEntry* entry = controller.GetVisibleEntry();
    652   ASSERT_TRUE(entry);
    653   EXPECT_TRUE(entry->GetHasPostData());
    654   EXPECT_EQ(entry->GetPostID(), 123);
    655 
    656   controller.LoadURL(
    657       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    658   main_test_rfh()->SendNavigate(0, url1);
    659 
    660   // We should not have produced a new session history entry.
    661   ASSERT_EQ(controller.GetVisibleEntry(), entry);
    662 
    663   // The post data should have been cleared due to the GET.
    664   EXPECT_FALSE(entry->GetHasPostData());
    665   EXPECT_EQ(entry->GetPostID(), 0);
    666 }
    667 
    668 // Tests loading a URL but discarding it before the load commits.
    669 TEST_F(NavigationControllerTest, LoadURL_Discarded) {
    670   NavigationControllerImpl& controller = controller_impl();
    671   TestNotificationTracker notifications;
    672   RegisterForAllNavNotifications(&notifications, &controller);
    673 
    674   const GURL url1("http://foo1");
    675   const GURL url2("http://foo2");
    676 
    677   controller.LoadURL(
    678       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    679   EXPECT_EQ(0U, notifications.size());
    680   main_test_rfh()->SendNavigate(0, url1);
    681   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    682   navigation_entry_committed_counter_ = 0;
    683 
    684   ASSERT_TRUE(controller.GetVisibleEntry());
    685   const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
    686   EXPECT_FALSE(timestamp.is_null());
    687 
    688   controller.LoadURL(
    689       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    690   controller.DiscardNonCommittedEntries();
    691   EXPECT_EQ(0U, notifications.size());
    692 
    693   // Should not have produced a new session history entry.
    694   EXPECT_EQ(controller.GetEntryCount(), 1);
    695   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
    696   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
    697   EXPECT_TRUE(controller.GetLastCommittedEntry());
    698   EXPECT_FALSE(controller.GetPendingEntry());
    699   ASSERT_TRUE(controller.GetVisibleEntry());
    700   EXPECT_FALSE(controller.CanGoBack());
    701   EXPECT_FALSE(controller.CanGoForward());
    702 
    703   // Timestamp should not have changed.
    704   EXPECT_EQ(timestamp, controller.GetVisibleEntry()->GetTimestamp());
    705 }
    706 
    707 // Tests navigations that come in unrequested. This happens when the user
    708 // navigates from the web page, and here we test that there is no pending entry.
    709 TEST_F(NavigationControllerTest, LoadURL_NoPending) {
    710   NavigationControllerImpl& controller = controller_impl();
    711   TestNotificationTracker notifications;
    712   RegisterForAllNavNotifications(&notifications, &controller);
    713 
    714   // First make an existing committed entry.
    715   const GURL kExistingURL1("http://eh");
    716   controller.LoadURL(
    717       kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    718   main_test_rfh()->SendNavigate(0, kExistingURL1);
    719   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    720   navigation_entry_committed_counter_ = 0;
    721 
    722   // Do a new navigation without making a pending one.
    723   const GURL kNewURL("http://see");
    724   main_test_rfh()->SendNavigate(99, kNewURL);
    725 
    726   // There should no longer be any pending entry, and the third navigation we
    727   // just made should be committed.
    728   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    729   navigation_entry_committed_counter_ = 0;
    730   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    731   EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
    732   EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
    733 }
    734 
    735 // Tests navigating to a new URL when there is a new pending navigation that is
    736 // not the one that just loaded. This will happen if the user types in a URL to
    737 // somewhere slow, and then navigates the current page before the typed URL
    738 // commits.
    739 TEST_F(NavigationControllerTest, LoadURL_NewPending) {
    740   NavigationControllerImpl& controller = controller_impl();
    741   TestNotificationTracker notifications;
    742   RegisterForAllNavNotifications(&notifications, &controller);
    743 
    744   // First make an existing committed entry.
    745   const GURL kExistingURL1("http://eh");
    746   controller.LoadURL(
    747       kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    748   main_test_rfh()->SendNavigate(0, kExistingURL1);
    749   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    750   navigation_entry_committed_counter_ = 0;
    751 
    752   // Make a pending entry to somewhere new.
    753   const GURL kExistingURL2("http://bee");
    754   controller.LoadURL(
    755       kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    756   EXPECT_EQ(0U, notifications.size());
    757 
    758   // After the beforeunload but before it commits, do a new navigation.
    759   test_rvh()->SendBeforeUnloadACK(true);
    760   const GURL kNewURL("http://see");
    761   contents()->GetPendingMainFrame()->SendNavigate(3, kNewURL);
    762 
    763   // There should no longer be any pending entry, and the third navigation we
    764   // just made should be committed.
    765   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    766   navigation_entry_committed_counter_ = 0;
    767   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    768   EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
    769   EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
    770 }
    771 
    772 // Tests navigating to a new URL when there is a pending back/forward
    773 // navigation. This will happen if the user hits back, but before that commits,
    774 // they navigate somewhere new.
    775 TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
    776   NavigationControllerImpl& controller = controller_impl();
    777   TestNotificationTracker notifications;
    778   RegisterForAllNavNotifications(&notifications, &controller);
    779 
    780   // First make some history.
    781   const GURL kExistingURL1("http://foo/eh");
    782   controller.LoadURL(
    783       kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    784   main_test_rfh()->SendNavigate(0, kExistingURL1);
    785   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    786   navigation_entry_committed_counter_ = 0;
    787 
    788   const GURL kExistingURL2("http://foo/bee");
    789   controller.LoadURL(
    790       kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    791   main_test_rfh()->SendNavigate(1, kExistingURL2);
    792   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    793   navigation_entry_committed_counter_ = 0;
    794 
    795   // Now make a pending back/forward navigation. The zeroth entry should be
    796   // pending.
    797   controller.GoBack();
    798   EXPECT_EQ(0U, notifications.size());
    799   EXPECT_EQ(0, controller.GetPendingEntryIndex());
    800   EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
    801 
    802   // Before that commits, do a new navigation.
    803   const GURL kNewURL("http://foo/see");
    804   LoadCommittedDetails details;
    805   main_test_rfh()->SendNavigate(3, kNewURL);
    806 
    807   // There should no longer be any pending entry, and the third navigation we
    808   // just made should be committed.
    809   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    810   navigation_entry_committed_counter_ = 0;
    811   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    812   EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
    813   EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
    814 }
    815 
    816 // Tests navigating to a new URL when there is a pending back/forward
    817 // navigation to a cross-process, privileged URL. This will happen if the user
    818 // hits back, but before that commits, they navigate somewhere new.
    819 TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
    820   NavigationControllerImpl& controller = controller_impl();
    821   TestNotificationTracker notifications;
    822   RegisterForAllNavNotifications(&notifications, &controller);
    823 
    824   // First make some history, starting with a privileged URL.
    825   const GURL kExistingURL1("http://privileged");
    826   controller.LoadURL(
    827       kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    828   // Pretend it has bindings so we can tell if we incorrectly copy it.
    829   test_rvh()->AllowBindings(2);
    830   main_test_rfh()->SendNavigate(0, kExistingURL1);
    831   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    832   navigation_entry_committed_counter_ = 0;
    833 
    834   // Navigate cross-process to a second URL.
    835   const GURL kExistingURL2("http://foo/eh");
    836   controller.LoadURL(
    837       kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    838   test_rvh()->SendBeforeUnloadACK(true);
    839   TestRenderFrameHost* foo_rfh = contents()->GetPendingMainFrame();
    840   foo_rfh->SendNavigate(1, kExistingURL2);
    841   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    842   navigation_entry_committed_counter_ = 0;
    843 
    844   // Now make a pending back/forward navigation to a privileged entry.
    845   // The zeroth entry should be pending.
    846   controller.GoBack();
    847   foo_rfh->GetRenderViewHost()->SendBeforeUnloadACK(true);
    848   EXPECT_EQ(0U, notifications.size());
    849   EXPECT_EQ(0, controller.GetPendingEntryIndex());
    850   EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
    851   EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry(
    852                 controller.GetPendingEntry())->bindings());
    853 
    854   // Before that commits, do a new navigation.
    855   const GURL kNewURL("http://foo/bee");
    856   LoadCommittedDetails details;
    857   foo_rfh->SendNavigate(3, kNewURL);
    858 
    859   // There should no longer be any pending entry, and the third navigation we
    860   // just made should be committed.
    861   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    862   navigation_entry_committed_counter_ = 0;
    863   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    864   EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
    865   EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
    866   EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
    867                 controller.GetLastCommittedEntry())->bindings());
    868 }
    869 
    870 // Tests navigating to an existing URL when there is a pending new navigation.
    871 // This will happen if the user enters a URL, but before that commits, the
    872 // current page fires history.back().
    873 TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
    874   NavigationControllerImpl& controller = controller_impl();
    875   TestNotificationTracker notifications;
    876   RegisterForAllNavNotifications(&notifications, &controller);
    877 
    878   // First make some history.
    879   const GURL kExistingURL1("http://foo/eh");
    880   controller.LoadURL(
    881       kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    882   main_test_rfh()->SendNavigate(0, kExistingURL1);
    883   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    884   navigation_entry_committed_counter_ = 0;
    885 
    886   const GURL kExistingURL2("http://foo/bee");
    887   controller.LoadURL(
    888       kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    889   main_test_rfh()->SendNavigate(1, kExistingURL2);
    890   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    891   navigation_entry_committed_counter_ = 0;
    892 
    893   // Now make a pending new navigation.
    894   const GURL kNewURL("http://foo/see");
    895   controller.LoadURL(
    896       kNewURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    897   EXPECT_EQ(0U, notifications.size());
    898   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    899   EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
    900 
    901   // Before that commits, a back navigation from the renderer commits.
    902   main_test_rfh()->SendNavigate(0, kExistingURL1);
    903 
    904   // There should no longer be any pending entry, and the back navigation we
    905   // just made should be committed.
    906   EXPECT_EQ(1U, navigation_entry_committed_counter_);
    907   navigation_entry_committed_counter_ = 0;
    908   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    909   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
    910   EXPECT_EQ(kExistingURL1, controller.GetVisibleEntry()->GetURL());
    911 }
    912 
    913 // Tests an ignored navigation when there is a pending new navigation.
    914 // This will happen if the user enters a URL, but before that commits, the
    915 // current blank page reloads.  See http://crbug.com/77507.
    916 TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) {
    917   NavigationControllerImpl& controller = controller_impl();
    918   TestNotificationTracker notifications;
    919   RegisterForAllNavNotifications(&notifications, &controller);
    920 
    921   // Set a WebContentsDelegate to listen for state changes.
    922   scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
    923   EXPECT_FALSE(contents()->GetDelegate());
    924   contents()->SetDelegate(delegate.get());
    925 
    926   // Without any navigations, the renderer starts at about:blank.
    927   const GURL kExistingURL(url::kAboutBlankURL);
    928 
    929   // Now make a pending new navigation.
    930   const GURL kNewURL("http://eh");
    931   controller.LoadURL(
    932       kNewURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    933   EXPECT_EQ(0U, notifications.size());
    934   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    935   EXPECT_TRUE(controller.GetPendingEntry());
    936   EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
    937   EXPECT_EQ(1, delegate->navigation_state_change_count());
    938 
    939   // Before that commits, a document.write and location.reload can cause the
    940   // renderer to send a FrameNavigate with page_id -1.
    941   main_test_rfh()->SendNavigate(-1, kExistingURL);
    942 
    943   // This should clear the pending entry and notify of a navigation state
    944   // change, so that we do not keep displaying kNewURL.
    945   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    946   EXPECT_FALSE(controller.GetPendingEntry());
    947   EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
    948   EXPECT_EQ(2, delegate->navigation_state_change_count());
    949 
    950   contents()->SetDelegate(NULL);
    951 }
    952 
    953 // Tests that the pending entry state is correct after an abort.
    954 // We do not want to clear the pending entry, so that the user doesn't
    955 // lose a typed URL.  (See http://crbug.com/9682.)
    956 TEST_F(NavigationControllerTest, LoadURL_AbortDoesntCancelPending) {
    957   NavigationControllerImpl& controller = controller_impl();
    958   TestNotificationTracker notifications;
    959   RegisterForAllNavNotifications(&notifications, &controller);
    960 
    961   // Set a WebContentsDelegate to listen for state changes.
    962   scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
    963   EXPECT_FALSE(contents()->GetDelegate());
    964   contents()->SetDelegate(delegate.get());
    965 
    966   // Start with a pending new navigation.
    967   const GURL kNewURL("http://eh");
    968   controller.LoadURL(
    969       kNewURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    970   EXPECT_EQ(0U, notifications.size());
    971   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    972   EXPECT_TRUE(controller.GetPendingEntry());
    973   EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
    974   EXPECT_EQ(1, delegate->navigation_state_change_count());
    975 
    976   // It may abort before committing, if it's a download or due to a stop or
    977   // a new navigation from the user.
    978   FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
    979   params.error_code = net::ERR_ABORTED;
    980   params.error_description = base::string16();
    981   params.url = kNewURL;
    982   params.showing_repost_interstitial = false;
    983   main_test_rfh()->OnMessageReceived(
    984       FrameHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
    985                                                    params));
    986 
    987   // This should not clear the pending entry or notify of a navigation state
    988   // change, so that we keep displaying kNewURL (until the user clears it).
    989   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    990   EXPECT_TRUE(controller.GetPendingEntry());
    991   EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
    992   EXPECT_EQ(1, delegate->navigation_state_change_count());
    993   NavigationEntry* pending_entry = controller.GetPendingEntry();
    994 
    995   // Ensure that a reload keeps the same pending entry.
    996   controller.Reload(true);
    997   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
    998   EXPECT_TRUE(controller.GetPendingEntry());
    999   EXPECT_EQ(pending_entry, controller.GetPendingEntry());
   1000   EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
   1001 
   1002   contents()->SetDelegate(NULL);
   1003 }
   1004 
   1005 // Tests that the pending URL is not visible during a renderer-initiated
   1006 // redirect and abort.  See http://crbug.com/83031.
   1007 TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
   1008   NavigationControllerImpl& controller = controller_impl();
   1009   TestNotificationTracker notifications;
   1010   RegisterForAllNavNotifications(&notifications, &controller);
   1011 
   1012   // First make an existing committed entry.
   1013   const GURL kExistingURL("http://foo/eh");
   1014   controller.LoadURL(kExistingURL, content::Referrer(),
   1015                      ui::PAGE_TRANSITION_TYPED, std::string());
   1016   main_test_rfh()->SendNavigate(1, kExistingURL);
   1017   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1018   navigation_entry_committed_counter_ = 0;
   1019 
   1020   // Set a WebContentsDelegate to listen for state changes.
   1021   scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
   1022   EXPECT_FALSE(contents()->GetDelegate());
   1023   contents()->SetDelegate(delegate.get());
   1024 
   1025   // Now make a pending new navigation, initiated by the renderer.
   1026   const GURL kNewURL("http://foo/bee");
   1027   NavigationController::LoadURLParams load_url_params(kNewURL);
   1028   load_url_params.transition_type = ui::PAGE_TRANSITION_TYPED;
   1029   load_url_params.is_renderer_initiated = true;
   1030   controller.LoadURLWithParams(load_url_params);
   1031   EXPECT_EQ(0U, notifications.size());
   1032   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   1033   EXPECT_TRUE(controller.GetPendingEntry());
   1034   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   1035   EXPECT_EQ(0, delegate->navigation_state_change_count());
   1036 
   1037   // The visible entry should be the last committed URL, not the pending one.
   1038   EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
   1039 
   1040   // Now the navigation redirects. (There is no corresponding message here.)
   1041   const GURL kRedirectURL("http://foo/see");
   1042 
   1043   // We don't want to change the NavigationEntry's url, in case it cancels.
   1044   // Prevents regression of http://crbug.com/77786.
   1045   EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL());
   1046 
   1047   // It may abort before committing, if it's a download or due to a stop or
   1048   // a new navigation from the user.
   1049   FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
   1050   params.error_code = net::ERR_ABORTED;
   1051   params.error_description = base::string16();
   1052   params.url = kRedirectURL;
   1053   params.showing_repost_interstitial = false;
   1054   main_test_rfh()->OnMessageReceived(
   1055       FrameHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
   1056                                                    params));
   1057 
   1058   // Because the pending entry is renderer initiated and not visible, we
   1059   // clear it when it fails.
   1060   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   1061   EXPECT_FALSE(controller.GetPendingEntry());
   1062   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   1063   EXPECT_EQ(1, delegate->navigation_state_change_count());
   1064 
   1065   // The visible entry should be the last committed URL, not the pending one,
   1066   // so that no spoof is possible.
   1067   EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
   1068 
   1069   contents()->SetDelegate(NULL);
   1070 }
   1071 
   1072 // Ensure that NavigationEntries track which bindings their RenderViewHost had
   1073 // at the time they committed.  http://crbug.com/173672.
   1074 TEST_F(NavigationControllerTest, LoadURL_WithBindings) {
   1075   NavigationControllerImpl& controller = controller_impl();
   1076   TestNotificationTracker notifications;
   1077   RegisterForAllNavNotifications(&notifications, &controller);
   1078   std::vector<GURL> url_chain;
   1079 
   1080   const GURL url1("http://foo1");
   1081   const GURL url2("http://foo2");
   1082 
   1083   // Navigate to a first, unprivileged URL.
   1084   controller.LoadURL(
   1085       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1086   EXPECT_EQ(NavigationEntryImpl::kInvalidBindings,
   1087             NavigationEntryImpl::FromNavigationEntry(
   1088                 controller.GetPendingEntry())->bindings());
   1089 
   1090   // Commit.
   1091   TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
   1092   orig_rfh->SendNavigate(0, url1);
   1093   EXPECT_EQ(controller.GetEntryCount(), 1);
   1094   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   1095   EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
   1096       controller.GetLastCommittedEntry())->bindings());
   1097 
   1098   // Manually increase the number of active views in the SiteInstance
   1099   // that orig_rfh belongs to, to prevent it from being destroyed when
   1100   // it gets swapped out, so that we can reuse orig_rfh when the
   1101   // controller goes back.
   1102   static_cast<SiteInstanceImpl*>(orig_rfh->GetSiteInstance())->
   1103       increment_active_view_count();
   1104 
   1105   // Navigate to a second URL, simulate the beforeunload ack for the cross-site
   1106   // transition, and set bindings on the pending RenderViewHost to simulate a
   1107   // privileged url.
   1108   controller.LoadURL(
   1109       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1110   orig_rfh->GetRenderViewHost()->SendBeforeUnloadACK(true);
   1111   TestRenderFrameHost* new_rfh = contents()->GetPendingMainFrame();
   1112   new_rfh->GetRenderViewHost()->AllowBindings(1);
   1113   new_rfh->SendNavigate(1, url2);
   1114 
   1115   // The second load should be committed, and bindings should be remembered.
   1116   EXPECT_EQ(controller.GetEntryCount(), 2);
   1117   EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
   1118   EXPECT_TRUE(controller.CanGoBack());
   1119   EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry(
   1120       controller.GetLastCommittedEntry())->bindings());
   1121 
   1122   // Going back, the first entry should still appear unprivileged.
   1123   controller.GoBack();
   1124   new_rfh->GetRenderViewHost()->SendBeforeUnloadACK(true);
   1125   orig_rfh->SendNavigate(0, url1);
   1126   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   1127   EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
   1128       controller.GetLastCommittedEntry())->bindings());
   1129 }
   1130 
   1131 TEST_F(NavigationControllerTest, Reload) {
   1132   NavigationControllerImpl& controller = controller_impl();
   1133   TestNotificationTracker notifications;
   1134   RegisterForAllNavNotifications(&notifications, &controller);
   1135 
   1136   const GURL url1("http://foo1");
   1137 
   1138   controller.LoadURL(
   1139       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1140   EXPECT_EQ(0U, notifications.size());
   1141   main_test_rfh()->SendNavigate(0, url1);
   1142   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1143   navigation_entry_committed_counter_ = 0;
   1144   ASSERT_TRUE(controller.GetVisibleEntry());
   1145   controller.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
   1146   controller.Reload(true);
   1147   EXPECT_EQ(0U, notifications.size());
   1148 
   1149   const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
   1150   EXPECT_FALSE(timestamp.is_null());
   1151 
   1152   // The reload is pending.
   1153   EXPECT_EQ(controller.GetEntryCount(), 1);
   1154   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1155   EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
   1156   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1157   EXPECT_TRUE(controller.GetPendingEntry());
   1158   EXPECT_FALSE(controller.CanGoBack());
   1159   EXPECT_FALSE(controller.CanGoForward());
   1160   // Make sure the title has been cleared (will be redrawn just after reload).
   1161   // Avoids a stale cached title when the new page being reloaded has no title.
   1162   // See http://crbug.com/96041.
   1163   EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
   1164 
   1165   main_test_rfh()->SendNavigate(0, url1);
   1166   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1167   navigation_entry_committed_counter_ = 0;
   1168 
   1169   // Now the reload is committed.
   1170   EXPECT_EQ(controller.GetEntryCount(), 1);
   1171   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1172   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1173   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1174   EXPECT_FALSE(controller.GetPendingEntry());
   1175   EXPECT_FALSE(controller.CanGoBack());
   1176   EXPECT_FALSE(controller.CanGoForward());
   1177 
   1178   // The timestamp should have been updated.
   1179   ASSERT_TRUE(controller.GetVisibleEntry());
   1180   EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp);
   1181 }
   1182 
   1183 // Tests what happens when a reload navigation produces a new page.
   1184 TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
   1185   NavigationControllerImpl& controller = controller_impl();
   1186   TestNotificationTracker notifications;
   1187   RegisterForAllNavNotifications(&notifications, &controller);
   1188 
   1189   const GURL url1("http://foo1");
   1190   const GURL url2("http://foo2");
   1191 
   1192   controller.LoadURL(
   1193       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1194   main_test_rfh()->SendNavigate(0, url1);
   1195   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1196   navigation_entry_committed_counter_ = 0;
   1197 
   1198   controller.Reload(true);
   1199   EXPECT_EQ(0U, notifications.size());
   1200 
   1201   main_test_rfh()->SendNavigate(1, url2);
   1202   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1203   navigation_entry_committed_counter_ = 0;
   1204 
   1205   // Now the reload is committed.
   1206   EXPECT_EQ(controller.GetEntryCount(), 2);
   1207   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
   1208   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1209   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1210   EXPECT_FALSE(controller.GetPendingEntry());
   1211   EXPECT_TRUE(controller.CanGoBack());
   1212   EXPECT_FALSE(controller.CanGoForward());
   1213 }
   1214 
   1215 // This test ensures that when a guest renderer reloads, the reload goes through
   1216 // without ending up in the "we have a wrong process for the URL" branch in
   1217 // NavigationControllerImpl::ReloadInternal.
   1218 TEST_F(NavigationControllerTest, ReloadWithGuest) {
   1219   NavigationControllerImpl& controller = controller_impl();
   1220 
   1221   const GURL url1("http://foo1");
   1222   controller.LoadURL(
   1223       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1224   main_test_rfh()->SendNavigate(0, url1);
   1225   ASSERT_TRUE(controller.GetVisibleEntry());
   1226 
   1227   // Make the entry believe its RenderProcessHost is a guest.
   1228   NavigationEntryImpl* entry1 =
   1229       NavigationEntryImpl::FromNavigationEntry(controller.GetVisibleEntry());
   1230   reinterpret_cast<MockRenderProcessHost*>(
   1231       entry1->site_instance()->GetProcess())->set_is_isolated_guest(true);
   1232 
   1233   // And reload.
   1234   controller.Reload(true);
   1235 
   1236   // The reload is pending. Check that the NavigationEntry didn't get replaced
   1237   // because of having the wrong process.
   1238   EXPECT_EQ(controller.GetEntryCount(), 1);
   1239   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1240   EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
   1241 
   1242   NavigationEntryImpl* entry2 =
   1243       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
   1244   EXPECT_EQ(entry1, entry2);
   1245 }
   1246 
   1247 #if !defined(OS_ANDROID)  // http://crbug.com/157428
   1248 TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
   1249   NavigationControllerImpl& controller = controller_impl();
   1250   TestNotificationTracker notifications;
   1251   RegisterForAllNavNotifications(&notifications, &controller);
   1252 
   1253   const GURL original_url("http://foo1");
   1254   const GURL final_url("http://foo2");
   1255 
   1256   // Load up the original URL, but get redirected.
   1257   controller.LoadURL(
   1258       original_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1259   EXPECT_EQ(0U, notifications.size());
   1260   main_test_rfh()->SendNavigateWithOriginalRequestURL(
   1261       0, final_url, original_url);
   1262   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1263   navigation_entry_committed_counter_ = 0;
   1264 
   1265   // The NavigationEntry should save both the original URL and the final
   1266   // redirected URL.
   1267   EXPECT_EQ(
   1268       original_url, controller.GetVisibleEntry()->GetOriginalRequestURL());
   1269   EXPECT_EQ(final_url, controller.GetVisibleEntry()->GetURL());
   1270 
   1271   // Reload using the original URL.
   1272   controller.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
   1273   controller.ReloadOriginalRequestURL(false);
   1274   EXPECT_EQ(0U, notifications.size());
   1275 
   1276   // The reload is pending.  The request should point to the original URL.
   1277   EXPECT_EQ(original_url, navigated_url());
   1278   EXPECT_EQ(controller.GetEntryCount(), 1);
   1279   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1280   EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
   1281   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1282   EXPECT_TRUE(controller.GetPendingEntry());
   1283   EXPECT_FALSE(controller.CanGoBack());
   1284   EXPECT_FALSE(controller.CanGoForward());
   1285 
   1286   // Make sure the title has been cleared (will be redrawn just after reload).
   1287   // Avoids a stale cached title when the new page being reloaded has no title.
   1288   // See http://crbug.com/96041.
   1289   EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
   1290 
   1291   // Send that the navigation has proceeded; say it got redirected again.
   1292   main_test_rfh()->SendNavigate(0, final_url);
   1293   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1294   navigation_entry_committed_counter_ = 0;
   1295 
   1296   // Now the reload is committed.
   1297   EXPECT_EQ(controller.GetEntryCount(), 1);
   1298   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1299   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1300   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1301   EXPECT_FALSE(controller.GetPendingEntry());
   1302   EXPECT_FALSE(controller.CanGoBack());
   1303   EXPECT_FALSE(controller.CanGoForward());
   1304 }
   1305 
   1306 #endif  // !defined(OS_ANDROID)
   1307 
   1308 // Test that certain non-persisted NavigationEntryImpl values get reset after
   1309 // commit.
   1310 TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
   1311   NavigationControllerImpl& controller = controller_impl();
   1312   const GURL url1("http://foo1");
   1313   controller.LoadURL(
   1314       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1315 
   1316   // Set up some sample values.
   1317   const unsigned char* raw_data =
   1318       reinterpret_cast<const unsigned char*>("post\n\n\0data");
   1319   const int length = 11;
   1320   std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
   1321   scoped_refptr<base::RefCountedBytes> post_data =
   1322       base::RefCountedBytes::TakeVector(&post_data_vector);
   1323   GlobalRequestID transfer_id(3, 4);
   1324   std::vector<GURL> redirects;
   1325   redirects.push_back(GURL("http://foo2"));
   1326 
   1327   // Set non-persisted values on the pending entry.
   1328   NavigationEntryImpl* pending_entry =
   1329       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
   1330   pending_entry->SetBrowserInitiatedPostData(post_data.get());
   1331   pending_entry->set_is_renderer_initiated(true);
   1332   pending_entry->set_transferred_global_request_id(transfer_id);
   1333   pending_entry->set_should_replace_entry(true);
   1334   pending_entry->set_should_clear_history_list(true);
   1335   EXPECT_EQ(post_data.get(), pending_entry->GetBrowserInitiatedPostData());
   1336   EXPECT_TRUE(pending_entry->is_renderer_initiated());
   1337   EXPECT_EQ(transfer_id, pending_entry->transferred_global_request_id());
   1338   EXPECT_TRUE(pending_entry->should_replace_entry());
   1339   EXPECT_TRUE(pending_entry->should_clear_history_list());
   1340 
   1341   main_test_rfh()->SendNavigate(0, url1);
   1342 
   1343   // Certain values that are only used for pending entries get reset after
   1344   // commit.
   1345   NavigationEntryImpl* committed_entry =
   1346       NavigationEntryImpl::FromNavigationEntry(
   1347           controller.GetLastCommittedEntry());
   1348   EXPECT_FALSE(committed_entry->GetBrowserInitiatedPostData());
   1349   EXPECT_FALSE(committed_entry->is_renderer_initiated());
   1350   EXPECT_EQ(GlobalRequestID(-1, -1),
   1351             committed_entry->transferred_global_request_id());
   1352   EXPECT_FALSE(committed_entry->should_replace_entry());
   1353   EXPECT_FALSE(committed_entry->should_clear_history_list());
   1354 }
   1355 
   1356 // Test that Redirects are preserved after a commit.
   1357 TEST_F(NavigationControllerTest, RedirectsAreNotResetByCommit) {
   1358   NavigationControllerImpl& controller = controller_impl();
   1359   const GURL url1("http://foo1");
   1360   controller.LoadURL(
   1361       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1362 
   1363   // Set up some redirect values.
   1364   std::vector<GURL> redirects;
   1365   redirects.push_back(GURL("http://foo2"));
   1366 
   1367   // Set redirects on the pending entry.
   1368   NavigationEntryImpl* pending_entry =
   1369       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
   1370   pending_entry->SetRedirectChain(redirects);
   1371   EXPECT_EQ(1U, pending_entry->GetRedirectChain().size());
   1372   EXPECT_EQ(GURL("http://foo2"), pending_entry->GetRedirectChain()[0]);
   1373 
   1374   // Normal navigation will preserve redirects in the committed entry.
   1375   main_test_rfh()->SendNavigateWithRedirects(0, url1, redirects);
   1376   NavigationEntryImpl* committed_entry =
   1377       NavigationEntryImpl::FromNavigationEntry(
   1378           controller.GetLastCommittedEntry());
   1379   ASSERT_EQ(1U, committed_entry->GetRedirectChain().size());
   1380   EXPECT_EQ(GURL("http://foo2"), committed_entry->GetRedirectChain()[0]);
   1381 }
   1382 
   1383 // Tests what happens when we navigate back successfully
   1384 TEST_F(NavigationControllerTest, Back) {
   1385   NavigationControllerImpl& controller = controller_impl();
   1386   TestNotificationTracker notifications;
   1387   RegisterForAllNavNotifications(&notifications, &controller);
   1388 
   1389   const GURL url1("http://foo1");
   1390   main_test_rfh()->SendNavigate(0, url1);
   1391   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1392   navigation_entry_committed_counter_ = 0;
   1393 
   1394   const GURL url2("http://foo2");
   1395   main_test_rfh()->SendNavigate(1, url2);
   1396   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1397   navigation_entry_committed_counter_ = 0;
   1398 
   1399   controller.GoBack();
   1400   EXPECT_EQ(0U, notifications.size());
   1401 
   1402   // We should now have a pending navigation to go back.
   1403   EXPECT_EQ(controller.GetEntryCount(), 2);
   1404   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
   1405   EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
   1406   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1407   EXPECT_TRUE(controller.GetPendingEntry());
   1408   EXPECT_FALSE(controller.CanGoBack());
   1409   EXPECT_FALSE(controller.CanGoToOffset(-1));
   1410   EXPECT_TRUE(controller.CanGoForward());
   1411   EXPECT_TRUE(controller.CanGoToOffset(1));
   1412   EXPECT_FALSE(controller.CanGoToOffset(2));  // Cannot go foward 2 steps.
   1413 
   1414   // Timestamp for entry 1 should be on or after that of entry 0.
   1415   EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
   1416   EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
   1417             controller.GetEntryAtIndex(0)->GetTimestamp());
   1418 
   1419   main_test_rfh()->SendNavigate(0, url2);
   1420   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1421   navigation_entry_committed_counter_ = 0;
   1422 
   1423   // The back navigation completed successfully.
   1424   EXPECT_EQ(controller.GetEntryCount(), 2);
   1425   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1426   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1427   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1428   EXPECT_FALSE(controller.GetPendingEntry());
   1429   EXPECT_FALSE(controller.CanGoBack());
   1430   EXPECT_FALSE(controller.CanGoToOffset(-1));
   1431   EXPECT_TRUE(controller.CanGoForward());
   1432   EXPECT_TRUE(controller.CanGoToOffset(1));
   1433   EXPECT_FALSE(controller.CanGoToOffset(2));  // Cannot go foward 2 steps.
   1434 
   1435   // Timestamp for entry 0 should be on or after that of entry 1
   1436   // (since we went back to it).
   1437   EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
   1438             controller.GetEntryAtIndex(1)->GetTimestamp());
   1439 }
   1440 
   1441 // Tests what happens when a back navigation produces a new page.
   1442 TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
   1443   NavigationControllerImpl& controller = controller_impl();
   1444   TestNotificationTracker notifications;
   1445   RegisterForAllNavNotifications(&notifications, &controller);
   1446 
   1447   const GURL url1("http://foo/1");
   1448   const GURL url2("http://foo/2");
   1449   const GURL url3("http://foo/3");
   1450 
   1451   controller.LoadURL(
   1452       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1453   main_test_rfh()->SendNavigate(0, url1);
   1454   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1455   navigation_entry_committed_counter_ = 0;
   1456 
   1457   controller.LoadURL(
   1458       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1459   main_test_rfh()->SendNavigate(1, url2);
   1460   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1461   navigation_entry_committed_counter_ = 0;
   1462 
   1463   controller.GoBack();
   1464   EXPECT_EQ(0U, notifications.size());
   1465 
   1466   // We should now have a pending navigation to go back.
   1467   EXPECT_EQ(controller.GetEntryCount(), 2);
   1468   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
   1469   EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
   1470   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1471   EXPECT_TRUE(controller.GetPendingEntry());
   1472   EXPECT_FALSE(controller.CanGoBack());
   1473   EXPECT_TRUE(controller.CanGoForward());
   1474 
   1475   main_test_rfh()->SendNavigate(2, url3);
   1476   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1477   navigation_entry_committed_counter_ = 0;
   1478 
   1479   // The back navigation resulted in a completely new navigation.
   1480   // TODO(darin): perhaps this behavior will be confusing to users?
   1481   EXPECT_EQ(controller.GetEntryCount(), 3);
   1482   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
   1483   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1484   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1485   EXPECT_FALSE(controller.GetPendingEntry());
   1486   EXPECT_TRUE(controller.CanGoBack());
   1487   EXPECT_FALSE(controller.CanGoForward());
   1488 }
   1489 
   1490 // Receives a back message when there is a new pending navigation entry.
   1491 TEST_F(NavigationControllerTest, Back_NewPending) {
   1492   NavigationControllerImpl& controller = controller_impl();
   1493   TestNotificationTracker notifications;
   1494   RegisterForAllNavNotifications(&notifications, &controller);
   1495 
   1496   const GURL kUrl1("http://foo1");
   1497   const GURL kUrl2("http://foo2");
   1498   const GURL kUrl3("http://foo3");
   1499 
   1500   // First navigate two places so we have some back history.
   1501   main_test_rfh()->SendNavigate(0, kUrl1);
   1502   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1503   navigation_entry_committed_counter_ = 0;
   1504 
   1505   // controller.LoadURL(kUrl2, ui::PAGE_TRANSITION_TYPED);
   1506   main_test_rfh()->SendNavigate(1, kUrl2);
   1507   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1508   navigation_entry_committed_counter_ = 0;
   1509 
   1510   // Now start a new pending navigation and go back before it commits.
   1511   controller.LoadURL(
   1512       kUrl3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1513   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   1514   EXPECT_EQ(kUrl3, controller.GetPendingEntry()->GetURL());
   1515   controller.GoBack();
   1516 
   1517   // The pending navigation should now be the "back" item and the new one
   1518   // should be gone.
   1519   EXPECT_EQ(0, controller.GetPendingEntryIndex());
   1520   EXPECT_EQ(kUrl1, controller.GetPendingEntry()->GetURL());
   1521 }
   1522 
   1523 // Receives a back message when there is a different renavigation already
   1524 // pending.
   1525 TEST_F(NavigationControllerTest, Back_OtherBackPending) {
   1526   NavigationControllerImpl& controller = controller_impl();
   1527   const GURL kUrl1("http://foo/1");
   1528   const GURL kUrl2("http://foo/2");
   1529   const GURL kUrl3("http://foo/3");
   1530 
   1531   // First navigate three places so we have some back history.
   1532   main_test_rfh()->SendNavigate(0, kUrl1);
   1533   main_test_rfh()->SendNavigate(1, kUrl2);
   1534   main_test_rfh()->SendNavigate(2, kUrl3);
   1535 
   1536   // With nothing pending, say we get a navigation to the second entry.
   1537   main_test_rfh()->SendNavigate(1, kUrl2);
   1538 
   1539   // We know all the entries have the same site instance, so we can just grab
   1540   // a random one for looking up other entries.
   1541   SiteInstance* site_instance =
   1542       NavigationEntryImpl::FromNavigationEntry(
   1543           controller.GetLastCommittedEntry())->site_instance();
   1544 
   1545   // That second URL should be the last committed and it should have gotten the
   1546   // new title.
   1547   EXPECT_EQ(kUrl2, controller.GetEntryWithPageID(site_instance, 1)->GetURL());
   1548   EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
   1549   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   1550 
   1551   // Now go forward to the last item again and say it was committed.
   1552   controller.GoForward();
   1553   main_test_rfh()->SendNavigate(2, kUrl3);
   1554 
   1555   // Now start going back one to the second page. It will be pending.
   1556   controller.GoBack();
   1557   EXPECT_EQ(1, controller.GetPendingEntryIndex());
   1558   EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
   1559 
   1560   // Not synthesize a totally new back event to the first page. This will not
   1561   // match the pending one.
   1562   main_test_rfh()->SendNavigate(0, kUrl1);
   1563 
   1564   // The committed navigation should clear the pending entry.
   1565   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   1566 
   1567   // But the navigated entry should be the last committed.
   1568   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   1569   EXPECT_EQ(kUrl1, controller.GetLastCommittedEntry()->GetURL());
   1570 }
   1571 
   1572 // Tests what happens when we navigate forward successfully.
   1573 TEST_F(NavigationControllerTest, Forward) {
   1574   NavigationControllerImpl& controller = controller_impl();
   1575   TestNotificationTracker notifications;
   1576   RegisterForAllNavNotifications(&notifications, &controller);
   1577 
   1578   const GURL url1("http://foo1");
   1579   const GURL url2("http://foo2");
   1580 
   1581   main_test_rfh()->SendNavigate(0, url1);
   1582   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1583   navigation_entry_committed_counter_ = 0;
   1584 
   1585   main_test_rfh()->SendNavigate(1, url2);
   1586   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1587   navigation_entry_committed_counter_ = 0;
   1588 
   1589   controller.GoBack();
   1590   main_test_rfh()->SendNavigate(0, url1);
   1591   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1592   navigation_entry_committed_counter_ = 0;
   1593 
   1594   controller.GoForward();
   1595 
   1596   // We should now have a pending navigation to go forward.
   1597   EXPECT_EQ(controller.GetEntryCount(), 2);
   1598   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1599   EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
   1600   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1601   EXPECT_TRUE(controller.GetPendingEntry());
   1602   EXPECT_TRUE(controller.CanGoBack());
   1603   EXPECT_TRUE(controller.CanGoToOffset(-1));
   1604   EXPECT_FALSE(controller.CanGoToOffset(-2));  // Cannot go back 2 steps.
   1605   EXPECT_FALSE(controller.CanGoForward());
   1606   EXPECT_FALSE(controller.CanGoToOffset(1));
   1607 
   1608   // Timestamp for entry 0 should be on or after that of entry 1
   1609   // (since we went back to it).
   1610   EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
   1611   EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
   1612             controller.GetEntryAtIndex(1)->GetTimestamp());
   1613 
   1614   main_test_rfh()->SendNavigate(1, url2);
   1615   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1616   navigation_entry_committed_counter_ = 0;
   1617 
   1618   // The forward navigation completed successfully.
   1619   EXPECT_EQ(controller.GetEntryCount(), 2);
   1620   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
   1621   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1622   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1623   EXPECT_FALSE(controller.GetPendingEntry());
   1624   EXPECT_TRUE(controller.CanGoBack());
   1625   EXPECT_TRUE(controller.CanGoToOffset(-1));
   1626   EXPECT_FALSE(controller.CanGoToOffset(-2));  // Cannot go back 2 steps.
   1627   EXPECT_FALSE(controller.CanGoForward());
   1628   EXPECT_FALSE(controller.CanGoToOffset(1));
   1629 
   1630   // Timestamp for entry 1 should be on or after that of entry 0
   1631   // (since we went forward to it).
   1632   EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
   1633             controller.GetEntryAtIndex(0)->GetTimestamp());
   1634 }
   1635 
   1636 // Tests what happens when a forward navigation produces a new page.
   1637 TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
   1638   NavigationControllerImpl& controller = controller_impl();
   1639   TestNotificationTracker notifications;
   1640   RegisterForAllNavNotifications(&notifications, &controller);
   1641 
   1642   const GURL url1("http://foo1");
   1643   const GURL url2("http://foo2");
   1644   const GURL url3("http://foo3");
   1645 
   1646   main_test_rfh()->SendNavigate(0, url1);
   1647   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1648   navigation_entry_committed_counter_ = 0;
   1649   main_test_rfh()->SendNavigate(1, url2);
   1650   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1651   navigation_entry_committed_counter_ = 0;
   1652 
   1653   controller.GoBack();
   1654   main_test_rfh()->SendNavigate(0, url1);
   1655   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1656   navigation_entry_committed_counter_ = 0;
   1657 
   1658   controller.GoForward();
   1659   EXPECT_EQ(0U, notifications.size());
   1660 
   1661   // Should now have a pending navigation to go forward.
   1662   EXPECT_EQ(controller.GetEntryCount(), 2);
   1663   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1664   EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
   1665   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1666   EXPECT_TRUE(controller.GetPendingEntry());
   1667   EXPECT_TRUE(controller.CanGoBack());
   1668   EXPECT_FALSE(controller.CanGoForward());
   1669 
   1670   main_test_rfh()->SendNavigate(2, url3);
   1671   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1672   navigation_entry_committed_counter_ = 0;
   1673   EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED));
   1674 
   1675   EXPECT_EQ(controller.GetEntryCount(), 2);
   1676   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
   1677   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1678   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1679   EXPECT_FALSE(controller.GetPendingEntry());
   1680   EXPECT_TRUE(controller.CanGoBack());
   1681   EXPECT_FALSE(controller.CanGoForward());
   1682 }
   1683 
   1684 // Two consequent navigation for the same URL entered in should be considered
   1685 // as SAME_PAGE navigation even when we are redirected to some other page.
   1686 TEST_F(NavigationControllerTest, Redirect) {
   1687   NavigationControllerImpl& controller = controller_impl();
   1688   TestNotificationTracker notifications;
   1689   RegisterForAllNavNotifications(&notifications, &controller);
   1690 
   1691   const GURL url1("http://foo1");
   1692   const GURL url2("http://foo2");  // Redirection target
   1693 
   1694   // First request
   1695   controller.LoadURL(
   1696       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1697 
   1698   EXPECT_EQ(0U, notifications.size());
   1699   main_test_rfh()->SendNavigate(0, url2);
   1700   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1701   navigation_entry_committed_counter_ = 0;
   1702 
   1703   // Second request
   1704   controller.LoadURL(
   1705       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1706 
   1707   EXPECT_TRUE(controller.GetPendingEntry());
   1708   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1709   EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
   1710 
   1711   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   1712   params.page_id = 0;
   1713   params.url = url2;
   1714   params.transition = ui::PAGE_TRANSITION_SERVER_REDIRECT;
   1715   params.redirects.push_back(GURL("http://foo1"));
   1716   params.redirects.push_back(GURL("http://foo2"));
   1717   params.should_update_history = false;
   1718   params.gesture = NavigationGestureAuto;
   1719   params.is_post = false;
   1720   params.page_state = PageState::CreateFromURL(url2);
   1721 
   1722   LoadCommittedDetails details;
   1723 
   1724   EXPECT_EQ(0U, notifications.size());
   1725   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   1726                                              &details));
   1727   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1728   navigation_entry_committed_counter_ = 0;
   1729 
   1730   EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
   1731   EXPECT_EQ(controller.GetEntryCount(), 1);
   1732   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1733   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1734   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1735   EXPECT_FALSE(controller.GetPendingEntry());
   1736   EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
   1737 
   1738   EXPECT_FALSE(controller.CanGoBack());
   1739   EXPECT_FALSE(controller.CanGoForward());
   1740 }
   1741 
   1742 // Similar to Redirect above, but the first URL is requested by POST,
   1743 // the second URL is requested by GET. NavigationEntry::has_post_data_
   1744 // must be cleared. http://crbug.com/21245
   1745 TEST_F(NavigationControllerTest, PostThenRedirect) {
   1746   NavigationControllerImpl& controller = controller_impl();
   1747   TestNotificationTracker notifications;
   1748   RegisterForAllNavNotifications(&notifications, &controller);
   1749 
   1750   const GURL url1("http://foo1");
   1751   const GURL url2("http://foo2");  // Redirection target
   1752 
   1753   // First request as POST
   1754   controller.LoadURL(
   1755       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1756   controller.GetVisibleEntry()->SetHasPostData(true);
   1757 
   1758   EXPECT_EQ(0U, notifications.size());
   1759   main_test_rfh()->SendNavigate(0, url2);
   1760   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1761   navigation_entry_committed_counter_ = 0;
   1762 
   1763   // Second request
   1764   controller.LoadURL(
   1765       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1766 
   1767   EXPECT_TRUE(controller.GetPendingEntry());
   1768   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1769   EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
   1770 
   1771   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   1772   params.page_id = 0;
   1773   params.url = url2;
   1774   params.transition = ui::PAGE_TRANSITION_SERVER_REDIRECT;
   1775   params.redirects.push_back(GURL("http://foo1"));
   1776   params.redirects.push_back(GURL("http://foo2"));
   1777   params.should_update_history = false;
   1778   params.gesture = NavigationGestureAuto;
   1779   params.is_post = false;
   1780   params.page_state = PageState::CreateFromURL(url2);
   1781 
   1782   LoadCommittedDetails details;
   1783 
   1784   EXPECT_EQ(0U, notifications.size());
   1785   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   1786                                              &details));
   1787   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1788   navigation_entry_committed_counter_ = 0;
   1789 
   1790   EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
   1791   EXPECT_EQ(controller.GetEntryCount(), 1);
   1792   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1793   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1794   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1795   EXPECT_FALSE(controller.GetPendingEntry());
   1796   EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
   1797   EXPECT_FALSE(controller.GetVisibleEntry()->GetHasPostData());
   1798 
   1799   EXPECT_FALSE(controller.CanGoBack());
   1800   EXPECT_FALSE(controller.CanGoForward());
   1801 }
   1802 
   1803 // A redirect right off the bat should be a NEW_PAGE.
   1804 TEST_F(NavigationControllerTest, ImmediateRedirect) {
   1805   NavigationControllerImpl& controller = controller_impl();
   1806   TestNotificationTracker notifications;
   1807   RegisterForAllNavNotifications(&notifications, &controller);
   1808 
   1809   const GURL url1("http://foo1");
   1810   const GURL url2("http://foo2");  // Redirection target
   1811 
   1812   // First request
   1813   controller.LoadURL(
   1814       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   1815 
   1816   EXPECT_TRUE(controller.GetPendingEntry());
   1817   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1818   EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
   1819 
   1820   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   1821   params.page_id = 0;
   1822   params.url = url2;
   1823   params.transition = ui::PAGE_TRANSITION_SERVER_REDIRECT;
   1824   params.redirects.push_back(GURL("http://foo1"));
   1825   params.redirects.push_back(GURL("http://foo2"));
   1826   params.should_update_history = false;
   1827   params.gesture = NavigationGestureAuto;
   1828   params.is_post = false;
   1829   params.page_state = PageState::CreateFromURL(url2);
   1830 
   1831   LoadCommittedDetails details;
   1832 
   1833   EXPECT_EQ(0U, notifications.size());
   1834   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   1835                                              &details));
   1836   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1837   navigation_entry_committed_counter_ = 0;
   1838 
   1839   EXPECT_TRUE(details.type == NAVIGATION_TYPE_NEW_PAGE);
   1840   EXPECT_EQ(controller.GetEntryCount(), 1);
   1841   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   1842   EXPECT_TRUE(controller.GetLastCommittedEntry());
   1843   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   1844   EXPECT_FALSE(controller.GetPendingEntry());
   1845   EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
   1846 
   1847   EXPECT_FALSE(controller.CanGoBack());
   1848   EXPECT_FALSE(controller.CanGoForward());
   1849 }
   1850 
   1851 // Tests navigation via link click within a subframe. A new navigation entry
   1852 // should be created.
   1853 TEST_F(NavigationControllerTest, NewSubframe) {
   1854   NavigationControllerImpl& controller = controller_impl();
   1855   TestNotificationTracker notifications;
   1856   RegisterForAllNavNotifications(&notifications, &controller);
   1857 
   1858   const GURL url1("http://foo1");
   1859   main_test_rfh()->SendNavigate(0, url1);
   1860   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1861   navigation_entry_committed_counter_ = 0;
   1862 
   1863   const GURL url2("http://foo2");
   1864   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   1865   params.page_id = 1;
   1866   params.url = url2;
   1867   params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
   1868   params.should_update_history = false;
   1869   params.gesture = NavigationGestureUser;
   1870   params.is_post = false;
   1871   params.page_state = PageState::CreateFromURL(url2);
   1872 
   1873   LoadCommittedDetails details;
   1874   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   1875                                              &details));
   1876   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1877   navigation_entry_committed_counter_ = 0;
   1878   EXPECT_EQ(url1, details.previous_url);
   1879   EXPECT_FALSE(details.is_in_page);
   1880   EXPECT_FALSE(details.is_main_frame);
   1881 
   1882   // The new entry should be appended.
   1883   EXPECT_EQ(2, controller.GetEntryCount());
   1884 
   1885   // New entry should refer to the new page, but the old URL (entries only
   1886   // reflect the toplevel URL).
   1887   EXPECT_EQ(url1, details.entry->GetURL());
   1888   EXPECT_EQ(params.page_id, details.entry->GetPageID());
   1889 }
   1890 
   1891 // Some pages create a popup, then write an iframe into it. This causes a
   1892 // subframe navigation without having any committed entry. Such navigations
   1893 // just get thrown on the ground, but we shouldn't crash.
   1894 TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
   1895   NavigationControllerImpl& controller = controller_impl();
   1896   TestNotificationTracker notifications;
   1897   RegisterForAllNavNotifications(&notifications, &controller);
   1898 
   1899   // Navigation controller currently has no entries.
   1900   const GURL url("http://foo2");
   1901   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   1902   params.page_id = 1;
   1903   params.url = url;
   1904   params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
   1905   params.should_update_history = false;
   1906   params.gesture = NavigationGestureAuto;
   1907   params.is_post = false;
   1908   params.page_state = PageState::CreateFromURL(url);
   1909 
   1910   LoadCommittedDetails details;
   1911   EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
   1912                                               &details));
   1913   EXPECT_EQ(0U, notifications.size());
   1914 }
   1915 
   1916 // Auto subframes are ones the page loads automatically like ads. They should
   1917 // not create new navigation entries.
   1918 TEST_F(NavigationControllerTest, AutoSubframe) {
   1919   NavigationControllerImpl& controller = controller_impl();
   1920   TestNotificationTracker notifications;
   1921   RegisterForAllNavNotifications(&notifications, &controller);
   1922 
   1923   const GURL url1("http://foo1");
   1924   main_test_rfh()->SendNavigate(0, url1);
   1925   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1926   navigation_entry_committed_counter_ = 0;
   1927 
   1928   const GURL url2("http://foo2");
   1929   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   1930   params.page_id = 0;
   1931   params.url = url2;
   1932   params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
   1933   params.should_update_history = false;
   1934   params.gesture = NavigationGestureUser;
   1935   params.is_post = false;
   1936   params.page_state = PageState::CreateFromURL(url2);
   1937 
   1938   // Navigating should do nothing.
   1939   LoadCommittedDetails details;
   1940   EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
   1941                                               &details));
   1942   EXPECT_EQ(0U, notifications.size());
   1943 
   1944   // There should still be only one entry.
   1945   EXPECT_EQ(1, controller.GetEntryCount());
   1946 }
   1947 
   1948 // Tests navigation and then going back to a subframe navigation.
   1949 TEST_F(NavigationControllerTest, BackSubframe) {
   1950   NavigationControllerImpl& controller = controller_impl();
   1951   TestNotificationTracker notifications;
   1952   RegisterForAllNavNotifications(&notifications, &controller);
   1953 
   1954   // Main page.
   1955   const GURL url1("http://foo1");
   1956   main_test_rfh()->SendNavigate(0, url1);
   1957   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1958   navigation_entry_committed_counter_ = 0;
   1959 
   1960   // First manual subframe navigation.
   1961   const GURL url2("http://foo2");
   1962   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   1963   params.page_id = 1;
   1964   params.url = url2;
   1965   params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
   1966   params.should_update_history = false;
   1967   params.gesture = NavigationGestureUser;
   1968   params.is_post = false;
   1969   params.page_state = PageState::CreateFromURL(url2);
   1970 
   1971   // This should generate a new entry.
   1972   LoadCommittedDetails details;
   1973   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   1974                                              &details));
   1975   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1976   navigation_entry_committed_counter_ = 0;
   1977   EXPECT_EQ(2, controller.GetEntryCount());
   1978 
   1979   // Second manual subframe navigation should also make a new entry.
   1980   const GURL url3("http://foo3");
   1981   params.page_id = 2;
   1982   params.url = url3;
   1983   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   1984                                              &details));
   1985   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1986   navigation_entry_committed_counter_ = 0;
   1987   EXPECT_EQ(3, controller.GetEntryCount());
   1988   EXPECT_EQ(2, controller.GetCurrentEntryIndex());
   1989 
   1990   // Go back one.
   1991   controller.GoBack();
   1992   params.url = url2;
   1993   params.page_id = 1;
   1994   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   1995                                              &details));
   1996   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   1997   navigation_entry_committed_counter_ = 0;
   1998   EXPECT_EQ(3, controller.GetEntryCount());
   1999   EXPECT_EQ(1, controller.GetCurrentEntryIndex());
   2000   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   2001   EXPECT_FALSE(controller.GetPendingEntry());
   2002 
   2003   // Go back one more.
   2004   controller.GoBack();
   2005   params.url = url1;
   2006   params.page_id = 0;
   2007   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   2008                                              &details));
   2009   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2010   navigation_entry_committed_counter_ = 0;
   2011   EXPECT_EQ(3, controller.GetEntryCount());
   2012   EXPECT_EQ(0, controller.GetCurrentEntryIndex());
   2013   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   2014   EXPECT_FALSE(controller.GetPendingEntry());
   2015 }
   2016 
   2017 TEST_F(NavigationControllerTest, LinkClick) {
   2018   NavigationControllerImpl& controller = controller_impl();
   2019   TestNotificationTracker notifications;
   2020   RegisterForAllNavNotifications(&notifications, &controller);
   2021 
   2022   const GURL url1("http://foo1");
   2023   const GURL url2("http://foo2");
   2024 
   2025   main_test_rfh()->SendNavigate(0, url1);
   2026   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2027   navigation_entry_committed_counter_ = 0;
   2028 
   2029   main_test_rfh()->SendNavigate(1, url2);
   2030   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2031   navigation_entry_committed_counter_ = 0;
   2032 
   2033   // Should not have produced a new session history entry.
   2034   EXPECT_EQ(controller.GetEntryCount(), 2);
   2035   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
   2036   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   2037   EXPECT_TRUE(controller.GetLastCommittedEntry());
   2038   EXPECT_FALSE(controller.GetPendingEntry());
   2039   EXPECT_TRUE(controller.CanGoBack());
   2040   EXPECT_FALSE(controller.CanGoForward());
   2041 }
   2042 
   2043 TEST_F(NavigationControllerTest, InPage) {
   2044   NavigationControllerImpl& controller = controller_impl();
   2045   TestNotificationTracker notifications;
   2046   RegisterForAllNavNotifications(&notifications, &controller);
   2047 
   2048   // Main page.
   2049   const GURL url1("http://foo");
   2050   main_test_rfh()->SendNavigate(0, url1);
   2051   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2052   navigation_entry_committed_counter_ = 0;
   2053 
   2054   // Ensure main page navigation to same url respects the was_within_same_page
   2055   // hint provided in the params.
   2056   FrameHostMsg_DidCommitProvisionalLoad_Params self_params;
   2057   self_params.page_id = 0;
   2058   self_params.url = url1;
   2059   self_params.transition = ui::PAGE_TRANSITION_LINK;
   2060   self_params.should_update_history = false;
   2061   self_params.gesture = NavigationGestureUser;
   2062   self_params.is_post = false;
   2063   self_params.page_state = PageState::CreateFromURL(url1);
   2064   self_params.was_within_same_page = true;
   2065 
   2066   LoadCommittedDetails details;
   2067   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), self_params,
   2068                                              &details));
   2069   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2070   navigation_entry_committed_counter_ = 0;
   2071   EXPECT_TRUE(details.is_in_page);
   2072   EXPECT_TRUE(details.did_replace_entry);
   2073   EXPECT_EQ(1, controller.GetEntryCount());
   2074 
   2075   // Fragment navigation to a new page_id.
   2076   const GURL url2("http://foo#a");
   2077   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   2078   params.page_id = 1;
   2079   params.url = url2;
   2080   params.transition = ui::PAGE_TRANSITION_LINK;
   2081   params.should_update_history = false;
   2082   params.gesture = NavigationGestureUser;
   2083   params.is_post = false;
   2084   params.page_state = PageState::CreateFromURL(url2);
   2085   params.was_within_same_page = true;
   2086 
   2087   // This should generate a new entry.
   2088   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   2089                                              &details));
   2090   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2091   navigation_entry_committed_counter_ = 0;
   2092   EXPECT_TRUE(details.is_in_page);
   2093   EXPECT_FALSE(details.did_replace_entry);
   2094   EXPECT_EQ(2, controller.GetEntryCount());
   2095 
   2096   // Go back one.
   2097   FrameHostMsg_DidCommitProvisionalLoad_Params back_params(params);
   2098   controller.GoBack();
   2099   back_params.url = url1;
   2100   back_params.page_id = 0;
   2101   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), back_params,
   2102                                              &details));
   2103   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2104   navigation_entry_committed_counter_ = 0;
   2105   EXPECT_TRUE(details.is_in_page);
   2106   EXPECT_EQ(2, controller.GetEntryCount());
   2107   EXPECT_EQ(0, controller.GetCurrentEntryIndex());
   2108   EXPECT_EQ(back_params.url, controller.GetVisibleEntry()->GetURL());
   2109 
   2110   // Go forward
   2111   FrameHostMsg_DidCommitProvisionalLoad_Params forward_params(params);
   2112   controller.GoForward();
   2113   forward_params.url = url2;
   2114   forward_params.page_id = 1;
   2115   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), forward_params,
   2116                                              &details));
   2117   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2118   navigation_entry_committed_counter_ = 0;
   2119   EXPECT_TRUE(details.is_in_page);
   2120   EXPECT_EQ(2, controller.GetEntryCount());
   2121   EXPECT_EQ(1, controller.GetCurrentEntryIndex());
   2122   EXPECT_EQ(forward_params.url,
   2123             controller.GetVisibleEntry()->GetURL());
   2124 
   2125   // Now go back and forward again. This is to work around a bug where we would
   2126   // compare the incoming URL with the last committed entry rather than the
   2127   // one identified by an existing page ID. This would result in the second URL
   2128   // losing the reference fragment when you navigate away from it and then back.
   2129   controller.GoBack();
   2130   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), back_params,
   2131                                              &details));
   2132   controller.GoForward();
   2133   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), forward_params,
   2134                                              &details));
   2135   EXPECT_EQ(forward_params.url,
   2136             controller.GetVisibleEntry()->GetURL());
   2137 
   2138   // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
   2139   const GURL url3("http://bar");
   2140   params.page_id = 2;
   2141   params.url = url3;
   2142   navigation_entry_committed_counter_ = 0;
   2143   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   2144                                              &details));
   2145   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2146   navigation_entry_committed_counter_ = 0;
   2147   EXPECT_FALSE(details.is_in_page);
   2148   EXPECT_EQ(3, controller.GetEntryCount());
   2149   EXPECT_EQ(2, controller.GetCurrentEntryIndex());
   2150 }
   2151 
   2152 TEST_F(NavigationControllerTest, InPage_Replace) {
   2153   NavigationControllerImpl& controller = controller_impl();
   2154   TestNotificationTracker notifications;
   2155   RegisterForAllNavNotifications(&notifications, &controller);
   2156 
   2157   // Main page.
   2158   const GURL url1("http://foo");
   2159   main_test_rfh()->SendNavigate(0, url1);
   2160   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2161   navigation_entry_committed_counter_ = 0;
   2162 
   2163   // First navigation.
   2164   const GURL url2("http://foo#a");
   2165   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   2166   params.page_id = 0;  // Same page_id
   2167   params.url = url2;
   2168   params.transition = ui::PAGE_TRANSITION_LINK;
   2169   params.should_update_history = false;
   2170   params.gesture = NavigationGestureUser;
   2171   params.is_post = false;
   2172   params.page_state = PageState::CreateFromURL(url2);
   2173   params.was_within_same_page = true;
   2174 
   2175   // This should NOT generate a new entry, nor prune the list.
   2176   LoadCommittedDetails details;
   2177   EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   2178                                              &details));
   2179   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2180   navigation_entry_committed_counter_ = 0;
   2181   EXPECT_TRUE(details.is_in_page);
   2182   EXPECT_TRUE(details.did_replace_entry);
   2183   EXPECT_EQ(1, controller.GetEntryCount());
   2184 }
   2185 
   2186 // Tests for http://crbug.com/40395
   2187 // Simulates this:
   2188 //   <script>
   2189 //     window.location.replace("#a");
   2190 //     window.location='http://foo3/';
   2191 //   </script>
   2192 TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
   2193   NavigationControllerImpl& controller = controller_impl();
   2194   TestNotificationTracker notifications;
   2195   RegisterForAllNavNotifications(&notifications, &controller);
   2196 
   2197   // Load an initial page.
   2198   {
   2199     const GURL url("http://foo/");
   2200     main_test_rfh()->SendNavigate(0, url);
   2201     EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2202     navigation_entry_committed_counter_ = 0;
   2203   }
   2204 
   2205   // Navigate to a new page.
   2206   {
   2207     const GURL url("http://foo2/");
   2208     main_test_rfh()->SendNavigate(1, url);
   2209     EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2210     navigation_entry_committed_counter_ = 0;
   2211   }
   2212 
   2213   // Navigate within the page.
   2214   {
   2215     const GURL url("http://foo2/#a");
   2216     FrameHostMsg_DidCommitProvisionalLoad_Params params;
   2217     params.page_id = 1;  // Same page_id
   2218     params.url = url;
   2219     params.transition = ui::PAGE_TRANSITION_LINK;
   2220     params.redirects.push_back(url);
   2221     params.should_update_history = true;
   2222     params.gesture = NavigationGestureUnknown;
   2223     params.is_post = false;
   2224     params.page_state = PageState::CreateFromURL(url);
   2225     params.was_within_same_page = true;
   2226 
   2227     // This should NOT generate a new entry, nor prune the list.
   2228     LoadCommittedDetails details;
   2229     EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   2230                                                &details));
   2231     EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2232     navigation_entry_committed_counter_ = 0;
   2233     EXPECT_TRUE(details.is_in_page);
   2234     EXPECT_TRUE(details.did_replace_entry);
   2235     EXPECT_EQ(2, controller.GetEntryCount());
   2236   }
   2237 
   2238   // Perform a client redirect to a new page.
   2239   {
   2240     const GURL url("http://foo3/");
   2241     FrameHostMsg_DidCommitProvisionalLoad_Params params;
   2242     params.page_id = 2;  // New page_id
   2243     params.url = url;
   2244     params.transition = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
   2245     params.redirects.push_back(GURL("http://foo2/#a"));
   2246     params.redirects.push_back(url);
   2247     params.should_update_history = true;
   2248     params.gesture = NavigationGestureUnknown;
   2249     params.is_post = false;
   2250     params.page_state = PageState::CreateFromURL(url);
   2251 
   2252     // This SHOULD generate a new entry.
   2253     LoadCommittedDetails details;
   2254     EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
   2255                                                &details));
   2256     EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2257     navigation_entry_committed_counter_ = 0;
   2258     EXPECT_FALSE(details.is_in_page);
   2259     EXPECT_EQ(3, controller.GetEntryCount());
   2260   }
   2261 
   2262   // Verify that BACK brings us back to http://foo2/.
   2263   {
   2264     const GURL url("http://foo2/");
   2265     controller.GoBack();
   2266     main_test_rfh()->SendNavigate(1, url);
   2267     EXPECT_EQ(1U, navigation_entry_committed_counter_);
   2268     navigation_entry_committed_counter_ = 0;
   2269     EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
   2270   }
   2271 }
   2272 
   2273 TEST_F(NavigationControllerTest, PushStateWithoutPreviousEntry)
   2274 {
   2275   ASSERT_FALSE(controller_impl().GetLastCommittedEntry());
   2276   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   2277   GURL url("http://foo");
   2278   params.page_id = 1;
   2279   params.url = url;
   2280   params.page_state = PageState::CreateFromURL(url);
   2281   params.was_within_same_page = true;
   2282   test_rvh()->SendNavigateWithParams(&params);
   2283   // We pass if we don't crash.
   2284 }
   2285 
   2286 // NotificationObserver implementation used in verifying we've received the
   2287 // NOTIFICATION_NAV_LIST_PRUNED method.
   2288 class PrunedListener : public NotificationObserver {
   2289  public:
   2290   explicit PrunedListener(NavigationControllerImpl* controller)
   2291       : notification_count_(0) {
   2292     registrar_.Add(this, NOTIFICATION_NAV_LIST_PRUNED,
   2293                    Source<NavigationController>(controller));
   2294   }
   2295 
   2296   virtual void Observe(int type,
   2297                        const NotificationSource& source,
   2298                        const NotificationDetails& details) OVERRIDE {
   2299     if (type == NOTIFICATION_NAV_LIST_PRUNED) {
   2300       notification_count_++;
   2301       details_ = *(Details<PrunedDetails>(details).ptr());
   2302     }
   2303   }
   2304 
   2305   // Number of times NAV_LIST_PRUNED has been observed.
   2306   int notification_count_;
   2307 
   2308   // Details from the last NAV_LIST_PRUNED.
   2309   PrunedDetails details_;
   2310 
   2311  private:
   2312   NotificationRegistrar registrar_;
   2313 
   2314   DISALLOW_COPY_AND_ASSIGN(PrunedListener);
   2315 };
   2316 
   2317 // Tests that we limit the number of navigation entries created correctly.
   2318 TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
   2319   NavigationControllerImpl& controller = controller_impl();
   2320   size_t original_count = NavigationControllerImpl::max_entry_count();
   2321   const int kMaxEntryCount = 5;
   2322 
   2323   NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
   2324 
   2325   int url_index;
   2326   // Load up to the max count, all entries should be there.
   2327   for (url_index = 0; url_index < kMaxEntryCount; url_index++) {
   2328     GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
   2329     controller.LoadURL(
   2330         url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2331     main_test_rfh()->SendNavigate(url_index, url);
   2332   }
   2333 
   2334   EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
   2335 
   2336   // Created a PrunedListener to observe prune notifications.
   2337   PrunedListener listener(&controller);
   2338 
   2339   // Navigate some more.
   2340   GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
   2341   controller.LoadURL(
   2342       url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2343   main_test_rfh()->SendNavigate(url_index, url);
   2344   url_index++;
   2345 
   2346   // We should have got a pruned navigation.
   2347   EXPECT_EQ(1, listener.notification_count_);
   2348   EXPECT_TRUE(listener.details_.from_front);
   2349   EXPECT_EQ(1, listener.details_.count);
   2350 
   2351   // We expect http://www.a.com/0 to be gone.
   2352   EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
   2353   EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
   2354             GURL("http:////www.a.com/1"));
   2355 
   2356   // More navigations.
   2357   for (int i = 0; i < 3; i++) {
   2358     url = GURL(base::StringPrintf("http:////www.a.com/%d", url_index));
   2359     controller.LoadURL(
   2360         url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2361     main_test_rfh()->SendNavigate(url_index, url);
   2362     url_index++;
   2363   }
   2364   EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
   2365   EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
   2366             GURL("http:////www.a.com/4"));
   2367 
   2368   NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
   2369 }
   2370 
   2371 // Tests that we can do a restore and navigate to the restored entries and
   2372 // everything is updated properly. This can be tricky since there is no
   2373 // SiteInstance for the entries created initially.
   2374 TEST_F(NavigationControllerTest, RestoreNavigate) {
   2375   // Create a NavigationController with a restored set of tabs.
   2376   GURL url("http://foo");
   2377   std::vector<NavigationEntry*> entries;
   2378   NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
   2379       url, Referrer(), ui::PAGE_TRANSITION_RELOAD, false, std::string(),
   2380       browser_context());
   2381   entry->SetPageID(0);
   2382   entry->SetTitle(base::ASCIIToUTF16("Title"));
   2383   entry->SetPageState(PageState::CreateFromEncodedData("state"));
   2384   const base::Time timestamp = base::Time::Now();
   2385   entry->SetTimestamp(timestamp);
   2386   entries.push_back(entry);
   2387   scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
   2388       WebContents::Create(WebContents::CreateParams(browser_context()))));
   2389   NavigationControllerImpl& our_controller = our_contents->GetController();
   2390   our_controller.Restore(
   2391       0,
   2392       NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
   2393       &entries);
   2394   ASSERT_EQ(0u, entries.size());
   2395 
   2396   // Before navigating to the restored entry, it should have a restore_type
   2397   // and no SiteInstance.
   2398   ASSERT_EQ(1, our_controller.GetEntryCount());
   2399   EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
   2400             NavigationEntryImpl::FromNavigationEntry(
   2401                 our_controller.GetEntryAtIndex(0))->restore_type());
   2402   EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
   2403       our_controller.GetEntryAtIndex(0))->site_instance());
   2404 
   2405   // After navigating, we should have one entry, and it should be "pending".
   2406   // It should now have a SiteInstance and no restore_type.
   2407   our_controller.GoToIndex(0);
   2408   EXPECT_EQ(1, our_controller.GetEntryCount());
   2409   EXPECT_EQ(our_controller.GetEntryAtIndex(0),
   2410             our_controller.GetPendingEntry());
   2411   EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
   2412   EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
   2413             NavigationEntryImpl::FromNavigationEntry
   2414                 (our_controller.GetEntryAtIndex(0))->restore_type());
   2415   EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
   2416       our_controller.GetEntryAtIndex(0))->site_instance());
   2417 
   2418   // Timestamp should remain the same before the navigation finishes.
   2419   EXPECT_EQ(timestamp, our_controller.GetEntryAtIndex(0)->GetTimestamp());
   2420 
   2421   // Say we navigated to that entry.
   2422   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   2423   params.page_id = 0;
   2424   params.url = url;
   2425   params.transition = ui::PAGE_TRANSITION_LINK;
   2426   params.should_update_history = false;
   2427   params.gesture = NavigationGestureUser;
   2428   params.is_post = false;
   2429   params.page_state = PageState::CreateFromURL(url);
   2430   LoadCommittedDetails details;
   2431   our_controller.RendererDidNavigate(our_contents->GetMainFrame(), params,
   2432                                      &details);
   2433 
   2434   // There should be no longer any pending entry and one committed one. This
   2435   // means that we were able to locate the entry, assign its site instance, and
   2436   // commit it properly.
   2437   EXPECT_EQ(1, our_controller.GetEntryCount());
   2438   EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
   2439   EXPECT_FALSE(our_controller.GetPendingEntry());
   2440   EXPECT_EQ(url,
   2441             NavigationEntryImpl::FromNavigationEntry(
   2442                 our_controller.GetLastCommittedEntry())->site_instance()->
   2443                     GetSiteURL());
   2444   EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
   2445             NavigationEntryImpl::FromNavigationEntry(
   2446                 our_controller.GetEntryAtIndex(0))->restore_type());
   2447 
   2448   // Timestamp should have been updated.
   2449   EXPECT_GE(our_controller.GetEntryAtIndex(0)->GetTimestamp(), timestamp);
   2450 }
   2451 
   2452 // Tests that we can still navigate to a restored entry after a different
   2453 // navigation fails and clears the pending entry.  http://crbug.com/90085
   2454 TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
   2455   // Create a NavigationController with a restored set of tabs.
   2456   GURL url("http://foo");
   2457   std::vector<NavigationEntry*> entries;
   2458   NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
   2459       url, Referrer(), ui::PAGE_TRANSITION_RELOAD, false, std::string(),
   2460       browser_context());
   2461   entry->SetPageID(0);
   2462   entry->SetTitle(base::ASCIIToUTF16("Title"));
   2463   entry->SetPageState(PageState::CreateFromEncodedData("state"));
   2464   entries.push_back(entry);
   2465   scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
   2466       WebContents::Create(WebContents::CreateParams(browser_context()))));
   2467   NavigationControllerImpl& our_controller = our_contents->GetController();
   2468   our_controller.Restore(
   2469       0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, &entries);
   2470   ASSERT_EQ(0u, entries.size());
   2471 
   2472   // Before navigating to the restored entry, it should have a restore_type
   2473   // and no SiteInstance.
   2474   EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
   2475             NavigationEntryImpl::FromNavigationEntry(
   2476                 our_controller.GetEntryAtIndex(0))->restore_type());
   2477   EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
   2478       our_controller.GetEntryAtIndex(0))->site_instance());
   2479 
   2480   // After navigating, we should have one entry, and it should be "pending".
   2481   // It should now have a SiteInstance and no restore_type.
   2482   our_controller.GoToIndex(0);
   2483   EXPECT_EQ(1, our_controller.GetEntryCount());
   2484   EXPECT_EQ(our_controller.GetEntryAtIndex(0),
   2485             our_controller.GetPendingEntry());
   2486   EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
   2487   EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
   2488             NavigationEntryImpl::FromNavigationEntry(
   2489                 our_controller.GetEntryAtIndex(0))->restore_type());
   2490   EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
   2491       our_controller.GetEntryAtIndex(0))->site_instance());
   2492 
   2493   // This pending navigation may have caused a different navigation to fail,
   2494   // which causes the pending entry to be cleared.
   2495   FrameHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params;
   2496   fail_load_params.error_code = net::ERR_ABORTED;
   2497   fail_load_params.error_description = base::string16();
   2498   fail_load_params.url = url;
   2499   fail_load_params.showing_repost_interstitial = false;
   2500   main_test_rfh()->OnMessageReceived(
   2501       FrameHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
   2502                                                   fail_load_params));
   2503 
   2504   // Now the pending restored entry commits.
   2505   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   2506   params.page_id = 0;
   2507   params.url = url;
   2508   params.transition = ui::PAGE_TRANSITION_LINK;
   2509   params.should_update_history = false;
   2510   params.gesture = NavigationGestureUser;
   2511   params.is_post = false;
   2512   params.page_state = PageState::CreateFromURL(url);
   2513   LoadCommittedDetails details;
   2514   our_controller.RendererDidNavigate(our_contents->GetMainFrame(), params,
   2515                                      &details);
   2516 
   2517   // There should be no pending entry and one committed one.
   2518   EXPECT_EQ(1, our_controller.GetEntryCount());
   2519   EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
   2520   EXPECT_FALSE(our_controller.GetPendingEntry());
   2521   EXPECT_EQ(url,
   2522             NavigationEntryImpl::FromNavigationEntry(
   2523                 our_controller.GetLastCommittedEntry())->site_instance()->
   2524                     GetSiteURL());
   2525   EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
   2526             NavigationEntryImpl::FromNavigationEntry(
   2527                 our_controller.GetEntryAtIndex(0))->restore_type());
   2528 }
   2529 
   2530 // Make sure that the page type and stuff is correct after an interstitial.
   2531 TEST_F(NavigationControllerTest, Interstitial) {
   2532   NavigationControllerImpl& controller = controller_impl();
   2533   // First navigate somewhere normal.
   2534   const GURL url1("http://foo");
   2535   controller.LoadURL(
   2536       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2537   main_test_rfh()->SendNavigate(0, url1);
   2538 
   2539   // Now navigate somewhere with an interstitial.
   2540   const GURL url2("http://bar");
   2541   controller.LoadURL(
   2542       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2543   NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
   2544       set_page_type(PAGE_TYPE_INTERSTITIAL);
   2545 
   2546   // At this point the interstitial will be displayed and the load will still
   2547   // be pending. If the user continues, the load will commit.
   2548   main_test_rfh()->SendNavigate(1, url2);
   2549 
   2550   // The page should be a normal page again.
   2551   EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
   2552   EXPECT_EQ(PAGE_TYPE_NORMAL,
   2553             controller.GetLastCommittedEntry()->GetPageType());
   2554 }
   2555 
   2556 TEST_F(NavigationControllerTest, RemoveEntry) {
   2557   NavigationControllerImpl& controller = controller_impl();
   2558   const GURL url1("http://foo/1");
   2559   const GURL url2("http://foo/2");
   2560   const GURL url3("http://foo/3");
   2561   const GURL url4("http://foo/4");
   2562   const GURL url5("http://foo/5");
   2563   const GURL pending_url("http://foo/pending");
   2564   const GURL default_url("http://foo/default");
   2565 
   2566   controller.LoadURL(
   2567       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2568   main_test_rfh()->SendNavigate(0, url1);
   2569   controller.LoadURL(
   2570       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2571   main_test_rfh()->SendNavigate(1, url2);
   2572   controller.LoadURL(
   2573       url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2574   main_test_rfh()->SendNavigate(2, url3);
   2575   controller.LoadURL(
   2576       url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2577   main_test_rfh()->SendNavigate(3, url4);
   2578   controller.LoadURL(
   2579       url5, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2580   main_test_rfh()->SendNavigate(4, url5);
   2581 
   2582   // Try to remove the last entry.  Will fail because it is the current entry.
   2583   EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
   2584   EXPECT_EQ(5, controller.GetEntryCount());
   2585   EXPECT_EQ(4, controller.GetLastCommittedEntryIndex());
   2586 
   2587   // Go back, but don't commit yet. Check that we can't delete the current
   2588   // and pending entries.
   2589   controller.GoBack();
   2590   EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
   2591   EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 2));
   2592 
   2593   // Now commit and delete the last entry.
   2594   main_test_rfh()->SendNavigate(3, url4);
   2595   EXPECT_TRUE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
   2596   EXPECT_EQ(4, controller.GetEntryCount());
   2597   EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
   2598   EXPECT_FALSE(controller.GetPendingEntry());
   2599 
   2600   // Remove an entry which is not the last committed one.
   2601   EXPECT_TRUE(controller.RemoveEntryAtIndex(0));
   2602   EXPECT_EQ(3, controller.GetEntryCount());
   2603   EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
   2604   EXPECT_FALSE(controller.GetPendingEntry());
   2605 
   2606   // Remove the 2 remaining entries.
   2607   controller.RemoveEntryAtIndex(1);
   2608   controller.RemoveEntryAtIndex(0);
   2609 
   2610   // This should leave us with only the last committed entry.
   2611   EXPECT_EQ(1, controller.GetEntryCount());
   2612   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   2613 }
   2614 
   2615 // Tests the transient entry, making sure it goes away with all navigations.
   2616 TEST_F(NavigationControllerTest, TransientEntry) {
   2617   NavigationControllerImpl& controller = controller_impl();
   2618   TestNotificationTracker notifications;
   2619   RegisterForAllNavNotifications(&notifications, &controller);
   2620 
   2621   const GURL url0("http://foo/0");
   2622   const GURL url1("http://foo/1");
   2623   const GURL url2("http://foo/2");
   2624   const GURL url3("http://foo/3");
   2625   const GURL url3_ref("http://foo/3#bar");
   2626   const GURL url4("http://foo/4");
   2627   const GURL transient_url("http://foo/transient");
   2628 
   2629   controller.LoadURL(
   2630       url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2631   main_test_rfh()->SendNavigate(0, url0);
   2632   controller.LoadURL(
   2633       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2634   main_test_rfh()->SendNavigate(1, url1);
   2635 
   2636   notifications.Reset();
   2637 
   2638   // Adding a transient with no pending entry.
   2639   NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
   2640   transient_entry->SetURL(transient_url);
   2641   controller.SetTransientEntry(transient_entry);
   2642 
   2643   // We should not have received any notifications.
   2644   EXPECT_EQ(0U, notifications.size());
   2645 
   2646   // Check our state.
   2647   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2648   EXPECT_EQ(controller.GetEntryCount(), 3);
   2649   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
   2650   EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
   2651   EXPECT_TRUE(controller.GetLastCommittedEntry());
   2652   EXPECT_FALSE(controller.GetPendingEntry());
   2653   EXPECT_TRUE(controller.CanGoBack());
   2654   EXPECT_FALSE(controller.CanGoForward());
   2655   EXPECT_EQ(contents()->GetMaxPageID(), 1);
   2656 
   2657   // Navigate.
   2658   controller.LoadURL(
   2659       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2660   main_test_rfh()->SendNavigate(2, url2);
   2661 
   2662   // We should have navigated, transient entry should be gone.
   2663   EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
   2664   EXPECT_EQ(controller.GetEntryCount(), 3);
   2665 
   2666   // Add a transient again, then navigate with no pending entry this time.
   2667   transient_entry = new NavigationEntryImpl;
   2668   transient_entry->SetURL(transient_url);
   2669   controller.SetTransientEntry(transient_entry);
   2670   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2671   main_test_rfh()->SendNavigate(3, url3);
   2672   // Transient entry should be gone.
   2673   EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
   2674   EXPECT_EQ(controller.GetEntryCount(), 4);
   2675 
   2676   // Initiate a navigation, add a transient then commit navigation.
   2677   controller.LoadURL(
   2678       url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2679   transient_entry = new NavigationEntryImpl;
   2680   transient_entry->SetURL(transient_url);
   2681   controller.SetTransientEntry(transient_entry);
   2682   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2683   main_test_rfh()->SendNavigate(4, url4);
   2684   EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
   2685   EXPECT_EQ(controller.GetEntryCount(), 5);
   2686 
   2687   // Add a transient and go back.  This should simply remove the transient.
   2688   transient_entry = new NavigationEntryImpl;
   2689   transient_entry->SetURL(transient_url);
   2690   controller.SetTransientEntry(transient_entry);
   2691   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2692   EXPECT_TRUE(controller.CanGoBack());
   2693   EXPECT_FALSE(controller.CanGoForward());
   2694   controller.GoBack();
   2695   // Transient entry should be gone.
   2696   EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
   2697   EXPECT_EQ(controller.GetEntryCount(), 5);
   2698   main_test_rfh()->SendNavigate(3, url3);
   2699 
   2700   // Add a transient and go to an entry before the current one.
   2701   transient_entry = new NavigationEntryImpl;
   2702   transient_entry->SetURL(transient_url);
   2703   controller.SetTransientEntry(transient_entry);
   2704   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2705   controller.GoToIndex(1);
   2706   // The navigation should have been initiated, transient entry should be gone.
   2707   EXPECT_FALSE(controller.GetTransientEntry());
   2708   EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
   2709   // Visible entry does not update for history navigations until commit.
   2710   EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
   2711   main_test_rfh()->SendNavigate(1, url1);
   2712   EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
   2713 
   2714   // Add a transient and go to an entry after the current one.
   2715   transient_entry = new NavigationEntryImpl;
   2716   transient_entry->SetURL(transient_url);
   2717   controller.SetTransientEntry(transient_entry);
   2718   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2719   controller.GoToIndex(3);
   2720   // The navigation should have been initiated, transient entry should be gone.
   2721   // Because of the transient entry that is removed, going to index 3 makes us
   2722   // land on url2 (which is visible after the commit).
   2723   EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
   2724   EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
   2725   main_test_rfh()->SendNavigate(2, url2);
   2726   EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
   2727 
   2728   // Add a transient and go forward.
   2729   transient_entry = new NavigationEntryImpl;
   2730   transient_entry->SetURL(transient_url);
   2731   controller.SetTransientEntry(transient_entry);
   2732   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2733   EXPECT_TRUE(controller.CanGoForward());
   2734   controller.GoForward();
   2735   // We should have navigated, transient entry should be gone.
   2736   EXPECT_FALSE(controller.GetTransientEntry());
   2737   EXPECT_EQ(url3, controller.GetPendingEntry()->GetURL());
   2738   EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
   2739   main_test_rfh()->SendNavigate(3, url3);
   2740   EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
   2741 
   2742   // Add a transient and do an in-page navigation, replacing the current entry.
   2743   transient_entry = new NavigationEntryImpl;
   2744   transient_entry->SetURL(transient_url);
   2745   controller.SetTransientEntry(transient_entry);
   2746   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2747   main_test_rfh()->SendNavigate(3, url3_ref);
   2748   // Transient entry should be gone.
   2749   EXPECT_FALSE(controller.GetTransientEntry());
   2750   EXPECT_EQ(url3_ref, controller.GetVisibleEntry()->GetURL());
   2751 
   2752   // Ensure the URLs are correct.
   2753   EXPECT_EQ(controller.GetEntryCount(), 5);
   2754   EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
   2755   EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), url1);
   2756   EXPECT_EQ(controller.GetEntryAtIndex(2)->GetURL(), url2);
   2757   EXPECT_EQ(controller.GetEntryAtIndex(3)->GetURL(), url3_ref);
   2758   EXPECT_EQ(controller.GetEntryAtIndex(4)->GetURL(), url4);
   2759 }
   2760 
   2761 // Test that Reload initiates a new navigation to a transient entry's URL.
   2762 TEST_F(NavigationControllerTest, ReloadTransient) {
   2763   NavigationControllerImpl& controller = controller_impl();
   2764   const GURL url0("http://foo/0");
   2765   const GURL url1("http://foo/1");
   2766   const GURL transient_url("http://foo/transient");
   2767 
   2768   // Load |url0|, and start a pending navigation to |url1|.
   2769   controller.LoadURL(
   2770       url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2771   main_test_rfh()->SendNavigate(0, url0);
   2772   controller.LoadURL(
   2773       url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2774 
   2775   // A transient entry is added, interrupting the navigation.
   2776   NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
   2777   transient_entry->SetURL(transient_url);
   2778   controller.SetTransientEntry(transient_entry);
   2779   EXPECT_TRUE(controller.GetTransientEntry());
   2780   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2781 
   2782   // The page is reloaded, which should remove the pending entry for |url1| and
   2783   // the transient entry for |transient_url|, and start a navigation to
   2784   // |transient_url|.
   2785   controller.Reload(true);
   2786   EXPECT_FALSE(controller.GetTransientEntry());
   2787   EXPECT_TRUE(controller.GetPendingEntry());
   2788   EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
   2789   ASSERT_EQ(controller.GetEntryCount(), 1);
   2790   EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
   2791 
   2792   // Load of |transient_url| completes.
   2793   main_test_rfh()->SendNavigate(1, transient_url);
   2794   ASSERT_EQ(controller.GetEntryCount(), 2);
   2795   EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
   2796   EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), transient_url);
   2797 }
   2798 
   2799 // Ensure that renderer initiated pending entries get replaced, so that we
   2800 // don't show a stale virtual URL when a navigation commits.
   2801 // See http://crbug.com/266922.
   2802 TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
   2803   NavigationControllerImpl& controller = controller_impl();
   2804   Navigator* navigator =
   2805       contents()->GetFrameTree()->root()->navigator();
   2806 
   2807   const GURL url1("nonexistent:12121");
   2808   const GURL url1_fixed("http://nonexistent:12121/");
   2809   const GURL url2("http://foo");
   2810 
   2811   // We create pending entries for renderer-initiated navigations so that we
   2812   // can show them in new tabs when it is safe.
   2813   navigator->DidStartProvisionalLoad(main_test_rfh(), url1, false);
   2814 
   2815   // Simulate what happens if a BrowserURLHandler rewrites the URL, causing
   2816   // the virtual URL to differ from the URL.
   2817   controller.GetPendingEntry()->SetURL(url1_fixed);
   2818   controller.GetPendingEntry()->SetVirtualURL(url1);
   2819 
   2820   EXPECT_EQ(url1_fixed, controller.GetPendingEntry()->GetURL());
   2821   EXPECT_EQ(url1, controller.GetPendingEntry()->GetVirtualURL());
   2822   EXPECT_TRUE(
   2823       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
   2824           is_renderer_initiated());
   2825 
   2826   // If the user clicks another link, we should replace the pending entry.
   2827   navigator->DidStartProvisionalLoad(main_test_rfh(), url2, false);
   2828   EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
   2829   EXPECT_EQ(url2, controller.GetPendingEntry()->GetVirtualURL());
   2830 
   2831   // Once it commits, the URL and virtual URL should reflect the actual page.
   2832   main_test_rfh()->SendNavigate(0, url2);
   2833   EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
   2834   EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetVirtualURL());
   2835 
   2836   // We should not replace the pending entry for an error URL.
   2837   navigator->DidStartProvisionalLoad(main_test_rfh(), url1, false);
   2838   EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
   2839   navigator->DidStartProvisionalLoad(main_test_rfh(),
   2840                                      GURL(kUnreachableWebDataURL), false);
   2841   EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
   2842 
   2843   // We should remember if the pending entry will replace the current one.
   2844   // http://crbug.com/308444.
   2845   navigator->DidStartProvisionalLoad(main_test_rfh(), url1, false);
   2846   NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
   2847       set_should_replace_entry(true);
   2848   navigator->DidStartProvisionalLoad(main_test_rfh(), url2, false);
   2849   EXPECT_TRUE(
   2850       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
   2851           should_replace_entry());
   2852   // TODO(nasko): Until OnNavigate is moved to RenderFrameHost, we need
   2853   // to go through the RenderViewHost. The TestRenderViewHost routes navigations
   2854   // to the main frame.
   2855   main_test_rfh()->SendNavigate(0, url2);
   2856   EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
   2857 }
   2858 
   2859 // Tests that the URLs for renderer-initiated navigations are not displayed to
   2860 // the user until the navigation commits, to prevent URL spoof attacks.
   2861 // See http://crbug.com/99016.
   2862 TEST_F(NavigationControllerTest, DontShowRendererURLUntilCommit) {
   2863   NavigationControllerImpl& controller = controller_impl();
   2864   TestNotificationTracker notifications;
   2865   RegisterForAllNavNotifications(&notifications, &controller);
   2866 
   2867   const GURL url0("http://foo/0");
   2868   const GURL url1("http://foo/1");
   2869 
   2870   // For typed navigations (browser-initiated), both pending and visible entries
   2871   // should update before commit.
   2872   controller.LoadURL(
   2873       url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   2874   EXPECT_EQ(url0, controller.GetPendingEntry()->GetURL());
   2875   EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
   2876   main_test_rfh()->SendNavigate(0, url0);
   2877 
   2878   // For link clicks (renderer-initiated navigations), the pending entry should
   2879   // update before commit but the visible should not.
   2880   NavigationController::LoadURLParams load_url_params(url1);
   2881   load_url_params.is_renderer_initiated = true;
   2882   controller.LoadURLWithParams(load_url_params);
   2883   EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
   2884   EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
   2885   EXPECT_TRUE(
   2886       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
   2887           is_renderer_initiated());
   2888 
   2889   // After commit, both visible should be updated, there should be no pending
   2890   // entry, and we should no longer treat the entry as renderer-initiated.
   2891   main_test_rfh()->SendNavigate(1, url1);
   2892   EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
   2893   EXPECT_FALSE(controller.GetPendingEntry());
   2894   EXPECT_FALSE(
   2895       NavigationEntryImpl::FromNavigationEntry(
   2896           controller.GetLastCommittedEntry())->is_renderer_initiated());
   2897 
   2898   notifications.Reset();
   2899 }
   2900 
   2901 // Tests that the URLs for renderer-initiated navigations in new tabs are
   2902 // displayed to the user before commit, as long as the initial about:blank
   2903 // page has not been modified.  If so, we must revert to showing about:blank.
   2904 // See http://crbug.com/9682.
   2905 TEST_F(NavigationControllerTest, ShowRendererURLInNewTabUntilModified) {
   2906   NavigationControllerImpl& controller = controller_impl();
   2907   TestNotificationTracker notifications;
   2908   RegisterForAllNavNotifications(&notifications, &controller);
   2909 
   2910   const GURL url("http://foo");
   2911 
   2912   // For renderer-initiated navigations in new tabs (with no committed entries),
   2913   // we show the pending entry's URL as long as the about:blank page is not
   2914   // modified.
   2915   NavigationController::LoadURLParams load_url_params(url);
   2916   load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
   2917   load_url_params.is_renderer_initiated = true;
   2918   controller.LoadURLWithParams(load_url_params);
   2919   EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
   2920   EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
   2921   EXPECT_TRUE(
   2922       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
   2923           is_renderer_initiated());
   2924   EXPECT_TRUE(controller.IsInitialNavigation());
   2925   EXPECT_FALSE(contents()->HasAccessedInitialDocument());
   2926 
   2927   // There should be no title yet.
   2928   EXPECT_TRUE(contents()->GetTitle().empty());
   2929 
   2930   // If something else modifies the contents of the about:blank page, then
   2931   // we must revert to showing about:blank to avoid a URL spoof.
   2932   main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
   2933   EXPECT_TRUE(contents()->HasAccessedInitialDocument());
   2934   EXPECT_FALSE(controller.GetVisibleEntry());
   2935   EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
   2936 
   2937   notifications.Reset();
   2938 }
   2939 
   2940 // Tests that the URLs for browser-initiated navigations in new tabs are
   2941 // displayed to the user even after they fail, as long as the initial
   2942 // about:blank page has not been modified.  If so, we must revert to showing
   2943 // about:blank. See http://crbug.com/355537.
   2944 TEST_F(NavigationControllerTest, ShowBrowserURLAfterFailUntilModified) {
   2945   NavigationControllerImpl& controller = controller_impl();
   2946   TestNotificationTracker notifications;
   2947   RegisterForAllNavNotifications(&notifications, &controller);
   2948 
   2949   const GURL url("http://foo");
   2950 
   2951   // For browser-initiated navigations in new tabs (with no committed entries),
   2952   // we show the pending entry's URL as long as the about:blank page is not
   2953   // modified.  This is possible in cases that the user types a URL into a popup
   2954   // tab created with a slow URL.
   2955   NavigationController::LoadURLParams load_url_params(url);
   2956   load_url_params.transition_type = ui::PAGE_TRANSITION_TYPED;
   2957   load_url_params.is_renderer_initiated = false;
   2958   controller.LoadURLWithParams(load_url_params);
   2959   EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
   2960   EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
   2961   EXPECT_FALSE(
   2962       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
   2963           is_renderer_initiated());
   2964   EXPECT_TRUE(controller.IsInitialNavigation());
   2965   EXPECT_FALSE(contents()->HasAccessedInitialDocument());
   2966 
   2967   // There should be no title yet.
   2968   EXPECT_TRUE(contents()->GetTitle().empty());
   2969 
   2970   // Suppose it aborts before committing, if it's a 204 or download or due to a
   2971   // stop or a new navigation from the user.  The URL should remain visible.
   2972   FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
   2973   params.error_code = net::ERR_ABORTED;
   2974   params.error_description = base::string16();
   2975   params.url = url;
   2976   params.showing_repost_interstitial = false;
   2977   main_test_rfh()->OnMessageReceived(
   2978       FrameHostMsg_DidFailProvisionalLoadWithError(0, params));
   2979   contents()->SetIsLoading(test_rvh(), false, true, NULL);
   2980   EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
   2981 
   2982   // If something else later modifies the contents of the about:blank page, then
   2983   // we must revert to showing about:blank to avoid a URL spoof.
   2984   main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
   2985   EXPECT_TRUE(contents()->HasAccessedInitialDocument());
   2986   EXPECT_FALSE(controller.GetVisibleEntry());
   2987   EXPECT_FALSE(controller.GetPendingEntry());
   2988 
   2989   notifications.Reset();
   2990 }
   2991 
   2992 // Tests that the URLs for renderer-initiated navigations in new tabs are
   2993 // displayed to the user even after they fail, as long as the initial
   2994 // about:blank page has not been modified.  If so, we must revert to showing
   2995 // about:blank. See http://crbug.com/355537.
   2996 TEST_F(NavigationControllerTest, ShowRendererURLAfterFailUntilModified) {
   2997   NavigationControllerImpl& controller = controller_impl();
   2998   TestNotificationTracker notifications;
   2999   RegisterForAllNavNotifications(&notifications, &controller);
   3000 
   3001   const GURL url("http://foo");
   3002 
   3003   // For renderer-initiated navigations in new tabs (with no committed entries),
   3004   // we show the pending entry's URL as long as the about:blank page is not
   3005   // modified.
   3006   NavigationController::LoadURLParams load_url_params(url);
   3007   load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
   3008   load_url_params.is_renderer_initiated = true;
   3009   controller.LoadURLWithParams(load_url_params);
   3010   EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
   3011   EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
   3012   EXPECT_TRUE(
   3013       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
   3014           is_renderer_initiated());
   3015   EXPECT_TRUE(controller.IsInitialNavigation());
   3016   EXPECT_FALSE(contents()->HasAccessedInitialDocument());
   3017 
   3018   // There should be no title yet.
   3019   EXPECT_TRUE(contents()->GetTitle().empty());
   3020 
   3021   // Suppose it aborts before committing, if it's a 204 or download or due to a
   3022   // stop or a new navigation from the user.  The URL should remain visible.
   3023   FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
   3024   params.error_code = net::ERR_ABORTED;
   3025   params.error_description = base::string16();
   3026   params.url = url;
   3027   params.showing_repost_interstitial = false;
   3028   main_test_rfh()->OnMessageReceived(
   3029       FrameHostMsg_DidFailProvisionalLoadWithError(0, params));
   3030   EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
   3031 
   3032   // If something else later modifies the contents of the about:blank page, then
   3033   // we must revert to showing about:blank to avoid a URL spoof.
   3034   main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
   3035   EXPECT_TRUE(contents()->HasAccessedInitialDocument());
   3036   EXPECT_FALSE(controller.GetVisibleEntry());
   3037   EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
   3038 
   3039   notifications.Reset();
   3040 }
   3041 
   3042 TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) {
   3043   NavigationControllerImpl& controller = controller_impl();
   3044   TestNotificationTracker notifications;
   3045   RegisterForAllNavNotifications(&notifications, &controller);
   3046 
   3047   const GURL url1("http://foo/eh");
   3048   const GURL url2("http://foo/bee");
   3049 
   3050   // For renderer-initiated navigations in new tabs (with no committed entries),
   3051   // we show the pending entry's URL as long as the about:blank page is not
   3052   // modified.
   3053   NavigationController::LoadURLParams load_url_params(url1);
   3054   load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
   3055   load_url_params.is_renderer_initiated = true;
   3056   controller.LoadURLWithParams(load_url_params);
   3057   EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
   3058   EXPECT_TRUE(
   3059       NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
   3060           is_renderer_initiated());
   3061   EXPECT_TRUE(controller.IsInitialNavigation());
   3062   EXPECT_FALSE(contents()->HasAccessedInitialDocument());
   3063 
   3064   // Simulate a commit and then starting a new pending navigation.
   3065   main_test_rfh()->SendNavigate(0, url1);
   3066   NavigationController::LoadURLParams load_url2_params(url2);
   3067   load_url2_params.transition_type = ui::PAGE_TRANSITION_LINK;
   3068   load_url2_params.is_renderer_initiated = true;
   3069   controller.LoadURLWithParams(load_url2_params);
   3070 
   3071   // We should not consider this an initial navigation, and thus should
   3072   // not show the pending URL.
   3073   EXPECT_FALSE(contents()->HasAccessedInitialDocument());
   3074   EXPECT_FALSE(controller.IsInitialNavigation());
   3075   EXPECT_TRUE(controller.GetVisibleEntry());
   3076   EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
   3077 
   3078   notifications.Reset();
   3079 }
   3080 
   3081 // Tests that IsInPageNavigation returns appropriate results.  Prevents
   3082 // regression for bug 1126349.
   3083 TEST_F(NavigationControllerTest, IsInPageNavigation) {
   3084   NavigationControllerImpl& controller = controller_impl();
   3085   const GURL url("http://www.google.com/home.html");
   3086 
   3087   // If the renderer claims it performed an in-page navigation from
   3088   // about:blank, trust the renderer.
   3089   // This can happen when an iframe is created and populated via
   3090   // document.write(), then tries to perform a fragment navigation.
   3091   // TODO(japhet): We should only trust the renderer if the about:blank
   3092   // was the first document in the given frame, but we don't have enough
   3093   // information to identify that case currently.
   3094   const GURL blank_url(url::kAboutBlankURL);
   3095   main_test_rfh()->SendNavigate(0, blank_url);
   3096   EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
   3097       main_test_rfh()));
   3098 
   3099   // Navigate to URL with no refs.
   3100   main_test_rfh()->SendNavigate(0, url);
   3101 
   3102   // Reloading the page is not an in-page navigation.
   3103   EXPECT_FALSE(controller.IsURLInPageNavigation(url, false,
   3104       main_test_rfh()));
   3105   const GURL other_url("http://www.google.com/add.html");
   3106   EXPECT_FALSE(controller.IsURLInPageNavigation(other_url, false,
   3107       main_test_rfh()));
   3108   const GURL url_with_ref("http://www.google.com/home.html#my_ref");
   3109   EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
   3110       main_test_rfh()));
   3111 
   3112   // Navigate to URL with refs.
   3113   main_test_rfh()->SendNavigate(1, url_with_ref);
   3114 
   3115   // Reloading the page is not an in-page navigation.
   3116   EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref, false,
   3117       main_test_rfh()));
   3118   EXPECT_FALSE(controller.IsURLInPageNavigation(url, false,
   3119       main_test_rfh()));
   3120   EXPECT_FALSE(controller.IsURLInPageNavigation(other_url, false,
   3121       main_test_rfh()));
   3122   const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
   3123   EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref, true,
   3124       main_test_rfh()));
   3125 
   3126   // Going to the same url again will be considered in-page
   3127   // if the renderer says it is even if the navigation type isn't IN_PAGE.
   3128   EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
   3129       main_test_rfh()));
   3130 
   3131   // Going back to the non ref url will be considered in-page if the navigation
   3132   // type is IN_PAGE.
   3133   EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
   3134       main_test_rfh()));
   3135 
   3136   // If the renderer says this is a same-origin in-page navigation, believe it.
   3137   // This is the pushState/replaceState case.
   3138   EXPECT_TRUE(controller.IsURLInPageNavigation(other_url, true,
   3139       main_test_rfh()));
   3140 
   3141   // Test allow_universal_access_from_file_urls flag.
   3142   const GURL different_origin_url("http://www.example.com");
   3143   MockRenderProcessHost* rph =
   3144       static_cast<MockRenderProcessHost*>(main_test_rfh()->GetProcess());
   3145   WebPreferences prefs = test_rvh()->GetWebkitPreferences();
   3146   prefs.allow_universal_access_from_file_urls = true;
   3147   test_rvh()->UpdateWebkitPreferences(prefs);
   3148   prefs = test_rvh()->GetWebkitPreferences();
   3149   EXPECT_TRUE(prefs.allow_universal_access_from_file_urls);
   3150   // Allow in page navigation if existing URL is file scheme.
   3151   const GURL file_url("file:///foo/index.html");
   3152   main_test_rfh()->SendNavigate(0, file_url);
   3153   EXPECT_EQ(0, rph->bad_msg_count());
   3154   EXPECT_TRUE(controller.IsURLInPageNavigation(different_origin_url, true,
   3155       main_test_rfh()));
   3156   EXPECT_EQ(0, rph->bad_msg_count());
   3157   // Don't honor allow_universal_access_from_file_urls if existing URL is
   3158   // not file scheme.
   3159   main_test_rfh()->SendNavigate(0, url);
   3160   EXPECT_FALSE(controller.IsURLInPageNavigation(different_origin_url, true,
   3161       main_test_rfh()));
   3162   EXPECT_EQ(1, rph->bad_msg_count());
   3163 
   3164   // Remove allow_universal_access_from_file_urls flag.
   3165   prefs.allow_universal_access_from_file_urls = false;
   3166   test_rvh()->UpdateWebkitPreferences(prefs);
   3167   prefs = test_rvh()->GetWebkitPreferences();
   3168   EXPECT_FALSE(prefs.allow_universal_access_from_file_urls);
   3169 
   3170   // Don't believe the renderer if it claims a cross-origin navigation is
   3171   // in-page.
   3172   EXPECT_EQ(1, rph->bad_msg_count());
   3173   EXPECT_FALSE(controller.IsURLInPageNavigation(different_origin_url, true,
   3174       main_test_rfh()));
   3175   EXPECT_EQ(2, rph->bad_msg_count());
   3176 }
   3177 
   3178 // Some pages can have subframes with the same base URL (minus the reference) as
   3179 // the main page. Even though this is hard, it can happen, and we don't want
   3180 // these subframe navigations to affect the toplevel document. They should
   3181 // instead be ignored.  http://crbug.com/5585
   3182 TEST_F(NavigationControllerTest, SameSubframe) {
   3183   NavigationControllerImpl& controller = controller_impl();
   3184   // Navigate the main frame.
   3185   const GURL url("http://www.google.com/");
   3186   main_test_rfh()->SendNavigate(0, url);
   3187 
   3188   // We should be at the first navigation entry.
   3189   EXPECT_EQ(controller.GetEntryCount(), 1);
   3190   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   3191 
   3192   // Navigate a subframe that would normally count as in-page.
   3193   const GURL subframe("http://www.google.com/#");
   3194   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   3195   params.page_id = 0;
   3196   params.url = subframe;
   3197   params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
   3198   params.should_update_history = false;
   3199   params.gesture = NavigationGestureAuto;
   3200   params.is_post = false;
   3201   params.page_state = PageState::CreateFromURL(subframe);
   3202   LoadCommittedDetails details;
   3203   EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
   3204                                               &details));
   3205 
   3206   // Nothing should have changed.
   3207   EXPECT_EQ(controller.GetEntryCount(), 1);
   3208   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   3209 }
   3210 
   3211 // Make sure that on cloning a WebContentsImpl and going back needs_reload is
   3212 // false.
   3213 TEST_F(NavigationControllerTest, CloneAndGoBack) {
   3214   NavigationControllerImpl& controller = controller_impl();
   3215   const GURL url1("http://foo1");
   3216   const GURL url2("http://foo2");
   3217   const base::string16 title(base::ASCIIToUTF16("Title"));
   3218 
   3219   NavigateAndCommit(url1);
   3220   controller.GetVisibleEntry()->SetTitle(title);
   3221   NavigateAndCommit(url2);
   3222 
   3223   scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
   3224 
   3225   ASSERT_EQ(2, clone->GetController().GetEntryCount());
   3226   EXPECT_TRUE(clone->GetController().NeedsReload());
   3227   clone->GetController().GoBack();
   3228   // Navigating back should have triggered needs_reload_ to go false.
   3229   EXPECT_FALSE(clone->GetController().NeedsReload());
   3230 
   3231   // Ensure that the pending URL and its title are visible.
   3232   EXPECT_EQ(url1, clone->GetController().GetVisibleEntry()->GetURL());
   3233   EXPECT_EQ(title, clone->GetTitle());
   3234 }
   3235 
   3236 // Make sure that reloading a cloned tab doesn't change its pending entry index.
   3237 // See http://crbug.com/234491.
   3238 TEST_F(NavigationControllerTest, CloneAndReload) {
   3239   NavigationControllerImpl& controller = controller_impl();
   3240   const GURL url1("http://foo1");
   3241   const GURL url2("http://foo2");
   3242   const base::string16 title(base::ASCIIToUTF16("Title"));
   3243 
   3244   NavigateAndCommit(url1);
   3245   controller.GetVisibleEntry()->SetTitle(title);
   3246   NavigateAndCommit(url2);
   3247 
   3248   scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
   3249   clone->GetController().LoadIfNecessary();
   3250 
   3251   ASSERT_EQ(2, clone->GetController().GetEntryCount());
   3252   EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
   3253 
   3254   clone->GetController().Reload(true);
   3255   EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
   3256 }
   3257 
   3258 // Make sure that cloning a WebContentsImpl doesn't copy interstitials.
   3259 TEST_F(NavigationControllerTest, CloneOmitsInterstitials) {
   3260   NavigationControllerImpl& controller = controller_impl();
   3261   const GURL url1("http://foo1");
   3262   const GURL url2("http://foo2");
   3263 
   3264   NavigateAndCommit(url1);
   3265   NavigateAndCommit(url2);
   3266 
   3267   // Add an interstitial entry.  Should be deleted with controller.
   3268   NavigationEntryImpl* interstitial_entry = new NavigationEntryImpl();
   3269   interstitial_entry->set_page_type(PAGE_TYPE_INTERSTITIAL);
   3270   controller.SetTransientEntry(interstitial_entry);
   3271 
   3272   scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
   3273 
   3274   ASSERT_EQ(2, clone->GetController().GetEntryCount());
   3275 }
   3276 
   3277 // Test requesting and triggering a lazy reload.
   3278 TEST_F(NavigationControllerTest, LazyReload) {
   3279   NavigationControllerImpl& controller = controller_impl();
   3280   const GURL url("http://foo");
   3281   NavigateAndCommit(url);
   3282   ASSERT_FALSE(controller.NeedsReload());
   3283 
   3284   // Request a reload to happen when the controller becomes active (e.g. after
   3285   // the renderer gets killed in background on Android).
   3286   controller.SetNeedsReload();
   3287   ASSERT_TRUE(controller.NeedsReload());
   3288 
   3289   // Set the controller as active, triggering the requested reload.
   3290   controller.SetActive(true);
   3291   ASSERT_FALSE(controller.NeedsReload());
   3292 }
   3293 
   3294 // Tests a subframe navigation while a toplevel navigation is pending.
   3295 // http://crbug.com/43967
   3296 TEST_F(NavigationControllerTest, SubframeWhilePending) {
   3297   NavigationControllerImpl& controller = controller_impl();
   3298   // Load the first page.
   3299   const GURL url1("http://foo/");
   3300   NavigateAndCommit(url1);
   3301 
   3302   // Now start a pending load to a totally different page, but don't commit it.
   3303   const GURL url2("http://bar/");
   3304   controller.LoadURL(
   3305       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   3306 
   3307   // Send a subframe update from the first page, as if one had just
   3308   // automatically loaded. Auto subframes don't increment the page ID.
   3309   const GURL url1_sub("http://foo/subframe");
   3310   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   3311   params.page_id = controller.GetLastCommittedEntry()->GetPageID();
   3312   params.url = url1_sub;
   3313   params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
   3314   params.should_update_history = false;
   3315   params.gesture = NavigationGestureAuto;
   3316   params.is_post = false;
   3317   params.page_state = PageState::CreateFromURL(url1_sub);
   3318   LoadCommittedDetails details;
   3319 
   3320   // This should return false meaning that nothing was actually updated.
   3321   EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
   3322                                               &details));
   3323 
   3324   // The notification should have updated the last committed one, and not
   3325   // the pending load.
   3326   EXPECT_EQ(url1, controller.GetLastCommittedEntry()->GetURL());
   3327 
   3328   // The active entry should be unchanged by the subframe load.
   3329   EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
   3330 }
   3331 
   3332 // Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
   3333 TEST_F(NavigationControllerTest, CopyStateFrom) {
   3334   NavigationControllerImpl& controller = controller_impl();
   3335   const GURL url1("http://foo1");
   3336   const GURL url2("http://foo2");
   3337 
   3338   NavigateAndCommit(url1);
   3339   NavigateAndCommit(url2);
   3340   controller.GoBack();
   3341   contents()->CommitPendingNavigation();
   3342 
   3343   scoped_ptr<TestWebContents> other_contents(
   3344       static_cast<TestWebContents*>(CreateTestWebContents()));
   3345   NavigationControllerImpl& other_controller = other_contents->GetController();
   3346   other_controller.CopyStateFrom(controller);
   3347 
   3348   // other_controller should now contain 2 urls.
   3349   ASSERT_EQ(2, other_controller.GetEntryCount());
   3350   // We should be looking at the first one.
   3351   ASSERT_EQ(0, other_controller.GetCurrentEntryIndex());
   3352 
   3353   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3354   EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
   3355   EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
   3356   // This is a different site than url1, so the IDs start again at 0.
   3357   EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
   3358 
   3359   // The max page ID map should be copied over and updated with the max page ID
   3360   // from the current tab.
   3361   SiteInstance* instance1 =
   3362       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
   3363   EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
   3364 
   3365   // Ensure the SessionStorageNamespaceMaps are the same size and have
   3366   // the same partitons loaded.
   3367   //
   3368   // TODO(ajwong): We should load a url from a different partition earlier
   3369   // to make sure this map has more than one entry.
   3370   const SessionStorageNamespaceMap& session_storage_namespace_map =
   3371       controller.GetSessionStorageNamespaceMap();
   3372   const SessionStorageNamespaceMap& other_session_storage_namespace_map =
   3373       other_controller.GetSessionStorageNamespaceMap();
   3374   EXPECT_EQ(session_storage_namespace_map.size(),
   3375             other_session_storage_namespace_map.size());
   3376   for (SessionStorageNamespaceMap::const_iterator it =
   3377            session_storage_namespace_map.begin();
   3378        it != session_storage_namespace_map.end();
   3379        ++it) {
   3380     SessionStorageNamespaceMap::const_iterator other =
   3381         other_session_storage_namespace_map.find(it->first);
   3382     EXPECT_TRUE(other != other_session_storage_namespace_map.end());
   3383   }
   3384 }
   3385 
   3386 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
   3387 TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
   3388   NavigationControllerImpl& controller = controller_impl();
   3389   const GURL url1("http://foo/1");
   3390   const GURL url2("http://foo/2");
   3391   const GURL url3("http://foo/3");
   3392 
   3393   NavigateAndCommit(url1);
   3394   NavigateAndCommit(url2);
   3395 
   3396   // First two entries should have the same SiteInstance.
   3397   SiteInstance* instance1 =
   3398       GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
   3399   SiteInstance* instance2 =
   3400       GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
   3401   EXPECT_EQ(instance1, instance2);
   3402   EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
   3403   EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
   3404   EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1));
   3405 
   3406   scoped_ptr<TestWebContents> other_contents(
   3407       static_cast<TestWebContents*>(CreateTestWebContents()));
   3408   NavigationControllerImpl& other_controller = other_contents->GetController();
   3409   other_contents->NavigateAndCommit(url3);
   3410   other_contents->ExpectSetHistoryLengthAndPrune(
   3411       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
   3412       other_controller.GetEntryAtIndex(0)->GetPageID());
   3413   other_controller.CopyStateFromAndPrune(&controller, false);
   3414 
   3415   // other_controller should now contain the 3 urls: url1, url2 and url3.
   3416 
   3417   ASSERT_EQ(3, other_controller.GetEntryCount());
   3418 
   3419   ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
   3420 
   3421   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3422   EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
   3423   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
   3424   EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
   3425   EXPECT_EQ(1, other_controller.GetEntryAtIndex(1)->GetPageID());
   3426   EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
   3427 
   3428   // A new SiteInstance in a different BrowsingInstance should be used for the
   3429   // new tab.
   3430   SiteInstance* instance3 =
   3431       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
   3432   EXPECT_NE(instance3, instance1);
   3433   EXPECT_FALSE(instance3->IsRelatedSiteInstance(instance1));
   3434 
   3435   // The max page ID map should be copied over and updated with the max page ID
   3436   // from the current tab.
   3437   EXPECT_EQ(1, other_contents->GetMaxPageIDForSiteInstance(instance1));
   3438   EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance3));
   3439 }
   3440 
   3441 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in
   3442 // the target.
   3443 TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
   3444   NavigationControllerImpl& controller = controller_impl();
   3445   const GURL url1("http://foo1");
   3446   const GURL url2("http://foo2");
   3447   const GURL url3("http://foo3");
   3448 
   3449   NavigateAndCommit(url1);
   3450   NavigateAndCommit(url2);
   3451   controller.GoBack();
   3452   contents()->CommitPendingNavigation();
   3453 
   3454   scoped_ptr<TestWebContents> other_contents(
   3455       static_cast<TestWebContents*>(CreateTestWebContents()));
   3456   NavigationControllerImpl& other_controller = other_contents->GetController();
   3457   other_contents->NavigateAndCommit(url3);
   3458   other_contents->ExpectSetHistoryLengthAndPrune(
   3459       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
   3460       other_controller.GetEntryAtIndex(0)->GetPageID());
   3461   other_controller.CopyStateFromAndPrune(&controller, false);
   3462 
   3463   // other_controller should now contain: url1, url3
   3464 
   3465   ASSERT_EQ(2, other_controller.GetEntryCount());
   3466   ASSERT_EQ(1, other_controller.GetCurrentEntryIndex());
   3467 
   3468   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3469   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
   3470   EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
   3471 
   3472   // The max page ID map should be copied over and updated with the max page ID
   3473   // from the current tab.
   3474   SiteInstance* instance1 =
   3475       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
   3476   EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
   3477 }
   3478 
   3479 // Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in
   3480 // the target.
   3481 TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
   3482   NavigationControllerImpl& controller = controller_impl();
   3483   const GURL url1("http://foo1");
   3484   const GURL url2("http://foo2");
   3485   const GURL url3("http://foo3");
   3486   const GURL url4("http://foo4");
   3487 
   3488   NavigateAndCommit(url1);
   3489   NavigateAndCommit(url2);
   3490 
   3491   scoped_ptr<TestWebContents> other_contents(
   3492       static_cast<TestWebContents*>(CreateTestWebContents()));
   3493   NavigationControllerImpl& other_controller = other_contents->GetController();
   3494   other_contents->NavigateAndCommit(url3);
   3495   other_contents->NavigateAndCommit(url4);
   3496   other_contents->ExpectSetHistoryLengthAndPrune(
   3497       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1)), 2,
   3498       other_controller.GetEntryAtIndex(0)->GetPageID());
   3499   other_controller.CopyStateFromAndPrune(&controller, false);
   3500 
   3501   // other_controller should now contain: url1, url2, url4
   3502 
   3503   ASSERT_EQ(3, other_controller.GetEntryCount());
   3504   ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
   3505 
   3506   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3507   EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
   3508   EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
   3509 
   3510   // The max page ID map should be copied over and updated with the max page ID
   3511   // from the current tab.
   3512   SiteInstance* instance1 =
   3513       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
   3514   EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
   3515 }
   3516 
   3517 // Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with
   3518 // not the last entry selected in the target.
   3519 TEST_F(NavigationControllerTest, CopyStateFromAndPruneNotLast) {
   3520   NavigationControllerImpl& controller = controller_impl();
   3521   const GURL url1("http://foo1");
   3522   const GURL url2("http://foo2");
   3523   const GURL url3("http://foo3");
   3524   const GURL url4("http://foo4");
   3525 
   3526   NavigateAndCommit(url1);
   3527   NavigateAndCommit(url2);
   3528 
   3529   scoped_ptr<TestWebContents> other_contents(
   3530       static_cast<TestWebContents*>(CreateTestWebContents()));
   3531   NavigationControllerImpl& other_controller = other_contents->GetController();
   3532   other_contents->NavigateAndCommit(url3);
   3533   other_contents->NavigateAndCommit(url4);
   3534   other_controller.GoBack();
   3535   other_contents->CommitPendingNavigation();
   3536   other_contents->ExpectSetHistoryLengthAndPrune(
   3537       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
   3538       other_controller.GetEntryAtIndex(0)->GetPageID());
   3539   other_controller.CopyStateFromAndPrune(&controller, false);
   3540 
   3541   // other_controller should now contain: url1, url2, url3
   3542 
   3543   ASSERT_EQ(3, other_controller.GetEntryCount());
   3544   ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
   3545 
   3546   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3547   EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
   3548   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
   3549 
   3550   // The max page ID map should be copied over and updated with the max page ID
   3551   // from the current tab.
   3552   SiteInstance* instance1 =
   3553       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
   3554   EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
   3555 }
   3556 
   3557 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus
   3558 // a pending entry in the target.
   3559 TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending) {
   3560   NavigationControllerImpl& controller = controller_impl();
   3561   const GURL url1("http://foo1");
   3562   const GURL url2("http://foo2");
   3563   const GURL url3("http://foo3");
   3564   const GURL url4("http://foo4");
   3565 
   3566   NavigateAndCommit(url1);
   3567   NavigateAndCommit(url2);
   3568   controller.GoBack();
   3569   contents()->CommitPendingNavigation();
   3570 
   3571   scoped_ptr<TestWebContents> other_contents(
   3572       static_cast<TestWebContents*>(CreateTestWebContents()));
   3573   NavigationControllerImpl& other_controller = other_contents->GetController();
   3574   other_contents->NavigateAndCommit(url3);
   3575   other_controller.LoadURL(
   3576       url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   3577   other_contents->ExpectSetHistoryLengthAndPrune(
   3578       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
   3579       other_controller.GetEntryAtIndex(0)->GetPageID());
   3580   other_controller.CopyStateFromAndPrune(&controller, false);
   3581 
   3582   // other_controller should now contain url1, url3, and a pending entry
   3583   // for url4.
   3584 
   3585   ASSERT_EQ(2, other_controller.GetEntryCount());
   3586   EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
   3587 
   3588   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3589   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
   3590 
   3591   // And there should be a pending entry for url4.
   3592   ASSERT_TRUE(other_controller.GetPendingEntry());
   3593   EXPECT_EQ(url4, other_controller.GetPendingEntry()->GetURL());
   3594 
   3595   // The max page ID map should be copied over and updated with the max page ID
   3596   // from the current tab.
   3597   SiteInstance* instance1 =
   3598       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
   3599   EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
   3600 }
   3601 
   3602 // Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending
   3603 // client redirect entry (with the same page ID) in the target.  This used to
   3604 // crash because the last committed entry would be pruned but max_page_id
   3605 // remembered the page ID (http://crbug.com/234809).
   3606 TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending2) {
   3607   NavigationControllerImpl& controller = controller_impl();
   3608   const GURL url1("http://foo1");
   3609   const GURL url2a("http://foo2/a");
   3610   const GURL url2b("http://foo2/b");
   3611 
   3612   NavigateAndCommit(url1);
   3613 
   3614   scoped_ptr<TestWebContents> other_contents(
   3615       static_cast<TestWebContents*>(CreateTestWebContents()));
   3616   NavigationControllerImpl& other_controller = other_contents->GetController();
   3617   other_contents->NavigateAndCommit(url2a);
   3618   // Simulate a client redirect, which has the same page ID as entry 2a.
   3619   other_controller.LoadURL(
   3620       url2b, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
   3621   other_controller.GetPendingEntry()->SetPageID(
   3622       other_controller.GetLastCommittedEntry()->GetPageID());
   3623 
   3624   other_contents->ExpectSetHistoryLengthAndPrune(
   3625       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
   3626       other_controller.GetEntryAtIndex(0)->GetPageID());
   3627   other_controller.CopyStateFromAndPrune(&controller, false);
   3628 
   3629   // other_controller should now contain url1, url2a, and a pending entry
   3630   // for url2b.
   3631 
   3632   ASSERT_EQ(2, other_controller.GetEntryCount());
   3633   EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
   3634 
   3635   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3636   EXPECT_EQ(url2a, other_controller.GetEntryAtIndex(1)->GetURL());
   3637 
   3638   // And there should be a pending entry for url4.
   3639   ASSERT_TRUE(other_controller.GetPendingEntry());
   3640   EXPECT_EQ(url2b, other_controller.GetPendingEntry()->GetURL());
   3641 
   3642   // Let the pending entry commit.
   3643   other_contents->CommitPendingNavigation();
   3644 
   3645   // The max page ID map should be copied over and updated with the max page ID
   3646   // from the current tab.
   3647   SiteInstance* instance1 =
   3648       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
   3649   EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
   3650 }
   3651 
   3652 // Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
   3653 // source, and 1 entry in the target. The back pending entry should be ignored.
   3654 TEST_F(NavigationControllerTest, CopyStateFromAndPruneSourcePending) {
   3655   NavigationControllerImpl& controller = controller_impl();
   3656   const GURL url1("http://foo1");
   3657   const GURL url2("http://foo2");
   3658   const GURL url3("http://foo3");
   3659 
   3660   NavigateAndCommit(url1);
   3661   NavigateAndCommit(url2);
   3662   controller.GoBack();
   3663 
   3664   scoped_ptr<TestWebContents> other_contents(
   3665       static_cast<TestWebContents*>(CreateTestWebContents()));
   3666   NavigationControllerImpl& other_controller = other_contents->GetController();
   3667   other_contents->NavigateAndCommit(url3);
   3668   other_contents->ExpectSetHistoryLengthAndPrune(
   3669       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
   3670       other_controller.GetEntryAtIndex(0)->GetPageID());
   3671   other_controller.CopyStateFromAndPrune(&controller, false);
   3672 
   3673   // other_controller should now contain: url1, url2, url3
   3674 
   3675   ASSERT_EQ(3, other_controller.GetEntryCount());
   3676   ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
   3677 
   3678   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3679   EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
   3680   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
   3681   EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
   3682 
   3683   // The max page ID map should be copied over and updated with the max page ID
   3684   // from the current tab.
   3685   SiteInstance* instance1 =
   3686       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
   3687   EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
   3688 }
   3689 
   3690 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
   3691 // when the max entry count is 3.  We should prune one entry.
   3692 TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntries) {
   3693   NavigationControllerImpl& controller = controller_impl();
   3694   size_t original_count = NavigationControllerImpl::max_entry_count();
   3695   const int kMaxEntryCount = 3;
   3696 
   3697   NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
   3698 
   3699   const GURL url1("http://foo/1");
   3700   const GURL url2("http://foo/2");
   3701   const GURL url3("http://foo/3");
   3702   const GURL url4("http://foo/4");
   3703 
   3704   // Create a PrunedListener to observe prune notifications.
   3705   PrunedListener listener(&controller);
   3706 
   3707   NavigateAndCommit(url1);
   3708   NavigateAndCommit(url2);
   3709   NavigateAndCommit(url3);
   3710 
   3711   scoped_ptr<TestWebContents> other_contents(
   3712       static_cast<TestWebContents*>(CreateTestWebContents()));
   3713   NavigationControllerImpl& other_controller = other_contents->GetController();
   3714   other_contents->NavigateAndCommit(url4);
   3715   other_contents->ExpectSetHistoryLengthAndPrune(
   3716       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
   3717       other_controller.GetEntryAtIndex(0)->GetPageID());
   3718   other_controller.CopyStateFromAndPrune(&controller, false);
   3719 
   3720   // We should have received a pruned notification.
   3721   EXPECT_EQ(1, listener.notification_count_);
   3722   EXPECT_TRUE(listener.details_.from_front);
   3723   EXPECT_EQ(1, listener.details_.count);
   3724 
   3725   // other_controller should now contain only 3 urls: url2, url3 and url4.
   3726 
   3727   ASSERT_EQ(3, other_controller.GetEntryCount());
   3728 
   3729   ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
   3730 
   3731   EXPECT_EQ(url2, other_controller.GetEntryAtIndex(0)->GetURL());
   3732   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
   3733   EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
   3734   EXPECT_EQ(1, other_controller.GetEntryAtIndex(0)->GetPageID());
   3735   EXPECT_EQ(2, other_controller.GetEntryAtIndex(1)->GetPageID());
   3736   EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
   3737 
   3738   NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
   3739 }
   3740 
   3741 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest, with
   3742 // replace_entry set to true.
   3743 TEST_F(NavigationControllerTest, CopyStateFromAndPruneReplaceEntry) {
   3744   NavigationControllerImpl& controller = controller_impl();
   3745   const GURL url1("http://foo/1");
   3746   const GURL url2("http://foo/2");
   3747   const GURL url3("http://foo/3");
   3748 
   3749   NavigateAndCommit(url1);
   3750   NavigateAndCommit(url2);
   3751 
   3752   // First two entries should have the same SiteInstance.
   3753   SiteInstance* instance1 =
   3754       GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
   3755   SiteInstance* instance2 =
   3756       GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
   3757   EXPECT_EQ(instance1, instance2);
   3758   EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
   3759   EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
   3760   EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1));
   3761 
   3762   scoped_ptr<TestWebContents> other_contents(
   3763       static_cast<TestWebContents*>(CreateTestWebContents()));
   3764   NavigationControllerImpl& other_controller = other_contents->GetController();
   3765   other_contents->NavigateAndCommit(url3);
   3766   other_contents->ExpectSetHistoryLengthAndPrune(
   3767       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
   3768       other_controller.GetEntryAtIndex(0)->GetPageID());
   3769   other_controller.CopyStateFromAndPrune(&controller, true);
   3770 
   3771   // other_controller should now contain the 2 urls: url1 and url3.
   3772 
   3773   ASSERT_EQ(2, other_controller.GetEntryCount());
   3774 
   3775   ASSERT_EQ(1, other_controller.GetCurrentEntryIndex());
   3776 
   3777   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3778   EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
   3779   EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
   3780   EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
   3781 
   3782   // A new SiteInstance in a different BrowsingInstance should be used for the
   3783   // new tab.
   3784   SiteInstance* instance3 =
   3785       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
   3786   EXPECT_NE(instance3, instance1);
   3787   EXPECT_FALSE(instance3->IsRelatedSiteInstance(instance1));
   3788 
   3789   // The max page ID map should be copied over and updated with the max page ID
   3790   // from the current tab.
   3791   EXPECT_EQ(1, other_contents->GetMaxPageIDForSiteInstance(instance1));
   3792   EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance3));
   3793 }
   3794 
   3795 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest, when the max
   3796 // entry count is 3 and replace_entry is true.  We should not prune entries.
   3797 TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntriesReplaceEntry) {
   3798   NavigationControllerImpl& controller = controller_impl();
   3799   size_t original_count = NavigationControllerImpl::max_entry_count();
   3800   const int kMaxEntryCount = 3;
   3801 
   3802   NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
   3803 
   3804   const GURL url1("http://foo/1");
   3805   const GURL url2("http://foo/2");
   3806   const GURL url3("http://foo/3");
   3807   const GURL url4("http://foo/4");
   3808 
   3809   // Create a PrunedListener to observe prune notifications.
   3810   PrunedListener listener(&controller);
   3811 
   3812   NavigateAndCommit(url1);
   3813   NavigateAndCommit(url2);
   3814   NavigateAndCommit(url3);
   3815 
   3816   scoped_ptr<TestWebContents> other_contents(
   3817       static_cast<TestWebContents*>(CreateTestWebContents()));
   3818   NavigationControllerImpl& other_controller = other_contents->GetController();
   3819   other_contents->NavigateAndCommit(url4);
   3820   other_contents->ExpectSetHistoryLengthAndPrune(
   3821       GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
   3822       other_controller.GetEntryAtIndex(0)->GetPageID());
   3823   other_controller.CopyStateFromAndPrune(&controller, true);
   3824 
   3825   // We should have received no pruned notification.
   3826   EXPECT_EQ(0, listener.notification_count_);
   3827 
   3828   // other_controller should now contain only 3 urls: url1, url2 and url4.
   3829 
   3830   ASSERT_EQ(3, other_controller.GetEntryCount());
   3831 
   3832   ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
   3833 
   3834   EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
   3835   EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
   3836   EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
   3837   EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
   3838   EXPECT_EQ(1, other_controller.GetEntryAtIndex(1)->GetPageID());
   3839   EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
   3840 
   3841   NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
   3842 }
   3843 
   3844 // Tests that we can navigate to the restored entries
   3845 // imported by CopyStateFromAndPrune.
   3846 TEST_F(NavigationControllerTest, CopyRestoredStateAndNavigate) {
   3847   const GURL kRestoredUrls[] = {
   3848     GURL("http://site1.com"),
   3849     GURL("http://site2.com"),
   3850   };
   3851   const GURL kInitialUrl("http://site3.com");
   3852 
   3853   std::vector<NavigationEntry*> entries;
   3854   for (size_t i = 0; i < arraysize(kRestoredUrls); ++i) {
   3855     NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
   3856         kRestoredUrls[i], Referrer(), ui::PAGE_TRANSITION_RELOAD, false,
   3857         std::string(), browser_context());
   3858     entry->SetPageID(static_cast<int>(i));
   3859     entries.push_back(entry);
   3860   }
   3861 
   3862   // Create a WebContents with restored entries.
   3863   scoped_ptr<TestWebContents> source_contents(
   3864       static_cast<TestWebContents*>(CreateTestWebContents()));
   3865   NavigationControllerImpl& source_controller =
   3866       source_contents->GetController();
   3867   source_controller.Restore(
   3868       entries.size() - 1,
   3869       NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
   3870       &entries);
   3871   ASSERT_EQ(0u, entries.size());
   3872   source_controller.LoadIfNecessary();
   3873   source_contents->CommitPendingNavigation();
   3874 
   3875   // Load a page, then copy state from |source_contents|.
   3876   NavigateAndCommit(kInitialUrl);
   3877   contents()->ExpectSetHistoryLengthAndPrune(
   3878       GetSiteInstanceFromEntry(controller_impl().GetEntryAtIndex(0)), 2,
   3879       controller_impl().GetEntryAtIndex(0)->GetPageID());
   3880   controller_impl().CopyStateFromAndPrune(&source_controller, false);
   3881   ASSERT_EQ(3, controller_impl().GetEntryCount());
   3882 
   3883   // Go back to the first entry one at a time and
   3884   // verify that it works as expected.
   3885   EXPECT_EQ(2, controller_impl().GetCurrentEntryIndex());
   3886   EXPECT_EQ(kInitialUrl, controller_impl().GetActiveEntry()->GetURL());
   3887 
   3888   controller_impl().GoBack();
   3889   contents()->CommitPendingNavigation();
   3890   EXPECT_EQ(1, controller_impl().GetCurrentEntryIndex());
   3891   EXPECT_EQ(kRestoredUrls[1], controller_impl().GetActiveEntry()->GetURL());
   3892 
   3893   controller_impl().GoBack();
   3894   contents()->CommitPendingNavigation();
   3895   EXPECT_EQ(0, controller_impl().GetCurrentEntryIndex());
   3896   EXPECT_EQ(kRestoredUrls[0], controller_impl().GetActiveEntry()->GetURL());
   3897 }
   3898 
   3899 // Tests that navigations initiated from the page (with the history object)
   3900 // work as expected, creating pending entries.
   3901 TEST_F(NavigationControllerTest, HistoryNavigate) {
   3902   NavigationControllerImpl& controller = controller_impl();
   3903   const GURL url1("http://foo/1");
   3904   const GURL url2("http://foo/2");
   3905   const GURL url3("http://foo/3");
   3906 
   3907   NavigateAndCommit(url1);
   3908   NavigateAndCommit(url2);
   3909   NavigateAndCommit(url3);
   3910   controller.GoBack();
   3911   contents()->CommitPendingNavigation();
   3912 
   3913   // Simulate the page calling history.back(). It should create a pending entry.
   3914   contents()->OnGoToEntryAtOffset(-1);
   3915   EXPECT_EQ(0, controller.GetPendingEntryIndex());
   3916   // The actual cross-navigation is suspended until the current RVH tells us
   3917   // it unloaded, simulate that.
   3918   contents()->ProceedWithCrossSiteNavigation();
   3919   // Also make sure we told the page to navigate.
   3920   const IPC::Message* message =
   3921       process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
   3922   ASSERT_TRUE(message != NULL);
   3923   Tuple1<FrameMsg_Navigate_Params> nav_params;
   3924   FrameMsg_Navigate::Read(message, &nav_params);
   3925   EXPECT_EQ(url1, nav_params.a.url);
   3926   process()->sink().ClearMessages();
   3927 
   3928   // Now test history.forward()
   3929   contents()->OnGoToEntryAtOffset(2);
   3930   EXPECT_EQ(2, controller.GetPendingEntryIndex());
   3931   // The actual cross-navigation is suspended until the current RVH tells us
   3932   // it unloaded, simulate that.
   3933   contents()->ProceedWithCrossSiteNavigation();
   3934   message = process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
   3935   ASSERT_TRUE(message != NULL);
   3936   FrameMsg_Navigate::Read(message, &nav_params);
   3937   EXPECT_EQ(url3, nav_params.a.url);
   3938   process()->sink().ClearMessages();
   3939 
   3940   controller.DiscardNonCommittedEntries();
   3941 
   3942   // Make sure an extravagant history.go() doesn't break.
   3943   contents()->OnGoToEntryAtOffset(120);  // Out of bounds.
   3944   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   3945   message = process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
   3946   EXPECT_TRUE(message == NULL);
   3947 }
   3948 
   3949 // Test call to PruneAllButLastCommitted for the only entry.
   3950 TEST_F(NavigationControllerTest, PruneAllButLastCommittedForSingle) {
   3951   NavigationControllerImpl& controller = controller_impl();
   3952   const GURL url1("http://foo1");
   3953   NavigateAndCommit(url1);
   3954 
   3955   contents()->ExpectSetHistoryLengthAndPrune(
   3956       GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
   3957       controller.GetEntryAtIndex(0)->GetPageID());
   3958 
   3959   controller.PruneAllButLastCommitted();
   3960 
   3961   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   3962   EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
   3963 }
   3964 
   3965 // Test call to PruneAllButLastCommitted for first entry.
   3966 TEST_F(NavigationControllerTest, PruneAllButLastCommittedForFirst) {
   3967   NavigationControllerImpl& controller = controller_impl();
   3968   const GURL url1("http://foo/1");
   3969   const GURL url2("http://foo/2");
   3970   const GURL url3("http://foo/3");
   3971 
   3972   NavigateAndCommit(url1);
   3973   NavigateAndCommit(url2);
   3974   NavigateAndCommit(url3);
   3975   controller.GoBack();
   3976   controller.GoBack();
   3977   contents()->CommitPendingNavigation();
   3978 
   3979   contents()->ExpectSetHistoryLengthAndPrune(
   3980       GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
   3981       controller.GetEntryAtIndex(0)->GetPageID());
   3982 
   3983   controller.PruneAllButLastCommitted();
   3984 
   3985   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   3986   EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
   3987 }
   3988 
   3989 // Test call to PruneAllButLastCommitted for intermediate entry.
   3990 TEST_F(NavigationControllerTest, PruneAllButLastCommittedForIntermediate) {
   3991   NavigationControllerImpl& controller = controller_impl();
   3992   const GURL url1("http://foo/1");
   3993   const GURL url2("http://foo/2");
   3994   const GURL url3("http://foo/3");
   3995 
   3996   NavigateAndCommit(url1);
   3997   NavigateAndCommit(url2);
   3998   NavigateAndCommit(url3);
   3999   controller.GoBack();
   4000   contents()->CommitPendingNavigation();
   4001 
   4002   contents()->ExpectSetHistoryLengthAndPrune(
   4003       GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1)), 0,
   4004       controller.GetEntryAtIndex(1)->GetPageID());
   4005 
   4006   controller.PruneAllButLastCommitted();
   4007 
   4008   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   4009   EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url2);
   4010 }
   4011 
   4012 // Test call to PruneAllButLastCommitted for a pending entry that is not yet in
   4013 // the list of entries.
   4014 TEST_F(NavigationControllerTest, PruneAllButLastCommittedForPendingNotInList) {
   4015   NavigationControllerImpl& controller = controller_impl();
   4016   const GURL url1("http://foo/1");
   4017   const GURL url2("http://foo/2");
   4018   const GURL url3("http://foo/3");
   4019 
   4020   NavigateAndCommit(url1);
   4021   NavigateAndCommit(url2);
   4022 
   4023   // Create a pending entry that is not in the entry list.
   4024   controller.LoadURL(
   4025       url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   4026   EXPECT_TRUE(controller.GetPendingEntry());
   4027   EXPECT_EQ(2, controller.GetEntryCount());
   4028 
   4029   contents()->ExpectSetHistoryLengthAndPrune(
   4030       NULL, 0, controller.GetPendingEntry()->GetPageID());
   4031   controller.PruneAllButLastCommitted();
   4032 
   4033   // We should only have the last committed and pending entries at this point,
   4034   // and the pending entry should still not be in the entry list.
   4035   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   4036   EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL());
   4037   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   4038   EXPECT_TRUE(controller.GetPendingEntry());
   4039   EXPECT_EQ(1, controller.GetEntryCount());
   4040 
   4041   // Try to commit the pending entry.
   4042   main_test_rfh()->SendNavigate(2, url3);
   4043   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   4044   EXPECT_FALSE(controller.GetPendingEntry());
   4045   EXPECT_EQ(2, controller.GetEntryCount());
   4046   EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL());
   4047 }
   4048 
   4049 // Test to ensure that when we do a history navigation back to the current
   4050 // committed page (e.g., going forward to a slow-loading page, then pressing
   4051 // the back button), we just stop the navigation to prevent the throbber from
   4052 // running continuously. Otherwise, the RenderViewHost forces the throbber to
   4053 // start, but WebKit essentially ignores the navigation and never sends a
   4054 // message to stop the throbber.
   4055 TEST_F(NavigationControllerTest, StopOnHistoryNavigationToCurrentPage) {
   4056   NavigationControllerImpl& controller = controller_impl();
   4057   const GURL url0("http://foo/0");
   4058   const GURL url1("http://foo/1");
   4059 
   4060   NavigateAndCommit(url0);
   4061   NavigateAndCommit(url1);
   4062 
   4063   // Go back to the original page, then forward to the slow page, then back
   4064   controller.GoBack();
   4065   contents()->CommitPendingNavigation();
   4066 
   4067   controller.GoForward();
   4068   EXPECT_EQ(1, controller.GetPendingEntryIndex());
   4069 
   4070   controller.GoBack();
   4071   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   4072 }
   4073 
   4074 TEST_F(NavigationControllerTest, IsInitialNavigation) {
   4075   NavigationControllerImpl& controller = controller_impl();
   4076   TestNotificationTracker notifications;
   4077   RegisterForAllNavNotifications(&notifications, &controller);
   4078 
   4079   // Initial state.
   4080   EXPECT_TRUE(controller.IsInitialNavigation());
   4081 
   4082   // After commit, it stays false.
   4083   const GURL url1("http://foo1");
   4084   main_test_rfh()->SendNavigate(0, url1);
   4085   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   4086   navigation_entry_committed_counter_ = 0;
   4087   EXPECT_FALSE(controller.IsInitialNavigation());
   4088 
   4089   // After starting a new navigation, it stays false.
   4090   const GURL url2("http://foo2");
   4091   controller.LoadURL(
   4092       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   4093 }
   4094 
   4095 // Check that the favicon is not reused across a client redirect.
   4096 // (crbug.com/28515)
   4097 TEST_F(NavigationControllerTest, ClearFaviconOnRedirect) {
   4098   const GURL kPageWithFavicon("http://withfavicon.html");
   4099   const GURL kPageWithoutFavicon("http://withoutfavicon.html");
   4100   const GURL kIconURL("http://withfavicon.ico");
   4101   const gfx::Image kDefaultFavicon = FaviconStatus().image;
   4102 
   4103   NavigationControllerImpl& controller = controller_impl();
   4104   TestNotificationTracker notifications;
   4105   RegisterForAllNavNotifications(&notifications, &controller);
   4106 
   4107   main_test_rfh()->SendNavigate(0, kPageWithFavicon);
   4108   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   4109   navigation_entry_committed_counter_ = 0;
   4110 
   4111   NavigationEntry* entry = controller.GetLastCommittedEntry();
   4112   EXPECT_TRUE(entry);
   4113   EXPECT_EQ(kPageWithFavicon, entry->GetURL());
   4114 
   4115   // Simulate Chromium having set the favicon for |kPageWithFavicon|.
   4116   content::FaviconStatus& favicon_status = entry->GetFavicon();
   4117   favicon_status.image = CreateImage(SK_ColorWHITE);
   4118   favicon_status.url = kIconURL;
   4119   favicon_status.valid = true;
   4120   EXPECT_FALSE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
   4121 
   4122   main_test_rfh()->SendNavigateWithTransition(
   4123       0,  // same page ID.
   4124       kPageWithoutFavicon,
   4125       ui::PAGE_TRANSITION_CLIENT_REDIRECT);
   4126   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   4127   navigation_entry_committed_counter_ = 0;
   4128 
   4129   entry = controller.GetLastCommittedEntry();
   4130   EXPECT_TRUE(entry);
   4131   EXPECT_EQ(kPageWithoutFavicon, entry->GetURL());
   4132 
   4133   EXPECT_TRUE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
   4134 }
   4135 
   4136 // Check that the favicon is not cleared for NavigationEntries which were
   4137 // previously navigated to.
   4138 TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) {
   4139   const GURL kUrl1("http://www.a.com/1");
   4140   const GURL kUrl2("http://www.a.com/2");
   4141   const GURL kIconURL("http://www.a.com/1/favicon.ico");
   4142 
   4143   NavigationControllerImpl& controller = controller_impl();
   4144   TestNotificationTracker notifications;
   4145   RegisterForAllNavNotifications(&notifications, &controller);
   4146 
   4147   main_test_rfh()->SendNavigate(0, kUrl1);
   4148   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   4149   navigation_entry_committed_counter_ = 0;
   4150 
   4151   // Simulate Chromium having set the favicon for |kUrl1|.
   4152   gfx::Image favicon_image = CreateImage(SK_ColorWHITE);
   4153   content::NavigationEntry* entry = controller.GetLastCommittedEntry();
   4154   EXPECT_TRUE(entry);
   4155   content::FaviconStatus& favicon_status = entry->GetFavicon();
   4156   favicon_status.image = favicon_image;
   4157   favicon_status.url = kIconURL;
   4158   favicon_status.valid = true;
   4159 
   4160   // Navigate to another page and go back to the original page.
   4161   main_test_rfh()->SendNavigate(1, kUrl2);
   4162   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   4163   navigation_entry_committed_counter_ = 0;
   4164   main_test_rfh()->SendNavigateWithTransition(
   4165       0,
   4166       kUrl1,
   4167       ui::PAGE_TRANSITION_FORWARD_BACK);
   4168   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   4169   navigation_entry_committed_counter_ = 0;
   4170 
   4171   // Verify that the favicon for the page at |kUrl1| was not cleared.
   4172   entry = controller.GetEntryAtIndex(0);
   4173   EXPECT_TRUE(entry);
   4174   EXPECT_EQ(kUrl1, entry->GetURL());
   4175   EXPECT_TRUE(DoImagesMatch(favicon_image, entry->GetFavicon().image));
   4176 }
   4177 
   4178 // The test crashes on android: http://crbug.com/170449
   4179 #if defined(OS_ANDROID)
   4180 #define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
   4181 #else
   4182 #define MAYBE_PurgeScreenshot PurgeScreenshot
   4183 #endif
   4184 // Tests that screenshot are purged correctly.
   4185 TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
   4186   NavigationControllerImpl& controller = controller_impl();
   4187 
   4188   NavigationEntryImpl* entry;
   4189 
   4190   // Navigate enough times to make sure that some screenshots are purged.
   4191   for (int i = 0; i < 12; ++i) {
   4192     const GURL url(base::StringPrintf("http://foo%d/", i));
   4193     NavigateAndCommit(url);
   4194     EXPECT_EQ(i, controller.GetCurrentEntryIndex());
   4195   }
   4196 
   4197   MockScreenshotManager* screenshot_manager =
   4198       new MockScreenshotManager(&controller);
   4199   controller.SetScreenshotManager(screenshot_manager);
   4200   for (int i = 0; i < controller.GetEntryCount(); ++i) {
   4201     entry = NavigationEntryImpl::FromNavigationEntry(
   4202         controller.GetEntryAtIndex(i));
   4203     screenshot_manager->TakeScreenshotFor(entry);
   4204     EXPECT_TRUE(entry->screenshot().get());
   4205   }
   4206 
   4207   NavigateAndCommit(GURL("https://foo/"));
   4208   EXPECT_EQ(13, controller.GetEntryCount());
   4209   entry = NavigationEntryImpl::FromNavigationEntry(
   4210       controller.GetEntryAtIndex(11));
   4211   screenshot_manager->TakeScreenshotFor(entry);
   4212 
   4213   for (int i = 0; i < 2; ++i) {
   4214     entry = NavigationEntryImpl::FromNavigationEntry(
   4215         controller.GetEntryAtIndex(i));
   4216     EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
   4217                                             << " not purged";
   4218   }
   4219 
   4220   for (int i = 2; i < controller.GetEntryCount() - 1; ++i) {
   4221     entry = NavigationEntryImpl::FromNavigationEntry(
   4222         controller.GetEntryAtIndex(i));
   4223     EXPECT_TRUE(entry->screenshot().get()) << "Screenshot not found for " << i;
   4224   }
   4225 
   4226   // Navigate to index 5 and then try to assign screenshot to all entries.
   4227   controller.GoToIndex(5);
   4228   contents()->CommitPendingNavigation();
   4229   EXPECT_EQ(5, controller.GetCurrentEntryIndex());
   4230   for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
   4231     entry = NavigationEntryImpl::FromNavigationEntry(
   4232         controller.GetEntryAtIndex(i));
   4233     screenshot_manager->TakeScreenshotFor(entry);
   4234   }
   4235 
   4236   for (int i = 10; i <= 12; ++i) {
   4237     entry = NavigationEntryImpl::FromNavigationEntry(
   4238         controller.GetEntryAtIndex(i));
   4239     EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
   4240                                             << " not purged";
   4241     screenshot_manager->TakeScreenshotFor(entry);
   4242   }
   4243 
   4244   // Navigate to index 7 and assign screenshot to all entries.
   4245   controller.GoToIndex(7);
   4246   contents()->CommitPendingNavigation();
   4247   EXPECT_EQ(7, controller.GetCurrentEntryIndex());
   4248   for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
   4249     entry = NavigationEntryImpl::FromNavigationEntry(
   4250         controller.GetEntryAtIndex(i));
   4251     screenshot_manager->TakeScreenshotFor(entry);
   4252   }
   4253 
   4254   for (int i = 0; i < 2; ++i) {
   4255     entry = NavigationEntryImpl::FromNavigationEntry(
   4256         controller.GetEntryAtIndex(i));
   4257     EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
   4258                                             << " not purged";
   4259   }
   4260 
   4261   // Clear all screenshots.
   4262   EXPECT_EQ(13, controller.GetEntryCount());
   4263   EXPECT_EQ(10, screenshot_manager->GetScreenshotCount());
   4264   controller.ClearAllScreenshots();
   4265   EXPECT_EQ(0, screenshot_manager->GetScreenshotCount());
   4266   for (int i = 0; i < controller.GetEntryCount(); ++i) {
   4267     entry = NavigationEntryImpl::FromNavigationEntry(
   4268         controller.GetEntryAtIndex(i));
   4269     EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
   4270                                             << " not cleared";
   4271   }
   4272 }
   4273 
   4274 TEST_F(NavigationControllerTest, PushStateUpdatesTitleAndFavicon) {
   4275   // Navigate.
   4276   test_rvh()->SendNavigate(1, GURL("http://foo"));
   4277 
   4278   // Set title and favicon.
   4279   base::string16 title(base::ASCIIToUTF16("Title"));
   4280   FaviconStatus favicon;
   4281   favicon.valid = true;
   4282   favicon.url = GURL("http://foo/favicon.ico");
   4283   controller().GetLastCommittedEntry()->SetTitle(title);
   4284   controller().GetLastCommittedEntry()->GetFavicon() = favicon;
   4285 
   4286   // history.pushState() is called.
   4287   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   4288   GURL url("http://foo#foo");
   4289   params.page_id = 2;
   4290   params.url = url;
   4291   params.page_state = PageState::CreateFromURL(url);
   4292   params.was_within_same_page = true;
   4293   test_rvh()->SendNavigateWithParams(&params);
   4294 
   4295   // The title should immediately be visible on the new NavigationEntry.
   4296   base::string16 new_title =
   4297       controller().GetLastCommittedEntry()->GetTitleForDisplay(std::string());
   4298   EXPECT_EQ(title, new_title);
   4299   FaviconStatus new_favicon =
   4300       controller().GetLastCommittedEntry()->GetFavicon();
   4301   EXPECT_EQ(favicon.valid, new_favicon.valid);
   4302   EXPECT_EQ(favicon.url, new_favicon.url);
   4303 }
   4304 
   4305 // Test that the navigation controller clears its session history when a
   4306 // navigation commits with the clear history list flag set.
   4307 TEST_F(NavigationControllerTest, ClearHistoryList) {
   4308   const GURL url1("http://foo1");
   4309   const GURL url2("http://foo2");
   4310   const GURL url3("http://foo3");
   4311   const GURL url4("http://foo4");
   4312 
   4313   NavigationControllerImpl& controller = controller_impl();
   4314 
   4315   // Create a session history with three entries, second entry is active.
   4316   NavigateAndCommit(url1);
   4317   NavigateAndCommit(url2);
   4318   NavigateAndCommit(url3);
   4319   controller.GoBack();
   4320   contents()->CommitPendingNavigation();
   4321   EXPECT_EQ(3, controller.GetEntryCount());
   4322   EXPECT_EQ(1, controller.GetCurrentEntryIndex());
   4323 
   4324   // Create a new pending navigation, and indicate that the session history
   4325   // should be cleared.
   4326   NavigationController::LoadURLParams params(url4);
   4327   params.should_clear_history_list = true;
   4328   controller.LoadURLWithParams(params);
   4329 
   4330   // Verify that the pending entry correctly indicates that the session history
   4331   // should be cleared.
   4332   NavigationEntryImpl* entry =
   4333       NavigationEntryImpl::FromNavigationEntry(
   4334           controller.GetPendingEntry());
   4335   ASSERT_TRUE(entry);
   4336   EXPECT_TRUE(entry->should_clear_history_list());
   4337 
   4338   // Assume that the RV correctly cleared its history and commit the navigation.
   4339   contents()->GetPendingMainFrame()->GetRenderViewHost()->
   4340       set_simulate_history_list_was_cleared(true);
   4341   contents()->CommitPendingNavigation();
   4342 
   4343   // Verify that the NavigationController's session history was correctly
   4344   // cleared.
   4345   EXPECT_EQ(1, controller.GetEntryCount());
   4346   EXPECT_EQ(0, controller.GetCurrentEntryIndex());
   4347   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   4348   EXPECT_EQ(-1, controller.GetPendingEntryIndex());
   4349   EXPECT_FALSE(controller.CanGoBack());
   4350   EXPECT_FALSE(controller.CanGoForward());
   4351   EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
   4352 }
   4353 
   4354 TEST_F(NavigationControllerTest, PostThenReplaceStateThenReload) {
   4355   scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
   4356   EXPECT_FALSE(contents()->GetDelegate());
   4357   contents()->SetDelegate(delegate.get());
   4358 
   4359   // Submit a form.
   4360   GURL url("http://foo");
   4361   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   4362   params.page_id = 1;
   4363   params.url = url;
   4364   params.transition = ui::PAGE_TRANSITION_FORM_SUBMIT;
   4365   params.gesture = NavigationGestureUser;
   4366   params.page_state = PageState::CreateFromURL(url);
   4367   params.was_within_same_page = false;
   4368   params.is_post = true;
   4369   params.post_id = 2;
   4370   test_rvh()->SendNavigateWithParams(&params);
   4371 
   4372   // history.replaceState() is called.
   4373   GURL replace_url("http://foo#foo");
   4374   params.page_id = 1;
   4375   params.url = replace_url;
   4376   params.transition = ui::PAGE_TRANSITION_LINK;
   4377   params.gesture = NavigationGestureUser;
   4378   params.page_state = PageState::CreateFromURL(replace_url);
   4379   params.was_within_same_page = true;
   4380   params.is_post = false;
   4381   params.post_id = -1;
   4382   test_rvh()->SendNavigateWithParams(&params);
   4383 
   4384   // Now reload. replaceState overrides the POST, so we should not show a
   4385   // repost warning dialog.
   4386   controller_impl().Reload(true);
   4387   EXPECT_EQ(0, delegate->repost_form_warning_count());
   4388 }
   4389 
   4390 }  // namespace content
   4391