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