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