1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/basictypes.h"
7 #include "base/file_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/path_service.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "content/browser/frame_host/cross_site_transferring_request.h"
15 #include "content/browser/frame_host/navigation_controller_impl.h"
16 #include "content/browser/frame_host/navigation_entry_impl.h"
17 #include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
18 #include "content/browser/frame_host/navigator.h"
19 #include "content/browser/site_instance_impl.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/common/frame_messages.h"
22 #include "content/common/view_messages.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/notification_registrar.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/browser/web_contents_delegate.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/common/page_state.h"
30 #include "content/public/common/url_constants.h"
31 #include "content/public/test/mock_render_process_host.h"
32 #include "content/public/test/test_notification_tracker.h"
33 #include "content/public/test/test_utils.h"
34 #include "content/test/test_render_view_host.h"
35 #include "content/test/test_web_contents.h"
36 #include "net/base/net_util.h"
37 #include "skia/ext/platform_canvas.h"
38 #include "testing/gtest/include/gtest/gtest.h"
44 // Creates an image with a 1x1 SkBitmap of the specified |color|.
45 gfx::Image
CreateImage(SkColor color
) {
47 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 1, 1);
49 bitmap
.eraseColor(color
);
50 return gfx::Image::CreateFrom1xBitmap(bitmap
);
53 // Returns true if images |a| and |b| have the same pixel data.
54 bool DoImagesMatch(const gfx::Image
& a
, const gfx::Image
& b
) {
55 // Assume that if the 1x bitmaps match, the images match.
56 SkBitmap a_bitmap
= a
.AsBitmap();
57 SkBitmap b_bitmap
= b
.AsBitmap();
59 if (a_bitmap
.width() != b_bitmap
.width() ||
60 a_bitmap
.height() != b_bitmap
.height()) {
63 SkAutoLockPixels
a_bitmap_lock(a_bitmap
);
64 SkAutoLockPixels
b_bitmap_lock(b_bitmap
);
65 return memcmp(a_bitmap
.getPixels(),
67 a_bitmap
.getSize()) == 0;
70 class MockScreenshotManager
: public content::NavigationEntryScreenshotManager
{
72 explicit MockScreenshotManager(content::NavigationControllerImpl
* owner
)
73 : content::NavigationEntryScreenshotManager(owner
),
74 encoding_screenshot_in_progress_(false) {
77 virtual ~MockScreenshotManager() {
80 void TakeScreenshotFor(content::NavigationEntryImpl
* entry
) {
82 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 1, 1);
84 bitmap
.eraseARGB(0, 0, 0, 0);
85 encoding_screenshot_in_progress_
= true;
86 OnScreenshotTaken(entry
->GetUniqueID(), true, bitmap
);
87 WaitUntilScreenshotIsReady();
90 int GetScreenshotCount() {
91 return content::NavigationEntryScreenshotManager::GetScreenshotCount();
94 void WaitUntilScreenshotIsReady() {
95 if (!encoding_screenshot_in_progress_
)
97 message_loop_runner_
= new content::MessageLoopRunner
;
98 message_loop_runner_
->Run();
102 // Overridden from content::NavigationEntryScreenshotManager:
103 virtual void TakeScreenshotImpl(
104 content::RenderViewHost
* host
,
105 content::NavigationEntryImpl
* entry
) OVERRIDE
{
108 virtual void OnScreenshotSet(content::NavigationEntryImpl
* entry
) OVERRIDE
{
109 encoding_screenshot_in_progress_
= false;
110 NavigationEntryScreenshotManager::OnScreenshotSet(entry
);
111 if (message_loop_runner_
.get())
112 message_loop_runner_
->Quit();
115 scoped_refptr
<content::MessageLoopRunner
> message_loop_runner_
;
116 bool encoding_screenshot_in_progress_
;
118 DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager
);
125 // TimeSmoother tests ----------------------------------------------------------
127 // With no duplicates, GetSmoothedTime should be the identity
129 TEST(TimeSmoother
, Basic
) {
130 NavigationControllerImpl::TimeSmoother smoother
;
131 for (int64 i
= 1; i
< 1000; ++i
) {
132 base::Time t
= base::Time::FromInternalValue(i
);
133 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
137 // With a single duplicate and timestamps thereafter increasing by one
138 // microsecond, the smoothed time should always be one behind.
139 TEST(TimeSmoother
, SingleDuplicate
) {
140 NavigationControllerImpl::TimeSmoother smoother
;
141 base::Time t
= base::Time::FromInternalValue(1);
142 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
143 for (int64 i
= 1; i
< 1000; ++i
) {
144 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
145 t
= base::Time::FromInternalValue(i
);
146 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
150 // With k duplicates and timestamps thereafter increasing by one
151 // microsecond, the smoothed time should always be k behind.
152 TEST(TimeSmoother
, ManyDuplicates
) {
153 const int64 kNumDuplicates
= 100;
154 NavigationControllerImpl::TimeSmoother smoother
;
155 base::Time t
= base::Time::FromInternalValue(1);
156 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
157 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
158 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
160 for (int64 i
= 1; i
< 1000; ++i
) {
161 base::Time expected_t
=
162 base::Time::FromInternalValue(i
+ kNumDuplicates
);
163 t
= base::Time::FromInternalValue(i
);
164 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
168 // If the clock jumps far back enough after a run of duplicates, it
169 // should immediately jump to that value.
170 TEST(TimeSmoother
, ClockBackwardsJump
) {
171 const int64 kNumDuplicates
= 100;
172 NavigationControllerImpl::TimeSmoother smoother
;
173 base::Time t
= base::Time::FromInternalValue(1000);
174 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
175 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1000);
176 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
178 t
= base::Time::FromInternalValue(500);
179 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
182 // NavigationControllerTest ----------------------------------------------------
184 class NavigationControllerTest
185 : public RenderViewHostImplTestHarness
,
186 public WebContentsObserver
{
188 NavigationControllerTest() : navigation_entry_committed_counter_(0) {
191 virtual void SetUp() OVERRIDE
{
192 RenderViewHostImplTestHarness::SetUp();
193 WebContents
* web_contents
= RenderViewHostImplTestHarness::web_contents();
194 ASSERT_TRUE(web_contents
); // The WebContents should be created by now.
195 WebContentsObserver::Observe(web_contents
);
198 // WebContentsObserver:
199 virtual void DidStartNavigationToPendingEntry(
201 NavigationController::ReloadType reload_type
) OVERRIDE
{
202 navigated_url_
= url
;
205 virtual void NavigationEntryCommitted(
206 const LoadCommittedDetails
& load_details
) OVERRIDE
{
207 navigation_entry_committed_counter_
++;
210 const GURL
& navigated_url() const {
211 return navigated_url_
;
214 NavigationControllerImpl
& controller_impl() {
215 return static_cast<NavigationControllerImpl
&>(controller());
220 size_t navigation_entry_committed_counter_
;
223 void RegisterForAllNavNotifications(TestNotificationTracker
* tracker
,
224 NavigationController
* controller
) {
225 tracker
->ListenFor(NOTIFICATION_NAV_LIST_PRUNED
,
226 Source
<NavigationController
>(controller
));
227 tracker
->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED
,
228 Source
<NavigationController
>(controller
));
231 SiteInstance
* GetSiteInstanceFromEntry(NavigationEntry
* entry
) {
232 return NavigationEntryImpl::FromNavigationEntry(entry
)->site_instance();
235 class TestWebContentsDelegate
: public WebContentsDelegate
{
237 explicit TestWebContentsDelegate() :
238 navigation_state_change_count_(0),
239 repost_form_warning_count_(0) {}
241 int navigation_state_change_count() {
242 return navigation_state_change_count_
;
245 int repost_form_warning_count() {
246 return repost_form_warning_count_
;
249 // Keep track of whether the tab has notified us of a navigation state change.
250 virtual void NavigationStateChanged(const WebContents
* source
,
251 unsigned changed_flags
) OVERRIDE
{
252 navigation_state_change_count_
++;
255 virtual void ShowRepostFormWarningDialog(WebContents
* source
) OVERRIDE
{
256 repost_form_warning_count_
++;
260 // The number of times NavigationStateChanged has been called.
261 int navigation_state_change_count_
;
263 // The number of times ShowRepostFormWarningDialog() was called.
264 int repost_form_warning_count_
;
267 // -----------------------------------------------------------------------------
269 TEST_F(NavigationControllerTest
, Defaults
) {
270 NavigationControllerImpl
& controller
= controller_impl();
272 EXPECT_FALSE(controller
.GetPendingEntry());
273 EXPECT_FALSE(controller
.GetVisibleEntry());
274 EXPECT_FALSE(controller
.GetLastCommittedEntry());
275 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
276 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
277 EXPECT_EQ(controller
.GetEntryCount(), 0);
278 EXPECT_FALSE(controller
.CanGoBack());
279 EXPECT_FALSE(controller
.CanGoForward());
282 TEST_F(NavigationControllerTest
, GoToOffset
) {
283 NavigationControllerImpl
& controller
= controller_impl();
284 TestNotificationTracker notifications
;
285 RegisterForAllNavNotifications(¬ifications
, &controller
);
287 const int kNumUrls
= 5;
288 std::vector
<GURL
> urls(kNumUrls
);
289 for (int i
= 0; i
< kNumUrls
; ++i
) {
290 urls
[i
] = GURL(base::StringPrintf("http://www.a.com/%d", i
));
293 main_test_rfh()->SendNavigate(0, urls
[0]);
294 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
295 navigation_entry_committed_counter_
= 0;
296 EXPECT_EQ(urls
[0], controller
.GetVisibleEntry()->GetVirtualURL());
297 EXPECT_FALSE(controller
.CanGoBack());
298 EXPECT_FALSE(controller
.CanGoForward());
299 EXPECT_FALSE(controller
.CanGoToOffset(1));
301 for (int i
= 1; i
<= 4; ++i
) {
302 main_test_rfh()->SendNavigate(i
, urls
[i
]);
303 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
304 navigation_entry_committed_counter_
= 0;
305 EXPECT_EQ(urls
[i
], controller
.GetVisibleEntry()->GetVirtualURL());
306 EXPECT_TRUE(controller
.CanGoToOffset(-i
));
307 EXPECT_FALSE(controller
.CanGoToOffset(-(i
+ 1)));
308 EXPECT_FALSE(controller
.CanGoToOffset(1));
311 // We have loaded 5 pages, and are currently at the last-loaded page.
315 GO_TO_MIDDLE_PAGE
= -2,
318 GO_TO_BEGINNING
= -2,
323 const int test_offsets
[NUM_TESTS
] = {
331 for (int test
= 0; test
< NUM_TESTS
; ++test
) {
332 int offset
= test_offsets
[test
];
333 controller
.GoToOffset(offset
);
335 // Check that the GoToOffset will land on the expected page.
336 EXPECT_EQ(urls
[url_index
], controller
.GetPendingEntry()->GetVirtualURL());
337 main_test_rfh()->SendNavigate(url_index
, urls
[url_index
]);
338 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
339 navigation_entry_committed_counter_
= 0;
340 // Check that we can go to any valid offset into the history.
341 for (size_t j
= 0; j
< urls
.size(); ++j
)
342 EXPECT_TRUE(controller
.CanGoToOffset(j
- url_index
));
343 // Check that we can't go beyond the beginning or end of the history.
344 EXPECT_FALSE(controller
.CanGoToOffset(-(url_index
+ 1)));
345 EXPECT_FALSE(controller
.CanGoToOffset(urls
.size() - url_index
));
349 TEST_F(NavigationControllerTest
, LoadURL
) {
350 NavigationControllerImpl
& controller
= controller_impl();
351 TestNotificationTracker notifications
;
352 RegisterForAllNavNotifications(¬ifications
, &controller
);
354 const GURL
url1("http://foo1");
355 const GURL
url2("http://foo2");
357 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
358 // Creating a pending notification should not have issued any of the
359 // notifications we're listening for.
360 EXPECT_EQ(0U, notifications
.size());
362 // The load should now be pending.
363 EXPECT_EQ(controller
.GetEntryCount(), 0);
364 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
365 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
366 EXPECT_FALSE(controller
.GetLastCommittedEntry());
367 ASSERT_TRUE(controller
.GetPendingEntry());
368 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetVisibleEntry());
369 EXPECT_FALSE(controller
.CanGoBack());
370 EXPECT_FALSE(controller
.CanGoForward());
371 EXPECT_EQ(contents()->GetMaxPageID(), -1);
373 // Neither the timestamp nor the status code should have been set yet.
374 EXPECT_TRUE(controller
.GetPendingEntry()->GetTimestamp().is_null());
375 EXPECT_EQ(0, controller
.GetPendingEntry()->GetHttpStatusCode());
377 // We should have gotten no notifications from the preceeding checks.
378 EXPECT_EQ(0U, notifications
.size());
380 main_test_rfh()->SendNavigate(0, url1
);
381 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
382 navigation_entry_committed_counter_
= 0;
384 // The load should now be committed.
385 EXPECT_EQ(controller
.GetEntryCount(), 1);
386 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
387 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
388 EXPECT_TRUE(controller
.GetLastCommittedEntry());
389 EXPECT_FALSE(controller
.GetPendingEntry());
390 ASSERT_TRUE(controller
.GetVisibleEntry());
391 EXPECT_FALSE(controller
.CanGoBack());
392 EXPECT_FALSE(controller
.CanGoForward());
393 EXPECT_EQ(contents()->GetMaxPageID(), 0);
394 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
395 controller
.GetLastCommittedEntry())->bindings());
397 // The timestamp should have been set.
398 EXPECT_FALSE(controller
.GetVisibleEntry()->GetTimestamp().is_null());
401 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
403 // The load should now be pending.
404 EXPECT_EQ(controller
.GetEntryCount(), 1);
405 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
406 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
407 EXPECT_TRUE(controller
.GetLastCommittedEntry());
408 ASSERT_TRUE(controller
.GetPendingEntry());
409 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetVisibleEntry());
410 // TODO(darin): maybe this should really be true?
411 EXPECT_FALSE(controller
.CanGoBack());
412 EXPECT_FALSE(controller
.CanGoForward());
413 EXPECT_EQ(contents()->GetMaxPageID(), 0);
415 EXPECT_TRUE(controller
.GetPendingEntry()->GetTimestamp().is_null());
417 // Simulate the beforeunload ack for the cross-site transition, and then the
419 test_rvh()->SendBeforeUnloadACK(true);
420 static_cast<TestRenderViewHost
*>(
421 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2
);
422 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
423 navigation_entry_committed_counter_
= 0;
425 // The load should now be committed.
426 EXPECT_EQ(controller
.GetEntryCount(), 2);
427 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
428 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
429 EXPECT_TRUE(controller
.GetLastCommittedEntry());
430 EXPECT_FALSE(controller
.GetPendingEntry());
431 ASSERT_TRUE(controller
.GetVisibleEntry());
432 EXPECT_TRUE(controller
.CanGoBack());
433 EXPECT_FALSE(controller
.CanGoForward());
434 EXPECT_EQ(contents()->GetMaxPageID(), 1);
436 EXPECT_FALSE(controller
.GetVisibleEntry()->GetTimestamp().is_null());
441 base::Time
GetFixedTime(base::Time time
) {
447 TEST_F(NavigationControllerTest
, LoadURLSameTime
) {
448 NavigationControllerImpl
& controller
= controller_impl();
449 TestNotificationTracker notifications
;
450 RegisterForAllNavNotifications(¬ifications
, &controller
);
452 // Set the clock to always return a timestamp of 1.
453 controller
.SetGetTimestampCallbackForTest(
454 base::Bind(&GetFixedTime
, base::Time::FromInternalValue(1)));
456 const GURL
url1("http://foo1");
457 const GURL
url2("http://foo2");
459 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
461 main_test_rfh()->SendNavigate(0, url1
);
462 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
463 navigation_entry_committed_counter_
= 0;
466 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
468 // Simulate the beforeunload ack for the cross-site transition, and then the
470 test_rvh()->SendBeforeUnloadACK(true);
471 main_test_rfh()->SendNavigate(1, url2
);
472 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
473 navigation_entry_committed_counter_
= 0;
475 // The two loads should now be committed.
476 ASSERT_EQ(controller
.GetEntryCount(), 2);
478 // Timestamps should be distinct despite the clock returning the
481 controller
.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
483 controller
.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
486 void CheckNavigationEntryMatchLoadParams(
487 NavigationController::LoadURLParams
& load_params
,
488 NavigationEntryImpl
* entry
) {
489 EXPECT_EQ(load_params
.url
, entry
->GetURL());
490 EXPECT_EQ(load_params
.referrer
.url
, entry
->GetReferrer().url
);
491 EXPECT_EQ(load_params
.referrer
.policy
, entry
->GetReferrer().policy
);
492 EXPECT_EQ(load_params
.transition_type
, entry
->GetTransitionType());
493 EXPECT_EQ(load_params
.extra_headers
, entry
->extra_headers());
495 EXPECT_EQ(load_params
.is_renderer_initiated
, entry
->is_renderer_initiated());
496 EXPECT_EQ(load_params
.base_url_for_data_url
, entry
->GetBaseURLForDataURL());
497 if (!load_params
.virtual_url_for_data_url
.is_empty()) {
498 EXPECT_EQ(load_params
.virtual_url_for_data_url
, entry
->GetVirtualURL());
500 if (NavigationController::UA_OVERRIDE_INHERIT
!=
501 load_params
.override_user_agent
) {
502 bool should_override
= (NavigationController::UA_OVERRIDE_TRUE
==
503 load_params
.override_user_agent
);
504 EXPECT_EQ(should_override
, entry
->GetIsOverridingUserAgent());
506 EXPECT_EQ(load_params
.browser_initiated_post_data
,
507 entry
->GetBrowserInitiatedPostData());
508 EXPECT_EQ(load_params
.transferred_global_request_id
,
509 entry
->transferred_global_request_id());
512 TEST_F(NavigationControllerTest
, LoadURLWithParams
) {
513 NavigationControllerImpl
& controller
= controller_impl();
515 NavigationController::LoadURLParams
load_params(GURL("http://foo"));
516 load_params
.referrer
=
517 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
518 load_params
.transition_type
= PAGE_TRANSITION_GENERATED
;
519 load_params
.extra_headers
= "content-type: text/plain";
520 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
521 load_params
.is_renderer_initiated
= true;
522 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
523 load_params
.transferred_global_request_id
= GlobalRequestID(2, 3);
525 controller
.LoadURLWithParams(load_params
);
526 NavigationEntryImpl
* entry
=
527 NavigationEntryImpl::FromNavigationEntry(
528 controller
.GetPendingEntry());
530 // The timestamp should not have been set yet.
532 EXPECT_TRUE(entry
->GetTimestamp().is_null());
534 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
537 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_Data
) {
538 NavigationControllerImpl
& controller
= controller_impl();
540 NavigationController::LoadURLParams
load_params(
541 GURL("data:text/html,dataurl"));
542 load_params
.load_type
= NavigationController::LOAD_TYPE_DATA
;
543 load_params
.base_url_for_data_url
= GURL("http://foo");
544 load_params
.virtual_url_for_data_url
= GURL(url::kAboutBlankURL
);
545 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_FALSE
;
547 controller
.LoadURLWithParams(load_params
);
548 NavigationEntryImpl
* entry
=
549 NavigationEntryImpl::FromNavigationEntry(
550 controller
.GetPendingEntry());
552 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
555 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_HttpPost
) {
556 NavigationControllerImpl
& controller
= controller_impl();
558 NavigationController::LoadURLParams
load_params(GURL("https://posturl"));
559 load_params
.transition_type
= PAGE_TRANSITION_TYPED
;
560 load_params
.load_type
=
561 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST
;
562 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
565 const unsigned char* raw_data
=
566 reinterpret_cast<const unsigned char*>("d\n\0a2");
567 const int length
= 5;
568 std::vector
<unsigned char> post_data_vector(raw_data
, raw_data
+length
);
569 scoped_refptr
<base::RefCountedBytes
> data
=
570 base::RefCountedBytes::TakeVector(&post_data_vector
);
571 load_params
.browser_initiated_post_data
= data
.get();
573 controller
.LoadURLWithParams(load_params
);
574 NavigationEntryImpl
* entry
=
575 NavigationEntryImpl::FromNavigationEntry(
576 controller
.GetPendingEntry());
578 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
581 // Tests what happens when the same page is loaded again. Should not create a
582 // new session history entry. This is what happens when you press enter in the
583 // URL bar to reload: a pending entry is created and then it is discarded when
584 // the load commits (because WebCore didn't actually make a new entry).
585 TEST_F(NavigationControllerTest
, LoadURL_SamePage
) {
586 NavigationControllerImpl
& controller
= controller_impl();
587 TestNotificationTracker notifications
;
588 RegisterForAllNavNotifications(¬ifications
, &controller
);
590 const GURL
url1("http://foo1");
592 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
593 EXPECT_EQ(0U, notifications
.size());
594 main_test_rfh()->SendNavigate(0, url1
);
595 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
596 navigation_entry_committed_counter_
= 0;
598 ASSERT_TRUE(controller
.GetVisibleEntry());
599 const base::Time timestamp
= controller
.GetVisibleEntry()->GetTimestamp();
600 EXPECT_FALSE(timestamp
.is_null());
602 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
603 EXPECT_EQ(0U, notifications
.size());
604 main_test_rfh()->SendNavigate(0, url1
);
605 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
606 navigation_entry_committed_counter_
= 0;
608 // We should not have produced a new session history entry.
609 EXPECT_EQ(controller
.GetEntryCount(), 1);
610 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
611 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
612 EXPECT_TRUE(controller
.GetLastCommittedEntry());
613 EXPECT_FALSE(controller
.GetPendingEntry());
614 ASSERT_TRUE(controller
.GetVisibleEntry());
615 EXPECT_FALSE(controller
.CanGoBack());
616 EXPECT_FALSE(controller
.CanGoForward());
618 // The timestamp should have been updated.
620 // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
621 // EXPECT_GT once we guarantee that timestamps are unique.
622 EXPECT_GE(controller
.GetVisibleEntry()->GetTimestamp(), timestamp
);
625 // Load the same page twice, once as a GET and once as a POST.
626 // We should update the post state on the NavigationEntry.
627 TEST_F(NavigationControllerTest
, LoadURL_SamePage_DifferentMethod
) {
628 NavigationControllerImpl
& controller
= controller_impl();
629 TestNotificationTracker notifications
;
630 RegisterForAllNavNotifications(¬ifications
, &controller
);
632 const GURL
url1("http://foo1");
634 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
635 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
638 params
.transition
= PAGE_TRANSITION_TYPED
;
639 params
.is_post
= true;
640 params
.post_id
= 123;
641 params
.page_state
= PageState::CreateForTesting(url1
, false, 0, 0);
642 main_test_rfh()->SendNavigateWithParams(¶ms
);
644 // The post data should be visible.
645 NavigationEntry
* entry
= controller
.GetVisibleEntry();
647 EXPECT_TRUE(entry
->GetHasPostData());
648 EXPECT_EQ(entry
->GetPostID(), 123);
650 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
651 main_test_rfh()->SendNavigate(0, url1
);
653 // We should not have produced a new session history entry.
654 ASSERT_EQ(controller
.GetVisibleEntry(), entry
);
656 // The post data should have been cleared due to the GET.
657 EXPECT_FALSE(entry
->GetHasPostData());
658 EXPECT_EQ(entry
->GetPostID(), 0);
661 // Tests loading a URL but discarding it before the load commits.
662 TEST_F(NavigationControllerTest
, LoadURL_Discarded
) {
663 NavigationControllerImpl
& controller
= controller_impl();
664 TestNotificationTracker notifications
;
665 RegisterForAllNavNotifications(¬ifications
, &controller
);
667 const GURL
url1("http://foo1");
668 const GURL
url2("http://foo2");
670 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
671 EXPECT_EQ(0U, notifications
.size());
672 main_test_rfh()->SendNavigate(0, url1
);
673 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
674 navigation_entry_committed_counter_
= 0;
676 ASSERT_TRUE(controller
.GetVisibleEntry());
677 const base::Time timestamp
= controller
.GetVisibleEntry()->GetTimestamp();
678 EXPECT_FALSE(timestamp
.is_null());
680 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
681 controller
.DiscardNonCommittedEntries();
682 EXPECT_EQ(0U, notifications
.size());
684 // Should not have produced a new session history entry.
685 EXPECT_EQ(controller
.GetEntryCount(), 1);
686 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
687 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
688 EXPECT_TRUE(controller
.GetLastCommittedEntry());
689 EXPECT_FALSE(controller
.GetPendingEntry());
690 ASSERT_TRUE(controller
.GetVisibleEntry());
691 EXPECT_FALSE(controller
.CanGoBack());
692 EXPECT_FALSE(controller
.CanGoForward());
694 // Timestamp should not have changed.
695 EXPECT_EQ(timestamp
, controller
.GetVisibleEntry()->GetTimestamp());
698 // Tests navigations that come in unrequested. This happens when the user
699 // navigates from the web page, and here we test that there is no pending entry.
700 TEST_F(NavigationControllerTest
, LoadURL_NoPending
) {
701 NavigationControllerImpl
& controller
= controller_impl();
702 TestNotificationTracker notifications
;
703 RegisterForAllNavNotifications(¬ifications
, &controller
);
705 // First make an existing committed entry.
706 const GURL
kExistingURL1("http://eh");
708 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
709 main_test_rfh()->SendNavigate(0, kExistingURL1
);
710 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
711 navigation_entry_committed_counter_
= 0;
713 // Do a new navigation without making a pending one.
714 const GURL
kNewURL("http://see");
715 main_test_rfh()->SendNavigate(99, kNewURL
);
717 // There should no longer be any pending entry, and the third navigation we
718 // just made should be committed.
719 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
720 navigation_entry_committed_counter_
= 0;
721 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
722 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
723 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
726 // Tests navigating to a new URL when there is a new pending navigation that is
727 // not the one that just loaded. This will happen if the user types in a URL to
728 // somewhere slow, and then navigates the current page before the typed URL
730 TEST_F(NavigationControllerTest
, LoadURL_NewPending
) {
731 NavigationControllerImpl
& controller
= controller_impl();
732 TestNotificationTracker notifications
;
733 RegisterForAllNavNotifications(¬ifications
, &controller
);
735 // First make an existing committed entry.
736 const GURL
kExistingURL1("http://eh");
738 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
739 main_test_rfh()->SendNavigate(0, kExistingURL1
);
740 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
741 navigation_entry_committed_counter_
= 0;
743 // Make a pending entry to somewhere new.
744 const GURL
kExistingURL2("http://bee");
746 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
747 EXPECT_EQ(0U, notifications
.size());
749 // After the beforeunload but before it commits, do a new navigation.
750 test_rvh()->SendBeforeUnloadACK(true);
751 const GURL
kNewURL("http://see");
752 static_cast<TestRenderViewHost
*>(
753 contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL
);
755 // There should no longer be any pending entry, and the third navigation we
756 // just made should be committed.
757 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
758 navigation_entry_committed_counter_
= 0;
759 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
760 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
761 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
764 // Tests navigating to a new URL when there is a pending back/forward
765 // navigation. This will happen if the user hits back, but before that commits,
766 // they navigate somewhere new.
767 TEST_F(NavigationControllerTest
, LoadURL_ExistingPending
) {
768 NavigationControllerImpl
& controller
= controller_impl();
769 TestNotificationTracker notifications
;
770 RegisterForAllNavNotifications(¬ifications
, &controller
);
772 // First make some history.
773 const GURL
kExistingURL1("http://foo/eh");
775 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
776 main_test_rfh()->SendNavigate(0, kExistingURL1
);
777 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
778 navigation_entry_committed_counter_
= 0;
780 const GURL
kExistingURL2("http://foo/bee");
782 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
783 main_test_rfh()->SendNavigate(1, kExistingURL2
);
784 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
785 navigation_entry_committed_counter_
= 0;
787 // Now make a pending back/forward navigation. The zeroth entry should be
790 EXPECT_EQ(0U, notifications
.size());
791 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
792 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
794 // Before that commits, do a new navigation.
795 const GURL
kNewURL("http://foo/see");
796 LoadCommittedDetails details
;
797 main_test_rfh()->SendNavigate(3, kNewURL
);
799 // There should no longer be any pending entry, and the third navigation we
800 // just made should be committed.
801 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
802 navigation_entry_committed_counter_
= 0;
803 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
804 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
805 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
808 // Tests navigating to a new URL when there is a pending back/forward
809 // navigation to a cross-process, privileged URL. This will happen if the user
810 // hits back, but before that commits, they navigate somewhere new.
811 TEST_F(NavigationControllerTest
, LoadURL_PrivilegedPending
) {
812 NavigationControllerImpl
& controller
= controller_impl();
813 TestNotificationTracker notifications
;
814 RegisterForAllNavNotifications(¬ifications
, &controller
);
816 // First make some history, starting with a privileged URL.
817 const GURL
kExistingURL1("http://privileged");
819 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
820 // Pretend it has bindings so we can tell if we incorrectly copy it.
821 test_rvh()->AllowBindings(2);
822 main_test_rfh()->SendNavigate(0, kExistingURL1
);
823 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
824 navigation_entry_committed_counter_
= 0;
826 // Navigate cross-process to a second URL.
827 const GURL
kExistingURL2("http://foo/eh");
829 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
830 test_rvh()->SendBeforeUnloadACK(true);
831 TestRenderViewHost
* foo_rvh
= static_cast<TestRenderViewHost
*>(
832 contents()->GetPendingRenderViewHost());
833 foo_rvh
->SendNavigate(1, kExistingURL2
);
834 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
835 navigation_entry_committed_counter_
= 0;
837 // Now make a pending back/forward navigation to a privileged entry.
838 // The zeroth entry should be pending.
840 foo_rvh
->SendBeforeUnloadACK(true);
841 EXPECT_EQ(0U, notifications
.size());
842 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
843 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
844 EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry(
845 controller
.GetPendingEntry())->bindings());
847 // Before that commits, do a new navigation.
848 const GURL
kNewURL("http://foo/bee");
849 LoadCommittedDetails details
;
850 foo_rvh
->SendNavigate(3, kNewURL
);
852 // There should no longer be any pending entry, and the third navigation we
853 // just made should be committed.
854 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
855 navigation_entry_committed_counter_
= 0;
856 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
857 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
858 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
859 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
860 controller
.GetLastCommittedEntry())->bindings());
863 // Tests navigating to an existing URL when there is a pending new navigation.
864 // This will happen if the user enters a URL, but before that commits, the
865 // current page fires history.back().
866 TEST_F(NavigationControllerTest
, LoadURL_BackPreemptsPending
) {
867 NavigationControllerImpl
& controller
= controller_impl();
868 TestNotificationTracker notifications
;
869 RegisterForAllNavNotifications(¬ifications
, &controller
);
871 // First make some history.
872 const GURL
kExistingURL1("http://foo/eh");
874 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
875 main_test_rfh()->SendNavigate(0, kExistingURL1
);
876 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
877 navigation_entry_committed_counter_
= 0;
879 const GURL
kExistingURL2("http://foo/bee");
881 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
882 main_test_rfh()->SendNavigate(1, kExistingURL2
);
883 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
884 navigation_entry_committed_counter_
= 0;
886 // Now make a pending new navigation.
887 const GURL
kNewURL("http://foo/see");
889 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
890 EXPECT_EQ(0U, notifications
.size());
891 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
892 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
894 // Before that commits, a back navigation from the renderer commits.
895 main_test_rfh()->SendNavigate(0, kExistingURL1
);
897 // There should no longer be any pending entry, and the back navigation we
898 // just made should be committed.
899 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
900 navigation_entry_committed_counter_
= 0;
901 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
902 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
903 EXPECT_EQ(kExistingURL1
, controller
.GetVisibleEntry()->GetURL());
906 // Tests an ignored navigation when there is a pending new navigation.
907 // This will happen if the user enters a URL, but before that commits, the
908 // current blank page reloads. See http://crbug.com/77507.
909 TEST_F(NavigationControllerTest
, LoadURL_IgnorePreemptsPending
) {
910 NavigationControllerImpl
& controller
= controller_impl();
911 TestNotificationTracker notifications
;
912 RegisterForAllNavNotifications(¬ifications
, &controller
);
914 // Set a WebContentsDelegate to listen for state changes.
915 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
916 EXPECT_FALSE(contents()->GetDelegate());
917 contents()->SetDelegate(delegate
.get());
919 // Without any navigations, the renderer starts at about:blank.
920 const GURL
kExistingURL(url::kAboutBlankURL
);
922 // Now make a pending new navigation.
923 const GURL
kNewURL("http://eh");
925 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
926 EXPECT_EQ(0U, notifications
.size());
927 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
928 EXPECT_TRUE(controller
.GetPendingEntry());
929 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
930 EXPECT_EQ(1, delegate
->navigation_state_change_count());
932 // Before that commits, a document.write and location.reload can cause the
933 // renderer to send a FrameNavigate with page_id -1.
934 main_test_rfh()->SendNavigate(-1, kExistingURL
);
936 // This should clear the pending entry and notify of a navigation state
937 // change, so that we do not keep displaying kNewURL.
938 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
939 EXPECT_FALSE(controller
.GetPendingEntry());
940 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
941 EXPECT_EQ(2, delegate
->navigation_state_change_count());
943 contents()->SetDelegate(NULL
);
946 // Tests that the pending entry state is correct after an abort.
947 // We do not want to clear the pending entry, so that the user doesn't
948 // lose a typed URL. (See http://crbug.com/9682.)
949 TEST_F(NavigationControllerTest
, LoadURL_AbortDoesntCancelPending
) {
950 NavigationControllerImpl
& controller
= controller_impl();
951 TestNotificationTracker notifications
;
952 RegisterForAllNavNotifications(¬ifications
, &controller
);
954 // Set a WebContentsDelegate to listen for state changes.
955 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
956 EXPECT_FALSE(contents()->GetDelegate());
957 contents()->SetDelegate(delegate
.get());
959 // Start with a pending new navigation.
960 const GURL
kNewURL("http://eh");
962 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
963 EXPECT_EQ(0U, notifications
.size());
964 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
965 EXPECT_TRUE(controller
.GetPendingEntry());
966 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
967 EXPECT_EQ(1, delegate
->navigation_state_change_count());
969 // It may abort before committing, if it's a download or due to a stop or
970 // a new navigation from the user.
971 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
972 params
.error_code
= net::ERR_ABORTED
;
973 params
.error_description
= base::string16();
974 params
.url
= kNewURL
;
975 params
.showing_repost_interstitial
= false;
976 main_test_rfh()->OnMessageReceived(
977 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
980 // This should not clear the pending entry or notify of a navigation state
981 // change, so that we keep displaying kNewURL (until the user clears it).
982 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
983 EXPECT_TRUE(controller
.GetPendingEntry());
984 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
985 EXPECT_EQ(1, delegate
->navigation_state_change_count());
986 NavigationEntry
* pending_entry
= controller
.GetPendingEntry();
988 // Ensure that a reload keeps the same pending entry.
989 controller
.Reload(true);
990 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
991 EXPECT_TRUE(controller
.GetPendingEntry());
992 EXPECT_EQ(pending_entry
, controller
.GetPendingEntry());
993 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
995 contents()->SetDelegate(NULL
);
998 // Tests that the pending URL is not visible during a renderer-initiated
999 // redirect and abort. See http://crbug.com/83031.
1000 TEST_F(NavigationControllerTest
, LoadURL_RedirectAbortDoesntShowPendingURL
) {
1001 NavigationControllerImpl
& controller
= controller_impl();
1002 TestNotificationTracker notifications
;
1003 RegisterForAllNavNotifications(¬ifications
, &controller
);
1005 // First make an existing committed entry.
1006 const GURL
kExistingURL("http://foo/eh");
1007 controller
.LoadURL(kExistingURL
, content::Referrer(),
1008 content::PAGE_TRANSITION_TYPED
, std::string());
1009 main_test_rfh()->SendNavigate(0, kExistingURL
);
1010 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1011 navigation_entry_committed_counter_
= 0;
1013 // Set a WebContentsDelegate to listen for state changes.
1014 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
1015 EXPECT_FALSE(contents()->GetDelegate());
1016 contents()->SetDelegate(delegate
.get());
1018 // Now make a pending new navigation, initiated by the renderer.
1019 const GURL
kNewURL("http://foo/bee");
1020 NavigationController::LoadURLParams
load_url_params(kNewURL
);
1021 load_url_params
.transition_type
= PAGE_TRANSITION_TYPED
;
1022 load_url_params
.is_renderer_initiated
= true;
1023 controller
.LoadURLWithParams(load_url_params
);
1024 EXPECT_EQ(0U, notifications
.size());
1025 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1026 EXPECT_TRUE(controller
.GetPendingEntry());
1027 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1028 EXPECT_EQ(0, delegate
->navigation_state_change_count());
1030 // The visible entry should be the last committed URL, not the pending one.
1031 EXPECT_EQ(kExistingURL
, controller
.GetVisibleEntry()->GetURL());
1033 // Now the navigation redirects.
1034 const GURL
kRedirectURL("http://foo/see");
1035 main_test_rfh()->OnMessageReceived(
1036 FrameHostMsg_DidRedirectProvisionalLoad(0, // routing_id
1037 -1, // pending page_id
1039 kRedirectURL
)); // new url
1041 // We don't want to change the NavigationEntry's url, in case it cancels.
1042 // Prevents regression of http://crbug.com/77786.
1043 EXPECT_EQ(kNewURL
, controller
.GetPendingEntry()->GetURL());
1045 // It may abort before committing, if it's a download or due to a stop or
1046 // a new navigation from the user.
1047 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
1048 params
.error_code
= net::ERR_ABORTED
;
1049 params
.error_description
= base::string16();
1050 params
.url
= kRedirectURL
;
1051 params
.showing_repost_interstitial
= false;
1052 main_test_rfh()->OnMessageReceived(
1053 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
1056 // Because the pending entry is renderer initiated and not visible, we
1057 // clear it when it fails.
1058 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1059 EXPECT_FALSE(controller
.GetPendingEntry());
1060 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1061 EXPECT_EQ(1, delegate
->navigation_state_change_count());
1063 // The visible entry should be the last committed URL, not the pending one,
1064 // so that no spoof is possible.
1065 EXPECT_EQ(kExistingURL
, controller
.GetVisibleEntry()->GetURL());
1067 contents()->SetDelegate(NULL
);
1070 // Ensure that NavigationEntries track which bindings their RenderViewHost had
1071 // at the time they committed. http://crbug.com/173672.
1072 TEST_F(NavigationControllerTest
, LoadURL_WithBindings
) {
1073 NavigationControllerImpl
& controller
= controller_impl();
1074 TestNotificationTracker notifications
;
1075 RegisterForAllNavNotifications(¬ifications
, &controller
);
1076 std::vector
<GURL
> url_chain
;
1078 const GURL
url1("http://foo1");
1079 const GURL
url2("http://foo2");
1081 // Navigate to a first, unprivileged URL.
1082 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1083 EXPECT_EQ(NavigationEntryImpl::kInvalidBindings
,
1084 NavigationEntryImpl::FromNavigationEntry(
1085 controller
.GetPendingEntry())->bindings());
1088 TestRenderViewHost
* orig_rvh
= static_cast<TestRenderViewHost
*>(test_rvh());
1089 orig_rvh
->SendNavigate(0, url1
);
1090 EXPECT_EQ(controller
.GetEntryCount(), 1);
1091 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1092 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1093 controller
.GetLastCommittedEntry())->bindings());
1095 // Manually increase the number of active views in the SiteInstance
1096 // that orig_rvh belongs to, to prevent it from being destroyed when
1097 // it gets swapped out, so that we can reuse orig_rvh when the
1098 // controller goes back.
1099 static_cast<SiteInstanceImpl
*>(orig_rvh
->GetSiteInstance())->
1100 increment_active_view_count();
1102 // Navigate to a second URL, simulate the beforeunload ack for the cross-site
1103 // transition, run the unload handler, and set bindings on the pending
1104 // RenderViewHost to simulate a privileged url.
1105 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1106 orig_rvh
->SendBeforeUnloadACK(true);
1107 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1108 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1109 GlobalRequestID(0, 0), scoped_ptr
<CrossSiteTransferringRequest
>(),
1110 url_chain
, Referrer(), PAGE_TRANSITION_TYPED
, false);
1111 TestRenderViewHost
* new_rvh
=
1112 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
1113 new_rvh
->AllowBindings(1);
1114 new_rvh
->SendNavigate(1, url2
);
1116 // The second load should be committed, and bindings should be remembered.
1117 EXPECT_EQ(controller
.GetEntryCount(), 2);
1118 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1119 EXPECT_TRUE(controller
.CanGoBack());
1120 EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry(
1121 controller
.GetLastCommittedEntry())->bindings());
1123 // Going back, the first entry should still appear unprivileged.
1124 controller
.GoBack();
1125 new_rvh
->SendBeforeUnloadACK(true);
1126 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1127 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1128 GlobalRequestID(0, 0), scoped_ptr
<CrossSiteTransferringRequest
>(),
1129 url_chain
, Referrer(), PAGE_TRANSITION_TYPED
, false);
1130 orig_rvh
->SendNavigate(0, url1
);
1131 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1132 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1133 controller
.GetLastCommittedEntry())->bindings());
1136 TEST_F(NavigationControllerTest
, Reload
) {
1137 NavigationControllerImpl
& controller
= controller_impl();
1138 TestNotificationTracker notifications
;
1139 RegisterForAllNavNotifications(¬ifications
, &controller
);
1141 const GURL
url1("http://foo1");
1143 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1144 EXPECT_EQ(0U, notifications
.size());
1145 main_test_rfh()->SendNavigate(0, url1
);
1146 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1147 navigation_entry_committed_counter_
= 0;
1148 ASSERT_TRUE(controller
.GetVisibleEntry());
1149 controller
.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
1150 controller
.Reload(true);
1151 EXPECT_EQ(0U, notifications
.size());
1153 const base::Time timestamp
= controller
.GetVisibleEntry()->GetTimestamp();
1154 EXPECT_FALSE(timestamp
.is_null());
1156 // The reload is pending.
1157 EXPECT_EQ(controller
.GetEntryCount(), 1);
1158 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1159 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1160 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1161 EXPECT_TRUE(controller
.GetPendingEntry());
1162 EXPECT_FALSE(controller
.CanGoBack());
1163 EXPECT_FALSE(controller
.CanGoForward());
1164 // Make sure the title has been cleared (will be redrawn just after reload).
1165 // Avoids a stale cached title when the new page being reloaded has no title.
1166 // See http://crbug.com/96041.
1167 EXPECT_TRUE(controller
.GetVisibleEntry()->GetTitle().empty());
1169 main_test_rfh()->SendNavigate(0, url1
);
1170 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1171 navigation_entry_committed_counter_
= 0;
1173 // Now the reload is committed.
1174 EXPECT_EQ(controller
.GetEntryCount(), 1);
1175 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1176 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1177 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1178 EXPECT_FALSE(controller
.GetPendingEntry());
1179 EXPECT_FALSE(controller
.CanGoBack());
1180 EXPECT_FALSE(controller
.CanGoForward());
1182 // The timestamp should have been updated.
1183 ASSERT_TRUE(controller
.GetVisibleEntry());
1184 EXPECT_GE(controller
.GetVisibleEntry()->GetTimestamp(), timestamp
);
1187 // Tests what happens when a reload navigation produces a new page.
1188 TEST_F(NavigationControllerTest
, Reload_GeneratesNewPage
) {
1189 NavigationControllerImpl
& controller
= controller_impl();
1190 TestNotificationTracker notifications
;
1191 RegisterForAllNavNotifications(¬ifications
, &controller
);
1193 const GURL
url1("http://foo1");
1194 const GURL
url2("http://foo2");
1196 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1197 main_test_rfh()->SendNavigate(0, url1
);
1198 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1199 navigation_entry_committed_counter_
= 0;
1201 controller
.Reload(true);
1202 EXPECT_EQ(0U, notifications
.size());
1204 main_test_rfh()->SendNavigate(1, url2
);
1205 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1206 navigation_entry_committed_counter_
= 0;
1208 // Now the reload is committed.
1209 EXPECT_EQ(controller
.GetEntryCount(), 2);
1210 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1211 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1212 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1213 EXPECT_FALSE(controller
.GetPendingEntry());
1214 EXPECT_TRUE(controller
.CanGoBack());
1215 EXPECT_FALSE(controller
.CanGoForward());
1218 // This test ensures that when a guest renderer reloads, the reload goes through
1219 // without ending up in the "we have a wrong process for the URL" branch in
1220 // NavigationControllerImpl::ReloadInternal.
1221 TEST_F(NavigationControllerTest
, ReloadWithGuest
) {
1222 NavigationControllerImpl
& controller
= controller_impl();
1224 const GURL
url1("http://foo1");
1225 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1226 main_test_rfh()->SendNavigate(0, url1
);
1227 ASSERT_TRUE(controller
.GetVisibleEntry());
1229 // Make the entry believe its RenderProcessHost is a guest.
1230 NavigationEntryImpl
* entry1
=
1231 NavigationEntryImpl::FromNavigationEntry(controller
.GetVisibleEntry());
1232 reinterpret_cast<MockRenderProcessHost
*>(
1233 entry1
->site_instance()->GetProcess())->set_is_isolated_guest(true);
1236 controller
.Reload(true);
1238 // The reload is pending. Check that the NavigationEntry didn't get replaced
1239 // because of having the wrong process.
1240 EXPECT_EQ(controller
.GetEntryCount(), 1);
1241 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1242 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1244 NavigationEntryImpl
* entry2
=
1245 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry());
1246 EXPECT_EQ(entry1
, entry2
);
1249 #if !defined(OS_ANDROID) // http://crbug.com/157428
1250 TEST_F(NavigationControllerTest
, ReloadOriginalRequestURL
) {
1251 NavigationControllerImpl
& controller
= controller_impl();
1252 TestNotificationTracker notifications
;
1253 RegisterForAllNavNotifications(¬ifications
, &controller
);
1255 const GURL
original_url("http://foo1");
1256 const GURL
final_url("http://foo2");
1258 // Load up the original URL, but get redirected.
1260 original_url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1261 EXPECT_EQ(0U, notifications
.size());
1262 main_test_rfh()->SendNavigateWithOriginalRequestURL(
1263 0, final_url
, original_url
);
1264 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1265 navigation_entry_committed_counter_
= 0;
1267 // The NavigationEntry should save both the original URL and the final
1270 original_url
, controller
.GetVisibleEntry()->GetOriginalRequestURL());
1271 EXPECT_EQ(final_url
, controller
.GetVisibleEntry()->GetURL());
1273 // Reload using the original URL.
1274 controller
.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
1275 controller
.ReloadOriginalRequestURL(false);
1276 EXPECT_EQ(0U, notifications
.size());
1278 // The reload is pending. The request should point to the original URL.
1279 EXPECT_EQ(original_url
, navigated_url());
1280 EXPECT_EQ(controller
.GetEntryCount(), 1);
1281 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1282 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1283 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1284 EXPECT_TRUE(controller
.GetPendingEntry());
1285 EXPECT_FALSE(controller
.CanGoBack());
1286 EXPECT_FALSE(controller
.CanGoForward());
1288 // Make sure the title has been cleared (will be redrawn just after reload).
1289 // Avoids a stale cached title when the new page being reloaded has no title.
1290 // See http://crbug.com/96041.
1291 EXPECT_TRUE(controller
.GetVisibleEntry()->GetTitle().empty());
1293 // Send that the navigation has proceeded; say it got redirected again.
1294 main_test_rfh()->SendNavigate(0, final_url
);
1295 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1296 navigation_entry_committed_counter_
= 0;
1298 // Now the reload is committed.
1299 EXPECT_EQ(controller
.GetEntryCount(), 1);
1300 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1301 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1302 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1303 EXPECT_FALSE(controller
.GetPendingEntry());
1304 EXPECT_FALSE(controller
.CanGoBack());
1305 EXPECT_FALSE(controller
.CanGoForward());
1308 #endif // !defined(OS_ANDROID)
1310 // Test that certain non-persisted NavigationEntryImpl values get reset after
1312 TEST_F(NavigationControllerTest
, ResetEntryValuesAfterCommit
) {
1313 NavigationControllerImpl
& controller
= controller_impl();
1314 const GURL
url1("http://foo1");
1315 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1317 // Set up some sample values.
1318 const unsigned char* raw_data
=
1319 reinterpret_cast<const unsigned char*>("post\n\n\0data");
1320 const int length
= 11;
1321 std::vector
<unsigned char> post_data_vector(raw_data
, raw_data
+length
);
1322 scoped_refptr
<base::RefCountedBytes
> post_data
=
1323 base::RefCountedBytes::TakeVector(&post_data_vector
);
1324 GlobalRequestID
transfer_id(3, 4);
1325 std::vector
<GURL
> redirects
;
1326 redirects
.push_back(GURL("http://foo2"));
1328 // Set non-persisted values on the pending entry.
1329 NavigationEntryImpl
* pending_entry
=
1330 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry());
1331 pending_entry
->SetBrowserInitiatedPostData(post_data
.get());
1332 pending_entry
->set_is_renderer_initiated(true);
1333 pending_entry
->set_transferred_global_request_id(transfer_id
);
1334 pending_entry
->set_should_replace_entry(true);
1335 pending_entry
->set_should_clear_history_list(true);
1336 EXPECT_EQ(post_data
.get(), pending_entry
->GetBrowserInitiatedPostData());
1337 EXPECT_TRUE(pending_entry
->is_renderer_initiated());
1338 EXPECT_EQ(transfer_id
, pending_entry
->transferred_global_request_id());
1339 EXPECT_TRUE(pending_entry
->should_replace_entry());
1340 EXPECT_TRUE(pending_entry
->should_clear_history_list());
1342 main_test_rfh()->SendNavigate(0, url1
);
1344 // Certain values that are only used for pending entries get reset after
1346 NavigationEntryImpl
* committed_entry
=
1347 NavigationEntryImpl::FromNavigationEntry(
1348 controller
.GetLastCommittedEntry());
1349 EXPECT_FALSE(committed_entry
->GetBrowserInitiatedPostData());
1350 EXPECT_FALSE(committed_entry
->is_renderer_initiated());
1351 EXPECT_EQ(GlobalRequestID(-1, -1),
1352 committed_entry
->transferred_global_request_id());
1353 EXPECT_FALSE(committed_entry
->should_replace_entry());
1354 EXPECT_FALSE(committed_entry
->should_clear_history_list());
1357 // Test that Redirects are preserved after a commit.
1358 TEST_F(NavigationControllerTest
, RedirectsAreNotResetByCommit
) {
1359 NavigationControllerImpl
& controller
= controller_impl();
1360 const GURL
url1("http://foo1");
1361 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1363 // Set up some redirect values.
1364 std::vector
<GURL
> redirects
;
1365 redirects
.push_back(GURL("http://foo2"));
1367 // Set redirects on the pending entry.
1368 NavigationEntryImpl
* pending_entry
=
1369 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry());
1370 pending_entry
->SetRedirectChain(redirects
);
1371 EXPECT_EQ(1U, pending_entry
->GetRedirectChain().size());
1372 EXPECT_EQ(GURL("http://foo2"), pending_entry
->GetRedirectChain()[0]);
1374 // Normal navigation will preserve redirects in the committed entry.
1375 main_test_rfh()->SendNavigateWithRedirects(0, url1
, redirects
);
1376 NavigationEntryImpl
* committed_entry
=
1377 NavigationEntryImpl::FromNavigationEntry(
1378 controller
.GetLastCommittedEntry());
1379 ASSERT_EQ(1U, committed_entry
->GetRedirectChain().size());
1380 EXPECT_EQ(GURL("http://foo2"), committed_entry
->GetRedirectChain()[0]);
1383 // Tests what happens when we navigate back successfully
1384 TEST_F(NavigationControllerTest
, Back
) {
1385 NavigationControllerImpl
& controller
= controller_impl();
1386 TestNotificationTracker notifications
;
1387 RegisterForAllNavNotifications(¬ifications
, &controller
);
1389 const GURL
url1("http://foo1");
1390 main_test_rfh()->SendNavigate(0, url1
);
1391 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1392 navigation_entry_committed_counter_
= 0;
1394 const GURL
url2("http://foo2");
1395 main_test_rfh()->SendNavigate(1, url2
);
1396 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1397 navigation_entry_committed_counter_
= 0;
1399 controller
.GoBack();
1400 EXPECT_EQ(0U, notifications
.size());
1402 // We should now have a pending navigation to go back.
1403 EXPECT_EQ(controller
.GetEntryCount(), 2);
1404 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1405 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1406 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1407 EXPECT_TRUE(controller
.GetPendingEntry());
1408 EXPECT_FALSE(controller
.CanGoBack());
1409 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1410 EXPECT_TRUE(controller
.CanGoForward());
1411 EXPECT_TRUE(controller
.CanGoToOffset(1));
1412 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1414 // Timestamp for entry 1 should be on or after that of entry 0.
1415 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1416 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1417 controller
.GetEntryAtIndex(0)->GetTimestamp());
1419 main_test_rfh()->SendNavigate(0, url2
);
1420 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1421 navigation_entry_committed_counter_
= 0;
1423 // The back navigation completed successfully.
1424 EXPECT_EQ(controller
.GetEntryCount(), 2);
1425 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1426 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1427 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1428 EXPECT_FALSE(controller
.GetPendingEntry());
1429 EXPECT_FALSE(controller
.CanGoBack());
1430 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1431 EXPECT_TRUE(controller
.CanGoForward());
1432 EXPECT_TRUE(controller
.CanGoToOffset(1));
1433 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1435 // Timestamp for entry 0 should be on or after that of entry 1
1436 // (since we went back to it).
1437 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1438 controller
.GetEntryAtIndex(1)->GetTimestamp());
1441 // Tests what happens when a back navigation produces a new page.
1442 TEST_F(NavigationControllerTest
, Back_GeneratesNewPage
) {
1443 NavigationControllerImpl
& controller
= controller_impl();
1444 TestNotificationTracker notifications
;
1445 RegisterForAllNavNotifications(¬ifications
, &controller
);
1447 const GURL
url1("http://foo/1");
1448 const GURL
url2("http://foo/2");
1449 const GURL
url3("http://foo/3");
1452 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1453 main_test_rfh()->SendNavigate(0, url1
);
1454 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1455 navigation_entry_committed_counter_
= 0;
1457 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1458 main_test_rfh()->SendNavigate(1, url2
);
1459 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1460 navigation_entry_committed_counter_
= 0;
1462 controller
.GoBack();
1463 EXPECT_EQ(0U, notifications
.size());
1465 // We should now have a pending navigation to go back.
1466 EXPECT_EQ(controller
.GetEntryCount(), 2);
1467 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1468 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1469 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1470 EXPECT_TRUE(controller
.GetPendingEntry());
1471 EXPECT_FALSE(controller
.CanGoBack());
1472 EXPECT_TRUE(controller
.CanGoForward());
1474 main_test_rfh()->SendNavigate(2, url3
);
1475 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1476 navigation_entry_committed_counter_
= 0;
1478 // The back navigation resulted in a completely new navigation.
1479 // TODO(darin): perhaps this behavior will be confusing to users?
1480 EXPECT_EQ(controller
.GetEntryCount(), 3);
1481 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 2);
1482 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1483 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1484 EXPECT_FALSE(controller
.GetPendingEntry());
1485 EXPECT_TRUE(controller
.CanGoBack());
1486 EXPECT_FALSE(controller
.CanGoForward());
1489 // Receives a back message when there is a new pending navigation entry.
1490 TEST_F(NavigationControllerTest
, Back_NewPending
) {
1491 NavigationControllerImpl
& controller
= controller_impl();
1492 TestNotificationTracker notifications
;
1493 RegisterForAllNavNotifications(¬ifications
, &controller
);
1495 const GURL
kUrl1("http://foo1");
1496 const GURL
kUrl2("http://foo2");
1497 const GURL
kUrl3("http://foo3");
1499 // First navigate two places so we have some back history.
1500 main_test_rfh()->SendNavigate(0, kUrl1
);
1501 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1502 navigation_entry_committed_counter_
= 0;
1504 // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED);
1505 main_test_rfh()->SendNavigate(1, kUrl2
);
1506 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1507 navigation_entry_committed_counter_
= 0;
1509 // Now start a new pending navigation and go back before it commits.
1510 controller
.LoadURL(kUrl3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1511 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1512 EXPECT_EQ(kUrl3
, controller
.GetPendingEntry()->GetURL());
1513 controller
.GoBack();
1515 // The pending navigation should now be the "back" item and the new one
1517 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
1518 EXPECT_EQ(kUrl1
, controller
.GetPendingEntry()->GetURL());
1521 // Receives a back message when there is a different renavigation already
1523 TEST_F(NavigationControllerTest
, Back_OtherBackPending
) {
1524 NavigationControllerImpl
& controller
= controller_impl();
1525 const GURL
kUrl1("http://foo/1");
1526 const GURL
kUrl2("http://foo/2");
1527 const GURL
kUrl3("http://foo/3");
1529 // First navigate three places so we have some back history.
1530 main_test_rfh()->SendNavigate(0, kUrl1
);
1531 main_test_rfh()->SendNavigate(1, kUrl2
);
1532 main_test_rfh()->SendNavigate(2, kUrl3
);
1534 // With nothing pending, say we get a navigation to the second entry.
1535 main_test_rfh()->SendNavigate(1, kUrl2
);
1537 // We know all the entries have the same site instance, so we can just grab
1538 // a random one for looking up other entries.
1539 SiteInstance
* site_instance
=
1540 NavigationEntryImpl::FromNavigationEntry(
1541 controller
.GetLastCommittedEntry())->site_instance();
1543 // That second URL should be the last committed and it should have gotten the
1545 EXPECT_EQ(kUrl2
, controller
.GetEntryWithPageID(site_instance
, 1)->GetURL());
1546 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1547 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1549 // Now go forward to the last item again and say it was committed.
1550 controller
.GoForward();
1551 main_test_rfh()->SendNavigate(2, kUrl3
);
1553 // Now start going back one to the second page. It will be pending.
1554 controller
.GoBack();
1555 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
1556 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1558 // Not synthesize a totally new back event to the first page. This will not
1559 // match the pending one.
1560 main_test_rfh()->SendNavigate(0, kUrl1
);
1562 // The committed navigation should clear the pending entry.
1563 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1565 // But the navigated entry should be the last committed.
1566 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1567 EXPECT_EQ(kUrl1
, controller
.GetLastCommittedEntry()->GetURL());
1570 // Tests what happens when we navigate forward successfully.
1571 TEST_F(NavigationControllerTest
, Forward
) {
1572 NavigationControllerImpl
& controller
= controller_impl();
1573 TestNotificationTracker notifications
;
1574 RegisterForAllNavNotifications(¬ifications
, &controller
);
1576 const GURL
url1("http://foo1");
1577 const GURL
url2("http://foo2");
1579 main_test_rfh()->SendNavigate(0, url1
);
1580 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1581 navigation_entry_committed_counter_
= 0;
1583 main_test_rfh()->SendNavigate(1, url2
);
1584 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1585 navigation_entry_committed_counter_
= 0;
1587 controller
.GoBack();
1588 main_test_rfh()->SendNavigate(0, url1
);
1589 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1590 navigation_entry_committed_counter_
= 0;
1592 controller
.GoForward();
1594 // We should now have a pending navigation to go forward.
1595 EXPECT_EQ(controller
.GetEntryCount(), 2);
1596 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1597 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1598 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1599 EXPECT_TRUE(controller
.GetPendingEntry());
1600 EXPECT_TRUE(controller
.CanGoBack());
1601 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1602 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1603 EXPECT_FALSE(controller
.CanGoForward());
1604 EXPECT_FALSE(controller
.CanGoToOffset(1));
1606 // Timestamp for entry 0 should be on or after that of entry 1
1607 // (since we went back to it).
1608 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1609 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1610 controller
.GetEntryAtIndex(1)->GetTimestamp());
1612 main_test_rfh()->SendNavigate(1, url2
);
1613 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1614 navigation_entry_committed_counter_
= 0;
1616 // The forward navigation completed successfully.
1617 EXPECT_EQ(controller
.GetEntryCount(), 2);
1618 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1619 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1620 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1621 EXPECT_FALSE(controller
.GetPendingEntry());
1622 EXPECT_TRUE(controller
.CanGoBack());
1623 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1624 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1625 EXPECT_FALSE(controller
.CanGoForward());
1626 EXPECT_FALSE(controller
.CanGoToOffset(1));
1628 // Timestamp for entry 1 should be on or after that of entry 0
1629 // (since we went forward to it).
1630 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1631 controller
.GetEntryAtIndex(0)->GetTimestamp());
1634 // Tests what happens when a forward navigation produces a new page.
1635 TEST_F(NavigationControllerTest
, Forward_GeneratesNewPage
) {
1636 NavigationControllerImpl
& controller
= controller_impl();
1637 TestNotificationTracker notifications
;
1638 RegisterForAllNavNotifications(¬ifications
, &controller
);
1640 const GURL
url1("http://foo1");
1641 const GURL
url2("http://foo2");
1642 const GURL
url3("http://foo3");
1644 main_test_rfh()->SendNavigate(0, url1
);
1645 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1646 navigation_entry_committed_counter_
= 0;
1647 main_test_rfh()->SendNavigate(1, url2
);
1648 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1649 navigation_entry_committed_counter_
= 0;
1651 controller
.GoBack();
1652 main_test_rfh()->SendNavigate(0, url1
);
1653 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1654 navigation_entry_committed_counter_
= 0;
1656 controller
.GoForward();
1657 EXPECT_EQ(0U, notifications
.size());
1659 // Should now have a pending navigation to go forward.
1660 EXPECT_EQ(controller
.GetEntryCount(), 2);
1661 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1662 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1663 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1664 EXPECT_TRUE(controller
.GetPendingEntry());
1665 EXPECT_TRUE(controller
.CanGoBack());
1666 EXPECT_FALSE(controller
.CanGoForward());
1668 main_test_rfh()->SendNavigate(2, url3
);
1669 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1670 navigation_entry_committed_counter_
= 0;
1671 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED
));
1673 EXPECT_EQ(controller
.GetEntryCount(), 2);
1674 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1675 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1676 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1677 EXPECT_FALSE(controller
.GetPendingEntry());
1678 EXPECT_TRUE(controller
.CanGoBack());
1679 EXPECT_FALSE(controller
.CanGoForward());
1682 // Two consequent navigation for the same URL entered in should be considered
1683 // as SAME_PAGE navigation even when we are redirected to some other page.
1684 TEST_F(NavigationControllerTest
, Redirect
) {
1685 NavigationControllerImpl
& controller
= controller_impl();
1686 TestNotificationTracker notifications
;
1687 RegisterForAllNavNotifications(¬ifications
, &controller
);
1689 const GURL
url1("http://foo1");
1690 const GURL
url2("http://foo2"); // Redirection target
1693 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1695 EXPECT_EQ(0U, notifications
.size());
1696 main_test_rfh()->SendNavigate(0, url2
);
1697 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1698 navigation_entry_committed_counter_
= 0;
1701 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1703 EXPECT_TRUE(controller
.GetPendingEntry());
1704 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1705 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
1707 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1710 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1711 params
.redirects
.push_back(GURL("http://foo1"));
1712 params
.redirects
.push_back(GURL("http://foo2"));
1713 params
.should_update_history
= false;
1714 params
.gesture
= NavigationGestureAuto
;
1715 params
.is_post
= false;
1716 params
.page_state
= PageState::CreateFromURL(url2
);
1718 LoadCommittedDetails details
;
1720 EXPECT_EQ(0U, notifications
.size());
1721 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1723 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1724 navigation_entry_committed_counter_
= 0;
1726 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1727 EXPECT_EQ(controller
.GetEntryCount(), 1);
1728 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1729 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1730 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1731 EXPECT_FALSE(controller
.GetPendingEntry());
1732 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
1734 EXPECT_FALSE(controller
.CanGoBack());
1735 EXPECT_FALSE(controller
.CanGoForward());
1738 // Similar to Redirect above, but the first URL is requested by POST,
1739 // the second URL is requested by GET. NavigationEntry::has_post_data_
1740 // must be cleared. http://crbug.com/21245
1741 TEST_F(NavigationControllerTest
, PostThenRedirect
) {
1742 NavigationControllerImpl
& controller
= controller_impl();
1743 TestNotificationTracker notifications
;
1744 RegisterForAllNavNotifications(¬ifications
, &controller
);
1746 const GURL
url1("http://foo1");
1747 const GURL
url2("http://foo2"); // Redirection target
1749 // First request as POST
1750 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1751 controller
.GetVisibleEntry()->SetHasPostData(true);
1753 EXPECT_EQ(0U, notifications
.size());
1754 main_test_rfh()->SendNavigate(0, url2
);
1755 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1756 navigation_entry_committed_counter_
= 0;
1759 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1761 EXPECT_TRUE(controller
.GetPendingEntry());
1762 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1763 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
1765 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1768 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1769 params
.redirects
.push_back(GURL("http://foo1"));
1770 params
.redirects
.push_back(GURL("http://foo2"));
1771 params
.should_update_history
= false;
1772 params
.gesture
= NavigationGestureAuto
;
1773 params
.is_post
= false;
1774 params
.page_state
= PageState::CreateFromURL(url2
);
1776 LoadCommittedDetails details
;
1778 EXPECT_EQ(0U, notifications
.size());
1779 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1781 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1782 navigation_entry_committed_counter_
= 0;
1784 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1785 EXPECT_EQ(controller
.GetEntryCount(), 1);
1786 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1787 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1788 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1789 EXPECT_FALSE(controller
.GetPendingEntry());
1790 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
1791 EXPECT_FALSE(controller
.GetVisibleEntry()->GetHasPostData());
1793 EXPECT_FALSE(controller
.CanGoBack());
1794 EXPECT_FALSE(controller
.CanGoForward());
1797 // A redirect right off the bat should be a NEW_PAGE.
1798 TEST_F(NavigationControllerTest
, ImmediateRedirect
) {
1799 NavigationControllerImpl
& controller
= controller_impl();
1800 TestNotificationTracker notifications
;
1801 RegisterForAllNavNotifications(¬ifications
, &controller
);
1803 const GURL
url1("http://foo1");
1804 const GURL
url2("http://foo2"); // Redirection target
1807 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1809 EXPECT_TRUE(controller
.GetPendingEntry());
1810 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1811 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
1813 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1816 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1817 params
.redirects
.push_back(GURL("http://foo1"));
1818 params
.redirects
.push_back(GURL("http://foo2"));
1819 params
.should_update_history
= false;
1820 params
.gesture
= NavigationGestureAuto
;
1821 params
.is_post
= false;
1822 params
.page_state
= PageState::CreateFromURL(url2
);
1824 LoadCommittedDetails details
;
1826 EXPECT_EQ(0U, notifications
.size());
1827 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1829 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1830 navigation_entry_committed_counter_
= 0;
1832 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_NEW_PAGE
);
1833 EXPECT_EQ(controller
.GetEntryCount(), 1);
1834 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1835 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1836 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1837 EXPECT_FALSE(controller
.GetPendingEntry());
1838 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
1840 EXPECT_FALSE(controller
.CanGoBack());
1841 EXPECT_FALSE(controller
.CanGoForward());
1844 // Tests navigation via link click within a subframe. A new navigation entry
1845 // should be created.
1846 TEST_F(NavigationControllerTest
, NewSubframe
) {
1847 NavigationControllerImpl
& controller
= controller_impl();
1848 TestNotificationTracker notifications
;
1849 RegisterForAllNavNotifications(¬ifications
, &controller
);
1851 const GURL
url1("http://foo1");
1852 main_test_rfh()->SendNavigate(0, url1
);
1853 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1854 navigation_entry_committed_counter_
= 0;
1856 const GURL
url2("http://foo2");
1857 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1860 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
1861 params
.should_update_history
= false;
1862 params
.gesture
= NavigationGestureUser
;
1863 params
.is_post
= false;
1864 params
.page_state
= PageState::CreateFromURL(url2
);
1866 LoadCommittedDetails details
;
1867 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1869 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1870 navigation_entry_committed_counter_
= 0;
1871 EXPECT_EQ(url1
, details
.previous_url
);
1872 EXPECT_FALSE(details
.is_in_page
);
1873 EXPECT_FALSE(details
.is_main_frame
);
1875 // The new entry should be appended.
1876 EXPECT_EQ(2, controller
.GetEntryCount());
1878 // New entry should refer to the new page, but the old URL (entries only
1879 // reflect the toplevel URL).
1880 EXPECT_EQ(url1
, details
.entry
->GetURL());
1881 EXPECT_EQ(params
.page_id
, details
.entry
->GetPageID());
1884 // Some pages create a popup, then write an iframe into it. This causes a
1885 // subframe navigation without having any committed entry. Such navigations
1886 // just get thrown on the ground, but we shouldn't crash.
1887 TEST_F(NavigationControllerTest
, SubframeOnEmptyPage
) {
1888 NavigationControllerImpl
& controller
= controller_impl();
1889 TestNotificationTracker notifications
;
1890 RegisterForAllNavNotifications(¬ifications
, &controller
);
1892 // Navigation controller currently has no entries.
1893 const GURL
url("http://foo2");
1894 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1897 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
1898 params
.should_update_history
= false;
1899 params
.gesture
= NavigationGestureAuto
;
1900 params
.is_post
= false;
1901 params
.page_state
= PageState::CreateFromURL(url
);
1903 LoadCommittedDetails details
;
1904 EXPECT_FALSE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1906 EXPECT_EQ(0U, notifications
.size());
1909 // Auto subframes are ones the page loads automatically like ads. They should
1910 // not create new navigation entries.
1911 TEST_F(NavigationControllerTest
, AutoSubframe
) {
1912 NavigationControllerImpl
& controller
= controller_impl();
1913 TestNotificationTracker notifications
;
1914 RegisterForAllNavNotifications(¬ifications
, &controller
);
1916 const GURL
url1("http://foo1");
1917 main_test_rfh()->SendNavigate(0, url1
);
1918 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1919 navigation_entry_committed_counter_
= 0;
1921 const GURL
url2("http://foo2");
1922 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1925 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
1926 params
.should_update_history
= false;
1927 params
.gesture
= NavigationGestureUser
;
1928 params
.is_post
= false;
1929 params
.page_state
= PageState::CreateFromURL(url2
);
1931 // Navigating should do nothing.
1932 LoadCommittedDetails details
;
1933 EXPECT_FALSE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1935 EXPECT_EQ(0U, notifications
.size());
1937 // There should still be only one entry.
1938 EXPECT_EQ(1, controller
.GetEntryCount());
1941 // Tests navigation and then going back to a subframe navigation.
1942 TEST_F(NavigationControllerTest
, BackSubframe
) {
1943 NavigationControllerImpl
& controller
= controller_impl();
1944 TestNotificationTracker notifications
;
1945 RegisterForAllNavNotifications(¬ifications
, &controller
);
1948 const GURL
url1("http://foo1");
1949 main_test_rfh()->SendNavigate(0, url1
);
1950 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1951 navigation_entry_committed_counter_
= 0;
1953 // First manual subframe navigation.
1954 const GURL
url2("http://foo2");
1955 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1958 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
1959 params
.should_update_history
= false;
1960 params
.gesture
= NavigationGestureUser
;
1961 params
.is_post
= false;
1962 params
.page_state
= PageState::CreateFromURL(url2
);
1964 // This should generate a new entry.
1965 LoadCommittedDetails details
;
1966 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1968 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1969 navigation_entry_committed_counter_
= 0;
1970 EXPECT_EQ(2, controller
.GetEntryCount());
1972 // Second manual subframe navigation should also make a new entry.
1973 const GURL
url3("http://foo3");
1976 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1978 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1979 navigation_entry_committed_counter_
= 0;
1980 EXPECT_EQ(3, controller
.GetEntryCount());
1981 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
1984 controller
.GoBack();
1987 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1989 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1990 navigation_entry_committed_counter_
= 0;
1991 EXPECT_EQ(3, controller
.GetEntryCount());
1992 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
1993 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1994 EXPECT_FALSE(controller
.GetPendingEntry());
1996 // Go back one more.
1997 controller
.GoBack();
2000 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2002 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2003 navigation_entry_committed_counter_
= 0;
2004 EXPECT_EQ(3, controller
.GetEntryCount());
2005 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
2006 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2007 EXPECT_FALSE(controller
.GetPendingEntry());
2010 TEST_F(NavigationControllerTest
, LinkClick
) {
2011 NavigationControllerImpl
& controller
= controller_impl();
2012 TestNotificationTracker notifications
;
2013 RegisterForAllNavNotifications(¬ifications
, &controller
);
2015 const GURL
url1("http://foo1");
2016 const GURL
url2("http://foo2");
2018 main_test_rfh()->SendNavigate(0, url1
);
2019 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2020 navigation_entry_committed_counter_
= 0;
2022 main_test_rfh()->SendNavigate(1, url2
);
2023 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2024 navigation_entry_committed_counter_
= 0;
2026 // Should not have produced a new session history entry.
2027 EXPECT_EQ(controller
.GetEntryCount(), 2);
2028 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
2029 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
2030 EXPECT_TRUE(controller
.GetLastCommittedEntry());
2031 EXPECT_FALSE(controller
.GetPendingEntry());
2032 EXPECT_TRUE(controller
.CanGoBack());
2033 EXPECT_FALSE(controller
.CanGoForward());
2036 TEST_F(NavigationControllerTest
, InPage
) {
2037 NavigationControllerImpl
& controller
= controller_impl();
2038 TestNotificationTracker notifications
;
2039 RegisterForAllNavNotifications(¬ifications
, &controller
);
2042 const GURL
url1("http://foo");
2043 main_test_rfh()->SendNavigate(0, url1
);
2044 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2045 navigation_entry_committed_counter_
= 0;
2047 // Ensure main page navigation to same url respects the was_within_same_page
2048 // hint provided in the params.
2049 FrameHostMsg_DidCommitProvisionalLoad_Params self_params
;
2050 self_params
.page_id
= 0;
2051 self_params
.url
= url1
;
2052 self_params
.transition
= PAGE_TRANSITION_LINK
;
2053 self_params
.should_update_history
= false;
2054 self_params
.gesture
= NavigationGestureUser
;
2055 self_params
.is_post
= false;
2056 self_params
.page_state
= PageState::CreateFromURL(url1
);
2057 self_params
.was_within_same_page
= true;
2059 LoadCommittedDetails details
;
2060 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), self_params
,
2062 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2063 navigation_entry_committed_counter_
= 0;
2064 EXPECT_TRUE(details
.is_in_page
);
2065 EXPECT_TRUE(details
.did_replace_entry
);
2066 EXPECT_EQ(1, controller
.GetEntryCount());
2068 // Fragment navigation to a new page_id.
2069 const GURL
url2("http://foo#a");
2070 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2073 params
.transition
= PAGE_TRANSITION_LINK
;
2074 params
.should_update_history
= false;
2075 params
.gesture
= NavigationGestureUser
;
2076 params
.is_post
= false;
2077 params
.page_state
= PageState::CreateFromURL(url2
);
2078 params
.was_within_same_page
= true;
2080 // This should generate a new entry.
2081 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2083 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2084 navigation_entry_committed_counter_
= 0;
2085 EXPECT_TRUE(details
.is_in_page
);
2086 EXPECT_FALSE(details
.did_replace_entry
);
2087 EXPECT_EQ(2, controller
.GetEntryCount());
2090 FrameHostMsg_DidCommitProvisionalLoad_Params
back_params(params
);
2091 controller
.GoBack();
2092 back_params
.url
= url1
;
2093 back_params
.page_id
= 0;
2094 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), back_params
,
2096 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2097 navigation_entry_committed_counter_
= 0;
2098 EXPECT_TRUE(details
.is_in_page
);
2099 EXPECT_EQ(2, controller
.GetEntryCount());
2100 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
2101 EXPECT_EQ(back_params
.url
, controller
.GetVisibleEntry()->GetURL());
2104 FrameHostMsg_DidCommitProvisionalLoad_Params
forward_params(params
);
2105 controller
.GoForward();
2106 forward_params
.url
= url2
;
2107 forward_params
.page_id
= 1;
2108 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), forward_params
,
2110 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2111 navigation_entry_committed_counter_
= 0;
2112 EXPECT_TRUE(details
.is_in_page
);
2113 EXPECT_EQ(2, controller
.GetEntryCount());
2114 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
2115 EXPECT_EQ(forward_params
.url
,
2116 controller
.GetVisibleEntry()->GetURL());
2118 // Now go back and forward again. This is to work around a bug where we would
2119 // compare the incoming URL with the last committed entry rather than the
2120 // one identified by an existing page ID. This would result in the second URL
2121 // losing the reference fragment when you navigate away from it and then back.
2122 controller
.GoBack();
2123 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), back_params
,
2125 controller
.GoForward();
2126 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), forward_params
,
2128 EXPECT_EQ(forward_params
.url
,
2129 controller
.GetVisibleEntry()->GetURL());
2131 // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
2132 const GURL
url3("http://bar");
2135 navigation_entry_committed_counter_
= 0;
2136 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2138 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2139 navigation_entry_committed_counter_
= 0;
2140 EXPECT_FALSE(details
.is_in_page
);
2141 EXPECT_EQ(3, controller
.GetEntryCount());
2142 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
2145 TEST_F(NavigationControllerTest
, InPage_Replace
) {
2146 NavigationControllerImpl
& controller
= controller_impl();
2147 TestNotificationTracker notifications
;
2148 RegisterForAllNavNotifications(¬ifications
, &controller
);
2151 const GURL
url1("http://foo");
2152 main_test_rfh()->SendNavigate(0, url1
);
2153 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2154 navigation_entry_committed_counter_
= 0;
2156 // First navigation.
2157 const GURL
url2("http://foo#a");
2158 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2159 params
.page_id
= 0; // Same page_id
2161 params
.transition
= PAGE_TRANSITION_LINK
;
2162 params
.should_update_history
= false;
2163 params
.gesture
= NavigationGestureUser
;
2164 params
.is_post
= false;
2165 params
.page_state
= PageState::CreateFromURL(url2
);
2166 params
.was_within_same_page
= true;
2168 // This should NOT generate a new entry, nor prune the list.
2169 LoadCommittedDetails details
;
2170 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2172 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2173 navigation_entry_committed_counter_
= 0;
2174 EXPECT_TRUE(details
.is_in_page
);
2175 EXPECT_TRUE(details
.did_replace_entry
);
2176 EXPECT_EQ(1, controller
.GetEntryCount());
2179 // Tests for http://crbug.com/40395
2182 // window.location.replace("#a");
2183 // window.location='http://foo3/';
2185 TEST_F(NavigationControllerTest
, ClientRedirectAfterInPageNavigation
) {
2186 NavigationControllerImpl
& controller
= controller_impl();
2187 TestNotificationTracker notifications
;
2188 RegisterForAllNavNotifications(¬ifications
, &controller
);
2190 // Load an initial page.
2192 const GURL
url("http://foo/");
2193 main_test_rfh()->SendNavigate(0, url
);
2194 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2195 navigation_entry_committed_counter_
= 0;
2198 // Navigate to a new page.
2200 const GURL
url("http://foo2/");
2201 main_test_rfh()->SendNavigate(1, url
);
2202 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2203 navigation_entry_committed_counter_
= 0;
2206 // Navigate within the page.
2208 const GURL
url("http://foo2/#a");
2209 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2210 params
.page_id
= 1; // Same page_id
2212 params
.transition
= PAGE_TRANSITION_LINK
;
2213 params
.redirects
.push_back(url
);
2214 params
.should_update_history
= true;
2215 params
.gesture
= NavigationGestureUnknown
;
2216 params
.is_post
= false;
2217 params
.page_state
= PageState::CreateFromURL(url
);
2218 params
.was_within_same_page
= true;
2220 // This should NOT generate a new entry, nor prune the list.
2221 LoadCommittedDetails details
;
2222 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2224 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2225 navigation_entry_committed_counter_
= 0;
2226 EXPECT_TRUE(details
.is_in_page
);
2227 EXPECT_TRUE(details
.did_replace_entry
);
2228 EXPECT_EQ(2, controller
.GetEntryCount());
2231 // Perform a client redirect to a new page.
2233 const GURL
url("http://foo3/");
2234 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2235 params
.page_id
= 2; // New page_id
2237 params
.transition
= PAGE_TRANSITION_CLIENT_REDIRECT
;
2238 params
.redirects
.push_back(GURL("http://foo2/#a"));
2239 params
.redirects
.push_back(url
);
2240 params
.should_update_history
= true;
2241 params
.gesture
= NavigationGestureUnknown
;
2242 params
.is_post
= false;
2243 params
.page_state
= PageState::CreateFromURL(url
);
2245 // This SHOULD generate a new entry.
2246 LoadCommittedDetails details
;
2247 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2249 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2250 navigation_entry_committed_counter_
= 0;
2251 EXPECT_FALSE(details
.is_in_page
);
2252 EXPECT_EQ(3, controller
.GetEntryCount());
2255 // Verify that BACK brings us back to http://foo2/.
2257 const GURL
url("http://foo2/");
2258 controller
.GoBack();
2259 main_test_rfh()->SendNavigate(1, url
);
2260 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2261 navigation_entry_committed_counter_
= 0;
2262 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
2266 TEST_F(NavigationControllerTest
, PushStateWithoutPreviousEntry
)
2268 ASSERT_FALSE(controller_impl().GetLastCommittedEntry());
2269 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2270 GURL
url("http://foo");
2273 params
.page_state
= PageState::CreateFromURL(url
);
2274 params
.was_within_same_page
= true;
2275 test_rvh()->SendNavigateWithParams(¶ms
);
2276 // We pass if we don't crash.
2279 // NotificationObserver implementation used in verifying we've received the
2280 // NOTIFICATION_NAV_LIST_PRUNED method.
2281 class PrunedListener
: public NotificationObserver
{
2283 explicit PrunedListener(NavigationControllerImpl
* controller
)
2284 : notification_count_(0) {
2285 registrar_
.Add(this, NOTIFICATION_NAV_LIST_PRUNED
,
2286 Source
<NavigationController
>(controller
));
2289 virtual void Observe(int type
,
2290 const NotificationSource
& source
,
2291 const NotificationDetails
& details
) OVERRIDE
{
2292 if (type
== NOTIFICATION_NAV_LIST_PRUNED
) {
2293 notification_count_
++;
2294 details_
= *(Details
<PrunedDetails
>(details
).ptr());
2298 // Number of times NAV_LIST_PRUNED has been observed.
2299 int notification_count_
;
2301 // Details from the last NAV_LIST_PRUNED.
2302 PrunedDetails details_
;
2305 NotificationRegistrar registrar_
;
2307 DISALLOW_COPY_AND_ASSIGN(PrunedListener
);
2310 // Tests that we limit the number of navigation entries created correctly.
2311 TEST_F(NavigationControllerTest
, EnforceMaxNavigationCount
) {
2312 NavigationControllerImpl
& controller
= controller_impl();
2313 size_t original_count
= NavigationControllerImpl::max_entry_count();
2314 const int kMaxEntryCount
= 5;
2316 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
2319 // Load up to the max count, all entries should be there.
2320 for (url_index
= 0; url_index
< kMaxEntryCount
; url_index
++) {
2321 GURL
url(base::StringPrintf("http://www.a.com/%d", url_index
));
2323 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2324 main_test_rfh()->SendNavigate(url_index
, url
);
2327 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2329 // Created a PrunedListener to observe prune notifications.
2330 PrunedListener
listener(&controller
);
2332 // Navigate some more.
2333 GURL
url(base::StringPrintf("http://www.a.com/%d", url_index
));
2335 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2336 main_test_rfh()->SendNavigate(url_index
, url
);
2339 // We should have got a pruned navigation.
2340 EXPECT_EQ(1, listener
.notification_count_
);
2341 EXPECT_TRUE(listener
.details_
.from_front
);
2342 EXPECT_EQ(1, listener
.details_
.count
);
2344 // We expect http://www.a.com/0 to be gone.
2345 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2346 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
2347 GURL("http:////www.a.com/1"));
2349 // More navigations.
2350 for (int i
= 0; i
< 3; i
++) {
2351 url
= GURL(base::StringPrintf("http:////www.a.com/%d", url_index
));
2353 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2354 main_test_rfh()->SendNavigate(url_index
, url
);
2357 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2358 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
2359 GURL("http:////www.a.com/4"));
2361 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
2364 // Tests that we can do a restore and navigate to the restored entries and
2365 // everything is updated properly. This can be tricky since there is no
2366 // SiteInstance for the entries created initially.
2367 TEST_F(NavigationControllerTest
, RestoreNavigate
) {
2368 // Create a NavigationController with a restored set of tabs.
2369 GURL
url("http://foo");
2370 std::vector
<NavigationEntry
*> entries
;
2371 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
2372 url
, Referrer(), PAGE_TRANSITION_RELOAD
, false, std::string(),
2374 entry
->SetPageID(0);
2375 entry
->SetTitle(base::ASCIIToUTF16("Title"));
2376 entry
->SetPageState(PageState::CreateFromEncodedData("state"));
2377 const base::Time timestamp
= base::Time::Now();
2378 entry
->SetTimestamp(timestamp
);
2379 entries
.push_back(entry
);
2380 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
2381 WebContents::Create(WebContents::CreateParams(browser_context()))));
2382 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
2383 our_controller
.Restore(
2385 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2387 ASSERT_EQ(0u, entries
.size());
2389 // Before navigating to the restored entry, it should have a restore_type
2390 // and no SiteInstance.
2391 ASSERT_EQ(1, our_controller
.GetEntryCount());
2392 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2393 NavigationEntryImpl::FromNavigationEntry(
2394 our_controller
.GetEntryAtIndex(0))->restore_type());
2395 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2396 our_controller
.GetEntryAtIndex(0))->site_instance());
2398 // After navigating, we should have one entry, and it should be "pending".
2399 // It should now have a SiteInstance and no restore_type.
2400 our_controller
.GoToIndex(0);
2401 EXPECT_EQ(1, our_controller
.GetEntryCount());
2402 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
2403 our_controller
.GetPendingEntry());
2404 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
2405 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2406 NavigationEntryImpl::FromNavigationEntry
2407 (our_controller
.GetEntryAtIndex(0))->restore_type());
2408 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2409 our_controller
.GetEntryAtIndex(0))->site_instance());
2411 // Timestamp should remain the same before the navigation finishes.
2412 EXPECT_EQ(timestamp
, our_controller
.GetEntryAtIndex(0)->GetTimestamp());
2414 // Say we navigated to that entry.
2415 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2418 params
.transition
= PAGE_TRANSITION_LINK
;
2419 params
.should_update_history
= false;
2420 params
.gesture
= NavigationGestureUser
;
2421 params
.is_post
= false;
2422 params
.page_state
= PageState::CreateFromURL(url
);
2423 LoadCommittedDetails details
;
2424 our_controller
.RendererDidNavigate(our_contents
->GetMainFrame(), params
,
2427 // There should be no longer any pending entry and one committed one. This
2428 // means that we were able to locate the entry, assign its site instance, and
2429 // commit it properly.
2430 EXPECT_EQ(1, our_controller
.GetEntryCount());
2431 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
2432 EXPECT_FALSE(our_controller
.GetPendingEntry());
2434 NavigationEntryImpl::FromNavigationEntry(
2435 our_controller
.GetLastCommittedEntry())->site_instance()->
2437 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2438 NavigationEntryImpl::FromNavigationEntry(
2439 our_controller
.GetEntryAtIndex(0))->restore_type());
2441 // Timestamp should have been updated.
2442 EXPECT_GE(our_controller
.GetEntryAtIndex(0)->GetTimestamp(), timestamp
);
2445 // Tests that we can still navigate to a restored entry after a different
2446 // navigation fails and clears the pending entry. http://crbug.com/90085
2447 TEST_F(NavigationControllerTest
, RestoreNavigateAfterFailure
) {
2448 // Create a NavigationController with a restored set of tabs.
2449 GURL
url("http://foo");
2450 std::vector
<NavigationEntry
*> entries
;
2451 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
2452 url
, Referrer(), PAGE_TRANSITION_RELOAD
, false, std::string(),
2454 entry
->SetPageID(0);
2455 entry
->SetTitle(base::ASCIIToUTF16("Title"));
2456 entry
->SetPageState(PageState::CreateFromEncodedData("state"));
2457 entries
.push_back(entry
);
2458 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
2459 WebContents::Create(WebContents::CreateParams(browser_context()))));
2460 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
2461 our_controller
.Restore(
2462 0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
, &entries
);
2463 ASSERT_EQ(0u, entries
.size());
2465 // Before navigating to the restored entry, it should have a restore_type
2466 // and no SiteInstance.
2467 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2468 NavigationEntryImpl::FromNavigationEntry(
2469 our_controller
.GetEntryAtIndex(0))->restore_type());
2470 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2471 our_controller
.GetEntryAtIndex(0))->site_instance());
2473 // After navigating, we should have one entry, and it should be "pending".
2474 // It should now have a SiteInstance and no restore_type.
2475 our_controller
.GoToIndex(0);
2476 EXPECT_EQ(1, our_controller
.GetEntryCount());
2477 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
2478 our_controller
.GetPendingEntry());
2479 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
2480 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2481 NavigationEntryImpl::FromNavigationEntry(
2482 our_controller
.GetEntryAtIndex(0))->restore_type());
2483 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2484 our_controller
.GetEntryAtIndex(0))->site_instance());
2486 // This pending navigation may have caused a different navigation to fail,
2487 // which causes the pending entry to be cleared.
2488 FrameHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params
;
2489 fail_load_params
.error_code
= net::ERR_ABORTED
;
2490 fail_load_params
.error_description
= base::string16();
2491 fail_load_params
.url
= url
;
2492 fail_load_params
.showing_repost_interstitial
= false;
2493 main_test_rfh()->OnMessageReceived(
2494 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
2497 // Now the pending restored entry commits.
2498 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2501 params
.transition
= PAGE_TRANSITION_LINK
;
2502 params
.should_update_history
= false;
2503 params
.gesture
= NavigationGestureUser
;
2504 params
.is_post
= false;
2505 params
.page_state
= PageState::CreateFromURL(url
);
2506 LoadCommittedDetails details
;
2507 our_controller
.RendererDidNavigate(our_contents
->GetMainFrame(), params
,
2510 // There should be no pending entry and one committed one.
2511 EXPECT_EQ(1, our_controller
.GetEntryCount());
2512 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
2513 EXPECT_FALSE(our_controller
.GetPendingEntry());
2515 NavigationEntryImpl::FromNavigationEntry(
2516 our_controller
.GetLastCommittedEntry())->site_instance()->
2518 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2519 NavigationEntryImpl::FromNavigationEntry(
2520 our_controller
.GetEntryAtIndex(0))->restore_type());
2523 // Make sure that the page type and stuff is correct after an interstitial.
2524 TEST_F(NavigationControllerTest
, Interstitial
) {
2525 NavigationControllerImpl
& controller
= controller_impl();
2526 // First navigate somewhere normal.
2527 const GURL
url1("http://foo");
2529 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2530 main_test_rfh()->SendNavigate(0, url1
);
2532 // Now navigate somewhere with an interstitial.
2533 const GURL
url2("http://bar");
2535 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2536 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2537 set_page_type(PAGE_TYPE_INTERSTITIAL
);
2539 // At this point the interstitial will be displayed and the load will still
2540 // be pending. If the user continues, the load will commit.
2541 main_test_rfh()->SendNavigate(1, url2
);
2543 // The page should be a normal page again.
2544 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2545 EXPECT_EQ(PAGE_TYPE_NORMAL
,
2546 controller
.GetLastCommittedEntry()->GetPageType());
2549 TEST_F(NavigationControllerTest
, RemoveEntry
) {
2550 NavigationControllerImpl
& controller
= controller_impl();
2551 const GURL
url1("http://foo/1");
2552 const GURL
url2("http://foo/2");
2553 const GURL
url3("http://foo/3");
2554 const GURL
url4("http://foo/4");
2555 const GURL
url5("http://foo/5");
2556 const GURL
pending_url("http://foo/pending");
2557 const GURL
default_url("http://foo/default");
2560 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2561 main_test_rfh()->SendNavigate(0, url1
);
2563 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2564 main_test_rfh()->SendNavigate(1, url2
);
2566 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2567 main_test_rfh()->SendNavigate(2, url3
);
2569 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2570 main_test_rfh()->SendNavigate(3, url4
);
2572 url5
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2573 main_test_rfh()->SendNavigate(4, url5
);
2575 // Try to remove the last entry. Will fail because it is the current entry.
2576 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2577 EXPECT_EQ(5, controller
.GetEntryCount());
2578 EXPECT_EQ(4, controller
.GetLastCommittedEntryIndex());
2580 // Go back, but don't commit yet. Check that we can't delete the current
2581 // and pending entries.
2582 controller
.GoBack();
2583 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2584 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 2));
2586 // Now commit and delete the last entry.
2587 main_test_rfh()->SendNavigate(3, url4
);
2588 EXPECT_TRUE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2589 EXPECT_EQ(4, controller
.GetEntryCount());
2590 EXPECT_EQ(3, controller
.GetLastCommittedEntryIndex());
2591 EXPECT_FALSE(controller
.GetPendingEntry());
2593 // Remove an entry which is not the last committed one.
2594 EXPECT_TRUE(controller
.RemoveEntryAtIndex(0));
2595 EXPECT_EQ(3, controller
.GetEntryCount());
2596 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
2597 EXPECT_FALSE(controller
.GetPendingEntry());
2599 // Remove the 2 remaining entries.
2600 controller
.RemoveEntryAtIndex(1);
2601 controller
.RemoveEntryAtIndex(0);
2603 // This should leave us with only the last committed entry.
2604 EXPECT_EQ(1, controller
.GetEntryCount());
2605 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
2608 // Tests the transient entry, making sure it goes away with all navigations.
2609 TEST_F(NavigationControllerTest
, TransientEntry
) {
2610 NavigationControllerImpl
& controller
= controller_impl();
2611 TestNotificationTracker notifications
;
2612 RegisterForAllNavNotifications(¬ifications
, &controller
);
2614 const GURL
url0("http://foo/0");
2615 const GURL
url1("http://foo/1");
2616 const GURL
url2("http://foo/2");
2617 const GURL
url3("http://foo/3");
2618 const GURL
url3_ref("http://foo/3#bar");
2619 const GURL
url4("http://foo/4");
2620 const GURL
transient_url("http://foo/transient");
2623 url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2624 main_test_rfh()->SendNavigate(0, url0
);
2626 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2627 main_test_rfh()->SendNavigate(1, url1
);
2629 notifications
.Reset();
2631 // Adding a transient with no pending entry.
2632 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2633 transient_entry
->SetURL(transient_url
);
2634 controller
.SetTransientEntry(transient_entry
);
2636 // We should not have received any notifications.
2637 EXPECT_EQ(0U, notifications
.size());
2640 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2641 EXPECT_EQ(controller
.GetEntryCount(), 3);
2642 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
2643 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
2644 EXPECT_TRUE(controller
.GetLastCommittedEntry());
2645 EXPECT_FALSE(controller
.GetPendingEntry());
2646 EXPECT_TRUE(controller
.CanGoBack());
2647 EXPECT_FALSE(controller
.CanGoForward());
2648 EXPECT_EQ(contents()->GetMaxPageID(), 1);
2652 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2653 main_test_rfh()->SendNavigate(2, url2
);
2655 // We should have navigated, transient entry should be gone.
2656 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2657 EXPECT_EQ(controller
.GetEntryCount(), 3);
2659 // Add a transient again, then navigate with no pending entry this time.
2660 transient_entry
= new NavigationEntryImpl
;
2661 transient_entry
->SetURL(transient_url
);
2662 controller
.SetTransientEntry(transient_entry
);
2663 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2664 main_test_rfh()->SendNavigate(3, url3
);
2665 // Transient entry should be gone.
2666 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2667 EXPECT_EQ(controller
.GetEntryCount(), 4);
2669 // Initiate a navigation, add a transient then commit navigation.
2671 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2672 transient_entry
= new NavigationEntryImpl
;
2673 transient_entry
->SetURL(transient_url
);
2674 controller
.SetTransientEntry(transient_entry
);
2675 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2676 main_test_rfh()->SendNavigate(4, url4
);
2677 EXPECT_EQ(url4
, controller
.GetVisibleEntry()->GetURL());
2678 EXPECT_EQ(controller
.GetEntryCount(), 5);
2680 // Add a transient and go back. This should simply remove the transient.
2681 transient_entry
= new NavigationEntryImpl
;
2682 transient_entry
->SetURL(transient_url
);
2683 controller
.SetTransientEntry(transient_entry
);
2684 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2685 EXPECT_TRUE(controller
.CanGoBack());
2686 EXPECT_FALSE(controller
.CanGoForward());
2687 controller
.GoBack();
2688 // Transient entry should be gone.
2689 EXPECT_EQ(url4
, controller
.GetVisibleEntry()->GetURL());
2690 EXPECT_EQ(controller
.GetEntryCount(), 5);
2691 main_test_rfh()->SendNavigate(3, url3
);
2693 // Add a transient and go to an entry before the current one.
2694 transient_entry
= new NavigationEntryImpl
;
2695 transient_entry
->SetURL(transient_url
);
2696 controller
.SetTransientEntry(transient_entry
);
2697 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2698 controller
.GoToIndex(1);
2699 // The navigation should have been initiated, transient entry should be gone.
2700 EXPECT_FALSE(controller
.GetTransientEntry());
2701 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2702 // Visible entry does not update for history navigations until commit.
2703 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2704 main_test_rfh()->SendNavigate(1, url1
);
2705 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2707 // Add a transient and go to an entry after the current one.
2708 transient_entry
= new NavigationEntryImpl
;
2709 transient_entry
->SetURL(transient_url
);
2710 controller
.SetTransientEntry(transient_entry
);
2711 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2712 controller
.GoToIndex(3);
2713 // The navigation should have been initiated, transient entry should be gone.
2714 // Because of the transient entry that is removed, going to index 3 makes us
2715 // land on url2 (which is visible after the commit).
2716 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetURL());
2717 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2718 main_test_rfh()->SendNavigate(2, url2
);
2719 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2721 // Add a transient and go forward.
2722 transient_entry
= new NavigationEntryImpl
;
2723 transient_entry
->SetURL(transient_url
);
2724 controller
.SetTransientEntry(transient_entry
);
2725 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2726 EXPECT_TRUE(controller
.CanGoForward());
2727 controller
.GoForward();
2728 // We should have navigated, transient entry should be gone.
2729 EXPECT_FALSE(controller
.GetTransientEntry());
2730 EXPECT_EQ(url3
, controller
.GetPendingEntry()->GetURL());
2731 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2732 main_test_rfh()->SendNavigate(3, url3
);
2733 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2735 // Add a transient and do an in-page navigation, replacing the current entry.
2736 transient_entry
= new NavigationEntryImpl
;
2737 transient_entry
->SetURL(transient_url
);
2738 controller
.SetTransientEntry(transient_entry
);
2739 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2740 main_test_rfh()->SendNavigate(3, url3_ref
);
2741 // Transient entry should be gone.
2742 EXPECT_FALSE(controller
.GetTransientEntry());
2743 EXPECT_EQ(url3_ref
, controller
.GetVisibleEntry()->GetURL());
2745 // Ensure the URLs are correct.
2746 EXPECT_EQ(controller
.GetEntryCount(), 5);
2747 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2748 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), url1
);
2749 EXPECT_EQ(controller
.GetEntryAtIndex(2)->GetURL(), url2
);
2750 EXPECT_EQ(controller
.GetEntryAtIndex(3)->GetURL(), url3_ref
);
2751 EXPECT_EQ(controller
.GetEntryAtIndex(4)->GetURL(), url4
);
2754 // Test that Reload initiates a new navigation to a transient entry's URL.
2755 TEST_F(NavigationControllerTest
, ReloadTransient
) {
2756 NavigationControllerImpl
& controller
= controller_impl();
2757 const GURL
url0("http://foo/0");
2758 const GURL
url1("http://foo/1");
2759 const GURL
transient_url("http://foo/transient");
2761 // Load |url0|, and start a pending navigation to |url1|.
2763 url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2764 main_test_rfh()->SendNavigate(0, url0
);
2766 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2768 // A transient entry is added, interrupting the navigation.
2769 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2770 transient_entry
->SetURL(transient_url
);
2771 controller
.SetTransientEntry(transient_entry
);
2772 EXPECT_TRUE(controller
.GetTransientEntry());
2773 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2775 // The page is reloaded, which should remove the pending entry for |url1| and
2776 // the transient entry for |transient_url|, and start a navigation to
2778 controller
.Reload(true);
2779 EXPECT_FALSE(controller
.GetTransientEntry());
2780 EXPECT_TRUE(controller
.GetPendingEntry());
2781 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2782 ASSERT_EQ(controller
.GetEntryCount(), 1);
2783 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2785 // Load of |transient_url| completes.
2786 main_test_rfh()->SendNavigate(1, transient_url
);
2787 ASSERT_EQ(controller
.GetEntryCount(), 2);
2788 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2789 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), transient_url
);
2792 // Ensure that renderer initiated pending entries get replaced, so that we
2793 // don't show a stale virtual URL when a navigation commits.
2794 // See http://crbug.com/266922.
2795 TEST_F(NavigationControllerTest
, RendererInitiatedPendingEntries
) {
2796 NavigationControllerImpl
& controller
= controller_impl();
2797 Navigator
* navigator
=
2798 contents()->GetFrameTree()->root()->navigator();
2800 const GURL
url1("nonexistent:12121");
2801 const GURL
url1_fixed("http://nonexistent:12121/");
2802 const GURL
url2("http://foo");
2804 // We create pending entries for renderer-initiated navigations so that we
2805 // can show them in new tabs when it is safe.
2806 navigator
->DidStartProvisionalLoad(main_test_rfh(), -1, url1
);
2808 // Simulate what happens if a BrowserURLHandler rewrites the URL, causing
2809 // the virtual URL to differ from the URL.
2810 controller
.GetPendingEntry()->SetURL(url1_fixed
);
2811 controller
.GetPendingEntry()->SetVirtualURL(url1
);
2813 EXPECT_EQ(url1_fixed
, controller
.GetPendingEntry()->GetURL());
2814 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetVirtualURL());
2816 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2817 is_renderer_initiated());
2819 // If the user clicks another link, we should replace the pending entry.
2820 navigator
->DidStartProvisionalLoad(main_test_rfh(), -1, url2
);
2821 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetURL());
2822 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetVirtualURL());
2824 // Once it commits, the URL and virtual URL should reflect the actual page.
2825 main_test_rfh()->SendNavigate(0, url2
);
2826 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2827 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetVirtualURL());
2829 // We should not replace the pending entry for an error URL.
2830 navigator
->DidStartProvisionalLoad(main_test_rfh(), -1, url1
);
2831 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2832 navigator
->DidStartProvisionalLoad(
2833 main_test_rfh(), -1, GURL(kUnreachableWebDataURL
));
2834 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2836 // We should remember if the pending entry will replace the current one.
2837 // http://crbug.com/308444.
2838 navigator
->DidStartProvisionalLoad(main_test_rfh(), -1, url1
);
2839 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2840 set_should_replace_entry(true);
2841 navigator
->DidStartProvisionalLoad(main_test_rfh(), -1, url2
);
2843 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2844 should_replace_entry());
2845 // TODO(nasko): Until OnNavigate is moved to RenderFrameHost, we need
2846 // to go through the RenderViewHost. The TestRenderViewHost routes navigations
2847 // to the main frame.
2848 main_test_rfh()->SendNavigate(0, url2
);
2849 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2852 // Tests that the URLs for renderer-initiated navigations are not displayed to
2853 // the user until the navigation commits, to prevent URL spoof attacks.
2854 // See http://crbug.com/99016.
2855 TEST_F(NavigationControllerTest
, DontShowRendererURLUntilCommit
) {
2856 NavigationControllerImpl
& controller
= controller_impl();
2857 TestNotificationTracker notifications
;
2858 RegisterForAllNavNotifications(¬ifications
, &controller
);
2860 const GURL
url0("http://foo/0");
2861 const GURL
url1("http://foo/1");
2863 // For typed navigations (browser-initiated), both pending and visible entries
2864 // should update before commit.
2865 controller
.LoadURL(url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2866 EXPECT_EQ(url0
, controller
.GetPendingEntry()->GetURL());
2867 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
2868 main_test_rfh()->SendNavigate(0, url0
);
2870 // For link clicks (renderer-initiated navigations), the pending entry should
2871 // update before commit but the visible should not.
2872 NavigationController::LoadURLParams
load_url_params(url1
);
2873 load_url_params
.is_renderer_initiated
= true;
2874 controller
.LoadURLWithParams(load_url_params
);
2875 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
2876 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2878 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2879 is_renderer_initiated());
2881 // After commit, both visible should be updated, there should be no pending
2882 // entry, and we should no longer treat the entry as renderer-initiated.
2883 main_test_rfh()->SendNavigate(1, url1
);
2884 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2885 EXPECT_FALSE(controller
.GetPendingEntry());
2887 NavigationEntryImpl::FromNavigationEntry(
2888 controller
.GetLastCommittedEntry())->is_renderer_initiated());
2890 notifications
.Reset();
2893 // Tests that the URLs for renderer-initiated navigations in new tabs are
2894 // displayed to the user before commit, as long as the initial about:blank
2895 // page has not been modified. If so, we must revert to showing about:blank.
2896 // See http://crbug.com/9682.
2897 TEST_F(NavigationControllerTest
, ShowRendererURLInNewTabUntilModified
) {
2898 NavigationControllerImpl
& controller
= controller_impl();
2899 TestNotificationTracker notifications
;
2900 RegisterForAllNavNotifications(¬ifications
, &controller
);
2902 const GURL
url("http://foo");
2904 // For renderer-initiated navigations in new tabs (with no committed entries),
2905 // we show the pending entry's URL as long as the about:blank page is not
2907 NavigationController::LoadURLParams
load_url_params(url
);
2908 load_url_params
.transition_type
= PAGE_TRANSITION_LINK
;
2909 load_url_params
.is_renderer_initiated
= true;
2910 controller
.LoadURLWithParams(load_url_params
);
2911 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
2912 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
2914 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2915 is_renderer_initiated());
2916 EXPECT_TRUE(controller
.IsInitialNavigation());
2917 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
2919 // There should be no title yet.
2920 EXPECT_TRUE(contents()->GetTitle().empty());
2922 // If something else modifies the contents of the about:blank page, then
2923 // we must revert to showing about:blank to avoid a URL spoof.
2924 main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
2925 EXPECT_TRUE(contents()->HasAccessedInitialDocument());
2926 EXPECT_FALSE(controller
.GetVisibleEntry());
2927 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
2929 notifications
.Reset();
2932 // Tests that the URLs for browser-initiated navigations in new tabs are
2933 // displayed to the user even after they fail, as long as the initial
2934 // about:blank page has not been modified. If so, we must revert to showing
2935 // about:blank. See http://crbug.com/355537.
2936 TEST_F(NavigationControllerTest
, ShowBrowserURLAfterFailUntilModified
) {
2937 NavigationControllerImpl
& controller
= controller_impl();
2938 TestNotificationTracker notifications
;
2939 RegisterForAllNavNotifications(¬ifications
, &controller
);
2941 const GURL
url("http://foo");
2943 // For browser-initiated navigations in new tabs (with no committed entries),
2944 // we show the pending entry's URL as long as the about:blank page is not
2945 // modified. This is possible in cases that the user types a URL into a popup
2946 // tab created with a slow URL.
2947 NavigationController::LoadURLParams
load_url_params(url
);
2948 load_url_params
.transition_type
= PAGE_TRANSITION_TYPED
;
2949 load_url_params
.is_renderer_initiated
= false;
2950 controller
.LoadURLWithParams(load_url_params
);
2951 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
2952 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
2954 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2955 is_renderer_initiated());
2956 EXPECT_TRUE(controller
.IsInitialNavigation());
2957 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
2959 // There should be no title yet.
2960 EXPECT_TRUE(contents()->GetTitle().empty());
2962 // Suppose it aborts before committing, if it's a 204 or download or due to a
2963 // stop or a new navigation from the user. The URL should remain visible.
2964 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
2965 params
.error_code
= net::ERR_ABORTED
;
2966 params
.error_description
= base::string16();
2968 params
.showing_repost_interstitial
= false;
2969 main_test_rfh()->OnMessageReceived(
2970 FrameHostMsg_DidFailProvisionalLoadWithError(0, params
));
2971 contents()->SetIsLoading(test_rvh(), false, true, NULL
);
2972 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
2974 // If something else later modifies the contents of the about:blank page, then
2975 // we must revert to showing about:blank to avoid a URL spoof.
2976 main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
2977 EXPECT_TRUE(contents()->HasAccessedInitialDocument());
2978 EXPECT_FALSE(controller
.GetVisibleEntry());
2979 EXPECT_FALSE(controller
.GetPendingEntry());
2981 notifications
.Reset();
2984 // Tests that the URLs for renderer-initiated navigations in new tabs are
2985 // displayed to the user even after they fail, as long as the initial
2986 // about:blank page has not been modified. If so, we must revert to showing
2987 // about:blank. See http://crbug.com/355537.
2988 TEST_F(NavigationControllerTest
, ShowRendererURLAfterFailUntilModified
) {
2989 NavigationControllerImpl
& controller
= controller_impl();
2990 TestNotificationTracker notifications
;
2991 RegisterForAllNavNotifications(¬ifications
, &controller
);
2993 const GURL
url("http://foo");
2995 // For renderer-initiated navigations in new tabs (with no committed entries),
2996 // we show the pending entry's URL as long as the about:blank page is not
2998 NavigationController::LoadURLParams
load_url_params(url
);
2999 load_url_params
.transition_type
= PAGE_TRANSITION_LINK
;
3000 load_url_params
.is_renderer_initiated
= true;
3001 controller
.LoadURLWithParams(load_url_params
);
3002 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
3003 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
3005 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
3006 is_renderer_initiated());
3007 EXPECT_TRUE(controller
.IsInitialNavigation());
3008 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3010 // There should be no title yet.
3011 EXPECT_TRUE(contents()->GetTitle().empty());
3013 // Suppose it aborts before committing, if it's a 204 or download or due to a
3014 // stop or a new navigation from the user. The URL should remain visible.
3015 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
3016 params
.error_code
= net::ERR_ABORTED
;
3017 params
.error_description
= base::string16();
3019 params
.showing_repost_interstitial
= false;
3020 main_test_rfh()->OnMessageReceived(
3021 FrameHostMsg_DidFailProvisionalLoadWithError(0, params
));
3022 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
3024 // If something else later modifies the contents of the about:blank page, then
3025 // we must revert to showing about:blank to avoid a URL spoof.
3026 main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
3027 EXPECT_TRUE(contents()->HasAccessedInitialDocument());
3028 EXPECT_FALSE(controller
.GetVisibleEntry());
3029 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
3031 notifications
.Reset();
3034 TEST_F(NavigationControllerTest
, DontShowRendererURLInNewTabAfterCommit
) {
3035 NavigationControllerImpl
& controller
= controller_impl();
3036 TestNotificationTracker notifications
;
3037 RegisterForAllNavNotifications(¬ifications
, &controller
);
3039 const GURL
url1("http://foo/eh");
3040 const GURL
url2("http://foo/bee");
3042 // For renderer-initiated navigations in new tabs (with no committed entries),
3043 // we show the pending entry's URL as long as the about:blank page is not
3045 NavigationController::LoadURLParams
load_url_params(url1
);
3046 load_url_params
.transition_type
= PAGE_TRANSITION_LINK
;
3047 load_url_params
.is_renderer_initiated
= true;
3048 controller
.LoadURLWithParams(load_url_params
);
3049 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
3051 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
3052 is_renderer_initiated());
3053 EXPECT_TRUE(controller
.IsInitialNavigation());
3054 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3056 // Simulate a commit and then starting a new pending navigation.
3057 main_test_rfh()->SendNavigate(0, url1
);
3058 NavigationController::LoadURLParams
load_url2_params(url2
);
3059 load_url2_params
.transition_type
= PAGE_TRANSITION_LINK
;
3060 load_url2_params
.is_renderer_initiated
= true;
3061 controller
.LoadURLWithParams(load_url2_params
);
3063 // We should not consider this an initial navigation, and thus should
3064 // not show the pending URL.
3065 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3066 EXPECT_FALSE(controller
.IsInitialNavigation());
3067 EXPECT_TRUE(controller
.GetVisibleEntry());
3068 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
3070 notifications
.Reset();
3073 // Tests that IsInPageNavigation returns appropriate results. Prevents
3074 // regression for bug 1126349.
3075 TEST_F(NavigationControllerTest
, IsInPageNavigation
) {
3076 NavigationControllerImpl
& controller
= controller_impl();
3077 // Navigate to URL with no refs.
3078 const GURL
url("http://www.google.com/home.html");
3079 main_test_rfh()->SendNavigate(0, url
);
3081 // Reloading the page is not an in-page navigation.
3082 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
, false,
3083 NAVIGATION_TYPE_UNKNOWN
));
3084 const GURL
other_url("http://www.google.com/add.html");
3085 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
, false,
3086 NAVIGATION_TYPE_UNKNOWN
));
3087 const GURL
url_with_ref("http://www.google.com/home.html#my_ref");
3088 EXPECT_TRUE(controller
.IsURLInPageNavigation(url_with_ref
, true,
3089 NAVIGATION_TYPE_UNKNOWN
));
3091 // Navigate to URL with refs.
3092 main_test_rfh()->SendNavigate(1, url_with_ref
);
3094 // Reloading the page is not an in-page navigation.
3095 EXPECT_FALSE(controller
.IsURLInPageNavigation(url_with_ref
, false,
3096 NAVIGATION_TYPE_UNKNOWN
));
3097 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
, false,
3098 NAVIGATION_TYPE_UNKNOWN
));
3099 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
, false,
3100 NAVIGATION_TYPE_UNKNOWN
));
3101 const GURL
other_url_with_ref("http://www.google.com/home.html#my_other_ref");
3102 EXPECT_TRUE(controller
.IsURLInPageNavigation(other_url_with_ref
, true,
3103 NAVIGATION_TYPE_UNKNOWN
));
3105 // Going to the same url again will be considered in-page
3106 // if the renderer says it is even if the navigation type isn't IN_PAGE.
3107 EXPECT_TRUE(controller
.IsURLInPageNavigation(url_with_ref
, true,
3108 NAVIGATION_TYPE_UNKNOWN
));
3110 // Going back to the non ref url will be considered in-page if the navigation
3112 EXPECT_TRUE(controller
.IsURLInPageNavigation(url
, true,
3113 NAVIGATION_TYPE_IN_PAGE
));
3115 // If the renderer says this is a same-origin in-page navigation, believe it.
3116 // This is the pushState/replaceState case.
3117 EXPECT_TRUE(controller
.IsURLInPageNavigation(other_url
, true,
3118 NAVIGATION_TYPE_UNKNOWN
));
3120 // Don't believe the renderer if it claims a cross-origin navigation is
3122 const GURL
different_origin_url("http://www.example.com");
3123 EXPECT_FALSE(controller
.IsURLInPageNavigation(different_origin_url
, true,
3124 NAVIGATION_TYPE_UNKNOWN
));
3127 // Some pages can have subframes with the same base URL (minus the reference) as
3128 // the main page. Even though this is hard, it can happen, and we don't want
3129 // these subframe navigations to affect the toplevel document. They should
3130 // instead be ignored. http://crbug.com/5585
3131 TEST_F(NavigationControllerTest
, SameSubframe
) {
3132 NavigationControllerImpl
& controller
= controller_impl();
3133 // Navigate the main frame.
3134 const GURL
url("http://www.google.com/");
3135 main_test_rfh()->SendNavigate(0, url
);
3137 // We should be at the first navigation entry.
3138 EXPECT_EQ(controller
.GetEntryCount(), 1);
3139 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
3141 // Navigate a subframe that would normally count as in-page.
3142 const GURL
subframe("http://www.google.com/#");
3143 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
3145 params
.url
= subframe
;
3146 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
3147 params
.should_update_history
= false;
3148 params
.gesture
= NavigationGestureAuto
;
3149 params
.is_post
= false;
3150 params
.page_state
= PageState::CreateFromURL(subframe
);
3151 LoadCommittedDetails details
;
3152 EXPECT_FALSE(controller
.RendererDidNavigate(main_test_rfh(), params
,
3155 // Nothing should have changed.
3156 EXPECT_EQ(controller
.GetEntryCount(), 1);
3157 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
3160 // Make sure that on cloning a WebContentsImpl and going back needs_reload is
3162 TEST_F(NavigationControllerTest
, CloneAndGoBack
) {
3163 NavigationControllerImpl
& controller
= controller_impl();
3164 const GURL
url1("http://foo1");
3165 const GURL
url2("http://foo2");
3166 const base::string16
title(base::ASCIIToUTF16("Title"));
3168 NavigateAndCommit(url1
);
3169 controller
.GetVisibleEntry()->SetTitle(title
);
3170 NavigateAndCommit(url2
);
3172 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
3174 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
3175 EXPECT_TRUE(clone
->GetController().NeedsReload());
3176 clone
->GetController().GoBack();
3177 // Navigating back should have triggered needs_reload_ to go false.
3178 EXPECT_FALSE(clone
->GetController().NeedsReload());
3180 // Ensure that the pending URL and its title are visible.
3181 EXPECT_EQ(url1
, clone
->GetController().GetVisibleEntry()->GetURL());
3182 EXPECT_EQ(title
, clone
->GetTitle());
3185 // Make sure that reloading a cloned tab doesn't change its pending entry index.
3186 // See http://crbug.com/234491.
3187 TEST_F(NavigationControllerTest
, CloneAndReload
) {
3188 NavigationControllerImpl
& controller
= controller_impl();
3189 const GURL
url1("http://foo1");
3190 const GURL
url2("http://foo2");
3191 const base::string16
title(base::ASCIIToUTF16("Title"));
3193 NavigateAndCommit(url1
);
3194 controller
.GetVisibleEntry()->SetTitle(title
);
3195 NavigateAndCommit(url2
);
3197 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
3198 clone
->GetController().LoadIfNecessary();
3200 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
3201 EXPECT_EQ(1, clone
->GetController().GetPendingEntryIndex());
3203 clone
->GetController().Reload(true);
3204 EXPECT_EQ(1, clone
->GetController().GetPendingEntryIndex());
3207 // Make sure that cloning a WebContentsImpl doesn't copy interstitials.
3208 TEST_F(NavigationControllerTest
, CloneOmitsInterstitials
) {
3209 NavigationControllerImpl
& controller
= controller_impl();
3210 const GURL
url1("http://foo1");
3211 const GURL
url2("http://foo2");
3213 NavigateAndCommit(url1
);
3214 NavigateAndCommit(url2
);
3216 // Add an interstitial entry. Should be deleted with controller.
3217 NavigationEntryImpl
* interstitial_entry
= new NavigationEntryImpl();
3218 interstitial_entry
->set_page_type(PAGE_TYPE_INTERSTITIAL
);
3219 controller
.SetTransientEntry(interstitial_entry
);
3221 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
3223 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
3226 // Test requesting and triggering a lazy reload.
3227 TEST_F(NavigationControllerTest
, LazyReload
) {
3228 NavigationControllerImpl
& controller
= controller_impl();
3229 const GURL
url("http://foo");
3230 NavigateAndCommit(url
);
3231 ASSERT_FALSE(controller
.NeedsReload());
3233 // Request a reload to happen when the controller becomes active (e.g. after
3234 // the renderer gets killed in background on Android).
3235 controller
.SetNeedsReload();
3236 ASSERT_TRUE(controller
.NeedsReload());
3238 // Set the controller as active, triggering the requested reload.
3239 controller
.SetActive(true);
3240 ASSERT_FALSE(controller
.NeedsReload());
3243 // Tests a subframe navigation while a toplevel navigation is pending.
3244 // http://crbug.com/43967
3245 TEST_F(NavigationControllerTest
, SubframeWhilePending
) {
3246 NavigationControllerImpl
& controller
= controller_impl();
3247 // Load the first page.
3248 const GURL
url1("http://foo/");
3249 NavigateAndCommit(url1
);
3251 // Now start a pending load to a totally different page, but don't commit it.
3252 const GURL
url2("http://bar/");
3254 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3256 // Send a subframe update from the first page, as if one had just
3257 // automatically loaded. Auto subframes don't increment the page ID.
3258 const GURL
url1_sub("http://foo/subframe");
3259 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
3260 params
.page_id
= controller
.GetLastCommittedEntry()->GetPageID();
3261 params
.url
= url1_sub
;
3262 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
3263 params
.should_update_history
= false;
3264 params
.gesture
= NavigationGestureAuto
;
3265 params
.is_post
= false;
3266 params
.page_state
= PageState::CreateFromURL(url1_sub
);
3267 LoadCommittedDetails details
;
3269 // This should return false meaning that nothing was actually updated.
3270 EXPECT_FALSE(controller
.RendererDidNavigate(main_test_rfh(), params
,
3273 // The notification should have updated the last committed one, and not
3274 // the pending load.
3275 EXPECT_EQ(url1
, controller
.GetLastCommittedEntry()->GetURL());
3277 // The active entry should be unchanged by the subframe load.
3278 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
3281 // Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
3282 TEST_F(NavigationControllerTest
, CopyStateFrom
) {
3283 NavigationControllerImpl
& controller
= controller_impl();
3284 const GURL
url1("http://foo1");
3285 const GURL
url2("http://foo2");
3287 NavigateAndCommit(url1
);
3288 NavigateAndCommit(url2
);
3289 controller
.GoBack();
3290 contents()->CommitPendingNavigation();
3292 scoped_ptr
<TestWebContents
> other_contents(
3293 static_cast<TestWebContents
*>(CreateTestWebContents()));
3294 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3295 other_controller
.CopyStateFrom(controller
);
3297 // other_controller should now contain 2 urls.
3298 ASSERT_EQ(2, other_controller
.GetEntryCount());
3299 // We should be looking at the first one.
3300 ASSERT_EQ(0, other_controller
.GetCurrentEntryIndex());
3302 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3303 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3304 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3305 // This is a different site than url1, so the IDs start again at 0.
3306 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3308 // The max page ID map should be copied over and updated with the max page ID
3309 // from the current tab.
3310 SiteInstance
* instance1
=
3311 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0));
3312 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3314 // Ensure the SessionStorageNamespaceMaps are the same size and have
3315 // the same partitons loaded.
3317 // TODO(ajwong): We should load a url from a different partition earlier
3318 // to make sure this map has more than one entry.
3319 const SessionStorageNamespaceMap
& session_storage_namespace_map
=
3320 controller
.GetSessionStorageNamespaceMap();
3321 const SessionStorageNamespaceMap
& other_session_storage_namespace_map
=
3322 other_controller
.GetSessionStorageNamespaceMap();
3323 EXPECT_EQ(session_storage_namespace_map
.size(),
3324 other_session_storage_namespace_map
.size());
3325 for (SessionStorageNamespaceMap::const_iterator it
=
3326 session_storage_namespace_map
.begin();
3327 it
!= session_storage_namespace_map
.end();
3329 SessionStorageNamespaceMap::const_iterator other
=
3330 other_session_storage_namespace_map
.find(it
->first
);
3331 EXPECT_TRUE(other
!= other_session_storage_namespace_map
.end());
3335 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
3336 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune
) {
3337 NavigationControllerImpl
& controller
= controller_impl();
3338 const GURL
url1("http://foo/1");
3339 const GURL
url2("http://foo/2");
3340 const GURL
url3("http://foo/3");
3342 NavigateAndCommit(url1
);
3343 NavigateAndCommit(url2
);
3345 // First two entries should have the same SiteInstance.
3346 SiteInstance
* instance1
=
3347 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0));
3348 SiteInstance
* instance2
=
3349 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(1));
3350 EXPECT_EQ(instance1
, instance2
);
3351 EXPECT_EQ(0, controller
.GetEntryAtIndex(0)->GetPageID());
3352 EXPECT_EQ(1, controller
.GetEntryAtIndex(1)->GetPageID());
3353 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1
));
3355 scoped_ptr
<TestWebContents
> other_contents(
3356 static_cast<TestWebContents
*>(CreateTestWebContents()));
3357 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3358 other_contents
->NavigateAndCommit(url3
);
3359 other_contents
->ExpectSetHistoryLengthAndPrune(
3360 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3361 other_controller
.GetEntryAtIndex(0)->GetPageID());
3362 other_controller
.CopyStateFromAndPrune(&controller
, false);
3364 // other_controller should now contain the 3 urls: url1, url2 and url3.
3366 ASSERT_EQ(3, other_controller
.GetEntryCount());
3368 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3370 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3371 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3372 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3373 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3374 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(1)->GetPageID());
3375 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3377 // A new SiteInstance in a different BrowsingInstance should be used for the
3379 SiteInstance
* instance3
=
3380 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3381 EXPECT_NE(instance3
, instance1
);
3382 EXPECT_FALSE(instance3
->IsRelatedSiteInstance(instance1
));
3384 // The max page ID map should be copied over and updated with the max page ID
3385 // from the current tab.
3386 EXPECT_EQ(1, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3387 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance3
));
3390 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in
3392 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune2
) {
3393 NavigationControllerImpl
& controller
= controller_impl();
3394 const GURL
url1("http://foo1");
3395 const GURL
url2("http://foo2");
3396 const GURL
url3("http://foo3");
3398 NavigateAndCommit(url1
);
3399 NavigateAndCommit(url2
);
3400 controller
.GoBack();
3401 contents()->CommitPendingNavigation();
3403 scoped_ptr
<TestWebContents
> other_contents(
3404 static_cast<TestWebContents
*>(CreateTestWebContents()));
3405 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3406 other_contents
->NavigateAndCommit(url3
);
3407 other_contents
->ExpectSetHistoryLengthAndPrune(
3408 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3409 other_controller
.GetEntryAtIndex(0)->GetPageID());
3410 other_controller
.CopyStateFromAndPrune(&controller
, false);
3412 // other_controller should now contain: url1, url3
3414 ASSERT_EQ(2, other_controller
.GetEntryCount());
3415 ASSERT_EQ(1, other_controller
.GetCurrentEntryIndex());
3417 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3418 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3419 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3421 // The max page ID map should be copied over and updated with the max page ID
3422 // from the current tab.
3423 SiteInstance
* instance1
=
3424 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1));
3425 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3428 // Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in
3430 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune3
) {
3431 NavigationControllerImpl
& controller
= controller_impl();
3432 const GURL
url1("http://foo1");
3433 const GURL
url2("http://foo2");
3434 const GURL
url3("http://foo3");
3435 const GURL
url4("http://foo4");
3437 NavigateAndCommit(url1
);
3438 NavigateAndCommit(url2
);
3440 scoped_ptr
<TestWebContents
> other_contents(
3441 static_cast<TestWebContents
*>(CreateTestWebContents()));
3442 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3443 other_contents
->NavigateAndCommit(url3
);
3444 other_contents
->NavigateAndCommit(url4
);
3445 other_contents
->ExpectSetHistoryLengthAndPrune(
3446 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1)), 2,
3447 other_controller
.GetEntryAtIndex(0)->GetPageID());
3448 other_controller
.CopyStateFromAndPrune(&controller
, false);
3450 // other_controller should now contain: url1, url2, url4
3452 ASSERT_EQ(3, other_controller
.GetEntryCount());
3453 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3455 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3456 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3457 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3459 // The max page ID map should be copied over and updated with the max page ID
3460 // from the current tab.
3461 SiteInstance
* instance1
=
3462 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3463 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3466 // Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with
3467 // not the last entry selected in the target.
3468 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneNotLast
) {
3469 NavigationControllerImpl
& controller
= controller_impl();
3470 const GURL
url1("http://foo1");
3471 const GURL
url2("http://foo2");
3472 const GURL
url3("http://foo3");
3473 const GURL
url4("http://foo4");
3475 NavigateAndCommit(url1
);
3476 NavigateAndCommit(url2
);
3478 scoped_ptr
<TestWebContents
> other_contents(
3479 static_cast<TestWebContents
*>(CreateTestWebContents()));
3480 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3481 other_contents
->NavigateAndCommit(url3
);
3482 other_contents
->NavigateAndCommit(url4
);
3483 other_controller
.GoBack();
3484 other_contents
->CommitPendingNavigation();
3485 other_contents
->ExpectSetHistoryLengthAndPrune(
3486 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3487 other_controller
.GetEntryAtIndex(0)->GetPageID());
3488 other_controller
.CopyStateFromAndPrune(&controller
, false);
3490 // other_controller should now contain: url1, url2, url3
3492 ASSERT_EQ(3, other_controller
.GetEntryCount());
3493 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3495 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3496 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3497 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3499 // The max page ID map should be copied over and updated with the max page ID
3500 // from the current tab.
3501 SiteInstance
* instance1
=
3502 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3503 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3506 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus
3507 // a pending entry in the target.
3508 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneTargetPending
) {
3509 NavigationControllerImpl
& controller
= controller_impl();
3510 const GURL
url1("http://foo1");
3511 const GURL
url2("http://foo2");
3512 const GURL
url3("http://foo3");
3513 const GURL
url4("http://foo4");
3515 NavigateAndCommit(url1
);
3516 NavigateAndCommit(url2
);
3517 controller
.GoBack();
3518 contents()->CommitPendingNavigation();
3520 scoped_ptr
<TestWebContents
> other_contents(
3521 static_cast<TestWebContents
*>(CreateTestWebContents()));
3522 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3523 other_contents
->NavigateAndCommit(url3
);
3524 other_controller
.LoadURL(
3525 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3526 other_contents
->ExpectSetHistoryLengthAndPrune(
3527 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3528 other_controller
.GetEntryAtIndex(0)->GetPageID());
3529 other_controller
.CopyStateFromAndPrune(&controller
, false);
3531 // other_controller should now contain url1, url3, and a pending entry
3534 ASSERT_EQ(2, other_controller
.GetEntryCount());
3535 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
3537 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3538 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3540 // And there should be a pending entry for url4.
3541 ASSERT_TRUE(other_controller
.GetPendingEntry());
3542 EXPECT_EQ(url4
, other_controller
.GetPendingEntry()->GetURL());
3544 // The max page ID map should be copied over and updated with the max page ID
3545 // from the current tab.
3546 SiteInstance
* instance1
=
3547 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0));
3548 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3551 // Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending
3552 // client redirect entry (with the same page ID) in the target. This used to
3553 // crash because the last committed entry would be pruned but max_page_id
3554 // remembered the page ID (http://crbug.com/234809).
3555 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneTargetPending2
) {
3556 NavigationControllerImpl
& controller
= controller_impl();
3557 const GURL
url1("http://foo1");
3558 const GURL
url2a("http://foo2/a");
3559 const GURL
url2b("http://foo2/b");
3561 NavigateAndCommit(url1
);
3563 scoped_ptr
<TestWebContents
> other_contents(
3564 static_cast<TestWebContents
*>(CreateTestWebContents()));
3565 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3566 other_contents
->NavigateAndCommit(url2a
);
3567 // Simulate a client redirect, which has the same page ID as entry 2a.
3568 other_controller
.LoadURL(
3569 url2b
, Referrer(), PAGE_TRANSITION_LINK
, std::string());
3570 other_controller
.GetPendingEntry()->SetPageID(
3571 other_controller
.GetLastCommittedEntry()->GetPageID());
3573 other_contents
->ExpectSetHistoryLengthAndPrune(
3574 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3575 other_controller
.GetEntryAtIndex(0)->GetPageID());
3576 other_controller
.CopyStateFromAndPrune(&controller
, false);
3578 // other_controller should now contain url1, url2a, and a pending entry
3581 ASSERT_EQ(2, other_controller
.GetEntryCount());
3582 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
3584 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3585 EXPECT_EQ(url2a
, other_controller
.GetEntryAtIndex(1)->GetURL());
3587 // And there should be a pending entry for url4.
3588 ASSERT_TRUE(other_controller
.GetPendingEntry());
3589 EXPECT_EQ(url2b
, other_controller
.GetPendingEntry()->GetURL());
3591 // Let the pending entry commit.
3592 other_contents
->CommitPendingNavigation();
3594 // The max page ID map should be copied over and updated with the max page ID
3595 // from the current tab.
3596 SiteInstance
* instance1
=
3597 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1));
3598 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3601 // Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
3602 // source, and 1 entry in the target. The back pending entry should be ignored.
3603 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneSourcePending
) {
3604 NavigationControllerImpl
& controller
= controller_impl();
3605 const GURL
url1("http://foo1");
3606 const GURL
url2("http://foo2");
3607 const GURL
url3("http://foo3");
3609 NavigateAndCommit(url1
);
3610 NavigateAndCommit(url2
);
3611 controller
.GoBack();
3613 scoped_ptr
<TestWebContents
> other_contents(
3614 static_cast<TestWebContents
*>(CreateTestWebContents()));
3615 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3616 other_contents
->NavigateAndCommit(url3
);
3617 other_contents
->ExpectSetHistoryLengthAndPrune(
3618 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3619 other_controller
.GetEntryAtIndex(0)->GetPageID());
3620 other_controller
.CopyStateFromAndPrune(&controller
, false);
3622 // other_controller should now contain: url1, url2, url3
3624 ASSERT_EQ(3, other_controller
.GetEntryCount());
3625 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3627 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3628 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3629 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3630 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3632 // The max page ID map should be copied over and updated with the max page ID
3633 // from the current tab.
3634 SiteInstance
* instance1
=
3635 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3636 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3639 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
3640 // when the max entry count is 3. We should prune one entry.
3641 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneMaxEntries
) {
3642 NavigationControllerImpl
& controller
= controller_impl();
3643 size_t original_count
= NavigationControllerImpl::max_entry_count();
3644 const int kMaxEntryCount
= 3;
3646 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
3648 const GURL
url1("http://foo/1");
3649 const GURL
url2("http://foo/2");
3650 const GURL
url3("http://foo/3");
3651 const GURL
url4("http://foo/4");
3653 // Create a PrunedListener to observe prune notifications.
3654 PrunedListener
listener(&controller
);
3656 NavigateAndCommit(url1
);
3657 NavigateAndCommit(url2
);
3658 NavigateAndCommit(url3
);
3660 scoped_ptr
<TestWebContents
> other_contents(
3661 static_cast<TestWebContents
*>(CreateTestWebContents()));
3662 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3663 other_contents
->NavigateAndCommit(url4
);
3664 other_contents
->ExpectSetHistoryLengthAndPrune(
3665 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3666 other_controller
.GetEntryAtIndex(0)->GetPageID());
3667 other_controller
.CopyStateFromAndPrune(&controller
, false);
3669 // We should have received a pruned notification.
3670 EXPECT_EQ(1, listener
.notification_count_
);
3671 EXPECT_TRUE(listener
.details_
.from_front
);
3672 EXPECT_EQ(1, listener
.details_
.count
);
3674 // other_controller should now contain only 3 urls: url2, url3 and url4.
3676 ASSERT_EQ(3, other_controller
.GetEntryCount());
3678 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3680 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(0)->GetURL());
3681 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3682 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3683 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(0)->GetPageID());
3684 EXPECT_EQ(2, other_controller
.GetEntryAtIndex(1)->GetPageID());
3685 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3687 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
3690 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest, with
3691 // replace_entry set to true.
3692 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneReplaceEntry
) {
3693 NavigationControllerImpl
& controller
= controller_impl();
3694 const GURL
url1("http://foo/1");
3695 const GURL
url2("http://foo/2");
3696 const GURL
url3("http://foo/3");
3698 NavigateAndCommit(url1
);
3699 NavigateAndCommit(url2
);
3701 // First two entries should have the same SiteInstance.
3702 SiteInstance
* instance1
=
3703 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0));
3704 SiteInstance
* instance2
=
3705 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(1));
3706 EXPECT_EQ(instance1
, instance2
);
3707 EXPECT_EQ(0, controller
.GetEntryAtIndex(0)->GetPageID());
3708 EXPECT_EQ(1, controller
.GetEntryAtIndex(1)->GetPageID());
3709 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1
));
3711 scoped_ptr
<TestWebContents
> other_contents(
3712 static_cast<TestWebContents
*>(CreateTestWebContents()));
3713 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3714 other_contents
->NavigateAndCommit(url3
);
3715 other_contents
->ExpectSetHistoryLengthAndPrune(
3716 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3717 other_controller
.GetEntryAtIndex(0)->GetPageID());
3718 other_controller
.CopyStateFromAndPrune(&controller
, true);
3720 // other_controller should now contain the 2 urls: url1 and url3.
3722 ASSERT_EQ(2, other_controller
.GetEntryCount());
3724 ASSERT_EQ(1, other_controller
.GetCurrentEntryIndex());
3726 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3727 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3728 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3729 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3731 // A new SiteInstance in a different BrowsingInstance should be used for the
3733 SiteInstance
* instance3
=
3734 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1));
3735 EXPECT_NE(instance3
, instance1
);
3736 EXPECT_FALSE(instance3
->IsRelatedSiteInstance(instance1
));
3738 // The max page ID map should be copied over and updated with the max page ID
3739 // from the current tab.
3740 EXPECT_EQ(1, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3741 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance3
));
3744 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest, when the max
3745 // entry count is 3 and replace_entry is true. We should not prune entries.
3746 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneMaxEntriesReplaceEntry
) {
3747 NavigationControllerImpl
& controller
= controller_impl();
3748 size_t original_count
= NavigationControllerImpl::max_entry_count();
3749 const int kMaxEntryCount
= 3;
3751 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
3753 const GURL
url1("http://foo/1");
3754 const GURL
url2("http://foo/2");
3755 const GURL
url3("http://foo/3");
3756 const GURL
url4("http://foo/4");
3758 // Create a PrunedListener to observe prune notifications.
3759 PrunedListener
listener(&controller
);
3761 NavigateAndCommit(url1
);
3762 NavigateAndCommit(url2
);
3763 NavigateAndCommit(url3
);
3765 scoped_ptr
<TestWebContents
> other_contents(
3766 static_cast<TestWebContents
*>(CreateTestWebContents()));
3767 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3768 other_contents
->NavigateAndCommit(url4
);
3769 other_contents
->ExpectSetHistoryLengthAndPrune(
3770 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3771 other_controller
.GetEntryAtIndex(0)->GetPageID());
3772 other_controller
.CopyStateFromAndPrune(&controller
, true);
3774 // We should have received no pruned notification.
3775 EXPECT_EQ(0, listener
.notification_count_
);
3777 // other_controller should now contain only 3 urls: url1, url2 and url4.
3779 ASSERT_EQ(3, other_controller
.GetEntryCount());
3781 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3783 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3784 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3785 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3786 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3787 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(1)->GetPageID());
3788 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3790 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
3793 // Tests that we can navigate to the restored entries
3794 // imported by CopyStateFromAndPrune.
3795 TEST_F(NavigationControllerTest
, CopyRestoredStateAndNavigate
) {
3796 const GURL kRestoredUrls
[] = {
3797 GURL("http://site1.com"),
3798 GURL("http://site2.com"),
3800 const GURL
kInitialUrl("http://site3.com");
3802 std::vector
<NavigationEntry
*> entries
;
3803 for (size_t i
= 0; i
< arraysize(kRestoredUrls
); ++i
) {
3804 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
3805 kRestoredUrls
[i
], Referrer(), PAGE_TRANSITION_RELOAD
, false,
3806 std::string(), browser_context());
3807 entry
->SetPageID(static_cast<int>(i
));
3808 entries
.push_back(entry
);
3811 // Create a WebContents with restored entries.
3812 scoped_ptr
<TestWebContents
> source_contents(
3813 static_cast<TestWebContents
*>(CreateTestWebContents()));
3814 NavigationControllerImpl
& source_controller
=
3815 source_contents
->GetController();
3816 source_controller
.Restore(
3818 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
3820 ASSERT_EQ(0u, entries
.size());
3821 source_controller
.LoadIfNecessary();
3822 source_contents
->CommitPendingNavigation();
3824 // Load a page, then copy state from |source_contents|.
3825 NavigateAndCommit(kInitialUrl
);
3826 contents()->ExpectSetHistoryLengthAndPrune(
3827 GetSiteInstanceFromEntry(controller_impl().GetEntryAtIndex(0)), 2,
3828 controller_impl().GetEntryAtIndex(0)->GetPageID());
3829 controller_impl().CopyStateFromAndPrune(&source_controller
, false);
3830 ASSERT_EQ(3, controller_impl().GetEntryCount());
3832 // Go back to the first entry one at a time and
3833 // verify that it works as expected.
3834 EXPECT_EQ(2, controller_impl().GetCurrentEntryIndex());
3835 EXPECT_EQ(kInitialUrl
, controller_impl().GetActiveEntry()->GetURL());
3837 controller_impl().GoBack();
3838 contents()->CommitPendingNavigation();
3839 EXPECT_EQ(1, controller_impl().GetCurrentEntryIndex());
3840 EXPECT_EQ(kRestoredUrls
[1], controller_impl().GetActiveEntry()->GetURL());
3842 controller_impl().GoBack();
3843 contents()->CommitPendingNavigation();
3844 EXPECT_EQ(0, controller_impl().GetCurrentEntryIndex());
3845 EXPECT_EQ(kRestoredUrls
[0], controller_impl().GetActiveEntry()->GetURL());
3848 // Tests that navigations initiated from the page (with the history object)
3849 // work as expected, creating pending entries.
3850 TEST_F(NavigationControllerTest
, HistoryNavigate
) {
3851 NavigationControllerImpl
& controller
= controller_impl();
3852 const GURL
url1("http://foo/1");
3853 const GURL
url2("http://foo/2");
3854 const GURL
url3("http://foo/3");
3856 NavigateAndCommit(url1
);
3857 NavigateAndCommit(url2
);
3858 NavigateAndCommit(url3
);
3859 controller
.GoBack();
3860 contents()->CommitPendingNavigation();
3862 // Simulate the page calling history.back(). It should create a pending entry.
3863 contents()->OnGoToEntryAtOffset(-1);
3864 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
3865 // The actual cross-navigation is suspended until the current RVH tells us
3866 // it unloaded, simulate that.
3867 contents()->ProceedWithCrossSiteNavigation();
3868 // Also make sure we told the page to navigate.
3869 const IPC::Message
* message
=
3870 process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID
);
3871 ASSERT_TRUE(message
!= NULL
);
3872 Tuple1
<FrameMsg_Navigate_Params
> nav_params
;
3873 FrameMsg_Navigate::Read(message
, &nav_params
);
3874 EXPECT_EQ(url1
, nav_params
.a
.url
);
3875 process()->sink().ClearMessages();
3877 // Now test history.forward()
3878 contents()->OnGoToEntryAtOffset(2);
3879 EXPECT_EQ(2, controller
.GetPendingEntryIndex());
3880 // The actual cross-navigation is suspended until the current RVH tells us
3881 // it unloaded, simulate that.
3882 contents()->ProceedWithCrossSiteNavigation();
3883 message
= process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID
);
3884 ASSERT_TRUE(message
!= NULL
);
3885 FrameMsg_Navigate::Read(message
, &nav_params
);
3886 EXPECT_EQ(url3
, nav_params
.a
.url
);
3887 process()->sink().ClearMessages();
3889 controller
.DiscardNonCommittedEntries();
3891 // Make sure an extravagant history.go() doesn't break.
3892 contents()->OnGoToEntryAtOffset(120); // Out of bounds.
3893 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3894 message
= process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID
);
3895 EXPECT_TRUE(message
== NULL
);
3898 // Test call to PruneAllButLastCommitted for the only entry.
3899 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForSingle
) {
3900 NavigationControllerImpl
& controller
= controller_impl();
3901 const GURL
url1("http://foo1");
3902 NavigateAndCommit(url1
);
3904 contents()->ExpectSetHistoryLengthAndPrune(
3905 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0)), 0,
3906 controller
.GetEntryAtIndex(0)->GetPageID());
3908 controller
.PruneAllButLastCommitted();
3910 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3911 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
3914 // Test call to PruneAllButLastCommitted for first entry.
3915 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForFirst
) {
3916 NavigationControllerImpl
& controller
= controller_impl();
3917 const GURL
url1("http://foo/1");
3918 const GURL
url2("http://foo/2");
3919 const GURL
url3("http://foo/3");
3921 NavigateAndCommit(url1
);
3922 NavigateAndCommit(url2
);
3923 NavigateAndCommit(url3
);
3924 controller
.GoBack();
3925 controller
.GoBack();
3926 contents()->CommitPendingNavigation();
3928 contents()->ExpectSetHistoryLengthAndPrune(
3929 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0)), 0,
3930 controller
.GetEntryAtIndex(0)->GetPageID());
3932 controller
.PruneAllButLastCommitted();
3934 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3935 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
3938 // Test call to PruneAllButLastCommitted for intermediate entry.
3939 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForIntermediate
) {
3940 NavigationControllerImpl
& controller
= controller_impl();
3941 const GURL
url1("http://foo/1");
3942 const GURL
url2("http://foo/2");
3943 const GURL
url3("http://foo/3");
3945 NavigateAndCommit(url1
);
3946 NavigateAndCommit(url2
);
3947 NavigateAndCommit(url3
);
3948 controller
.GoBack();
3949 contents()->CommitPendingNavigation();
3951 contents()->ExpectSetHistoryLengthAndPrune(
3952 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(1)), 0,
3953 controller
.GetEntryAtIndex(1)->GetPageID());
3955 controller
.PruneAllButLastCommitted();
3957 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3958 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url2
);
3961 // Test call to PruneAllButLastCommitted for a pending entry that is not yet in
3962 // the list of entries.
3963 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForPendingNotInList
) {
3964 NavigationControllerImpl
& controller
= controller_impl();
3965 const GURL
url1("http://foo/1");
3966 const GURL
url2("http://foo/2");
3967 const GURL
url3("http://foo/3");
3969 NavigateAndCommit(url1
);
3970 NavigateAndCommit(url2
);
3972 // Create a pending entry that is not in the entry list.
3974 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3975 EXPECT_TRUE(controller
.GetPendingEntry());
3976 EXPECT_EQ(2, controller
.GetEntryCount());
3978 contents()->ExpectSetHistoryLengthAndPrune(
3979 NULL
, 0, controller
.GetPendingEntry()->GetPageID());
3980 controller
.PruneAllButLastCommitted();
3982 // We should only have the last committed and pending entries at this point,
3983 // and the pending entry should still not be in the entry list.
3984 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
3985 EXPECT_EQ(url2
, controller
.GetEntryAtIndex(0)->GetURL());
3986 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3987 EXPECT_TRUE(controller
.GetPendingEntry());
3988 EXPECT_EQ(1, controller
.GetEntryCount());
3990 // Try to commit the pending entry.
3991 main_test_rfh()->SendNavigate(2, url3
);
3992 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3993 EXPECT_FALSE(controller
.GetPendingEntry());
3994 EXPECT_EQ(2, controller
.GetEntryCount());
3995 EXPECT_EQ(url3
, controller
.GetEntryAtIndex(1)->GetURL());
3998 // Test to ensure that when we do a history navigation back to the current
3999 // committed page (e.g., going forward to a slow-loading page, then pressing
4000 // the back button), we just stop the navigation to prevent the throbber from
4001 // running continuously. Otherwise, the RenderViewHost forces the throbber to
4002 // start, but WebKit essentially ignores the navigation and never sends a
4003 // message to stop the throbber.
4004 TEST_F(NavigationControllerTest
, StopOnHistoryNavigationToCurrentPage
) {
4005 NavigationControllerImpl
& controller
= controller_impl();
4006 const GURL
url0("http://foo/0");
4007 const GURL
url1("http://foo/1");
4009 NavigateAndCommit(url0
);
4010 NavigateAndCommit(url1
);
4012 // Go back to the original page, then forward to the slow page, then back
4013 controller
.GoBack();
4014 contents()->CommitPendingNavigation();
4016 controller
.GoForward();
4017 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
4019 controller
.GoBack();
4020 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4023 TEST_F(NavigationControllerTest
, IsInitialNavigation
) {
4024 NavigationControllerImpl
& controller
= controller_impl();
4025 TestNotificationTracker notifications
;
4026 RegisterForAllNavNotifications(¬ifications
, &controller
);
4029 EXPECT_TRUE(controller
.IsInitialNavigation());
4031 // After commit, it stays false.
4032 const GURL
url1("http://foo1");
4033 main_test_rfh()->SendNavigate(0, url1
);
4034 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4035 navigation_entry_committed_counter_
= 0;
4036 EXPECT_FALSE(controller
.IsInitialNavigation());
4038 // After starting a new navigation, it stays false.
4039 const GURL
url2("http://foo2");
4041 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
4044 // Check that the favicon is not reused across a client redirect.
4045 // (crbug.com/28515)
4046 TEST_F(NavigationControllerTest
, ClearFaviconOnRedirect
) {
4047 const GURL
kPageWithFavicon("http://withfavicon.html");
4048 const GURL
kPageWithoutFavicon("http://withoutfavicon.html");
4049 const GURL
kIconURL("http://withfavicon.ico");
4050 const gfx::Image kDefaultFavicon
= FaviconStatus().image
;
4052 NavigationControllerImpl
& controller
= controller_impl();
4053 TestNotificationTracker notifications
;
4054 RegisterForAllNavNotifications(¬ifications
, &controller
);
4056 main_test_rfh()->SendNavigate(0, kPageWithFavicon
);
4057 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4058 navigation_entry_committed_counter_
= 0;
4060 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
4062 EXPECT_EQ(kPageWithFavicon
, entry
->GetURL());
4064 // Simulate Chromium having set the favicon for |kPageWithFavicon|.
4065 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
4066 favicon_status
.image
= CreateImage(SK_ColorWHITE
);
4067 favicon_status
.url
= kIconURL
;
4068 favicon_status
.valid
= true;
4069 EXPECT_FALSE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
4071 main_test_rfh()->SendNavigateWithTransition(
4073 kPageWithoutFavicon
,
4074 PAGE_TRANSITION_CLIENT_REDIRECT
);
4075 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4076 navigation_entry_committed_counter_
= 0;
4078 entry
= controller
.GetLastCommittedEntry();
4080 EXPECT_EQ(kPageWithoutFavicon
, entry
->GetURL());
4082 EXPECT_TRUE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
4085 // Check that the favicon is not cleared for NavigationEntries which were
4086 // previously navigated to.
4087 TEST_F(NavigationControllerTest
, BackNavigationDoesNotClearFavicon
) {
4088 const GURL
kUrl1("http://www.a.com/1");
4089 const GURL
kUrl2("http://www.a.com/2");
4090 const GURL
kIconURL("http://www.a.com/1/favicon.ico");
4092 NavigationControllerImpl
& controller
= controller_impl();
4093 TestNotificationTracker notifications
;
4094 RegisterForAllNavNotifications(¬ifications
, &controller
);
4096 main_test_rfh()->SendNavigate(0, kUrl1
);
4097 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4098 navigation_entry_committed_counter_
= 0;
4100 // Simulate Chromium having set the favicon for |kUrl1|.
4101 gfx::Image favicon_image
= CreateImage(SK_ColorWHITE
);
4102 content::NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
4104 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
4105 favicon_status
.image
= favicon_image
;
4106 favicon_status
.url
= kIconURL
;
4107 favicon_status
.valid
= true;
4109 // Navigate to another page and go back to the original page.
4110 main_test_rfh()->SendNavigate(1, kUrl2
);
4111 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4112 navigation_entry_committed_counter_
= 0;
4113 main_test_rfh()->SendNavigateWithTransition(
4116 PAGE_TRANSITION_FORWARD_BACK
);
4117 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4118 navigation_entry_committed_counter_
= 0;
4120 // Verify that the favicon for the page at |kUrl1| was not cleared.
4121 entry
= controller
.GetEntryAtIndex(0);
4123 EXPECT_EQ(kUrl1
, entry
->GetURL());
4124 EXPECT_TRUE(DoImagesMatch(favicon_image
, entry
->GetFavicon().image
));
4127 // The test crashes on android: http://crbug.com/170449
4128 #if defined(OS_ANDROID)
4129 #define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
4131 #define MAYBE_PurgeScreenshot PurgeScreenshot
4133 // Tests that screenshot are purged correctly.
4134 TEST_F(NavigationControllerTest
, MAYBE_PurgeScreenshot
) {
4135 NavigationControllerImpl
& controller
= controller_impl();
4137 NavigationEntryImpl
* entry
;
4139 // Navigate enough times to make sure that some screenshots are purged.
4140 for (int i
= 0; i
< 12; ++i
) {
4141 const GURL
url(base::StringPrintf("http://foo%d/", i
));
4142 NavigateAndCommit(url
);
4143 EXPECT_EQ(i
, controller
.GetCurrentEntryIndex());
4146 MockScreenshotManager
* screenshot_manager
=
4147 new MockScreenshotManager(&controller
);
4148 controller
.SetScreenshotManager(screenshot_manager
);
4149 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
4150 entry
= NavigationEntryImpl::FromNavigationEntry(
4151 controller
.GetEntryAtIndex(i
));
4152 screenshot_manager
->TakeScreenshotFor(entry
);
4153 EXPECT_TRUE(entry
->screenshot().get());
4156 NavigateAndCommit(GURL("https://foo/"));
4157 EXPECT_EQ(13, controller
.GetEntryCount());
4158 entry
= NavigationEntryImpl::FromNavigationEntry(
4159 controller
.GetEntryAtIndex(11));
4160 screenshot_manager
->TakeScreenshotFor(entry
);
4162 for (int i
= 0; i
< 2; ++i
) {
4163 entry
= NavigationEntryImpl::FromNavigationEntry(
4164 controller
.GetEntryAtIndex(i
));
4165 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
4169 for (int i
= 2; i
< controller
.GetEntryCount() - 1; ++i
) {
4170 entry
= NavigationEntryImpl::FromNavigationEntry(
4171 controller
.GetEntryAtIndex(i
));
4172 EXPECT_TRUE(entry
->screenshot().get()) << "Screenshot not found for " << i
;
4175 // Navigate to index 5 and then try to assign screenshot to all entries.
4176 controller
.GoToIndex(5);
4177 contents()->CommitPendingNavigation();
4178 EXPECT_EQ(5, controller
.GetCurrentEntryIndex());
4179 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
4180 entry
= NavigationEntryImpl::FromNavigationEntry(
4181 controller
.GetEntryAtIndex(i
));
4182 screenshot_manager
->TakeScreenshotFor(entry
);
4185 for (int i
= 10; i
<= 12; ++i
) {
4186 entry
= NavigationEntryImpl::FromNavigationEntry(
4187 controller
.GetEntryAtIndex(i
));
4188 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
4190 screenshot_manager
->TakeScreenshotFor(entry
);
4193 // Navigate to index 7 and assign screenshot to all entries.
4194 controller
.GoToIndex(7);
4195 contents()->CommitPendingNavigation();
4196 EXPECT_EQ(7, controller
.GetCurrentEntryIndex());
4197 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
4198 entry
= NavigationEntryImpl::FromNavigationEntry(
4199 controller
.GetEntryAtIndex(i
));
4200 screenshot_manager
->TakeScreenshotFor(entry
);
4203 for (int i
= 0; i
< 2; ++i
) {
4204 entry
= NavigationEntryImpl::FromNavigationEntry(
4205 controller
.GetEntryAtIndex(i
));
4206 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
4210 // Clear all screenshots.
4211 EXPECT_EQ(13, controller
.GetEntryCount());
4212 EXPECT_EQ(10, screenshot_manager
->GetScreenshotCount());
4213 controller
.ClearAllScreenshots();
4214 EXPECT_EQ(0, screenshot_manager
->GetScreenshotCount());
4215 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
4216 entry
= NavigationEntryImpl::FromNavigationEntry(
4217 controller
.GetEntryAtIndex(i
));
4218 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
4223 TEST_F(NavigationControllerTest
, PushStateUpdatesTitle
) {
4226 test_rvh()->SendNavigate(1, GURL("http://foo"));
4229 base::string16
title(base::ASCIIToUTF16("Title"));
4230 controller().GetLastCommittedEntry()->SetTitle(title
);
4232 // history.pushState() is called.
4233 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
4234 GURL
url("http://foo#foo");
4237 params
.page_state
= PageState::CreateFromURL(url
);
4238 params
.was_within_same_page
= true;
4239 test_rvh()->SendNavigateWithParams(¶ms
);
4241 // The title should immediately be visible on the new NavigationEntry.
4242 base::string16 new_title
=
4243 controller().GetLastCommittedEntry()->GetTitleForDisplay(std::string());
4244 EXPECT_EQ(title
, new_title
);
4247 // Test that the navigation controller clears its session history when a
4248 // navigation commits with the clear history list flag set.
4249 TEST_F(NavigationControllerTest
, ClearHistoryList
) {
4250 const GURL
url1("http://foo1");
4251 const GURL
url2("http://foo2");
4252 const GURL
url3("http://foo3");
4253 const GURL
url4("http://foo4");
4255 NavigationControllerImpl
& controller
= controller_impl();
4257 // Create a session history with three entries, second entry is active.
4258 NavigateAndCommit(url1
);
4259 NavigateAndCommit(url2
);
4260 NavigateAndCommit(url3
);
4261 controller
.GoBack();
4262 contents()->CommitPendingNavigation();
4263 EXPECT_EQ(3, controller
.GetEntryCount());
4264 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
4266 // Create a new pending navigation, and indicate that the session history
4267 // should be cleared.
4268 NavigationController::LoadURLParams
params(url4
);
4269 params
.should_clear_history_list
= true;
4270 controller
.LoadURLWithParams(params
);
4272 // Verify that the pending entry correctly indicates that the session history
4273 // should be cleared.
4274 NavigationEntryImpl
* entry
=
4275 NavigationEntryImpl::FromNavigationEntry(
4276 controller
.GetPendingEntry());
4278 EXPECT_TRUE(entry
->should_clear_history_list());
4280 // Assume that the RV correctly cleared its history and commit the navigation.
4281 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost())->
4282 set_simulate_history_list_was_cleared(true);
4283 contents()->CommitPendingNavigation();
4285 // Verify that the NavigationController's session history was correctly
4287 EXPECT_EQ(1, controller
.GetEntryCount());
4288 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
4289 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
4290 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4291 EXPECT_FALSE(controller
.CanGoBack());
4292 EXPECT_FALSE(controller
.CanGoForward());
4293 EXPECT_EQ(url4
, controller
.GetVisibleEntry()->GetURL());
4296 TEST_F(NavigationControllerTest
, PostThenReplaceStateThenReload
) {
4297 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
4298 EXPECT_FALSE(contents()->GetDelegate());
4299 contents()->SetDelegate(delegate
.get());
4302 GURL
url("http://foo");
4303 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
4306 params
.transition
= PAGE_TRANSITION_FORM_SUBMIT
;
4307 params
.gesture
= NavigationGestureUser
;
4308 params
.page_state
= PageState::CreateFromURL(url
);
4309 params
.was_within_same_page
= false;
4310 params
.is_post
= true;
4312 test_rvh()->SendNavigateWithParams(¶ms
);
4314 // history.replaceState() is called.
4315 GURL
replace_url("http://foo#foo");
4317 params
.url
= replace_url
;
4318 params
.transition
= PAGE_TRANSITION_LINK
;
4319 params
.gesture
= NavigationGestureUser
;
4320 params
.page_state
= PageState::CreateFromURL(replace_url
);
4321 params
.was_within_same_page
= true;
4322 params
.is_post
= false;
4323 params
.post_id
= -1;
4324 test_rvh()->SendNavigateWithParams(¶ms
);
4326 // Now reload. replaceState overrides the POST, so we should not show a
4327 // repost warning dialog.
4328 controller_impl().Reload(true);
4329 EXPECT_EQ(0, delegate
->repost_form_warning_count());
4332 } // namespace content