| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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/file_util.h" | |
| 6 #include "base/path_service.h" | |
| 7 #include "base/scoped_ptr.h" | |
| 8 #include "base/stl_util-inl.h" | |
| 9 #include "base/string_util.h" | |
| 10 #include "base/utf_string_conversions.h" | |
| 11 #include "chrome/browser/profiles/profile_manager.h" | |
| 12 #include "chrome/browser/history/history.h" | |
| 13 #include "chrome/browser/renderer_host/site_instance.h" | |
| 14 #include "chrome/browser/renderer_host/test/test_render_view_host.h" | |
| 15 #include "chrome/browser/sessions/session_service.h" | |
| 16 #include "chrome/browser/sessions/session_service_test_helper.h" | |
| 17 #include "chrome/browser/sessions/session_types.h" | |
| 18 #include "chrome/browser/tab_contents/navigation_controller.h" | |
| 19 #include "chrome/browser/tab_contents/navigation_entry.h" | |
| 20 #include "chrome/browser/tab_contents/tab_contents.h" | |
| 21 #include "chrome/browser/tab_contents/tab_contents_delegate.h" | |
| 22 #include "chrome/browser/tab_contents/test_tab_contents.h" | |
| 23 #include "chrome/common/notification_registrar.h" | |
| 24 #include "chrome/common/render_messages.h" | |
| 25 #include "chrome/common/render_messages_params.h" | |
| 26 #include "chrome/test/test_notification_tracker.h" | |
| 27 #include "chrome/test/testing_profile.h" | |
| 28 #include "net/base/net_util.h" | |
| 29 #include "testing/gtest/include/gtest/gtest.h" | |
| 30 #include "webkit/glue/webkit_glue.h" | |
| 31 | |
| 32 using base::Time; | |
| 33 | |
| 34 // NavigationControllerTest ---------------------------------------------------- | |
| 35 | |
| 36 class NavigationControllerTest : public RenderViewHostTestHarness { | |
| 37 public: | |
| 38 NavigationControllerTest() {} | |
| 39 }; | |
| 40 | |
| 41 // NavigationControllerHistoryTest --------------------------------------------- | |
| 42 | |
| 43 class NavigationControllerHistoryTest : public NavigationControllerTest { | |
| 44 public: | |
| 45 NavigationControllerHistoryTest() | |
| 46 : url0("http://foo1"), | |
| 47 url1("http://foo1"), | |
| 48 url2("http://foo1"), | |
| 49 profile_manager_(NULL) { | |
| 50 } | |
| 51 | |
| 52 virtual ~NavigationControllerHistoryTest() { | |
| 53 // Prevent our base class from deleting the profile since profile's | |
| 54 // lifetime is managed by profile_manager_. | |
| 55 STLDeleteElements(&windows_); | |
| 56 } | |
| 57 | |
| 58 // testing::Test overrides. | |
| 59 virtual void SetUp() { | |
| 60 NavigationControllerTest::SetUp(); | |
| 61 | |
| 62 // Force the session service to be created. | |
| 63 SessionService* service = new SessionService(profile()); | |
| 64 profile()->set_session_service(service); | |
| 65 service->SetWindowType(window_id, Browser::TYPE_NORMAL); | |
| 66 service->SetWindowBounds(window_id, gfx::Rect(0, 1, 2, 3), false); | |
| 67 service->SetTabIndexInWindow(window_id, | |
| 68 controller().session_id(), 0); | |
| 69 controller().SetWindowID(window_id); | |
| 70 | |
| 71 session_helper_.set_service(service); | |
| 72 } | |
| 73 | |
| 74 virtual void TearDown() { | |
| 75 // Release profile's reference to the session service. Otherwise the file | |
| 76 // will still be open and we won't be able to delete the directory below. | |
| 77 profile()->set_session_service(NULL); | |
| 78 session_helper_.set_service(NULL); | |
| 79 | |
| 80 // Make sure we wait for history to shut down before continuing. The task | |
| 81 // we add will cause our message loop to quit once it is destroyed. | |
| 82 HistoryService* history = | |
| 83 profile()->GetHistoryService(Profile::IMPLICIT_ACCESS); | |
| 84 if (history) { | |
| 85 history->SetOnBackendDestroyTask(new MessageLoop::QuitTask); | |
| 86 MessageLoop::current()->Run(); | |
| 87 } | |
| 88 | |
| 89 // Do normal cleanup before deleting the profile directory below. | |
| 90 NavigationControllerTest::TearDown(); | |
| 91 | |
| 92 ASSERT_TRUE(file_util::Delete(test_dir_, true)); | |
| 93 ASSERT_FALSE(file_util::PathExists(test_dir_)); | |
| 94 } | |
| 95 | |
| 96 // Deletes the current profile manager and creates a new one. Indirectly this | |
| 97 // shuts down the history database and reopens it. | |
| 98 void ReopenDatabase() { | |
| 99 session_helper_.set_service(NULL); | |
| 100 profile()->set_session_service(NULL); | |
| 101 | |
| 102 SessionService* service = new SessionService(profile()); | |
| 103 profile()->set_session_service(service); | |
| 104 session_helper_.set_service(service); | |
| 105 } | |
| 106 | |
| 107 void GetLastSession() { | |
| 108 profile()->GetSessionService()->TabClosed(controller().window_id(), | |
| 109 controller().session_id(), | |
| 110 false); | |
| 111 | |
| 112 ReopenDatabase(); | |
| 113 Time close_time; | |
| 114 | |
| 115 session_helper_.ReadWindows(&windows_); | |
| 116 } | |
| 117 | |
| 118 CancelableRequestConsumer consumer; | |
| 119 | |
| 120 // URLs for testing. | |
| 121 const GURL url0; | |
| 122 const GURL url1; | |
| 123 const GURL url2; | |
| 124 | |
| 125 std::vector<SessionWindow*> windows_; | |
| 126 | |
| 127 SessionID window_id; | |
| 128 | |
| 129 SessionServiceTestHelper session_helper_; | |
| 130 | |
| 131 private: | |
| 132 ProfileManager* profile_manager_; | |
| 133 FilePath test_dir_; | |
| 134 }; | |
| 135 | |
| 136 void RegisterForAllNavNotifications(TestNotificationTracker* tracker, | |
| 137 NavigationController* controller) { | |
| 138 tracker->ListenFor(NotificationType::NAV_ENTRY_COMMITTED, | |
| 139 Source<NavigationController>(controller)); | |
| 140 tracker->ListenFor(NotificationType::NAV_LIST_PRUNED, | |
| 141 Source<NavigationController>(controller)); | |
| 142 tracker->ListenFor(NotificationType::NAV_ENTRY_CHANGED, | |
| 143 Source<NavigationController>(controller)); | |
| 144 } | |
| 145 | |
| 146 // ----------------------------------------------------------------------------- | |
| 147 | |
| 148 TEST_F(NavigationControllerTest, Defaults) { | |
| 149 EXPECT_FALSE(controller().pending_entry()); | |
| 150 EXPECT_FALSE(controller().GetLastCommittedEntry()); | |
| 151 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 152 EXPECT_EQ(controller().last_committed_entry_index(), -1); | |
| 153 EXPECT_EQ(controller().entry_count(), 0); | |
| 154 EXPECT_FALSE(controller().CanGoBack()); | |
| 155 EXPECT_FALSE(controller().CanGoForward()); | |
| 156 } | |
| 157 | |
| 158 TEST_F(NavigationControllerTest, LoadURL) { | |
| 159 TestNotificationTracker notifications; | |
| 160 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 161 | |
| 162 const GURL url1("http://foo1"); | |
| 163 const GURL url2("http://foo2"); | |
| 164 | |
| 165 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 166 // Creating a pending notification should not have issued any of the | |
| 167 // notifications we're listening for. | |
| 168 EXPECT_EQ(0U, notifications.size()); | |
| 169 | |
| 170 // The load should now be pending. | |
| 171 EXPECT_EQ(controller().entry_count(), 0); | |
| 172 EXPECT_EQ(controller().last_committed_entry_index(), -1); | |
| 173 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 174 EXPECT_FALSE(controller().GetLastCommittedEntry()); | |
| 175 EXPECT_TRUE(controller().pending_entry()); | |
| 176 EXPECT_FALSE(controller().CanGoBack()); | |
| 177 EXPECT_FALSE(controller().CanGoForward()); | |
| 178 EXPECT_EQ(contents()->GetMaxPageID(), -1); | |
| 179 | |
| 180 // We should have gotten no notifications from the preceeding checks. | |
| 181 EXPECT_EQ(0U, notifications.size()); | |
| 182 | |
| 183 rvh()->SendNavigate(0, url1); | |
| 184 EXPECT_TRUE(notifications.Check1AndReset( | |
| 185 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 186 | |
| 187 // The load should now be committed. | |
| 188 EXPECT_EQ(controller().entry_count(), 1); | |
| 189 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 190 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 191 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 192 EXPECT_FALSE(controller().pending_entry()); | |
| 193 EXPECT_FALSE(controller().CanGoBack()); | |
| 194 EXPECT_FALSE(controller().CanGoForward()); | |
| 195 EXPECT_EQ(contents()->GetMaxPageID(), 0); | |
| 196 | |
| 197 // Load another... | |
| 198 controller().LoadURL(url2, GURL(), PageTransition::TYPED); | |
| 199 | |
| 200 // The load should now be pending. | |
| 201 EXPECT_EQ(controller().entry_count(), 1); | |
| 202 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 203 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 204 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 205 EXPECT_TRUE(controller().pending_entry()); | |
| 206 // TODO(darin): maybe this should really be true? | |
| 207 EXPECT_FALSE(controller().CanGoBack()); | |
| 208 EXPECT_FALSE(controller().CanGoForward()); | |
| 209 EXPECT_EQ(contents()->GetMaxPageID(), 0); | |
| 210 | |
| 211 rvh()->SendNavigate(1, url2); | |
| 212 EXPECT_TRUE(notifications.Check1AndReset( | |
| 213 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 214 | |
| 215 // The load should now be committed. | |
| 216 EXPECT_EQ(controller().entry_count(), 2); | |
| 217 EXPECT_EQ(controller().last_committed_entry_index(), 1); | |
| 218 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 219 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 220 EXPECT_FALSE(controller().pending_entry()); | |
| 221 EXPECT_TRUE(controller().CanGoBack()); | |
| 222 EXPECT_FALSE(controller().CanGoForward()); | |
| 223 EXPECT_EQ(contents()->GetMaxPageID(), 1); | |
| 224 } | |
| 225 | |
| 226 // Tests what happens when the same page is loaded again. Should not create a | |
| 227 // new session history entry. This is what happens when you press enter in the | |
| 228 // URL bar to reload: a pending entry is created and then it is discarded when | |
| 229 // the load commits (because WebCore didn't actually make a new entry). | |
| 230 TEST_F(NavigationControllerTest, LoadURL_SamePage) { | |
| 231 TestNotificationTracker notifications; | |
| 232 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 233 | |
| 234 const GURL url1("http://foo1"); | |
| 235 | |
| 236 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 237 EXPECT_EQ(0U, notifications.size()); | |
| 238 rvh()->SendNavigate(0, url1); | |
| 239 EXPECT_TRUE(notifications.Check1AndReset( | |
| 240 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 241 | |
| 242 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 243 EXPECT_EQ(0U, notifications.size()); | |
| 244 rvh()->SendNavigate(0, url1); | |
| 245 EXPECT_TRUE(notifications.Check1AndReset( | |
| 246 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 247 | |
| 248 // We should not have produced a new session history entry. | |
| 249 EXPECT_EQ(controller().entry_count(), 1); | |
| 250 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 251 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 252 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 253 EXPECT_FALSE(controller().pending_entry()); | |
| 254 EXPECT_FALSE(controller().CanGoBack()); | |
| 255 EXPECT_FALSE(controller().CanGoForward()); | |
| 256 } | |
| 257 | |
| 258 // Tests loading a URL but discarding it before the load commits. | |
| 259 TEST_F(NavigationControllerTest, LoadURL_Discarded) { | |
| 260 TestNotificationTracker notifications; | |
| 261 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 262 | |
| 263 const GURL url1("http://foo1"); | |
| 264 const GURL url2("http://foo2"); | |
| 265 | |
| 266 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 267 EXPECT_EQ(0U, notifications.size()); | |
| 268 rvh()->SendNavigate(0, url1); | |
| 269 EXPECT_TRUE(notifications.Check1AndReset( | |
| 270 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 271 | |
| 272 controller().LoadURL(url2, GURL(), PageTransition::TYPED); | |
| 273 controller().DiscardNonCommittedEntries(); | |
| 274 EXPECT_EQ(0U, notifications.size()); | |
| 275 | |
| 276 // Should not have produced a new session history entry. | |
| 277 EXPECT_EQ(controller().entry_count(), 1); | |
| 278 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 279 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 280 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 281 EXPECT_FALSE(controller().pending_entry()); | |
| 282 EXPECT_FALSE(controller().CanGoBack()); | |
| 283 EXPECT_FALSE(controller().CanGoForward()); | |
| 284 } | |
| 285 | |
| 286 // Tests navigations that come in unrequested. This happens when the user | |
| 287 // navigates from the web page, and here we test that there is no pending entry. | |
| 288 TEST_F(NavigationControllerTest, LoadURL_NoPending) { | |
| 289 TestNotificationTracker notifications; | |
| 290 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 291 | |
| 292 // First make an existing committed entry. | |
| 293 const GURL kExistingURL1("http://eh"); | |
| 294 controller().LoadURL(kExistingURL1, GURL(), | |
| 295 PageTransition::TYPED); | |
| 296 rvh()->SendNavigate(0, kExistingURL1); | |
| 297 EXPECT_TRUE(notifications.Check1AndReset( | |
| 298 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 299 | |
| 300 // Do a new navigation without making a pending one. | |
| 301 const GURL kNewURL("http://see"); | |
| 302 rvh()->SendNavigate(99, kNewURL); | |
| 303 | |
| 304 // There should no longer be any pending entry, and the third navigation we | |
| 305 // just made should be committed. | |
| 306 EXPECT_TRUE(notifications.Check1AndReset( | |
| 307 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 308 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 309 EXPECT_EQ(1, controller().last_committed_entry_index()); | |
| 310 EXPECT_EQ(kNewURL, controller().GetActiveEntry()->url()); | |
| 311 } | |
| 312 | |
| 313 // Tests navigating to a new URL when there is a new pending navigation that is | |
| 314 // not the one that just loaded. This will happen if the user types in a URL to | |
| 315 // somewhere slow, and then navigates the current page before the typed URL | |
| 316 // commits. | |
| 317 TEST_F(NavigationControllerTest, LoadURL_NewPending) { | |
| 318 TestNotificationTracker notifications; | |
| 319 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 320 | |
| 321 // First make an existing committed entry. | |
| 322 const GURL kExistingURL1("http://eh"); | |
| 323 controller().LoadURL(kExistingURL1, GURL(), | |
| 324 PageTransition::TYPED); | |
| 325 rvh()->SendNavigate(0, kExistingURL1); | |
| 326 EXPECT_TRUE(notifications.Check1AndReset( | |
| 327 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 328 | |
| 329 // Make a pending entry to somewhere new. | |
| 330 const GURL kExistingURL2("http://bee"); | |
| 331 controller().LoadURL(kExistingURL2, GURL(), | |
| 332 PageTransition::TYPED); | |
| 333 EXPECT_EQ(0U, notifications.size()); | |
| 334 | |
| 335 // Before that commits, do a new navigation. | |
| 336 const GURL kNewURL("http://see"); | |
| 337 rvh()->SendNavigate(3, kNewURL); | |
| 338 | |
| 339 // There should no longer be any pending entry, and the third navigation we | |
| 340 // just made should be committed. | |
| 341 EXPECT_TRUE(notifications.Check1AndReset( | |
| 342 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 343 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 344 EXPECT_EQ(1, controller().last_committed_entry_index()); | |
| 345 EXPECT_EQ(kNewURL, controller().GetActiveEntry()->url()); | |
| 346 } | |
| 347 | |
| 348 // Tests navigating to a new URL when there is a pending back/forward | |
| 349 // navigation. This will happen if the user hits back, but before that commits, | |
| 350 // they navigate somewhere new. | |
| 351 TEST_F(NavigationControllerTest, LoadURL_ExistingPending) { | |
| 352 TestNotificationTracker notifications; | |
| 353 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 354 | |
| 355 // First make some history. | |
| 356 const GURL kExistingURL1("http://eh"); | |
| 357 controller().LoadURL(kExistingURL1, GURL(), | |
| 358 PageTransition::TYPED); | |
| 359 rvh()->SendNavigate(0, kExistingURL1); | |
| 360 EXPECT_TRUE(notifications.Check1AndReset( | |
| 361 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 362 | |
| 363 const GURL kExistingURL2("http://bee"); | |
| 364 controller().LoadURL(kExistingURL2, GURL(), | |
| 365 PageTransition::TYPED); | |
| 366 rvh()->SendNavigate(1, kExistingURL2); | |
| 367 EXPECT_TRUE(notifications.Check1AndReset( | |
| 368 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 369 | |
| 370 // Now make a pending back/forward navigation. The zeroth entry should be | |
| 371 // pending. | |
| 372 controller().GoBack(); | |
| 373 EXPECT_EQ(0U, notifications.size()); | |
| 374 EXPECT_EQ(0, controller().pending_entry_index()); | |
| 375 EXPECT_EQ(1, controller().last_committed_entry_index()); | |
| 376 | |
| 377 // Before that commits, do a new navigation. | |
| 378 const GURL kNewURL("http://see"); | |
| 379 NavigationController::LoadCommittedDetails details; | |
| 380 rvh()->SendNavigate(3, kNewURL); | |
| 381 | |
| 382 // There should no longer be any pending entry, and the third navigation we | |
| 383 // just made should be committed. | |
| 384 EXPECT_TRUE(notifications.Check1AndReset( | |
| 385 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 386 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 387 EXPECT_EQ(2, controller().last_committed_entry_index()); | |
| 388 EXPECT_EQ(kNewURL, controller().GetActiveEntry()->url()); | |
| 389 } | |
| 390 | |
| 391 TEST_F(NavigationControllerTest, Reload) { | |
| 392 TestNotificationTracker notifications; | |
| 393 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 394 | |
| 395 const GURL url1("http://foo1"); | |
| 396 | |
| 397 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 398 EXPECT_EQ(0U, notifications.size()); | |
| 399 rvh()->SendNavigate(0, url1); | |
| 400 EXPECT_TRUE(notifications.Check1AndReset( | |
| 401 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 402 | |
| 403 controller().Reload(true); | |
| 404 EXPECT_EQ(0U, notifications.size()); | |
| 405 | |
| 406 // The reload is pending. | |
| 407 EXPECT_EQ(controller().entry_count(), 1); | |
| 408 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 409 EXPECT_EQ(controller().pending_entry_index(), 0); | |
| 410 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 411 EXPECT_TRUE(controller().pending_entry()); | |
| 412 EXPECT_FALSE(controller().CanGoBack()); | |
| 413 EXPECT_FALSE(controller().CanGoForward()); | |
| 414 | |
| 415 rvh()->SendNavigate(0, url1); | |
| 416 EXPECT_TRUE(notifications.Check1AndReset( | |
| 417 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 418 | |
| 419 // Now the reload is committed. | |
| 420 EXPECT_EQ(controller().entry_count(), 1); | |
| 421 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 422 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 423 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 424 EXPECT_FALSE(controller().pending_entry()); | |
| 425 EXPECT_FALSE(controller().CanGoBack()); | |
| 426 EXPECT_FALSE(controller().CanGoForward()); | |
| 427 } | |
| 428 | |
| 429 // Tests what happens when a reload navigation produces a new page. | |
| 430 TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) { | |
| 431 TestNotificationTracker notifications; | |
| 432 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 433 | |
| 434 const GURL url1("http://foo1"); | |
| 435 const GURL url2("http://foo2"); | |
| 436 | |
| 437 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 438 rvh()->SendNavigate(0, url1); | |
| 439 EXPECT_TRUE(notifications.Check1AndReset( | |
| 440 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 441 | |
| 442 controller().Reload(true); | |
| 443 EXPECT_EQ(0U, notifications.size()); | |
| 444 | |
| 445 rvh()->SendNavigate(1, url2); | |
| 446 EXPECT_TRUE(notifications.Check1AndReset( | |
| 447 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 448 | |
| 449 // Now the reload is committed. | |
| 450 EXPECT_EQ(controller().entry_count(), 2); | |
| 451 EXPECT_EQ(controller().last_committed_entry_index(), 1); | |
| 452 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 453 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 454 EXPECT_FALSE(controller().pending_entry()); | |
| 455 EXPECT_TRUE(controller().CanGoBack()); | |
| 456 EXPECT_FALSE(controller().CanGoForward()); | |
| 457 } | |
| 458 | |
| 459 // Tests what happens when we navigate back successfully | |
| 460 TEST_F(NavigationControllerTest, Back) { | |
| 461 TestNotificationTracker notifications; | |
| 462 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 463 | |
| 464 const GURL url1("http://foo1"); | |
| 465 rvh()->SendNavigate(0, url1); | |
| 466 EXPECT_TRUE(notifications.Check1AndReset( | |
| 467 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 468 | |
| 469 const GURL url2("http://foo2"); | |
| 470 rvh()->SendNavigate(1, url2); | |
| 471 EXPECT_TRUE(notifications.Check1AndReset( | |
| 472 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 473 | |
| 474 controller().GoBack(); | |
| 475 EXPECT_EQ(0U, notifications.size()); | |
| 476 | |
| 477 // We should now have a pending navigation to go back. | |
| 478 EXPECT_EQ(controller().entry_count(), 2); | |
| 479 EXPECT_EQ(controller().last_committed_entry_index(), 1); | |
| 480 EXPECT_EQ(controller().pending_entry_index(), 0); | |
| 481 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 482 EXPECT_TRUE(controller().pending_entry()); | |
| 483 EXPECT_FALSE(controller().CanGoBack()); | |
| 484 EXPECT_TRUE(controller().CanGoForward()); | |
| 485 | |
| 486 rvh()->SendNavigate(0, url2); | |
| 487 EXPECT_TRUE(notifications.Check1AndReset( | |
| 488 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 489 | |
| 490 // The back navigation completed successfully. | |
| 491 EXPECT_EQ(controller().entry_count(), 2); | |
| 492 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 493 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 494 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 495 EXPECT_FALSE(controller().pending_entry()); | |
| 496 EXPECT_FALSE(controller().CanGoBack()); | |
| 497 EXPECT_TRUE(controller().CanGoForward()); | |
| 498 } | |
| 499 | |
| 500 // Tests what happens when a back navigation produces a new page. | |
| 501 TEST_F(NavigationControllerTest, Back_GeneratesNewPage) { | |
| 502 TestNotificationTracker notifications; | |
| 503 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 504 | |
| 505 const GURL url1("http://foo1"); | |
| 506 const GURL url2("http://foo2"); | |
| 507 const GURL url3("http://foo3"); | |
| 508 | |
| 509 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 510 rvh()->SendNavigate(0, url1); | |
| 511 EXPECT_TRUE(notifications.Check1AndReset( | |
| 512 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 513 | |
| 514 controller().LoadURL(url2, GURL(), PageTransition::TYPED); | |
| 515 rvh()->SendNavigate(1, url2); | |
| 516 EXPECT_TRUE(notifications.Check1AndReset( | |
| 517 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 518 | |
| 519 controller().GoBack(); | |
| 520 EXPECT_EQ(0U, notifications.size()); | |
| 521 | |
| 522 // We should now have a pending navigation to go back. | |
| 523 EXPECT_EQ(controller().entry_count(), 2); | |
| 524 EXPECT_EQ(controller().last_committed_entry_index(), 1); | |
| 525 EXPECT_EQ(controller().pending_entry_index(), 0); | |
| 526 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 527 EXPECT_TRUE(controller().pending_entry()); | |
| 528 EXPECT_FALSE(controller().CanGoBack()); | |
| 529 EXPECT_TRUE(controller().CanGoForward()); | |
| 530 | |
| 531 rvh()->SendNavigate(2, url3); | |
| 532 EXPECT_TRUE(notifications.Check1AndReset( | |
| 533 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 534 | |
| 535 // The back navigation resulted in a completely new navigation. | |
| 536 // TODO(darin): perhaps this behavior will be confusing to users? | |
| 537 EXPECT_EQ(controller().entry_count(), 3); | |
| 538 EXPECT_EQ(controller().last_committed_entry_index(), 2); | |
| 539 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 540 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 541 EXPECT_FALSE(controller().pending_entry()); | |
| 542 EXPECT_TRUE(controller().CanGoBack()); | |
| 543 EXPECT_FALSE(controller().CanGoForward()); | |
| 544 } | |
| 545 | |
| 546 // Receives a back message when there is a new pending navigation entry. | |
| 547 TEST_F(NavigationControllerTest, Back_NewPending) { | |
| 548 TestNotificationTracker notifications; | |
| 549 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 550 | |
| 551 const GURL kUrl1("http://foo1"); | |
| 552 const GURL kUrl2("http://foo2"); | |
| 553 const GURL kUrl3("http://foo3"); | |
| 554 | |
| 555 // First navigate two places so we have some back history. | |
| 556 rvh()->SendNavigate(0, kUrl1); | |
| 557 EXPECT_TRUE(notifications.Check1AndReset( | |
| 558 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 559 | |
| 560 // controller().LoadURL(kUrl2, PageTransition::TYPED); | |
| 561 rvh()->SendNavigate(1, kUrl2); | |
| 562 EXPECT_TRUE(notifications.Check1AndReset( | |
| 563 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 564 | |
| 565 // Now start a new pending navigation and go back before it commits. | |
| 566 controller().LoadURL(kUrl3, GURL(), PageTransition::TYPED); | |
| 567 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 568 EXPECT_EQ(kUrl3, controller().pending_entry()->url()); | |
| 569 controller().GoBack(); | |
| 570 | |
| 571 // The pending navigation should now be the "back" item and the new one | |
| 572 // should be gone. | |
| 573 EXPECT_EQ(0, controller().pending_entry_index()); | |
| 574 EXPECT_EQ(kUrl1, controller().pending_entry()->url()); | |
| 575 } | |
| 576 | |
| 577 // Receives a back message when there is a different renavigation already | |
| 578 // pending. | |
| 579 TEST_F(NavigationControllerTest, Back_OtherBackPending) { | |
| 580 const GURL kUrl1("http://foo/1"); | |
| 581 const GURL kUrl2("http://foo/2"); | |
| 582 const GURL kUrl3("http://foo/3"); | |
| 583 | |
| 584 // First navigate three places so we have some back history. | |
| 585 rvh()->SendNavigate(0, kUrl1); | |
| 586 rvh()->SendNavigate(1, kUrl2); | |
| 587 rvh()->SendNavigate(2, kUrl3); | |
| 588 | |
| 589 // With nothing pending, say we get a navigation to the second entry. | |
| 590 rvh()->SendNavigate(1, kUrl2); | |
| 591 | |
| 592 // We know all the entries have the same site instance, so we can just grab | |
| 593 // a random one for looking up other entries. | |
| 594 SiteInstance* site_instance = | |
| 595 controller().GetLastCommittedEntry()->site_instance(); | |
| 596 | |
| 597 // That second URL should be the last committed and it should have gotten the | |
| 598 // new title. | |
| 599 EXPECT_EQ(kUrl2, controller().GetEntryWithPageID(site_instance, 1)->url()); | |
| 600 EXPECT_EQ(1, controller().last_committed_entry_index()); | |
| 601 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 602 | |
| 603 // Now go forward to the last item again and say it was committed. | |
| 604 controller().GoForward(); | |
| 605 rvh()->SendNavigate(2, kUrl3); | |
| 606 | |
| 607 // Now start going back one to the second page. It will be pending. | |
| 608 controller().GoBack(); | |
| 609 EXPECT_EQ(1, controller().pending_entry_index()); | |
| 610 EXPECT_EQ(2, controller().last_committed_entry_index()); | |
| 611 | |
| 612 // Not synthesize a totally new back event to the first page. This will not | |
| 613 // match the pending one. | |
| 614 rvh()->SendNavigate(0, kUrl1); | |
| 615 | |
| 616 // The navigation should not have affected the pending entry. | |
| 617 EXPECT_EQ(1, controller().pending_entry_index()); | |
| 618 | |
| 619 // But the navigated entry should be the last committed. | |
| 620 EXPECT_EQ(0, controller().last_committed_entry_index()); | |
| 621 EXPECT_EQ(kUrl1, controller().GetLastCommittedEntry()->url()); | |
| 622 } | |
| 623 | |
| 624 // Tests what happens when we navigate forward successfully. | |
| 625 TEST_F(NavigationControllerTest, Forward) { | |
| 626 TestNotificationTracker notifications; | |
| 627 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 628 | |
| 629 const GURL url1("http://foo1"); | |
| 630 const GURL url2("http://foo2"); | |
| 631 | |
| 632 rvh()->SendNavigate(0, url1); | |
| 633 EXPECT_TRUE(notifications.Check1AndReset( | |
| 634 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 635 | |
| 636 rvh()->SendNavigate(1, url2); | |
| 637 EXPECT_TRUE(notifications.Check1AndReset( | |
| 638 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 639 | |
| 640 controller().GoBack(); | |
| 641 rvh()->SendNavigate(0, url1); | |
| 642 EXPECT_TRUE(notifications.Check1AndReset( | |
| 643 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 644 | |
| 645 controller().GoForward(); | |
| 646 | |
| 647 // We should now have a pending navigation to go forward. | |
| 648 EXPECT_EQ(controller().entry_count(), 2); | |
| 649 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 650 EXPECT_EQ(controller().pending_entry_index(), 1); | |
| 651 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 652 EXPECT_TRUE(controller().pending_entry()); | |
| 653 EXPECT_TRUE(controller().CanGoBack()); | |
| 654 EXPECT_FALSE(controller().CanGoForward()); | |
| 655 | |
| 656 rvh()->SendNavigate(1, url2); | |
| 657 EXPECT_TRUE(notifications.Check1AndReset( | |
| 658 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 659 | |
| 660 // The forward navigation completed successfully. | |
| 661 EXPECT_EQ(controller().entry_count(), 2); | |
| 662 EXPECT_EQ(controller().last_committed_entry_index(), 1); | |
| 663 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 664 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 665 EXPECT_FALSE(controller().pending_entry()); | |
| 666 EXPECT_TRUE(controller().CanGoBack()); | |
| 667 EXPECT_FALSE(controller().CanGoForward()); | |
| 668 } | |
| 669 | |
| 670 // Tests what happens when a forward navigation produces a new page. | |
| 671 TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) { | |
| 672 TestNotificationTracker notifications; | |
| 673 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 674 | |
| 675 const GURL url1("http://foo1"); | |
| 676 const GURL url2("http://foo2"); | |
| 677 const GURL url3("http://foo3"); | |
| 678 | |
| 679 rvh()->SendNavigate(0, url1); | |
| 680 EXPECT_TRUE(notifications.Check1AndReset( | |
| 681 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 682 rvh()->SendNavigate(1, url2); | |
| 683 EXPECT_TRUE(notifications.Check1AndReset( | |
| 684 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 685 | |
| 686 controller().GoBack(); | |
| 687 rvh()->SendNavigate(0, url1); | |
| 688 EXPECT_TRUE(notifications.Check1AndReset( | |
| 689 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 690 | |
| 691 controller().GoForward(); | |
| 692 EXPECT_EQ(0U, notifications.size()); | |
| 693 | |
| 694 // Should now have a pending navigation to go forward. | |
| 695 EXPECT_EQ(controller().entry_count(), 2); | |
| 696 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 697 EXPECT_EQ(controller().pending_entry_index(), 1); | |
| 698 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 699 EXPECT_TRUE(controller().pending_entry()); | |
| 700 EXPECT_TRUE(controller().CanGoBack()); | |
| 701 EXPECT_FALSE(controller().CanGoForward()); | |
| 702 | |
| 703 rvh()->SendNavigate(2, url3); | |
| 704 EXPECT_TRUE(notifications.Check2AndReset( | |
| 705 NotificationType::NAV_LIST_PRUNED, | |
| 706 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 707 | |
| 708 EXPECT_EQ(controller().entry_count(), 2); | |
| 709 EXPECT_EQ(controller().last_committed_entry_index(), 1); | |
| 710 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 711 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 712 EXPECT_FALSE(controller().pending_entry()); | |
| 713 EXPECT_TRUE(controller().CanGoBack()); | |
| 714 EXPECT_FALSE(controller().CanGoForward()); | |
| 715 } | |
| 716 | |
| 717 // Two consequent navigation for the same URL entered in should be considered | |
| 718 // as SAME_PAGE navigation even when we are redirected to some other page. | |
| 719 TEST_F(NavigationControllerTest, Redirect) { | |
| 720 TestNotificationTracker notifications; | |
| 721 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 722 | |
| 723 const GURL url1("http://foo1"); | |
| 724 const GURL url2("http://foo2"); // Redirection target | |
| 725 | |
| 726 // First request | |
| 727 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 728 | |
| 729 EXPECT_EQ(0U, notifications.size()); | |
| 730 rvh()->SendNavigate(0, url2); | |
| 731 EXPECT_TRUE(notifications.Check1AndReset( | |
| 732 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 733 | |
| 734 // Second request | |
| 735 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 736 | |
| 737 EXPECT_TRUE(controller().pending_entry()); | |
| 738 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 739 EXPECT_EQ(url1, controller().GetActiveEntry()->url()); | |
| 740 | |
| 741 ViewHostMsg_FrameNavigate_Params params; | |
| 742 params.page_id = 0; | |
| 743 params.url = url2; | |
| 744 params.transition = PageTransition::SERVER_REDIRECT; | |
| 745 params.redirects.push_back(GURL("http://foo1")); | |
| 746 params.redirects.push_back(GURL("http://foo2")); | |
| 747 params.should_update_history = false; | |
| 748 params.gesture = NavigationGestureAuto; | |
| 749 params.is_post = false; | |
| 750 | |
| 751 NavigationController::LoadCommittedDetails details; | |
| 752 | |
| 753 EXPECT_EQ(0U, notifications.size()); | |
| 754 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 755 EXPECT_TRUE(notifications.Check1AndReset( | |
| 756 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 757 | |
| 758 EXPECT_TRUE(details.type == NavigationType::SAME_PAGE); | |
| 759 EXPECT_EQ(controller().entry_count(), 1); | |
| 760 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 761 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 762 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 763 EXPECT_FALSE(controller().pending_entry()); | |
| 764 EXPECT_EQ(url2, controller().GetActiveEntry()->url()); | |
| 765 | |
| 766 EXPECT_FALSE(controller().CanGoBack()); | |
| 767 EXPECT_FALSE(controller().CanGoForward()); | |
| 768 } | |
| 769 | |
| 770 // Similar to Redirect above, but the first URL is requested by POST, | |
| 771 // the second URL is requested by GET. NavigationEntry::has_post_data_ | |
| 772 // must be cleared. http://crbug.com/21245 | |
| 773 TEST_F(NavigationControllerTest, PostThenRedirect) { | |
| 774 TestNotificationTracker notifications; | |
| 775 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 776 | |
| 777 const GURL url1("http://foo1"); | |
| 778 const GURL url2("http://foo2"); // Redirection target | |
| 779 | |
| 780 // First request as POST | |
| 781 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 782 controller().GetActiveEntry()->set_has_post_data(true); | |
| 783 | |
| 784 EXPECT_EQ(0U, notifications.size()); | |
| 785 rvh()->SendNavigate(0, url2); | |
| 786 EXPECT_TRUE(notifications.Check1AndReset( | |
| 787 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 788 | |
| 789 // Second request | |
| 790 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 791 | |
| 792 EXPECT_TRUE(controller().pending_entry()); | |
| 793 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 794 EXPECT_EQ(url1, controller().GetActiveEntry()->url()); | |
| 795 | |
| 796 ViewHostMsg_FrameNavigate_Params params; | |
| 797 params.page_id = 0; | |
| 798 params.url = url2; | |
| 799 params.transition = PageTransition::SERVER_REDIRECT; | |
| 800 params.redirects.push_back(GURL("http://foo1")); | |
| 801 params.redirects.push_back(GURL("http://foo2")); | |
| 802 params.should_update_history = false; | |
| 803 params.gesture = NavigationGestureAuto; | |
| 804 params.is_post = false; | |
| 805 | |
| 806 NavigationController::LoadCommittedDetails details; | |
| 807 | |
| 808 EXPECT_EQ(0U, notifications.size()); | |
| 809 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 810 EXPECT_TRUE(notifications.Check1AndReset( | |
| 811 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 812 | |
| 813 EXPECT_TRUE(details.type == NavigationType::SAME_PAGE); | |
| 814 EXPECT_EQ(controller().entry_count(), 1); | |
| 815 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 816 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 817 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 818 EXPECT_FALSE(controller().pending_entry()); | |
| 819 EXPECT_EQ(url2, controller().GetActiveEntry()->url()); | |
| 820 EXPECT_FALSE(controller().GetActiveEntry()->has_post_data()); | |
| 821 | |
| 822 EXPECT_FALSE(controller().CanGoBack()); | |
| 823 EXPECT_FALSE(controller().CanGoForward()); | |
| 824 } | |
| 825 | |
| 826 // A redirect right off the bat should be a NEW_PAGE. | |
| 827 TEST_F(NavigationControllerTest, ImmediateRedirect) { | |
| 828 TestNotificationTracker notifications; | |
| 829 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 830 | |
| 831 const GURL url1("http://foo1"); | |
| 832 const GURL url2("http://foo2"); // Redirection target | |
| 833 | |
| 834 // First request | |
| 835 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 836 | |
| 837 EXPECT_TRUE(controller().pending_entry()); | |
| 838 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 839 EXPECT_EQ(url1, controller().GetActiveEntry()->url()); | |
| 840 | |
| 841 ViewHostMsg_FrameNavigate_Params params; | |
| 842 params.page_id = 0; | |
| 843 params.url = url2; | |
| 844 params.transition = PageTransition::SERVER_REDIRECT; | |
| 845 params.redirects.push_back(GURL("http://foo1")); | |
| 846 params.redirects.push_back(GURL("http://foo2")); | |
| 847 params.should_update_history = false; | |
| 848 params.gesture = NavigationGestureAuto; | |
| 849 params.is_post = false; | |
| 850 | |
| 851 NavigationController::LoadCommittedDetails details; | |
| 852 | |
| 853 EXPECT_EQ(0U, notifications.size()); | |
| 854 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 855 EXPECT_TRUE(notifications.Check1AndReset( | |
| 856 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 857 | |
| 858 EXPECT_TRUE(details.type == NavigationType::NEW_PAGE); | |
| 859 EXPECT_EQ(controller().entry_count(), 1); | |
| 860 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 861 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 862 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 863 EXPECT_FALSE(controller().pending_entry()); | |
| 864 EXPECT_EQ(url2, controller().GetActiveEntry()->url()); | |
| 865 | |
| 866 EXPECT_FALSE(controller().CanGoBack()); | |
| 867 EXPECT_FALSE(controller().CanGoForward()); | |
| 868 } | |
| 869 | |
| 870 // Tests navigation via link click within a subframe. A new navigation entry | |
| 871 // should be created. | |
| 872 TEST_F(NavigationControllerTest, NewSubframe) { | |
| 873 TestNotificationTracker notifications; | |
| 874 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 875 | |
| 876 const GURL url1("http://foo1"); | |
| 877 rvh()->SendNavigate(0, url1); | |
| 878 EXPECT_TRUE(notifications.Check1AndReset( | |
| 879 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 880 | |
| 881 const GURL url2("http://foo2"); | |
| 882 ViewHostMsg_FrameNavigate_Params params; | |
| 883 params.page_id = 1; | |
| 884 params.url = url2; | |
| 885 params.transition = PageTransition::MANUAL_SUBFRAME; | |
| 886 params.should_update_history = false; | |
| 887 params.gesture = NavigationGestureUser; | |
| 888 params.is_post = false; | |
| 889 | |
| 890 NavigationController::LoadCommittedDetails details; | |
| 891 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 892 EXPECT_TRUE(notifications.Check1AndReset( | |
| 893 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 894 EXPECT_EQ(url1, details.previous_url); | |
| 895 EXPECT_FALSE(details.is_auto); | |
| 896 EXPECT_FALSE(details.is_in_page); | |
| 897 EXPECT_FALSE(details.is_main_frame); | |
| 898 | |
| 899 // The new entry should be appended. | |
| 900 EXPECT_EQ(2, controller().entry_count()); | |
| 901 | |
| 902 // New entry should refer to the new page, but the old URL (entries only | |
| 903 // reflect the toplevel URL). | |
| 904 EXPECT_EQ(url1, details.entry->url()); | |
| 905 EXPECT_EQ(params.page_id, details.entry->page_id()); | |
| 906 } | |
| 907 | |
| 908 // Some pages create a popup, then write an iframe into it. This causes a | |
| 909 // subframe navigation without having any committed entry. Such navigations | |
| 910 // just get thrown on the ground, but we shouldn't crash. | |
| 911 TEST_F(NavigationControllerTest, SubframeOnEmptyPage) { | |
| 912 TestNotificationTracker notifications; | |
| 913 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 914 | |
| 915 // Navigation controller currently has no entries. | |
| 916 const GURL url("http://foo2"); | |
| 917 ViewHostMsg_FrameNavigate_Params params; | |
| 918 params.page_id = 1; | |
| 919 params.url = url; | |
| 920 params.transition = PageTransition::AUTO_SUBFRAME; | |
| 921 params.should_update_history = false; | |
| 922 params.gesture = NavigationGestureAuto; | |
| 923 params.is_post = false; | |
| 924 | |
| 925 NavigationController::LoadCommittedDetails details; | |
| 926 EXPECT_FALSE(controller().RendererDidNavigate(params, 0, &details)); | |
| 927 EXPECT_EQ(0U, notifications.size()); | |
| 928 } | |
| 929 | |
| 930 // Auto subframes are ones the page loads automatically like ads. They should | |
| 931 // not create new navigation entries. | |
| 932 TEST_F(NavigationControllerTest, AutoSubframe) { | |
| 933 TestNotificationTracker notifications; | |
| 934 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 935 | |
| 936 const GURL url1("http://foo1"); | |
| 937 rvh()->SendNavigate(0, url1); | |
| 938 EXPECT_TRUE(notifications.Check1AndReset( | |
| 939 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 940 | |
| 941 const GURL url2("http://foo2"); | |
| 942 ViewHostMsg_FrameNavigate_Params params; | |
| 943 params.page_id = 0; | |
| 944 params.url = url2; | |
| 945 params.transition = PageTransition::AUTO_SUBFRAME; | |
| 946 params.should_update_history = false; | |
| 947 params.gesture = NavigationGestureUser; | |
| 948 params.is_post = false; | |
| 949 | |
| 950 // Navigating should do nothing. | |
| 951 NavigationController::LoadCommittedDetails details; | |
| 952 EXPECT_FALSE(controller().RendererDidNavigate(params, 0, &details)); | |
| 953 EXPECT_EQ(0U, notifications.size()); | |
| 954 | |
| 955 // There should still be only one entry. | |
| 956 EXPECT_EQ(1, controller().entry_count()); | |
| 957 } | |
| 958 | |
| 959 // Tests navigation and then going back to a subframe navigation. | |
| 960 TEST_F(NavigationControllerTest, BackSubframe) { | |
| 961 TestNotificationTracker notifications; | |
| 962 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 963 | |
| 964 // Main page. | |
| 965 const GURL url1("http://foo1"); | |
| 966 rvh()->SendNavigate(0, url1); | |
| 967 EXPECT_TRUE(notifications.Check1AndReset( | |
| 968 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 969 | |
| 970 // First manual subframe navigation. | |
| 971 const GURL url2("http://foo2"); | |
| 972 ViewHostMsg_FrameNavigate_Params params; | |
| 973 params.page_id = 1; | |
| 974 params.url = url2; | |
| 975 params.transition = PageTransition::MANUAL_SUBFRAME; | |
| 976 params.should_update_history = false; | |
| 977 params.gesture = NavigationGestureUser; | |
| 978 params.is_post = false; | |
| 979 | |
| 980 // This should generate a new entry. | |
| 981 NavigationController::LoadCommittedDetails details; | |
| 982 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 983 EXPECT_TRUE(notifications.Check1AndReset( | |
| 984 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 985 EXPECT_EQ(2, controller().entry_count()); | |
| 986 | |
| 987 // Second manual subframe navigation should also make a new entry. | |
| 988 const GURL url3("http://foo3"); | |
| 989 params.page_id = 2; | |
| 990 params.url = url3; | |
| 991 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 992 EXPECT_TRUE(notifications.Check1AndReset( | |
| 993 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 994 EXPECT_EQ(3, controller().entry_count()); | |
| 995 EXPECT_EQ(2, controller().GetCurrentEntryIndex()); | |
| 996 | |
| 997 // Go back one. | |
| 998 controller().GoBack(); | |
| 999 params.url = url2; | |
| 1000 params.page_id = 1; | |
| 1001 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 1002 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1003 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1004 EXPECT_EQ(3, controller().entry_count()); | |
| 1005 EXPECT_EQ(1, controller().GetCurrentEntryIndex()); | |
| 1006 | |
| 1007 // Go back one more. | |
| 1008 controller().GoBack(); | |
| 1009 params.url = url1; | |
| 1010 params.page_id = 0; | |
| 1011 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 1012 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1013 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1014 EXPECT_EQ(3, controller().entry_count()); | |
| 1015 EXPECT_EQ(0, controller().GetCurrentEntryIndex()); | |
| 1016 } | |
| 1017 | |
| 1018 TEST_F(NavigationControllerTest, LinkClick) { | |
| 1019 TestNotificationTracker notifications; | |
| 1020 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 1021 | |
| 1022 const GURL url1("http://foo1"); | |
| 1023 const GURL url2("http://foo2"); | |
| 1024 | |
| 1025 rvh()->SendNavigate(0, url1); | |
| 1026 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1027 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1028 | |
| 1029 rvh()->SendNavigate(1, url2); | |
| 1030 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1031 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1032 | |
| 1033 // Should not have produced a new session history entry. | |
| 1034 EXPECT_EQ(controller().entry_count(), 2); | |
| 1035 EXPECT_EQ(controller().last_committed_entry_index(), 1); | |
| 1036 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 1037 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 1038 EXPECT_FALSE(controller().pending_entry()); | |
| 1039 EXPECT_TRUE(controller().CanGoBack()); | |
| 1040 EXPECT_FALSE(controller().CanGoForward()); | |
| 1041 } | |
| 1042 | |
| 1043 TEST_F(NavigationControllerTest, InPage) { | |
| 1044 TestNotificationTracker notifications; | |
| 1045 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 1046 | |
| 1047 // Main page. | |
| 1048 const GURL url1("http://foo"); | |
| 1049 rvh()->SendNavigate(0, url1); | |
| 1050 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1051 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1052 | |
| 1053 // First navigation. | |
| 1054 const GURL url2("http://foo#a"); | |
| 1055 ViewHostMsg_FrameNavigate_Params params; | |
| 1056 params.page_id = 1; | |
| 1057 params.url = url2; | |
| 1058 params.transition = PageTransition::LINK; | |
| 1059 params.should_update_history = false; | |
| 1060 params.gesture = NavigationGestureUser; | |
| 1061 params.is_post = false; | |
| 1062 | |
| 1063 // This should generate a new entry. | |
| 1064 NavigationController::LoadCommittedDetails details; | |
| 1065 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 1066 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1067 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1068 EXPECT_TRUE(details.is_in_page); | |
| 1069 EXPECT_FALSE(details.did_replace_entry); | |
| 1070 EXPECT_EQ(2, controller().entry_count()); | |
| 1071 | |
| 1072 // Go back one. | |
| 1073 ViewHostMsg_FrameNavigate_Params back_params(params); | |
| 1074 controller().GoBack(); | |
| 1075 back_params.url = url1; | |
| 1076 back_params.page_id = 0; | |
| 1077 EXPECT_TRUE(controller().RendererDidNavigate(back_params, 0, &details)); | |
| 1078 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1079 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1080 // is_in_page is false in that case but should be true. | |
| 1081 // See comment in AreURLsInPageNavigation() in navigation_controller.cc | |
| 1082 // EXPECT_TRUE(details.is_in_page); | |
| 1083 EXPECT_EQ(2, controller().entry_count()); | |
| 1084 EXPECT_EQ(0, controller().GetCurrentEntryIndex()); | |
| 1085 EXPECT_EQ(back_params.url, controller().GetActiveEntry()->url()); | |
| 1086 | |
| 1087 // Go forward | |
| 1088 ViewHostMsg_FrameNavigate_Params forward_params(params); | |
| 1089 controller().GoForward(); | |
| 1090 forward_params.url = url2; | |
| 1091 forward_params.page_id = 1; | |
| 1092 EXPECT_TRUE(controller().RendererDidNavigate(forward_params, 0, &details)); | |
| 1093 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1094 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1095 EXPECT_TRUE(details.is_in_page); | |
| 1096 EXPECT_EQ(2, controller().entry_count()); | |
| 1097 EXPECT_EQ(1, controller().GetCurrentEntryIndex()); | |
| 1098 EXPECT_EQ(forward_params.url, | |
| 1099 controller().GetActiveEntry()->url()); | |
| 1100 | |
| 1101 // Now go back and forward again. This is to work around a bug where we would | |
| 1102 // compare the incoming URL with the last committed entry rather than the | |
| 1103 // one identified by an existing page ID. This would result in the second URL | |
| 1104 // losing the reference fragment when you navigate away from it and then back. | |
| 1105 controller().GoBack(); | |
| 1106 EXPECT_TRUE(controller().RendererDidNavigate(back_params, 0, &details)); | |
| 1107 controller().GoForward(); | |
| 1108 EXPECT_TRUE(controller().RendererDidNavigate(forward_params, 0, &details)); | |
| 1109 EXPECT_EQ(forward_params.url, | |
| 1110 controller().GetActiveEntry()->url()); | |
| 1111 | |
| 1112 // Finally, navigate to an unrelated URL to make sure in_page is not sticky. | |
| 1113 const GURL url3("http://bar"); | |
| 1114 params.page_id = 2; | |
| 1115 params.url = url3; | |
| 1116 notifications.Reset(); | |
| 1117 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 1118 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1119 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1120 EXPECT_FALSE(details.is_in_page); | |
| 1121 } | |
| 1122 | |
| 1123 TEST_F(NavigationControllerTest, InPage_Replace) { | |
| 1124 TestNotificationTracker notifications; | |
| 1125 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 1126 | |
| 1127 // Main page. | |
| 1128 const GURL url1("http://foo"); | |
| 1129 rvh()->SendNavigate(0, url1); | |
| 1130 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1131 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1132 | |
| 1133 // First navigation. | |
| 1134 const GURL url2("http://foo#a"); | |
| 1135 ViewHostMsg_FrameNavigate_Params params; | |
| 1136 params.page_id = 0; // Same page_id | |
| 1137 params.url = url2; | |
| 1138 params.transition = PageTransition::LINK; | |
| 1139 params.should_update_history = false; | |
| 1140 params.gesture = NavigationGestureUser; | |
| 1141 params.is_post = false; | |
| 1142 | |
| 1143 // This should NOT generate a new entry. | |
| 1144 NavigationController::LoadCommittedDetails details; | |
| 1145 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 1146 EXPECT_TRUE(notifications.Check2AndReset( | |
| 1147 NotificationType::NAV_LIST_PRUNED, | |
| 1148 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1149 EXPECT_TRUE(details.is_in_page); | |
| 1150 EXPECT_TRUE(details.did_replace_entry); | |
| 1151 EXPECT_EQ(1, controller().entry_count()); | |
| 1152 } | |
| 1153 | |
| 1154 // Tests for http://crbug.com/40395 | |
| 1155 // Simulates this: | |
| 1156 // <script> | |
| 1157 // window.location.replace("#a"); | |
| 1158 // window.location='http://foo3/'; | |
| 1159 // </script> | |
| 1160 TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) { | |
| 1161 TestNotificationTracker notifications; | |
| 1162 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 1163 | |
| 1164 // Load an initial page. | |
| 1165 { | |
| 1166 const GURL url("http://foo/"); | |
| 1167 rvh()->SendNavigate(0, url); | |
| 1168 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1169 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1170 } | |
| 1171 | |
| 1172 // Navigate to a new page. | |
| 1173 { | |
| 1174 const GURL url("http://foo2/"); | |
| 1175 rvh()->SendNavigate(1, url); | |
| 1176 controller().DocumentLoadedInFrame(); | |
| 1177 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1178 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1179 } | |
| 1180 | |
| 1181 // Navigate within the page. | |
| 1182 { | |
| 1183 const GURL url("http://foo2/#a"); | |
| 1184 ViewHostMsg_FrameNavigate_Params params; | |
| 1185 params.page_id = 1; // Same page_id | |
| 1186 params.url = url; | |
| 1187 params.transition = PageTransition::LINK; | |
| 1188 params.redirects.push_back(url); | |
| 1189 params.should_update_history = true; | |
| 1190 params.gesture = NavigationGestureUnknown; | |
| 1191 params.is_post = false; | |
| 1192 | |
| 1193 // This should NOT generate a new entry. | |
| 1194 NavigationController::LoadCommittedDetails details; | |
| 1195 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 1196 EXPECT_TRUE(notifications.Check2AndReset( | |
| 1197 NotificationType::NAV_LIST_PRUNED, | |
| 1198 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1199 EXPECT_TRUE(details.is_in_page); | |
| 1200 EXPECT_TRUE(details.did_replace_entry); | |
| 1201 EXPECT_EQ(2, controller().entry_count()); | |
| 1202 } | |
| 1203 | |
| 1204 // Perform a client redirect to a new page. | |
| 1205 { | |
| 1206 const GURL url("http://foo3/"); | |
| 1207 ViewHostMsg_FrameNavigate_Params params; | |
| 1208 params.page_id = 2; // New page_id | |
| 1209 params.url = url; | |
| 1210 params.transition = PageTransition::CLIENT_REDIRECT; | |
| 1211 params.redirects.push_back(GURL("http://foo2/#a")); | |
| 1212 params.redirects.push_back(url); | |
| 1213 params.should_update_history = true; | |
| 1214 params.gesture = NavigationGestureUnknown; | |
| 1215 params.is_post = false; | |
| 1216 | |
| 1217 // This SHOULD generate a new entry. | |
| 1218 NavigationController::LoadCommittedDetails details; | |
| 1219 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details)); | |
| 1220 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1221 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1222 EXPECT_FALSE(details.is_in_page); | |
| 1223 EXPECT_EQ(3, controller().entry_count()); | |
| 1224 } | |
| 1225 | |
| 1226 // Verify that BACK brings us back to http://foo2/. | |
| 1227 { | |
| 1228 const GURL url("http://foo2/"); | |
| 1229 controller().GoBack(); | |
| 1230 rvh()->SendNavigate(1, url); | |
| 1231 EXPECT_TRUE(notifications.Check1AndReset( | |
| 1232 NotificationType::NAV_ENTRY_COMMITTED)); | |
| 1233 EXPECT_EQ(url, controller().GetActiveEntry()->url()); | |
| 1234 } | |
| 1235 } | |
| 1236 | |
| 1237 // NotificationObserver implementation used in verifying we've received the | |
| 1238 // NotificationType::NAV_LIST_PRUNED method. | |
| 1239 class PrunedListener : public NotificationObserver { | |
| 1240 public: | |
| 1241 explicit PrunedListener(NavigationController* controller) | |
| 1242 : notification_count_(0) { | |
| 1243 registrar_.Add(this, NotificationType::NAV_LIST_PRUNED, | |
| 1244 Source<NavigationController>(controller)); | |
| 1245 } | |
| 1246 | |
| 1247 virtual void Observe(NotificationType type, | |
| 1248 const NotificationSource& source, | |
| 1249 const NotificationDetails& details) { | |
| 1250 if (type == NotificationType::NAV_LIST_PRUNED) { | |
| 1251 notification_count_++; | |
| 1252 details_ = *(Details<NavigationController::PrunedDetails>(details).ptr()); | |
| 1253 } | |
| 1254 } | |
| 1255 | |
| 1256 // Number of times NAV_LIST_PRUNED has been observed. | |
| 1257 int notification_count_; | |
| 1258 | |
| 1259 // Details from the last NAV_LIST_PRUNED. | |
| 1260 NavigationController::PrunedDetails details_; | |
| 1261 | |
| 1262 private: | |
| 1263 NotificationRegistrar registrar_; | |
| 1264 | |
| 1265 DISALLOW_COPY_AND_ASSIGN(PrunedListener); | |
| 1266 }; | |
| 1267 | |
| 1268 // Tests that we limit the number of navigation entries created correctly. | |
| 1269 TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) { | |
| 1270 size_t original_count = NavigationController::max_entry_count(); | |
| 1271 const int kMaxEntryCount = 5; | |
| 1272 | |
| 1273 NavigationController::set_max_entry_count(kMaxEntryCount); | |
| 1274 | |
| 1275 int url_index; | |
| 1276 // Load up to the max count, all entries should be there. | |
| 1277 for (url_index = 0; url_index < kMaxEntryCount; url_index++) { | |
| 1278 GURL url(StringPrintf("http://www.a.com/%d", url_index)); | |
| 1279 controller().LoadURL(url, GURL(), PageTransition::TYPED); | |
| 1280 rvh()->SendNavigate(url_index, url); | |
| 1281 } | |
| 1282 | |
| 1283 EXPECT_EQ(controller().entry_count(), kMaxEntryCount); | |
| 1284 | |
| 1285 // Created a PrunedListener to observe prune notifications. | |
| 1286 PrunedListener listener(&controller()); | |
| 1287 | |
| 1288 // Navigate some more. | |
| 1289 GURL url(StringPrintf("http://www.a.com/%d", url_index)); | |
| 1290 controller().LoadURL(url, GURL(), PageTransition::TYPED); | |
| 1291 rvh()->SendNavigate(url_index, url); | |
| 1292 url_index++; | |
| 1293 | |
| 1294 // We should have got a pruned navigation. | |
| 1295 EXPECT_EQ(1, listener.notification_count_); | |
| 1296 EXPECT_TRUE(listener.details_.from_front); | |
| 1297 EXPECT_EQ(1, listener.details_.count); | |
| 1298 | |
| 1299 // We expect http://www.a.com/0 to be gone. | |
| 1300 EXPECT_EQ(controller().entry_count(), kMaxEntryCount); | |
| 1301 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), | |
| 1302 GURL("http:////www.a.com/1")); | |
| 1303 | |
| 1304 // More navigations. | |
| 1305 for (int i = 0; i < 3; i++) { | |
| 1306 url = GURL(StringPrintf("http:////www.a.com/%d", url_index)); | |
| 1307 controller().LoadURL(url, GURL(), PageTransition::TYPED); | |
| 1308 rvh()->SendNavigate(url_index, url); | |
| 1309 url_index++; | |
| 1310 } | |
| 1311 EXPECT_EQ(controller().entry_count(), kMaxEntryCount); | |
| 1312 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), | |
| 1313 GURL("http:////www.a.com/4")); | |
| 1314 | |
| 1315 NavigationController::set_max_entry_count(original_count); | |
| 1316 } | |
| 1317 | |
| 1318 // Tests that we can do a restore and navigate to the restored entries and | |
| 1319 // everything is updated properly. This can be tricky since there is no | |
| 1320 // SiteInstance for the entries created initially. | |
| 1321 TEST_F(NavigationControllerTest, RestoreNavigate) { | |
| 1322 // Create a NavigationController with a restored set of tabs. | |
| 1323 GURL url("http://foo"); | |
| 1324 std::vector<TabNavigation> navigations; | |
| 1325 navigations.push_back(TabNavigation(0, url, GURL(), | |
| 1326 ASCIIToUTF16("Title"), "state", | |
| 1327 PageTransition::LINK)); | |
| 1328 TabContents our_contents(profile(), NULL, MSG_ROUTING_NONE, NULL, NULL); | |
| 1329 NavigationController& our_controller = our_contents.controller(); | |
| 1330 our_controller.RestoreFromState(navigations, 0, true); | |
| 1331 our_controller.GoToIndex(0); | |
| 1332 | |
| 1333 // We should now have one entry, and it should be "pending". | |
| 1334 EXPECT_EQ(1, our_controller.entry_count()); | |
| 1335 EXPECT_EQ(our_controller.GetEntryAtIndex(0), | |
| 1336 our_controller.pending_entry()); | |
| 1337 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->page_id()); | |
| 1338 EXPECT_EQ(NavigationEntry::RESTORE_LAST_SESSION, | |
| 1339 our_controller.GetEntryAtIndex(0)->restore_type()); | |
| 1340 | |
| 1341 // Say we navigated to that entry. | |
| 1342 ViewHostMsg_FrameNavigate_Params params; | |
| 1343 params.page_id = 0; | |
| 1344 params.url = url; | |
| 1345 params.transition = PageTransition::LINK; | |
| 1346 params.should_update_history = false; | |
| 1347 params.gesture = NavigationGestureUser; | |
| 1348 params.is_post = false; | |
| 1349 NavigationController::LoadCommittedDetails details; | |
| 1350 our_controller.RendererDidNavigate(params, 0, &details); | |
| 1351 | |
| 1352 // There should be no longer any pending entry and one committed one. This | |
| 1353 // means that we were able to locate the entry, assign its site instance, and | |
| 1354 // commit it properly. | |
| 1355 EXPECT_EQ(1, our_controller.entry_count()); | |
| 1356 EXPECT_EQ(0, our_controller.last_committed_entry_index()); | |
| 1357 EXPECT_FALSE(our_controller.pending_entry()); | |
| 1358 EXPECT_EQ(url, | |
| 1359 our_controller.GetLastCommittedEntry()->site_instance()->site()); | |
| 1360 EXPECT_EQ(NavigationEntry::RESTORE_NONE, | |
| 1361 our_controller.GetEntryAtIndex(0)->restore_type()); | |
| 1362 } | |
| 1363 | |
| 1364 // Make sure that the page type and stuff is correct after an interstitial. | |
| 1365 TEST_F(NavigationControllerTest, Interstitial) { | |
| 1366 // First navigate somewhere normal. | |
| 1367 const GURL url1("http://foo"); | |
| 1368 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 1369 rvh()->SendNavigate(0, url1); | |
| 1370 | |
| 1371 // Now navigate somewhere with an interstitial. | |
| 1372 const GURL url2("http://bar"); | |
| 1373 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 1374 controller().pending_entry()->set_page_type(INTERSTITIAL_PAGE); | |
| 1375 | |
| 1376 // At this point the interstitial will be displayed and the load will still | |
| 1377 // be pending. If the user continues, the load will commit. | |
| 1378 rvh()->SendNavigate(1, url2); | |
| 1379 | |
| 1380 // The page should be a normal page again. | |
| 1381 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->url()); | |
| 1382 EXPECT_EQ(NORMAL_PAGE, controller().GetLastCommittedEntry()->page_type()); | |
| 1383 } | |
| 1384 | |
| 1385 TEST_F(NavigationControllerTest, RemoveEntry) { | |
| 1386 const GURL url1("http://foo1"); | |
| 1387 const GURL url2("http://foo2"); | |
| 1388 const GURL url3("http://foo3"); | |
| 1389 const GURL url4("http://foo4"); | |
| 1390 const GURL url5("http://foo5"); | |
| 1391 const GURL pending_url("http://pending"); | |
| 1392 const GURL default_url("http://default"); | |
| 1393 | |
| 1394 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 1395 rvh()->SendNavigate(0, url1); | |
| 1396 controller().LoadURL(url2, GURL(), PageTransition::TYPED); | |
| 1397 rvh()->SendNavigate(1, url2); | |
| 1398 controller().LoadURL(url3, GURL(), PageTransition::TYPED); | |
| 1399 rvh()->SendNavigate(2, url3); | |
| 1400 controller().LoadURL(url4, GURL(), PageTransition::TYPED); | |
| 1401 rvh()->SendNavigate(3, url4); | |
| 1402 controller().LoadURL(url5, GURL(), PageTransition::TYPED); | |
| 1403 rvh()->SendNavigate(4, url5); | |
| 1404 | |
| 1405 // Remove the last entry. | |
| 1406 controller().RemoveEntryAtIndex( | |
| 1407 controller().entry_count() - 1, default_url); | |
| 1408 EXPECT_EQ(4, controller().entry_count()); | |
| 1409 EXPECT_EQ(3, controller().last_committed_entry_index()); | |
| 1410 NavigationEntry* pending_entry = controller().pending_entry(); | |
| 1411 EXPECT_TRUE(pending_entry && pending_entry->url() == url4); | |
| 1412 | |
| 1413 // Add a pending entry. | |
| 1414 controller().LoadURL(pending_url, GURL(), PageTransition::TYPED); | |
| 1415 // Now remove the last entry. | |
| 1416 controller().RemoveEntryAtIndex( | |
| 1417 controller().entry_count() - 1, default_url); | |
| 1418 // The pending entry should have been discarded and the last committed entry | |
| 1419 // removed. | |
| 1420 EXPECT_EQ(3, controller().entry_count()); | |
| 1421 EXPECT_EQ(2, controller().last_committed_entry_index()); | |
| 1422 pending_entry = controller().pending_entry(); | |
| 1423 EXPECT_TRUE(pending_entry && pending_entry->url() == url3); | |
| 1424 | |
| 1425 // Remove an entry which is not the last committed one. | |
| 1426 controller().RemoveEntryAtIndex(0, default_url); | |
| 1427 EXPECT_EQ(2, controller().entry_count()); | |
| 1428 EXPECT_EQ(1, controller().last_committed_entry_index()); | |
| 1429 // No navigation should have been initiated since we did not remove the | |
| 1430 // current entry. | |
| 1431 EXPECT_FALSE(controller().pending_entry()); | |
| 1432 | |
| 1433 // Remove the 2 remaining entries. | |
| 1434 controller().RemoveEntryAtIndex(1, default_url); | |
| 1435 controller().RemoveEntryAtIndex(0, default_url); | |
| 1436 | |
| 1437 // This should have created a pending default entry. | |
| 1438 EXPECT_EQ(0, controller().entry_count()); | |
| 1439 EXPECT_EQ(-1, controller().last_committed_entry_index()); | |
| 1440 pending_entry = controller().pending_entry(); | |
| 1441 EXPECT_TRUE(pending_entry && pending_entry->url() == default_url); | |
| 1442 } | |
| 1443 | |
| 1444 // Tests the transient entry, making sure it goes away with all navigations. | |
| 1445 TEST_F(NavigationControllerTest, TransientEntry) { | |
| 1446 TestNotificationTracker notifications; | |
| 1447 RegisterForAllNavNotifications(¬ifications, &controller()); | |
| 1448 | |
| 1449 const GURL url0("http://foo0"); | |
| 1450 const GURL url1("http://foo1"); | |
| 1451 const GURL url2("http://foo2"); | |
| 1452 const GURL url3("http://foo3"); | |
| 1453 const GURL url4("http://foo4"); | |
| 1454 const GURL transient_url("http://transient"); | |
| 1455 | |
| 1456 controller().LoadURL(url0, GURL(), PageTransition::TYPED); | |
| 1457 rvh()->SendNavigate(0, url0); | |
| 1458 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 1459 rvh()->SendNavigate(1, url1); | |
| 1460 | |
| 1461 notifications.Reset(); | |
| 1462 | |
| 1463 // Adding a transient with no pending entry. | |
| 1464 NavigationEntry* transient_entry = new NavigationEntry; | |
| 1465 transient_entry->set_url(transient_url); | |
| 1466 controller().AddTransientEntry(transient_entry); | |
| 1467 | |
| 1468 // We should not have received any notifications. | |
| 1469 EXPECT_EQ(0U, notifications.size()); | |
| 1470 | |
| 1471 // Check our state. | |
| 1472 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url()); | |
| 1473 EXPECT_EQ(controller().entry_count(), 3); | |
| 1474 EXPECT_EQ(controller().last_committed_entry_index(), 1); | |
| 1475 EXPECT_EQ(controller().pending_entry_index(), -1); | |
| 1476 EXPECT_TRUE(controller().GetLastCommittedEntry()); | |
| 1477 EXPECT_FALSE(controller().pending_entry()); | |
| 1478 EXPECT_TRUE(controller().CanGoBack()); | |
| 1479 EXPECT_FALSE(controller().CanGoForward()); | |
| 1480 EXPECT_EQ(contents()->GetMaxPageID(), 1); | |
| 1481 | |
| 1482 // Navigate. | |
| 1483 controller().LoadURL(url2, GURL(), PageTransition::TYPED); | |
| 1484 rvh()->SendNavigate(2, url2); | |
| 1485 | |
| 1486 // We should have navigated, transient entry should be gone. | |
| 1487 EXPECT_EQ(url2, controller().GetActiveEntry()->url()); | |
| 1488 EXPECT_EQ(controller().entry_count(), 3); | |
| 1489 | |
| 1490 // Add a transient again, then navigate with no pending entry this time. | |
| 1491 transient_entry = new NavigationEntry; | |
| 1492 transient_entry->set_url(transient_url); | |
| 1493 controller().AddTransientEntry(transient_entry); | |
| 1494 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url()); | |
| 1495 rvh()->SendNavigate(3, url3); | |
| 1496 // Transient entry should be gone. | |
| 1497 EXPECT_EQ(url3, controller().GetActiveEntry()->url()); | |
| 1498 EXPECT_EQ(controller().entry_count(), 4); | |
| 1499 | |
| 1500 // Initiate a navigation, add a transient then commit navigation. | |
| 1501 controller().LoadURL(url4, GURL(), PageTransition::TYPED); | |
| 1502 transient_entry = new NavigationEntry; | |
| 1503 transient_entry->set_url(transient_url); | |
| 1504 controller().AddTransientEntry(transient_entry); | |
| 1505 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url()); | |
| 1506 rvh()->SendNavigate(4, url4); | |
| 1507 EXPECT_EQ(url4, controller().GetActiveEntry()->url()); | |
| 1508 EXPECT_EQ(controller().entry_count(), 5); | |
| 1509 | |
| 1510 // Add a transient and go back. This should simply remove the transient. | |
| 1511 transient_entry = new NavigationEntry; | |
| 1512 transient_entry->set_url(transient_url); | |
| 1513 controller().AddTransientEntry(transient_entry); | |
| 1514 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url()); | |
| 1515 EXPECT_TRUE(controller().CanGoBack()); | |
| 1516 EXPECT_FALSE(controller().CanGoForward()); | |
| 1517 controller().GoBack(); | |
| 1518 // Transient entry should be gone. | |
| 1519 EXPECT_EQ(url4, controller().GetActiveEntry()->url()); | |
| 1520 EXPECT_EQ(controller().entry_count(), 5); | |
| 1521 rvh()->SendNavigate(3, url3); | |
| 1522 | |
| 1523 // Add a transient and go to an entry before the current one. | |
| 1524 transient_entry = new NavigationEntry; | |
| 1525 transient_entry->set_url(transient_url); | |
| 1526 controller().AddTransientEntry(transient_entry); | |
| 1527 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url()); | |
| 1528 controller().GoToIndex(1); | |
| 1529 // The navigation should have been initiated, transient entry should be gone. | |
| 1530 EXPECT_EQ(url1, controller().GetActiveEntry()->url()); | |
| 1531 rvh()->SendNavigate(1, url1); | |
| 1532 | |
| 1533 // Add a transient and go to an entry after the current one. | |
| 1534 transient_entry = new NavigationEntry; | |
| 1535 transient_entry->set_url(transient_url); | |
| 1536 controller().AddTransientEntry(transient_entry); | |
| 1537 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url()); | |
| 1538 controller().GoToIndex(3); | |
| 1539 // The navigation should have been initiated, transient entry should be gone. | |
| 1540 // Because of the transient entry that is removed, going to index 3 makes us | |
| 1541 // land on url2. | |
| 1542 EXPECT_EQ(url2, controller().GetActiveEntry()->url()); | |
| 1543 rvh()->SendNavigate(2, url2); | |
| 1544 | |
| 1545 // Add a transient and go forward. | |
| 1546 transient_entry = new NavigationEntry; | |
| 1547 transient_entry->set_url(transient_url); | |
| 1548 controller().AddTransientEntry(transient_entry); | |
| 1549 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url()); | |
| 1550 EXPECT_TRUE(controller().CanGoForward()); | |
| 1551 controller().GoForward(); | |
| 1552 // We should have navigated, transient entry should be gone. | |
| 1553 EXPECT_EQ(url3, controller().GetActiveEntry()->url()); | |
| 1554 rvh()->SendNavigate(3, url3); | |
| 1555 | |
| 1556 // Ensure the URLS are correct. | |
| 1557 EXPECT_EQ(controller().entry_count(), 5); | |
| 1558 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url0); | |
| 1559 EXPECT_EQ(controller().GetEntryAtIndex(1)->url(), url1); | |
| 1560 EXPECT_EQ(controller().GetEntryAtIndex(2)->url(), url2); | |
| 1561 EXPECT_EQ(controller().GetEntryAtIndex(3)->url(), url3); | |
| 1562 EXPECT_EQ(controller().GetEntryAtIndex(4)->url(), url4); | |
| 1563 } | |
| 1564 | |
| 1565 // Tests that IsInPageNavigation returns appropriate results. Prevents | |
| 1566 // regression for bug 1126349. | |
| 1567 TEST_F(NavigationControllerTest, IsInPageNavigation) { | |
| 1568 // Navigate to URL with no refs. | |
| 1569 const GURL url("http://www.google.com/home.html"); | |
| 1570 rvh()->SendNavigate(0, url); | |
| 1571 | |
| 1572 // Reloading the page is not an in-page navigation. | |
| 1573 EXPECT_FALSE(controller().IsURLInPageNavigation(url)); | |
| 1574 const GURL other_url("http://www.google.com/add.html"); | |
| 1575 EXPECT_FALSE(controller().IsURLInPageNavigation(other_url)); | |
| 1576 const GURL url_with_ref("http://www.google.com/home.html#my_ref"); | |
| 1577 EXPECT_TRUE(controller().IsURLInPageNavigation(url_with_ref)); | |
| 1578 | |
| 1579 // Navigate to URL with refs. | |
| 1580 rvh()->SendNavigate(1, url_with_ref); | |
| 1581 | |
| 1582 // Reloading the page is not an in-page navigation. | |
| 1583 EXPECT_FALSE(controller().IsURLInPageNavigation(url_with_ref)); | |
| 1584 EXPECT_FALSE(controller().IsURLInPageNavigation(url)); | |
| 1585 EXPECT_FALSE(controller().IsURLInPageNavigation(other_url)); | |
| 1586 const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref"); | |
| 1587 EXPECT_TRUE(controller().IsURLInPageNavigation( | |
| 1588 other_url_with_ref)); | |
| 1589 } | |
| 1590 | |
| 1591 // Some pages can have subframes with the same base URL (minus the reference) as | |
| 1592 // the main page. Even though this is hard, it can happen, and we don't want | |
| 1593 // these subframe navigations to affect the toplevel document. They should | |
| 1594 // instead be ignored. http://crbug.com/5585 | |
| 1595 TEST_F(NavigationControllerTest, SameSubframe) { | |
| 1596 // Navigate the main frame. | |
| 1597 const GURL url("http://www.google.com/"); | |
| 1598 rvh()->SendNavigate(0, url); | |
| 1599 | |
| 1600 // We should be at the first navigation entry. | |
| 1601 EXPECT_EQ(controller().entry_count(), 1); | |
| 1602 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 1603 | |
| 1604 // Navigate a subframe that would normally count as in-page. | |
| 1605 const GURL subframe("http://www.google.com/#"); | |
| 1606 ViewHostMsg_FrameNavigate_Params params; | |
| 1607 params.page_id = 0; | |
| 1608 params.url = subframe; | |
| 1609 params.transition = PageTransition::AUTO_SUBFRAME; | |
| 1610 params.should_update_history = false; | |
| 1611 params.gesture = NavigationGestureAuto; | |
| 1612 params.is_post = false; | |
| 1613 NavigationController::LoadCommittedDetails details; | |
| 1614 EXPECT_FALSE(controller().RendererDidNavigate(params, 0, &details)); | |
| 1615 | |
| 1616 // Nothing should have changed. | |
| 1617 EXPECT_EQ(controller().entry_count(), 1); | |
| 1618 EXPECT_EQ(controller().last_committed_entry_index(), 0); | |
| 1619 } | |
| 1620 | |
| 1621 // Test view source redirection is reflected in title bar. | |
| 1622 TEST_F(NavigationControllerTest, ViewSourceRedirect) { | |
| 1623 const char kUrl[] = "view-source:http://redirect.to/google.com"; | |
| 1624 const char kResult[] = "http://google.com"; | |
| 1625 const char kExpected[] = "view-source:google.com"; | |
| 1626 const GURL url(kUrl); | |
| 1627 const GURL result_url(kResult); | |
| 1628 | |
| 1629 controller().LoadURL(url, GURL(), PageTransition::TYPED); | |
| 1630 | |
| 1631 ViewHostMsg_FrameNavigate_Params params; | |
| 1632 params.page_id = 0; | |
| 1633 params.url = result_url; | |
| 1634 params.transition = PageTransition::SERVER_REDIRECT; | |
| 1635 params.should_update_history = false; | |
| 1636 params.gesture = NavigationGestureAuto; | |
| 1637 params.is_post = false; | |
| 1638 NavigationController::LoadCommittedDetails details; | |
| 1639 controller().RendererDidNavigate(params, 0, &details); | |
| 1640 | |
| 1641 EXPECT_EQ(ASCIIToUTF16(kExpected), contents()->GetTitle()); | |
| 1642 EXPECT_TRUE(contents()->ShouldDisplayURL()); | |
| 1643 } | |
| 1644 | |
| 1645 // Make sure that on cloning a tabcontents and going back needs_reload is false. | |
| 1646 TEST_F(NavigationControllerTest, CloneAndGoBack) { | |
| 1647 const GURL url1("http://foo1"); | |
| 1648 const GURL url2("http://foo2"); | |
| 1649 | |
| 1650 NavigateAndCommit(url1); | |
| 1651 NavigateAndCommit(url2); | |
| 1652 | |
| 1653 scoped_ptr<TabContents> clone(controller().tab_contents()->Clone()); | |
| 1654 | |
| 1655 ASSERT_EQ(2, clone->controller().entry_count()); | |
| 1656 EXPECT_TRUE(clone->controller().needs_reload()); | |
| 1657 clone->controller().GoBack(); | |
| 1658 // Navigating back should have triggered needs_reload_ to go false. | |
| 1659 EXPECT_FALSE(clone->controller().needs_reload()); | |
| 1660 } | |
| 1661 | |
| 1662 // Make sure that cloning a tabcontents doesn't copy interstitials. | |
| 1663 TEST_F(NavigationControllerTest, CloneOmitsInterstitials) { | |
| 1664 const GURL url1("http://foo1"); | |
| 1665 const GURL url2("http://foo2"); | |
| 1666 | |
| 1667 NavigateAndCommit(url1); | |
| 1668 NavigateAndCommit(url2); | |
| 1669 | |
| 1670 // Add an interstitial entry. Should be deleted with controller. | |
| 1671 NavigationEntry* interstitial_entry = new NavigationEntry(); | |
| 1672 interstitial_entry->set_page_type(INTERSTITIAL_PAGE); | |
| 1673 controller().AddTransientEntry(interstitial_entry); | |
| 1674 | |
| 1675 scoped_ptr<TabContents> clone(controller().tab_contents()->Clone()); | |
| 1676 | |
| 1677 ASSERT_EQ(2, clone->controller().entry_count()); | |
| 1678 } | |
| 1679 | |
| 1680 // Tests a subframe navigation while a toplevel navigation is pending. | |
| 1681 // http://crbug.com/43967 | |
| 1682 TEST_F(NavigationControllerTest, SubframeWhilePending) { | |
| 1683 // Load the first page. | |
| 1684 const GURL url1("http://foo/"); | |
| 1685 NavigateAndCommit(url1); | |
| 1686 | |
| 1687 // Now start a pending load to a totally different page, but don't commit it. | |
| 1688 const GURL url2("http://bar/"); | |
| 1689 controller().LoadURL(url2, GURL(), PageTransition::TYPED); | |
| 1690 | |
| 1691 // Send a subframe update from the first page, as if one had just | |
| 1692 // automatically loaded. Auto subframes don't increment the page ID. | |
| 1693 const GURL url1_sub("http://foo/subframe"); | |
| 1694 ViewHostMsg_FrameNavigate_Params params; | |
| 1695 params.page_id = controller().GetLastCommittedEntry()->page_id(); | |
| 1696 params.url = url1_sub; | |
| 1697 params.transition = PageTransition::AUTO_SUBFRAME; | |
| 1698 params.should_update_history = false; | |
| 1699 params.gesture = NavigationGestureAuto; | |
| 1700 params.is_post = false; | |
| 1701 NavigationController::LoadCommittedDetails details; | |
| 1702 | |
| 1703 // This should return false meaning that nothing was actually updated. | |
| 1704 EXPECT_FALSE(controller().RendererDidNavigate(params, 0, &details)); | |
| 1705 | |
| 1706 // The notification should have updated the last committed one, and not | |
| 1707 // the pending load. | |
| 1708 EXPECT_EQ(url1, controller().GetLastCommittedEntry()->url()); | |
| 1709 | |
| 1710 // The active entry should be unchanged by the subframe load. | |
| 1711 EXPECT_EQ(url2, controller().GetActiveEntry()->url()); | |
| 1712 } | |
| 1713 | |
| 1714 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest. | |
| 1715 TEST_F(NavigationControllerTest, CopyStateFromAndPrune) { | |
| 1716 SessionID id(controller().session_id()); | |
| 1717 const GURL url1("http://foo1"); | |
| 1718 const GURL url2("http://foo2"); | |
| 1719 const GURL url3("http://foo3"); | |
| 1720 | |
| 1721 NavigateAndCommit(url1); | |
| 1722 NavigateAndCommit(url2); | |
| 1723 | |
| 1724 scoped_ptr<TestTabContents> other_contents(CreateTestTabContents()); | |
| 1725 NavigationController& other_controller = other_contents->controller(); | |
| 1726 SessionID other_id(other_controller.session_id()); | |
| 1727 other_contents->NavigateAndCommit(url3); | |
| 1728 other_controller.CopyStateFromAndPrune(&controller()); | |
| 1729 | |
| 1730 // other_controller should now contain the 3 urls: url1, url2 and url3. | |
| 1731 | |
| 1732 ASSERT_EQ(3, other_controller.entry_count()); | |
| 1733 | |
| 1734 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex()); | |
| 1735 | |
| 1736 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url()); | |
| 1737 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->url()); | |
| 1738 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->url()); | |
| 1739 | |
| 1740 // Make sure session ids didn't change. | |
| 1741 EXPECT_EQ(id.id(), controller().session_id().id()); | |
| 1742 EXPECT_EQ(other_id.id(), other_controller.session_id().id()); | |
| 1743 } | |
| 1744 | |
| 1745 // Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in | |
| 1746 // the target. | |
| 1747 TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) { | |
| 1748 SessionID id(controller().session_id()); | |
| 1749 const GURL url1("http://foo1"); | |
| 1750 const GURL url2("http://foo2"); | |
| 1751 const GURL url3("http://foo3"); | |
| 1752 | |
| 1753 NavigateAndCommit(url1); | |
| 1754 NavigateAndCommit(url2); | |
| 1755 controller().GoBack(); | |
| 1756 | |
| 1757 scoped_ptr<TestTabContents> other_contents(CreateTestTabContents()); | |
| 1758 NavigationController& other_controller = other_contents->controller(); | |
| 1759 SessionID other_id(other_controller.session_id()); | |
| 1760 other_controller.CopyStateFromAndPrune(&controller()); | |
| 1761 | |
| 1762 // other_controller should now contain the 1 url: url1. | |
| 1763 | |
| 1764 ASSERT_EQ(1, other_controller.entry_count()); | |
| 1765 | |
| 1766 ASSERT_EQ(0, other_controller.GetCurrentEntryIndex()); | |
| 1767 | |
| 1768 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url()); | |
| 1769 | |
| 1770 // Make sure session ids didn't change. | |
| 1771 EXPECT_EQ(id.id(), controller().session_id().id()); | |
| 1772 EXPECT_EQ(other_id.id(), other_controller.session_id().id()); | |
| 1773 } | |
| 1774 | |
| 1775 // Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in | |
| 1776 // the target. | |
| 1777 TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) { | |
| 1778 SessionID id(controller().session_id()); | |
| 1779 const GURL url1("http://foo1"); | |
| 1780 const GURL url2("http://foo2"); | |
| 1781 const GURL url3("http://foo3"); | |
| 1782 | |
| 1783 NavigateAndCommit(url1); | |
| 1784 NavigateAndCommit(url2); | |
| 1785 controller().GoBack(); | |
| 1786 | |
| 1787 scoped_ptr<TestTabContents> other_contents(CreateTestTabContents()); | |
| 1788 NavigationController& other_controller = other_contents->controller(); | |
| 1789 SessionID other_id(other_controller.session_id()); | |
| 1790 other_controller.LoadURL(url3, GURL(), PageTransition::TYPED); | |
| 1791 other_controller.CopyStateFromAndPrune(&controller()); | |
| 1792 | |
| 1793 // other_controller should now contain 1 entry for url1, and a pending entry | |
| 1794 // for url3. | |
| 1795 | |
| 1796 ASSERT_EQ(1, other_controller.entry_count()); | |
| 1797 | |
| 1798 EXPECT_EQ(0, other_controller.GetCurrentEntryIndex()); | |
| 1799 | |
| 1800 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url()); | |
| 1801 | |
| 1802 // And there should be a pending entry for url3. | |
| 1803 ASSERT_TRUE(other_controller.pending_entry()); | |
| 1804 | |
| 1805 EXPECT_EQ(url3, other_controller.pending_entry()->url()); | |
| 1806 | |
| 1807 // Make sure session ids didn't change. | |
| 1808 EXPECT_EQ(id.id(), controller().session_id().id()); | |
| 1809 EXPECT_EQ(other_id.id(), other_controller.session_id().id()); | |
| 1810 } | |
| 1811 | |
| 1812 // Tests that navigations initiated from the page (with the history object) | |
| 1813 // work as expected without navigation entries. | |
| 1814 TEST_F(NavigationControllerTest, HistoryNavigate) { | |
| 1815 const GURL url1("http://foo1"); | |
| 1816 const GURL url2("http://foo2"); | |
| 1817 const GURL url3("http://foo3"); | |
| 1818 | |
| 1819 NavigateAndCommit(url1); | |
| 1820 NavigateAndCommit(url2); | |
| 1821 NavigateAndCommit(url3); | |
| 1822 controller().GoBack(); | |
| 1823 contents()->CommitPendingNavigation(); | |
| 1824 | |
| 1825 // Simulate the page calling history.back(), it should not create a pending | |
| 1826 // entry. | |
| 1827 contents()->OnGoToEntryAtOffset(-1); | |
| 1828 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 1829 // The actual cross-navigation is suspended until the current RVH tells us | |
| 1830 // it unloaded, simulate that. | |
| 1831 contents()->ProceedWithCrossSiteNavigation(); | |
| 1832 // Also make sure we told the page to navigate. | |
| 1833 const IPC::Message* message = | |
| 1834 process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID); | |
| 1835 ASSERT_TRUE(message != NULL); | |
| 1836 Tuple1<ViewMsg_Navigate_Params> nav_params; | |
| 1837 ViewMsg_Navigate::Read(message, &nav_params); | |
| 1838 EXPECT_EQ(url1, nav_params.a.url); | |
| 1839 process()->sink().ClearMessages(); | |
| 1840 | |
| 1841 // Now test history.forward() | |
| 1842 contents()->OnGoToEntryAtOffset(1); | |
| 1843 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 1844 // The actual cross-navigation is suspended until the current RVH tells us | |
| 1845 // it unloaded, simulate that. | |
| 1846 contents()->ProceedWithCrossSiteNavigation(); | |
| 1847 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID); | |
| 1848 ASSERT_TRUE(message != NULL); | |
| 1849 ViewMsg_Navigate::Read(message, &nav_params); | |
| 1850 EXPECT_EQ(url3, nav_params.a.url); | |
| 1851 process()->sink().ClearMessages(); | |
| 1852 | |
| 1853 // Make sure an extravagant history.go() doesn't break. | |
| 1854 contents()->OnGoToEntryAtOffset(120); // Out of bounds. | |
| 1855 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 1856 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID); | |
| 1857 EXPECT_TRUE(message == NULL); | |
| 1858 } | |
| 1859 | |
| 1860 // Test call to PruneAllButActive for the only entry. | |
| 1861 TEST_F(NavigationControllerTest, PruneAllButActiveForSingle) { | |
| 1862 const GURL url1("http://foo1"); | |
| 1863 NavigateAndCommit(url1); | |
| 1864 controller().PruneAllButActive(); | |
| 1865 | |
| 1866 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 1867 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url1); | |
| 1868 } | |
| 1869 | |
| 1870 // Test call to PruneAllButActive for last entry. | |
| 1871 TEST_F(NavigationControllerTest, PruneAllButActiveForLast) { | |
| 1872 const GURL url1("http://foo1"); | |
| 1873 const GURL url2("http://foo2"); | |
| 1874 const GURL url3("http://foo3"); | |
| 1875 | |
| 1876 NavigateAndCommit(url1); | |
| 1877 NavigateAndCommit(url2); | |
| 1878 NavigateAndCommit(url3); | |
| 1879 controller().GoBack(); | |
| 1880 controller().GoBack(); | |
| 1881 contents()->CommitPendingNavigation(); | |
| 1882 | |
| 1883 controller().PruneAllButActive(); | |
| 1884 | |
| 1885 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 1886 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url1); | |
| 1887 } | |
| 1888 | |
| 1889 // Test call to PruneAllButActive for intermediate entry. | |
| 1890 TEST_F(NavigationControllerTest, PruneAllButActiveForIntermediate) { | |
| 1891 const GURL url1("http://foo1"); | |
| 1892 const GURL url2("http://foo2"); | |
| 1893 const GURL url3("http://foo3"); | |
| 1894 | |
| 1895 NavigateAndCommit(url1); | |
| 1896 NavigateAndCommit(url2); | |
| 1897 NavigateAndCommit(url3); | |
| 1898 controller().GoBack(); | |
| 1899 contents()->CommitPendingNavigation(); | |
| 1900 | |
| 1901 controller().PruneAllButActive(); | |
| 1902 | |
| 1903 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 1904 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url2); | |
| 1905 } | |
| 1906 | |
| 1907 // Test call to PruneAllButActive for intermediate entry. | |
| 1908 TEST_F(NavigationControllerTest, PruneAllButActiveForPending) { | |
| 1909 const GURL url1("http://foo1"); | |
| 1910 const GURL url2("http://foo2"); | |
| 1911 const GURL url3("http://foo3"); | |
| 1912 | |
| 1913 NavigateAndCommit(url1); | |
| 1914 NavigateAndCommit(url2); | |
| 1915 NavigateAndCommit(url3); | |
| 1916 controller().GoBack(); | |
| 1917 | |
| 1918 controller().PruneAllButActive(); | |
| 1919 | |
| 1920 EXPECT_EQ(0, controller().pending_entry_index()); | |
| 1921 } | |
| 1922 | |
| 1923 // Test call to PruneAllButActive for transient entry. | |
| 1924 TEST_F(NavigationControllerTest, PruneAllButActiveForTransient) { | |
| 1925 const GURL url0("http://foo0"); | |
| 1926 const GURL url1("http://foo1"); | |
| 1927 const GURL transient_url("http://transient"); | |
| 1928 | |
| 1929 controller().LoadURL(url0, GURL(), PageTransition::TYPED); | |
| 1930 rvh()->SendNavigate(0, url0); | |
| 1931 controller().LoadURL(url1, GURL(), PageTransition::TYPED); | |
| 1932 rvh()->SendNavigate(1, url1); | |
| 1933 | |
| 1934 // Adding a transient with no pending entry. | |
| 1935 NavigationEntry* transient_entry = new NavigationEntry; | |
| 1936 transient_entry->set_url(transient_url); | |
| 1937 controller().AddTransientEntry(transient_entry); | |
| 1938 | |
| 1939 controller().PruneAllButActive(); | |
| 1940 | |
| 1941 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 1942 EXPECT_EQ(-1, controller().pending_entry_index()); | |
| 1943 EXPECT_EQ(controller().GetTransientEntry()->url(), transient_url); | |
| 1944 } | |
| 1945 | |
| 1946 /* TODO(brettw) These test pass on my local machine but fail on the XP buildbot | |
| 1947 (but not Vista) cleaning up the directory after they run. | |
| 1948 This should be fixed. | |
| 1949 | |
| 1950 // A basic test case. Navigates to a single url, and make sure the history | |
| 1951 // db matches. | |
| 1952 TEST_F(NavigationControllerHistoryTest, Basic) { | |
| 1953 controller().LoadURL(url0, GURL(), PageTransition::LINK); | |
| 1954 rvh()->SendNavigate(0, url0); | |
| 1955 | |
| 1956 GetLastSession(); | |
| 1957 | |
| 1958 session_helper_.AssertSingleWindowWithSingleTab(windows_, 1); | |
| 1959 session_helper_.AssertTabEquals(0, 0, 1, *(windows_[0]->tabs[0])); | |
| 1960 TabNavigation nav1(0, url0, GURL(), string16(), | |
| 1961 webkit_glue::CreateHistoryStateForURL(url0), | |
| 1962 PageTransition::LINK); | |
| 1963 session_helper_.AssertNavigationEquals(nav1, | |
| 1964 windows_[0]->tabs[0]->navigations[0]); | |
| 1965 } | |
| 1966 | |
| 1967 // Navigates to three urls, then goes back and make sure the history database | |
| 1968 // is in sync. | |
| 1969 TEST_F(NavigationControllerHistoryTest, NavigationThenBack) { | |
| 1970 rvh()->SendNavigate(0, url0); | |
| 1971 rvh()->SendNavigate(1, url1); | |
| 1972 rvh()->SendNavigate(2, url2); | |
| 1973 | |
| 1974 controller().GoBack(); | |
| 1975 rvh()->SendNavigate(1, url1); | |
| 1976 | |
| 1977 GetLastSession(); | |
| 1978 | |
| 1979 session_helper_.AssertSingleWindowWithSingleTab(windows_, 3); | |
| 1980 session_helper_.AssertTabEquals(0, 1, 3, *(windows_[0]->tabs[0])); | |
| 1981 | |
| 1982 TabNavigation nav(0, url0, GURL(), string16(), | |
| 1983 webkit_glue::CreateHistoryStateForURL(url0), | |
| 1984 PageTransition::LINK); | |
| 1985 session_helper_.AssertNavigationEquals(nav, | |
| 1986 windows_[0]->tabs[0]->navigations[0]); | |
| 1987 nav.set_url(url1); | |
| 1988 session_helper_.AssertNavigationEquals(nav, | |
| 1989 windows_[0]->tabs[0]->navigations[1]); | |
| 1990 nav.set_url(url2); | |
| 1991 session_helper_.AssertNavigationEquals(nav, | |
| 1992 windows_[0]->tabs[0]->navigations[2]); | |
| 1993 } | |
| 1994 | |
| 1995 // Navigates to three urls, then goes back twice, then loads a new url. | |
| 1996 TEST_F(NavigationControllerHistoryTest, NavigationPruning) { | |
| 1997 rvh()->SendNavigate(0, url0); | |
| 1998 rvh()->SendNavigate(1, url1); | |
| 1999 rvh()->SendNavigate(2, url2); | |
| 2000 | |
| 2001 controller().GoBack(); | |
| 2002 rvh()->SendNavigate(1, url1); | |
| 2003 | |
| 2004 controller().GoBack(); | |
| 2005 rvh()->SendNavigate(0, url0); | |
| 2006 | |
| 2007 rvh()->SendNavigate(3, url2); | |
| 2008 | |
| 2009 // Now have url0, and url2. | |
| 2010 | |
| 2011 GetLastSession(); | |
| 2012 | |
| 2013 session_helper_.AssertSingleWindowWithSingleTab(windows_, 2); | |
| 2014 session_helper_.AssertTabEquals(0, 1, 2, *(windows_[0]->tabs[0])); | |
| 2015 | |
| 2016 TabNavigation nav(0, url0, GURL(), string16(), | |
| 2017 webkit_glue::CreateHistoryStateForURL(url0), | |
| 2018 PageTransition::LINK); | |
| 2019 session_helper_.AssertNavigationEquals(nav, | |
| 2020 windows_[0]->tabs[0]->navigations[0]); | |
| 2021 nav.set_url(url2); | |
| 2022 session_helper_.AssertNavigationEquals(nav, | |
| 2023 windows_[0]->tabs[0]->navigations[1]); | |
| 2024 } | |
| 2025 */ | |
| OLD | NEW |