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