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